教你一招,简简单单就能抠图,想抠哪里抠哪里

  • 时间:2025-10-22 19:33 作者: 来源: 阅读:9
  • 扫一扫,手机访问
摘要:本文分享内容来自图书《学习OpenCV 4:基于Python的算法实战》,该书内容如下:第1章 OpenCV快速入门; 第2章 图像读写模块imgcodecs; 第3章 核心库模块core; 第4章 图像处理模块imgproc(一); 第5章 图像处理模块imgproc(二); 第6章 可视化模块highgui; 第7章 视频处理模块videoio; 第8章

本文分享内容来自图书《学习OpenCV 4:基于Python的算法实战》,该书内容如下:

第1章 OpenCV快速入门;
第2章 图像读写模块imgcodecs;
第3章 核心库模块core;
第4章 图像处理模块imgproc(一);
第5章 图像处理模块imgproc(二);
第6章 可视化模块highgui;
第7章 视频处理模块videoio;
第8章 视频分析模块video;
第9章 照片处理模块photo;
第10章 2D特征模块features2d;
第11章 相机标定与三维重建模块calib3d;
第12章 传统目标检测模块objdetect;
第13章 机器学习模块ml;
第14章 深度神经网络模块dnn

欢迎关注图书《深度学习计算机视觉实战》与《学习OpenCV4:基于Python的算法实战》。

Grabcuts是一种交互式前景提取算法,OpenCV允许读者在待分割的图像周围提供矩形框,矩形框之外的部分属于背景,此时不用指定前景。读者也可以使用一个全局掩膜,将图像的像素点分为确定前景、确定背景以及疑似前景和疑似背景,这样确定区域将被算法用于将疑似区域进行分割。

OpenCV中提供了Grabcuts算法的函数grabCut,函数定义如下:

mask, bgdModel, fgdModel = grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

参数说明如下:

u img,输入图像;

u mask,掩模(返回值);

u rect,包含分割对象的感兴趣区域;

u bgdModel,背景模型的临时数组(返回值);

u fgdModel,前景模型的临时数组(返回值);

u iterCount,算法迭代次数;

u mode,处理模式,由GrabCutModes定义。

本案例实现了一个交互式的图像分割,鼠标左键选取确定前景,鼠标右键选取确定背景,Grabcuts算法根据确定前景和确定背景进行图像分割。

Grabcuts算法图像分割案例代码如下:

import cv2import numpy as np#绘制前景/背景标识线标志drawing = False# 定义GrabCut类,作用是设置一些参数class GrabCut:def __init__(self, t_img):self.img = t_imgself.img_raw = img.copy()self.img_width = img.shape[0]self.img_height = img.shape[1]self.img_show = self.img.copy()self.img_gc = self.img.copy()self.img_gc = cv2.GaussianBlur(self.img_gc, (3, 3), 0)self.lb_up = Falseself.rb_up = Falseself.lb_down = Falseself.rb_down = Falseself.mask = np.full(self.img.shape[:2], 2, dtype=np.uint8)self.firt_choose = True# 鼠标操作的的回调函数def mouse_event(event, x, y, flags, param):global drawing, last_point, start_point# 左键按下,开始标识前景if event == cv2.EVENT_LBUTTONDOWN:drawing = True# 设置鼠标按下的起始点last_point = (x, y)start_point = last_pointparam.lb_down = True# 右键按下,开始标识背景elif event == cv2.EVENT_RBUTTONDOWN:# 读者请先标识前景,否则无法分割if param.firt_choose:print("Please select foreground first!")returndrawing = Truelast_point = (x, y)start_point = last_pointparam.rb_down = True# 鼠标移动,绘制标识前景和背景的线elif event == cv2.EVENT_MOUSEMOVE:if drawing:# 鼠标左键按下的绘制if param.lb_down:cv2.line(param.img_show, last_point, (x,y), (0, 0, 255), 2, -1)cv2.rectangle(param.mask, last_point, (x, y), 1, -1, 4)# 鼠标右键按下的绘制if param.rb_down:cv2.line(param.img_show, last_point, (x, y), (255, 0, 0), 2, -1)cv2.rectangle(param.mask, last_point, (x, y), 0, -1, 4)last_point = (x, y)# 左键释放,结束标识前景elif event == cv2.EVENT_LBUTTONUP:drawing = Falseparam.lb_up = Trueparam.lb_down = Falsecv2.line(param.img_show, last_point, (x,y), (0, 0, 255), 2, -1)# 如果第一次标识,切换状态if param.firt_choose:param.firt_choose = Falsecv2.rectangle(param.mask, last_point, (x,y), 1, -1, 4)# 右键释放,结束标识背景elif event == cv2.EVENT_RBUTTONUP:# 如果第一标识背景则不做处理if param.firt_choose:returndrawing = Falseparam.rb_up = Trueparam.rb_down = Falsecv2.line(param.img_show, last_point, (x,y), (255, 0, 0), 2, -1)cv2.rectangle(param.mask, last_point, (x,y), 0, -1, 4)#执行操作def process(img):if img is None:print('Can not read image correct!')returng_img = GrabCut(img)cv2.namedWindow('image')# 定义鼠标的回调函数cv2.setMouseCallback('image', mouse_event, g_img)while (True):cv2.imshow('image', g_img.img_show)# 鼠标左键或者右键抬起时,按照标识执行Grabcut算法if g_img.lb_up or g_img.rb_up:g_img.lb_up = Falseg_img.rb_up = False# 背景modelbgdModel = np.zeros((1, 65), np.float64)# 前景modelfgdModel = np.zeros((1, 65), np.float64)rect = (1, 1, g_img.img.shape[1], g_img.img.shape[0])mask = g_img.maskg_img.img_gc = g_img.img.copy()#执行Grabcut算法cv2.grabCut(g_img.img_gc, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_MASK)# 0和2做背景mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')# 使用蒙板来获取前景区域g_img.img_gc = g_img.img_gc * mask2[:, :, np.newaxis]cv2.imshow('Grabcut_result', g_img.img_gc)# 按下ESC键退出if cv2.waitKey(20) == 27:breakif __name__ == '__main__':img = cv2.imread("./src.jpg")process(img)

如图5.30为第一次选取前景的操作。


教你一招,简简单单就能抠图,想抠哪里抠哪里



图5.30

如图5.31为分割后的结果,图中人物被有效的抠取出来了。


教你一招,简简单单就能抠图,想抠哪里抠哪里



图5.31

继续使用右键选取背景区域,如图5.32所示。


教你一招,简简单单就能抠图,想抠哪里抠哪里



图5.32

抠取人像的结果如图5.33所示。


教你一招,简简单单就能抠图,想抠哪里抠哪里



图5.33

如果分割效果不佳,读者可以继续选取前景或者背景,多次迭代进行更加精细化的分割。

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部