zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【youcans 的 OpenCV 例程200篇】178.图像分割之 GrabCut 图割法(框选前景)

Opencv 图像 分割 200 例程 前景 youcans
2023-09-14 09:12:51 时间

【youcans 的 OpenCV 例程200篇】176.图像分割之均值漂移算法
【youcans 的 OpenCV 例程200篇】177.图像分割之 GraphCuts 图割法
【youcans 的 OpenCV 例程200篇】178.图像分割之 GrabCut 图割法(框选前景)
【youcans 的 OpenCV 例程200篇】179.图像分割之 GrabCut 图割法(掩模图像)
更多内容,请见:
【OpenCV 例程200篇 总目录-202206更新】


【youcans 的 OpenCV 例程200篇】178.图像分割之 GrabCut 图割法(框选前景)


6. 图像分割之图割法

基于图论的图像分割技术的基本思想是:将图像映射为带权的无向图,把像素视为节点,两个节点之间的边的权重对应于两个像素之间相似性的度量,割的容量就对应于能量函数;使用最大流最小割算法对图进行切割,得到的最小割就对应于最优图像分割。


6.3 图割分割算法 GrabCut

GrabCut 算法是对 GraphCut 的改进,使用高斯混合模型(GMM)对背景和目标建立模型,采用迭代方法实现分割能量的最小化,同时支持不完整的标记。

GrabCut 算法有效利用了图像中的纹理(颜色)信息和边界(反差)信息,只需要要少量的人工交互操作就可以对目标实现较好的分割效果。

GrabCut 与 GraphCut 的区别主要是:
(1)GraphCut 中目标和背景模型是基于灰度直方图,GrabCut 中使用三通道混合高斯模型GMM 取代;
(2)GraphCut 中直接求解能量最小化(分割),GrabCut 采用不断进行分割估计和模型参数学习的交互迭代过程;
(3)GraphCut 需要用户指定目标和背景的一些种子点,而 GrabCut 只要框选目标来提供背景区域的像素集,即允许不完全的标注(incomplete labelling)。

GrabCut 的优点是:
(1)交互简单,只要在目标外面画一个框来框选目标,就可以实现良好的分割效果;
(2)如果增加用户交互(指定一些属于目标的像素),可以得到更好的分割效果;
(3)Border Matting 技术使目标分割边界更加自然和完美。

GrabCut算法的工作原理是:

(1)指定图像中包含分割目标的矩形边界框,矩形框以外的区域被认为是“确定背景”。
(2)根据矩形框外部的“确定背景”的数据,来划分矩形框区域内的前景和背景。
(3)用高斯混合模型(Gaussians Mixture Model)对前景和背景建模,估计前景和背景的颜色分布。
(4)根据像素分布生成带有前景节点和背景节点的连通图(Graph),每个像素连接到前景节点或背景节点的边的权重,由像素是前景或背景的概率来决定。
(5)图像分割问题转换为图割问题,使用最大流最小割算法对图进行切割。
(6)重复上述过程,直至达到收敛条件或迭代次数。

OpenCV 也提供了函数 cv.grabCut 实现 GrabCut 图割算法。

函数说明:

cv.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode=GC_EVAL]) → mask, bgdModel, fgdModel 

参数说明:

  • image:输入图像,8-bit/3-channel 彩色图像
  • mask:输入/输出掩模,8-bit 单通道图像,如边界框选则自动产生掩模图像
  • rect:包含分割对象的边框矩形,格式为 (x,y,w,h),仅在 mode 为 cv2.GC_INIT_WITH_MASK 时适用
  • bgdModel:建模背景使用的临时数组,形状为 (1,65) 的 np.float 数组
  • fgdModel:建模前景时使用的临时数组,形状为 (1,65) 的 np.float 数组
  • iterCount:迭代次数
  • mode:操作模式
    • cv.GC_INIT_WITH_RECT:使用边界矩形初始化状态和掩模图像,运行迭代算法
    • cv.GC_INIT_WITH_MASK:使用提供的掩模图像进行状态初始化
    • cv.GC_EVAL:表示算法应该恢复
    • cv.GC_EVAL_FREEZE_MODEL:用固定模型执行一次迭代算法

OpenCV 的 GrabCut 返回一个3元组 (mask, bgdModel, fgdModel)

  • mask: 应用GrabCut后的输出掩模
  • bgModel: 用于建模背景的临时数组(可以忽略此值)
  • fgModel: 用于建模前景的临时数组(同样,你可以忽略此值)

