最近接了个抠图的功能,要求像这样子让用户把轮廓圈一下,把前景抠出来。这里用的是OpenCV的GrabCut算法。
void grabCut(InputArrayimg,InputOutputArraymask,Rectrect,InputOutputArraybgdModel,InputOutputArrayfgdModel,intiterCount,intmode=GC_EVAL)
Parameters:
img – Input 8-bit 3-channel image.
mask –Input/output 8-bit single-channel mask. The mask is initialized by the function when mode is set to GC_INIT_WITH_RECT. Its elements may have one of following values:
GC_BGD defines an obvious background pixels.
GC_FGD defines an obvious foreground (object) pixel.
GC_PR_BGD defines a possible background pixel.
GC_PR_FGD defines a possible foreground pixel.
rect – ROI containing a segmented object. The pixels outside of the ROI are marked as “obvious background”. The parameter is only used when mode==GC_INIT_WITH_RECT .
bgdModel – Temporary array for the background model. Do not modify it while you are processing the same image.
fgdModel – Temporary arrays for the foreground model. Do not modify it while you are processing the same image.
iterCount – Number of iterations the algorithm should make before returning the result. Note that the result can be refined with further calls with mode==GC_INIT_WITH_MASK or mode==GC_EVAL .
mode –Operation mode that could be one of the following:
GC_INIT_WITH_RECT The function initializes the state and the mask using the provided rectangle. After that it runs iterCount iterations of the algorithm.
GC_INIT_WITH_MASK The function initializes the state using the provided mask. Note that GC_INIT_WITH_RECT and GC_INIT_WITH_MASK can be combined. Then, all the pixels outside of the ROI are automatically initialized with GC_BGD .
GC_EVAL The value means that the algorithm should just resume.
传入的img是原图(CV_8UC3格式),mask是用户标记的前景和背景信息(矩阵中只含以上四种取值),rect是用户选中的感兴趣区域(ROI),bgdModel和fgdModel是临时数组(对同一张图片进行编辑时不要修改),iterCount是迭代次数,mode是运行模式(初始化或者不是初始化)。
总之,就是要用cv::GC_INIT_WITH_MASK模式去初始化,传入原图和用户圈出来的轮廓图。
用户圈完轮廓之后,用cv::findContours()生成一张类似这样的图。轮廓外部标记为已知背景,轮廓内部标记为已知前景,轮廓标记为未知。
初始化完之后,将mask和1做与,然后将原图copyTo一下,就能得到抠出来的图片。
alphaMask = mask & 1;
src.copyTo(dst, alphaMask);
第一次出来的结果可能会有些地方没分好,这时候用户再手动标记一下,用cv::GC_EVAL继续运行就好了。
Win10的画图3D有个神奇选择功能,就是grabCut算法这个流程的,要先框出ROI,有兴趣的可以尝试一下。