Python OpenCV GrabCut交互式前景提取实战
本文详解Python环境下OpenCV GrabCut算法的交互式使用实例。通过结合numpy库,演示如何利用鼠标左右键在图像上标记前景与后景区域,实现精确的前景提取。代码包含图像缩放、高斯模糊及掩膜处理逻辑,并展示实时结果与耗时统计,适用于需要手动辅助分割的场景。
GrabCut算法概述与效果预览
本文深入解析Python中OpenCV库GrabCut算法的具体应用案例,通过详细的代码示例展示其工作流程,为相关学习与工作提供具有实际价值的参考指南。
首先展示处理后的效果预览:

环境配置与交互操作说明
开发环境基于Python 3.7版本,并搭配OpenCV 3.x系列库进行构建。
实现过程中需引入numpy库以支持数组运算。
操作方式直观:在图像窗口中,使用鼠标左键点击标记前景区域,右键点击标记后景区域。
若需重新进行标记操作,需关闭当前程序窗口并重新启动运行。
核心代码实现解析
以下是该功能的具体代码实现部分:
# -*- coding:utf-8 -*-
'''
Python: 3.5.7
opencv 3.x
在图上用鼠标左键和右键标记前景和后景即可.
如果需要重新标记图像,关闭程序重新运行.
By Ynxf http://www.zhouws.com
'''
import cv2
import numpy as np
import time
img_src = '../test_images/3.jpg'
drawing = False
mode = False
class GrabCut:
def __init__(self, t_img):
self.img = t_img
self.img_raw = img.copy()
self.img_width = img.shape[0]
self.img_height = img.shape[1]
self.scale_size = 640 * self.img_width // self.img_height
if self.img_width > 640:
self.img = cv2.resize(self.img, (640, self.scale_size), interpolation=cv2.INTER_AREA)
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 = False
self.rb_up = False
self.lb_down = False
self.rb_down = False
self.mask = np.full(self.img.shape[:2], 2, dtype=np.uint8)
self.firt_choose = True
# 鼠标的回调函数
def mouse_event2(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_point
param.lb_down = True
print('mouse lb down')
elif event == cv2.EVENT_RBUTTONDOWN:
drawing = True
last_point = (x, y)
start_point = last_point
param.rb_down = True
print('mouse rb down')
# 鼠标移动,画图
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)
else:
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 = False
param.lb_up = True
param.lb_down = False
cv2.line(param.img_show, last_point, (x,y), (0, 0, 255), 2, -1)
if param.firt_choose:
param.firt_choose = False
cv2.rectangle(param.mask, last_point, (x,y), 1, -1, 4)
print('mouse lb up')
elif event == cv2.EVENT_RBUTTONUP:
drawing = False
param.rb_up = True
param.rb_down = False
cv2.line(param.img_show, last_point, (x,y), (255, 0, 0), 2, -1)
if param.firt_choose:
param.firt_choose = False
param.mask = np.full(param.img.shape[:2], 3, dtype=np.uint8)
cv2.rectangle(param.mask, last_point, (x,y), 0, -1, 4)
print('mouse rb up')
if __name__ == '__main__':
img = cv2.imread(img_src)
if img is None:
print('error: 图像为空')
g_img = GrabCut(img)
cv2.namedWindow('image')
# 定义鼠标的回调函数
cv2.setMouseCallback('image', mouse_event2, g_img)
while (True):
cv2.imshow('image', g_img.img_show)
if g_img.lb_up or g_img.rb_up:
g_img.lb_up = False
g_img.rb_up = False
start = time.process_time()
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (1, 1, g_img.img.shape[1], g_img.img.shape[0])
print(g_img.mask)
mask = g_img.mask
g_img.img_gc = g_img.img.copy()
cv2.grabCut(g_img.img_gc, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_MASK)
elapsed = (time.process_time() - start)
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8') # 0和2做背景
g_img.img_gc = g_img.img_gc * mask2[:, :, np.newaxis] # 使用蒙板来获取前景区域
cv2.imshow('result', g_img.img_gc)
print("Time used:", elapsed)
# 按下ESC键退出
if cv2.waitKey(20) == 27:
break
以上内容为本文的全部分享,希望能为读者的学习带来帮助,同时也欢迎持续关注与支持本站后续更新。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