注意事项:

  • OpenCV 的 GrabCut 返回元组 (mask, bgdModel, fgdModel),mask 是应用 GrabCut 算法后的输出掩模。
  • 迭代次数越多,GrabCut 运行的时间越长,理想情况下的性能会更好。
  • cv.GC_INIT_WITH_RECT 和 cv.GC_INIT_WITH_MASK 可以组合使用。

例程 11.35: GrabCut 图割分割算法(框选前景)

本例用 OpenCV 实现 GrabCut,显示原始图像,在图像上用鼠标设置矩形框(回车确认),作为目标前景的边界框。也可以直接在程序中设置边界框矩形的位置参数。

    # 11.35 GrabCut 图割分割算法(框选前景)
    image = cv2.imread("../images/imgGaia.tif", flags=1)  # 读取彩色图像(BGR)
    mask = np.zeros(image.shape[:2], dtype="uint8")

    # 定义矩形框,框选目标前景
    # rect = (118, 125, 220, 245)  # 直接设置矩形的位置参数,也可以鼠标框选 ROI
    print("Select a ROI and then press SPACE or ENTER button!\n")
    roi = cv2.selectROI(image, showCrosshair=True, fromCenter=False)
    xmin, ymin, w, h = roi  # 矩形裁剪区域 (ymin:ymin+h, xmin:xmin+w) 的位置参数
    rect = (xmin, ymin, w, h)  # 边界框矩形的坐标和尺寸
    imgROI = np.zeros_like(image)  # 创建与 image 相同形状的黑色图像
    imgROI[ymin:ymin + h, xmin:xmin + w] = image[ymin:ymin + h, xmin:xmin + w].copy()
    print(xmin, ymin, w, h)

    fgModel = np.zeros((1, 65), dtype="float")  # 前景模型, 13*5
    bgModel = np.zeros((1, 65), dtype="float")  # 背景模型, 13*5
    iter = 5
    (mask, bgModel, fgModel) = cv2.grabCut(image, mask, rect, bgModel, fgModel, iter,
                                           mode=cv2.GC_INIT_WITH_RECT)  # 框选前景分割模式

    # 将所有确定背景和可能背景像素设置为 0,而确定前景和可能前景像素设置为 1
    maskOutput = np.where((mask == cv2.GC_BGD) | (mask == cv2.GC_PR_BGD), 0, 1)
    maskGrabCut = (maskOutput * 255).astype("uint8")
    imgGrabCut = cv2.bitwise_and(image, image, mask=maskGrabCut)

    plt.figure(figsize=(10, 7))
    plt.subplot(231), plt.axis('off'), plt.title("Origin image")
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))  # 显示 img(RGB)
    plt.subplot(232), plt.axis('off'), plt.title("Bounding box")
    plt.imshow(cv2.cvtColor(imgROI, cv2.COLOR_BGR2RGB))  # 显示 img(RGB)
    plt.subplot(233), plt.axis('off'), plt.title("Mask for definite background")
    maskBGD = (mask == cv2.GC_BGD).astype("uint8") * 255
    plt.imshow(maskBGD, 'gray')  # definite background
    plt.subplot(234), plt.axis('off'), plt.title("Mask for probable background")
    maskPBGD = (mask == cv2.GC_PR_BGD).astype("uint8") * 255
    plt.imshow(maskPBGD, 'gray')  # probable background
    plt.subplot(235), plt.axis('off'), plt.title("GrabCut Mask")
    # maskGrabCut = np.where((mask==cv2.GC_BGD) | (mask==cv2.GC_PR_BGD), 0, 1)
    plt.imshow(maskGrabCut, 'gray')  # mask generated by GrabCut
    plt.subplot(236), plt.axis('off'), plt.title("GrabCut Output")
    plt.imshow(cv2.cvtColor(imgGrabCut, cv2.COLOR_BGR2RGB))  # GrabCut Output
    plt.tight_layout()
    plt.show()

在这里插入图片描述


(本节完)


版权声明:

OpenCV 例程200篇 总目录-202205更新
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/124744467)

Copyright 2022 youcans, XUPT
Crated:2022-5-12


欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中
欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中

【youcans 的 OpenCV 例程200篇】176.图像分割之均值漂移算法
【youcans 的 OpenCV 例程200篇】177.图像分割之 GraphCuts 图割法
【youcans 的 OpenCV 例程200篇】178.图像分割之 GrabCut 图割法(框选前景)
【youcans 的 OpenCV 例程200篇】179.图像分割之 GrabCut 图割法(掩模图像)
更多内容,请见:
【OpenCV 例程200篇 总目录-202206更新】