OpenCV4图像处理-图像交互式分割-GrabCut

本文将实现一个与人(鼠标)交互从而分割背景的程序。

GrabCut

  • 1.理论介绍
  • [2. 鼠标交互](#2. 鼠标交互)
  • [3. GrabCut](#3. GrabCut)

1.理论介绍

用户指定前景的大体区域,剩下为背景区域,还可以明确指出某些地方为前景或者背景,GrabCut算法采用分段迭代的方法分析前景物体形成模型树,最后根据权重决定某个像素是前景还是背景。

算法:GrabCut(img, mask, rect, bgdModel, fgdModel, 5, //iteratormode)

img:要分割的图像

mask:生称的掩码(以原图像大小为基准),该算法会把mask分为4部分,像素点的值为0,1,2,3四种值吗,其中每种值代表不同的意思。

rect:用户指定的矩形区域,元组的形式(起始坐标x, y , width,height)

bgdModel:1行65列的0矩阵,元素类型为float64。

fgdModel:1行65列的0矩阵,元素类型为float64。

5:迭代次数iterator

mode:第一次找用RECT,以后迭代用MASK

2. 鼠标交互

下面是一个鼠标交互的程序,可以通过点击鼠标滑动鼠标在图像上作图。

不太清楚的读者可以参考下面博客:Opencv(图像处理)-基于Python-绘图功能

代码如下:

python 复制代码
import cv2
import numpy as np


'''
该api可以在图上作图
点击并滑动鼠标可以在图上画出矩形框
'''


# 定义一个类来封装该方法
class MouseStich:
    startX = 0
    startY = 0
    rect_flag = False
    def onmouse(self, event, x, y, flags, param):
        # print("onmouse")
        if event == cv2.EVENT_LBUTTONDOWN:
            self.rect_flag = True
            self.startX = x
            self.startY = y
            # print("LBUTTONDOWN")
        elif event == cv2.EVENT_LBUTTONUP:
            # print("LBUTTONUP")
            self.rect_flag = False
            cv2.rectangle(self.img,
                          (self.startX, self.startY),
                          (x, y),
                          (0, 0, 255),
                          3)
        elif event == cv2.EVENT_MOUSEMOVE:
            # print("MOUSEMOVE")
            # 每次都在新的图像上画
            if self.rect_flag == True:
                self.img = self.img2.copy()
                cv2.rectangle(self.img,
                              (self.startX, self.startY),
                              (x, y),
                              (0, 255, 0),
                              3)

    def run(self):
        print("run....")
        # 绑定鼠标事件的窗口
        cv2.namedWindow('input')
        cv2.setMouseCallback('input', self.onmouse)
		# 暂存一个img2
        self.img = cv2.imread('./image/lena.jpg')
        self. img2 = self.img.copy()
        # 读取图片,在该窗口显示
        while(1):
            # 展示原图,被画的图
            cv2.imshow('input', self.img)
            k = cv2.waitKey(100) & 0xff
            if k == ord('q'):
                break




MouseStich().run()

3. GrabCut

将GrabCut需要的参数构造好后,传进去,获得mask掩模,然后我们用np.where把像素值是1,3的位置改成255,目的是用bitwise_and函数提取出前景区域。

python 复制代码
import cv2
import numpy as np


'''
该api可以在图上作图
点击并滑动鼠标可以在图上画出矩形框
'''


# 定义一个类来封装该方法
class MouseStich:
    startX = 0
    startY = 0
    rect_flag = False
    rect = (0, 0, 0, 0)
    def onmouse(self, event, x, y, flags, param):

        # print("onmouse")
        if event == cv2.EVENT_LBUTTONDOWN:
            self.rect_flag = True
            self.startX = x
            self.startY = y
            # print("LBUTTONDOWN")
        elif event == cv2.EVENT_LBUTTONUP:
            # print("LBUTTONUP")
            self.rect_flag = False
            cv2.rectangle(self.img,
                          (self.startX, self.startY),
                          (x, y),
                          (0, 0, 255),
                          3)
        elif event == cv2.EVENT_MOUSEMOVE:
            # print("MOUSEMOVE")
            # 每次都在新的图像上画
            if self.rect_flag == True:
                # 每次都在新的图像上画move
                self.img = self.img2.copy()
                cv2.rectangle(self.img,
                              (self.startX, self.startY),
                              (x, y),
                              (0, 255, 0),
                              3)
        # 构造矩形的信息
        self.rect = (min(self.startX, x), min(self.startY, y),
                     abs(self.startX - x), abs(self.startY - y))

    def run(self):
        print("run....")
        # 绑定鼠标事件的窗口
        cv2.namedWindow('input')
        cv2.setMouseCallback('input', self.onmouse)

        self.img = cv2.imread('./image/lena.jpg')
        self. img2 = self.img.copy()
        # 定义一个与图片相同大小的掩码
        self.mask = np.zeros(self.img.shape[:2], dtype=np.uint8)
        self.output = np.zeros(self.img.shape, dtype=np.uint8)


        # 读取图片,在该窗口显示
        while(1):
            # 展示原图,被画的图
            cv2.imshow('input', self.img)
            cv2.imshow('output', self.output)
            k = cv2.waitKey(100) & 0xff
            if k == ord('q'):
                break

            if k == ord('g'):
                bgdmodel = np.zeros((1, 65), np.float64)
                fgdmodel = np.zeros((1, 65), np.float64)
                cv2.grabCut(self.img2, self.mask, self.rect,
                            bgdmodel, fgdmodel,
                            1,
                            cv2.GC_INIT_WITH_RECT)
            # 构造提取前景的淹没
            mask2 = np.where((self.mask==1)|(self.mask==3), 255, 0).astype('uint8')
            self.output = cv2.bitwise_and(self.img2, self.img2, mask=mask2)



MouseStich().run()

展示效果:先使用鼠标画出区域,然后按'g'分割图片。

以上是关于GrabCut算法的实战内容,如有问题欢迎在评论区讨论。

相关推荐
2301_81459025几秒前
Python深度学习入门:TensorFlow 2.0/Keras实战
jvm·数据库·python
sun_tao115 分钟前
LlamaIndex + Qwen3.5-4B 关闭 Thinking 模式调试记录
python·llamaindex·qwen3.5-4b·huggingfacellm
书到用时方恨少!32 分钟前
Python os 模块使用指南:系统交互的瑞士军刀
开发语言·python
li三河1 小时前
opencv利用freetype写中文
人工智能·opencv·计算机视觉
带娃的IT创业者1 小时前
WeClaw_40_系统监控与日志体系:多层次日志架构与Trace追踪
java·开发语言·python·架构·系统监控·日志系统·链路追踪
亓才孓2 小时前
【提示词五要素】
python·ai·prompt
财经资讯数据_灵砚智能2 小时前
全球财经资讯日报(夜间-次晨)2026年3月28日
大数据·人工智能·python·语言模型·ai编程
水哥ansys2 小时前
Pyansys-PyMAPDL基本语法01-APDL原生命令流改写格式
python·二次开发·水哥ansys·pyansys·apdl
迷藏4942 小时前
# 发散创新:低代码开发新范式——用可视化逻辑构建企业级业务系统 在当今快速迭代的软件工程实践
java·python·低代码
我的xiaodoujiao2 小时前
API 接口自动化测试详细图文教程学习系列7--相关Python基础知识6
python·学习·测试工具·pytest