Working principle of the algorithm:
Initially, the user draws a rectangle around the foreground area (the foreground area should be completely located in the rectangular part). Then, the algorithm will segment it iteratively to obtain the best result. Done, but in some cases, the segmentation may not be good. For example, some foreground areas may have been marked as background, and vice versa. In this case, users need to refine. Just draw some strokes on the wrong segmentation area of the image. Then, in the next iteration, better results will be obtained.
It is mainly implemented using the cv.grabCut() function.
grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode) -> mask, bgdModel, fgdModel
The parameters are as follows:
- img: input image
- Mask: input / output mask, which is a mask image in which we specify which areas are background, foreground or possible background / foreground, etc. This is done with the following flags: cv.GC_BGD,cv.GC_FGD,
cv.GC_PR_BGD,cv.GC_PR_FGD, or pass 0,1,2,3 directly to the image - rect: rectangular coordinates of the border of the area to be divided. The format is (x,y,w,h). This parameter is only available when the mode is set to cv2.gc_ INIT_ WITH_ Used in mask
- bgdModel: a temporary array used when modeling the background inside the GrabCut
- fgdModel: a temporary array used by GrabCut when modeling the foreground
- iterCount: the number of iterations that GrabCut performs when modeling the foreground and background. The more iterations, the longer the GrabCut runs, and ideally the results will be better
- model: cv2.GC_INIT_WITH_RECT or cv2.GC_INIT_WITH_MASK, depending on whether the GrabCut is initialized with a border or a mask
- The GrabCut implementation of OpenCV returns a 3-tuple:
Mask: output mask after applying GrabCut
fgdMode: temporary array for modeling background (this value can be ignored)
fgdModel: temporary array for modeling foreground (this value can be ignored)
Code example:
from matplotlib import pyplot as plt import numpy as np import cv2 as cv img = cv.imread('C:\\Users\\dell\\Desktop\\prac files\\prac19.jpg') mask = np.zeros(img.shape[:2], np.uint8) bgdModel = np.zeros((1, 65), np.float64) fgdModel = np.zeros((1, 65), np.float64) rect = (100, 100, 700, 500) cv.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv.GC_INIT_WITH_RECT) mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8') img = img*mask2[:, :, np.newaxis] #cv.imwrite("result.jpg", img) plt.imshow(img), plt.colorbar(), plt.show()
There will be some errors in the results, some backgrounds are left, and some foreground is used as the background. Therefore, 1 pixel (to ensure the foreground) will be used for fine decoration. At the same time, some unnecessary ground also appears in the picture and need to be deleted. There, give some 0 pixel decoration (ensure the background). Here, you can directly enter the mask mode without directly initializing in the rect mode. Only 2 or 3 pixels (possible background / foreground) are needed to mark the rectangular area in the mask image. Then, as in the second example, put sure_foreground is marked as 1 pixel. Then directly apply the grabCut function in mask mode.
Code example:
#newmask is a manually marked image newmask = cv.imread('C:\\Users\\dell\\Desktop\\prac files\\newmask.jpg', 0) # Where marked white (ensure foreground), change mask = 1 # Where marked black (ensure background), change mask = 0 mask[newmask == 0] = 0 mask[newmask == 255] = 1 mask, bgdModel, fgdModel = cv.grabCut(img, mask, None, bgdModel, fgdModel, 5, cv.GC_INIT_WITH_MASK) mask = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8') img = img*mask[:, :, np.newaxis] plt.imshow(img), plt.colorbar(), plt.show()