本文架构
知识扩展
图像分割:选取图像中的指定目标,并将背景色置为黑色。识别目标
实例分割:在像素级识别对象轮廓的任务【最困难的视觉任务之一】。识别目标特征
GrabCut算法和GraphCut算法的关系
GrabCut函数参数的介绍
def grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None):
# grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode]) -> mask, bgdModel, fgdModel
mask只能选取四种情况:
mode可以选择的值有:
GrabCut算法的使用案例
import numpy as np
from matplotlib import pyplot as plt
import cv2
img = cv2.imread('../../data/messi5.jpg') # 读入目标图像
plt.imshow(img) # 显示图片,方便记录目标图像的起始点和大小,为rectangle函数做准备
plt.show()
mask = np.zeros(img.shape[:2],np.uint8) # 制作mask图像(注意:必须与原图的大小相同)
#mask = mask.ravel()
#print(set(mask)) # {0}
bgdModel = np.zeros((1,65),np.float64) # 定义前景模块:65为固定值
fgdModel = np.zeros((1,65),np.float64) # 定义背景模块
rect = (0,0,0,0) # 次数rect参数对结果无影响
cv2.rectangle(mask,(58,41),(58+445,41+283),(3,3,3),-1, cv2.LINE_AA) # 在mask图像中框出所要截取图像的目标
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,10,cv2.GC_INIT_WITH_MASK) # 使用grabcut函数,注意mask值得变化
#mask = mask.ravel()
#print(set(mask)) # {0, 2, 3}
mask2 = np.where((mask==1)|(mask==3),1,0).astype('uint8') # 提取前景
# mask2[:,:,np.newaxis]:将二维图像转换成三维图像
"""
mask2.shape
(342, 548)
mask2[:,:,np.newaxis].shape
(342, 548, 1)
"""
# 将原图与mask的每一个颜色空间相乘(广播)
img = img * mask2[:,:,np.newaxis] # 改变数组维度与原图保持一致
cv2.imshow('result',img) # 显示图片
cv2.waitKey(0)
cv2.destroyAllWindows()
GrabCut算法实现的步骤
GrabCut算法实现的原理
GrabCut分割算法在GraphCut算法的基础做了三方面的改进
1.灰度图像扩展到彩色图像
彩色图像是由RGB三色空间上的像素组成的,所以创建足够的彩色空间直方图是很难现实的,因此采用GMM模型来创建彩色空间数据模型。
GMM可以看作是一个 K K K维的协方差(通常为5)
为了方便处理GMM,在优化的过程中引入向量 K ( K 1 . . . K n ) K(K_1...K_n) K(K1...Kn)作为每个像素的独立GMM(前景或者背景)参数
并且每个像素点的不透明度为0或者1
故Gibbs能量函数可以改写为: E ( α , k , θ , z ) = U ( α , k , θ , z ) + V ( α , z ) E(α,k,θ,z) = U(α,k,θ,z) + V(α,z) E(α,k,θ,z)=U(α,k,θ,z)+V(α,z)
E ( α , k , θ , z ) = U ( α , k , θ , z ) + V ( α , z ) E(α,k,θ,z) = U(α,k,θ,z) + V(α,z) E(α,k,θ,z)=U(α,k,θ,z)+V(α,z):主要受到 k k k值的影响
引入GMM的彩色数据模型,数据项可以定义为: U ( α , k , θ , z ) = ∑ i = 1 n D ( α n , k n , θ , z n ) U(α,k,θ,z) = \sum_{i=1}^{n} D(α_n,k_n,θ,z_n) U(α,k,θ,z)=∑i=1nD(αn,kn,θ,zn)
其中: D ( α n , k n , θ , z n ) = − l o g p ( z n ∣ α n ) − l o g π ( α n , k n ) D(α_n,k_n,θ,z_n) = -log^p(z_n|α_n)-log^π(α_n,k_n) D(αn,kn,θ,zn)=−logp(zn∣αn)−logπ(αn,kn)
即可以推导出:
D ( α n , k n , θ , z n ) = − l o g π ( α n , k n ) + 1 2 l o g d e t ( α n , k n ) + 1 2 [ z n − μ ( α n , k n ) ] T ∑ ( α n , k n ) [ z n − μ ( α n , k n ) ] D(α_n,k_n,θ,z_n) = -log^π(α_n,k_n) + \frac{1}{2}logdet(α_n,k_n)+ \frac{1}{2}[z_n-μ(α_n,k_n)]^T\sum(α_n,k_n)[z_n-μ(α_n,k_n)] D(αn,kn,θ,zn)=−logπ(αn,kn)+21logdet(αn,kn)+21[zn−μ(αn,kn)]T∑(αn,kn)[zn−μ(αn,kn)]
因此模型的参数就确定为
θ = π ( α n , k n ) , μ ( α n , k n ) , ∑ ( α , k ) , k = 1 , 2 , . . . K θ = { π(α_n,k_n),μ(α_n,k_n),\sum(α,k), k = 1,2,...K } θ=π(αn,kn),μ(αn,kn),∑(α,k),k=1,2,...K
彩色图像的平滑项为:
V ( α , z ) = γ ∑ m n [ α m ≠ α n ] e x p ( − β ∥ z m − z n ∥ 2 ) V(α,z) = γ\sum_{m}^{n}[α_m≠α_n]exp(-β ∥z_m-z_n∥^2) V(α,z)=γ∑mn[αm=αn]exp(−β∥zm−zn∥2)
2.迭代算法代替一次最小估计来完成能量最小化
GrabCut中的能量最小化(能量越低,越稳定)通过迭代来实现的,不像GraphCuts算法一次就完成
迭代最小化的优点是可以自动修改不透明度的值,并利用初始三元图的 T U T_U TU像素中重新确定的像素来校正彩色模型的参数。
主要流程如下
迭代最小化过程可看成总能量 E E E在 k k k、 θ θ θ、 α α α三个方面上的单调递减。
这样可以保证算法最终收敛到 E E E的最小值。
当判断出 E E E大幅度衰减时,自动终止迭代。
3.用户交互与不完全三元图(非完全编号)
非完全编号取代完整三元图,能够对用户的交互带来更大的灵活性。
用户的初始交互只需要确定背景区域 T B T_B TB,并不需要确定前景(从代码中即可看出),可令 T F = 0 T_F=0 TF=0
迭代能量最小化是通过允许一些编号临时表示前景像素,而背景的编号是固定不变的。
GrabCut中的初始值 T B T_B TB是用户通过标定的矩形区域来确定的
GrabCut算法实现的原理参考于《GrabCut彩色图像分割算法的研究》部分节选