OpenCV3计算机视觉:Python实现 读书笔记-第四章

第四章

使用分水岭和GrabCut算法物体分割
  • GrabCut算法步骤
    • 在图片中定义含有(若干个)物体的矩形
    • 矩形外的区域被认为是背景
    • 对于用户定义的矩形区域,用背景中的数据区别里面的前景和背景
    • 用高斯混合模型对背景和前景建模,并将未定义的像素标记为可能的前景或背景
    • 图像中的每一个像素都被看作通过虚拟边与周围像素连接,而每条边都有一个属于前景或背景的概率,这基于它与周围像素颜色上的相似性
    • 每一个像素会与一个前景和背景节点连接
    • 节点完成连接后,对于一条边,两端节点若属于不同端,则切断。
用GrabCut进行前景检测
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('3_2.jpg')
mask = np.zeros(img.shape[:2],np.uint8) # 创建一个与所加载图像同形状的掩模,0填充

bgdModel = np.zeros((1,65),np.float64)  # 背景模型
fgdModel = np.zeros((1,65),np.float64)  # 前景模型

rect = ( 100 , 50 , 1024 , 1024 )
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,10,cv2.GC_INIT_WITH_RECT)   # 10为迭代次数

# 至此,掩模已经变成包含0-3之间的值
# 0,2转为0;1,3转为1,保存在mask2
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img * mask2[:,:,np.newaxis]   # np.newaxis : 增加新维度

plt.subplot(121) , plt.imshow(img)
plt.title("grabcut")  , plt.xticks([]) , plt.yticks([])

plt.subplot(122) , plt.imshow(cv2.cvtColor(cv2.imread('3_2.jpg'),cv2.COLOR_BGR2RGB))
plt.title("original") , plt.xticks([]) , plt.yticks([])
plt.show()
分水岭算法进行图像分割
- 获取二值图像
- 获取前景像素,前景为0
- 获取背景像素,255为背景
- 背景与前景做减运算,获取未知区域255
- 获取标记图,合成标记图像(未知0,背景1,前景>1)
  • 将原图和标记图像输入分水岭算法
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('3_4.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret , thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

kernel = np.ones((3,3),np.uint8)
# morphologyEx变换去除噪声数据(图像膨胀后腐蚀),提取图像特征
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2)
# 对变换后的图像膨胀操作,可得到大部分都是背景的区域
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# 通过distanceTransform获取确定的前景区域
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret , sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# 确定前景背景中重合部分
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)    # (重合即为不确定区域,减运算结果存于unknown)

# 设置“栅栏”阻止水汇聚()
ret , markers = cv2.connectedComponents(sure_fg) # marker中背景区域为0,其他为1开始的整数

# 背景区域加1,这会将unknown区域设为0
markers = markers + 1 # 保证背景是1
markers[unknown==255] = 0 # unknown置0(二值图像背景[255]-前景[0]重合区域为255)

# 打开门,让水漫起来将“栅栏”染红
markers = cv2.watershed(img,markers) #原图和标记图输入分水岭算法(0被识别为unknown区域)
img[markers == -1] = [255,0,0]
plt.imshow(img)
plt.show()

猜你喜欢

转载自blog.csdn.net/FrankAx/article/details/104929441