3、调用GrabCut实现图像分割
grabCut()
用法:
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode: None)
参数说明:
- mask:生成的掩码
- BGD:背景,0
- FGD:前景,1
- PR_BGD:可能是背景,2
- PR_FGD:可能是前景,3
- bgdModel, fgdModel:np.float64 type zero arrays of size(1, 65)
- mode:模式
- GC_INIT_WITH_RECT:指定某个区域,即在该区域中找前景
- GC_INIT_WITH_MASK:如果是第二次或第三次,可使用该参数再次迭代
代码实现(完整代码):
import cv2 import numpy as np class App: flag_rect = False rect = (0, 0, 0, 0) startX = 0 startY = 0 def onmouse(self, event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: self.flag_rect = True self.startX = x self.startY = y print('LBUTTONDOWN: 左键按下') elif event == cv2.EVENT_LBUTTONUP: self.flag_rect = False cv2.rectangle(self.img, (self.startX, self.startY), (x, y), (0, 0, 255), 3) self.rect = (min(self.startX, x), min(self.startY, y), abs(self.startX - x), abs(self.startY - y)) print('LBUTTONUP: 左键抬起') elif event == cv2.EVENT_MOUSEMOVE: if self.flag_rect == True: self.img = self.img2.copy() cv2.rectangle(self.img, (self.startX, self.startY), (x, y), (0, 255, 0), 3) print('MOUSEMOVE: 鼠标移动') print('onmouse') def run(self): print('run') cv2.namedWindow('input') cv2.setMouseCallback('input', self.onmouse) self.img = cv2.imread('../resource/lena.bmp') self.img2 = self.img.copy() self.mask = np.zeros(self.img.shape[:2], dtype=np.uint8) self.output = np.zeros(self.img.shape, np.uint8) while (1): cv2.imshow('input', self.img) cv2.imshow('output', self.output) key = cv2.waitKey(100) if key == 27: break if key == 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) App().run()
1.3 MeanShift法
严格来说,该方法并不是用来对图像分割的,而是在色彩层面的平滑滤波。
它会中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域。以图像上任一点p为圆心,半径为sp,色彩幅值为sr进行不断的迭代。
pyrMeanShiftFiltering()
用法:
cv2.pyrMeanShiftFiltering(src, sp, sr, dst: None, maxLevel: None, termcrit: None)
参数说明:
- sp:圆的半径
- sp:色彩幅值
代码实现:
import cv2 img = cv2.imread('../resource/flower.png') img_mean = cv2.pyrMeanShiftFiltering(img, 20, 30) img_canny = cv2.Canny(img_mean, 150, 300) contours, _ = cv2.findContours(img_canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, contours, -1, (0, 0, 255), 2) cv2.imshow('img', img) cv2.imshow('img_mean', img_mean) cv2.imshow('img_canny', img_canny) cv2.waitKey(0) cv2.destroyAllWindows()
2、视频前后景分离(视频背景抠图)
原视频:
原理:
- 视频是一组连续的帧(一幅幅图组成)
- 帧与帧之间关系密切(GOP)
- 在GOP中,背景几乎是不变的
MOG去背景: 混合高斯模型为基础的前景/背景分割算法
createBackgroundSubtractorMOG()
用法:
cv2.bgsegm.createBackgroundSubtractorMOG(history: None, nmixtures: None, backgroundRatio: None, noiseSigma: None)
参数说明:
- history:参考帧,默认 200
- nmixtures:高斯范围值,默认 5
- backgroundRatio:背景比率,默认 0.7
- noiseSigma:自动降噪,默认 0
代码实现:
import cv2 cap = cv2.VideoCapture('../resource/Car.mp4') mog = cv2.bgsegm.createBackgroundSubtractorMOG() while (True): ret, frame = cap.read() fgmask = mog.apply(frame) cv2.imshow('img', fgmask) key = cv2.waitKey(10) if key == 27: break cap.release() cv2.destroyAllWindows()
3.1 MOG2去背景
同MOG类似,不过对亮度产生的阴影有更好的识别.
createBackgroundSubtractorMOG2()
用法:
cv2.createBackgroundSubtractorMOG2(history: None, varThreshold: None, detectShadows: None)
参数说明:
- history:参数帧,默认 500
- detectShadows:是否检测阴影,默认 True
代码实现:
import cv2 cap = cv2.VideoCapture('../resource/Car.mp4') # 优点: 可以计算出阴影部分 # 缺点: 会产生很多噪点 mog2 = cv2.createBackgroundSubtractorMOG2() while (True): ret, frame = cap.read() fgmask = mog2.apply(frame) cv2.imshow('img', fgmask) key = cv2.waitKey(10) if key == 27: break cap.release() cv2.destroyAllWindows()
3.2 GMG去背景
静态背景图像估计和每个像素的贝叶斯分割,抗噪性更强。
createBackgroundSubtractorGMG()
用法:
cv2.bgsegm.createBackgroundSubtractorGMG(initializationFrames: None, decisionThreshold: None)
参数说明:
- initializationFrames:初始帧数,默认 120
代码实现:
import cv2 cap = cv2.VideoCapture('../resource/Car.mp4') # 优点: 可以算出阴影部分,同时减少了噪点 # 缺点: 如果采用默认值,则在开始会有很长时间不显示 gmg = cv2.bgsegm.createBackgroundSubtractorGMG(initializationFrames=10) # 解决办法: 调整初始参考帧的数量 while (True): ret, frame = cap.read() fgmask = gmg.apply(frame) cv2.imshow('img', fgmask) key = cv2.waitKey(10) if key == 27: break cap.release() cv2.destroyAllWindows()
3、图像修复
图像修复效果:
inpaint()
用法:
cv2.inpaint(src, inpaintMask, inpaintRadius, flags, dst: None)
参数说明:
- inpaintMask:修复掩码
- inpaintRadius:每个点的圆形领域半径
- flags:
- INPAINT_NS
- INPAINT_TELEA
- dst:输出与src具有相同大小和类型的图像
代码实现:
import cv2 import numpy as np img = cv2.imread('../resource/cvLogo_Ori.png') mask = cv2.imread('../resource/cvLogo_Mask.png', 0) dst = cv2.inpaint(img, mask, 5, cv2.INPAINT_TELEA) cv2.imshow('img', np.hstack((img, dst))) cv2.waitKey(0) cv2.destroyAllWindows()