條件隨機(jī)向量場(chǎng)CRF

1、什么是條件隨機(jī)向量場(chǎng)CRF?

一個(gè)普遍意義的條件隨機(jī)向量場(chǎng)

上述模型表示,以x_1,x_2,...,x_n表示觀測(cè)序列,以y_1,y_2,...,y_n表示隱含的狀態(tài)序列,那么觀察值x_iy_{i-1},y_i,y_{i+1}都有關(guān)。

2、圖像分割中的應(yīng)用全連接CRF

??由于CRF具有考慮上下文關(guān)系的特性,因此一般的CRF可以用在圖像去噪,平滑圖像的過(guò)程。但是圖像分割過(guò)程中產(chǎn)生了分類目標(biāo)邊界模糊的問(wèn)題,為了得到更精確的最終分類結(jié)果,通常要進(jìn)行一些圖像后處理??紤]到圖像像素之間的強(qiáng)相關(guān)性,因此提出了全連接CRF來(lái)解決這一問(wèn)題。

DeepLab V1

??全連接CRFs與稀疏CRFs的最大差別在于:每個(gè)像素點(diǎn)都與所有的像素點(diǎn)相連接構(gòu)成連接邊。為了簡(jiǎn)化計(jì)算,獻(xiàn)《Efficient Inference in Fully Connected CRFs with Gaussian Edge Potentials》給出了快速推理算法。接著我們就簡(jiǎn)單講解具體的求解算法:
首先,假設(shè)圖像中的每一點(diǎn)都符合吉布斯分布
P(x|I)=\frac{1}{Z(I)}e^{-E(X|I)}
其中x是觀測(cè)值,E(X|I)是能量函數(shù),也是我們優(yōu)化的目標(biāo),Z(X|I)是歸一化因子。
??能量函數(shù)E(X|I)由一元?jiǎng)莺瘮?shù)和二元?jiǎng)莺瘮?shù)構(gòu)成,如下公式所示:
E(x|I)=\sum_{i}\psi_u(x_i)+\sum_{i,j}\psi_p(x_i,x_j)
其中的一元?jiǎng)莺瘮?shù)用于衡量像素點(diǎn)的類別概率,自卷積神經(jīng)網(wǎng)絡(luò)網(wǎng)絡(luò)的后端輸出。二元?jiǎng)莺瘮?shù)用于描述像素點(diǎn)和像素點(diǎn)之間的關(guān)系,鼓勵(lì)相似像素分配相同的標(biāo)簽,而相差較大的像素分配不同的標(biāo)簽。這個(gè)相似的定義與顏色值rgb和實(shí)際相對(duì)距離xy相關(guān),所以CRF能夠使圖片盡量在邊界處分割。
二元?jiǎng)莺瘮?shù)公式如下:
\psi_p(x_i,x_j)=u(x_i,x_j)\sum_{}w^mK_{G}^m(f_i,f_j)
其中u(x_i,x_j)叫做標(biāo)簽兼容項(xiàng)(Label Compatibility),它約束了像素間傳導(dǎo)的條件,只有相同標(biāo)簽(label)條件下,能量才可以相互傳導(dǎo)。K_{G}^m(f_i,f_j)是特征函數(shù),以特征的形式表示了不同像素之前的“親密度”,第一項(xiàng)被稱作表面核,第二項(xiàng)被稱作平滑核,公式如下:
K_{G}^m(f_i,f_j)=W^{(1)}exp\left(-\frac{|p_i-p_j|^2}{2\theta_{\alpha}^2}-\frac{|I_i-I_j|^2}{2\theta_{\beta}^2}\right)+W^{(2)}exp\left(-\frac{|p_i-p_j|^2}{2\theta_{\gamma}^2}\right)

??在全連接CRFs進(jìn)行影像后處理的實(shí)際操作中,一元?jiǎng)菽転楦怕史植紙D,即由模型輸出的特征圖經(jīng)過(guò)softmax函數(shù)運(yùn)算得到的結(jié)果;二元?jiǎng)菽苤械奈恢眯畔⒑皖伾畔⒂稍加跋裉峁?。?dāng)能量E(x)越小時(shí),預(yù)測(cè)的類別標(biāo)簽X就越準(zhǔn)確,我們通過(guò)迭代最小化能量函數(shù),得到最終的后處理結(jié)果。

3、代碼理解

import numpy as np
import pydensecrf.densecrf as dcrf

try:
    from cv2 import imread, imwrite
except ImportError:
    # 如果沒(méi)有安裝OpenCV,就是用skimage
    from skimage.io import imread, imsave
    imwrite = imsave

from pydensecrf.utils import unary_from_labels, create_pairwise_bilateral, create_pairwise_gaussian

"""
original_image_path  原始圖像路徑
predicted_image_path  之前用自己的模型預(yù)測(cè)的圖像路徑
CRF_image_path  即將進(jìn)行CRF后處理得到的結(jié)果圖像保存路徑
"""
def CRFs(original_image_path,predicted_image_path,CRF_image_path):
    print("original_image_path: ",original_image_path)
    img = imread(original_image_path)
    
    # 將predicted_image的RGB顏色轉(zhuǎn)換為uint32顏色 0xbbggrr
    anno_rgb = imread(predicted_image_path).astype(np.uint32) #shape為(240, 320, 3)
    anno_lbl = anno_rgb[:,:,0] + (anno_rgb[:,:,1] << 8) + (anno_rgb[:,:,2] << 16) #shape變?yōu)榱?240, 320)
    
    # 將uint32顏色轉(zhuǎn)換為1,2,...
    # 如果是分兩類,colors會(huì)產(chǎn)生三種像素值,如:[0,16384,4227072];
   # labels為anno_lbl矩陣中像素值在colors中的索引,并以列表形式儲(chǔ)存, 因此labels的值只有0,1,2三種;shape為(240*320,)
    colors, labels = np.unique(anno_lbl, return_inverse=True)
    
    # 如果你的predicted_image里的黑色(0值)不是待分類類別,表示不確定區(qū)域,即將分為其他類別
    # 那么就取消注釋以下代碼
    #HAS_UNK = 0 in colors
    #if HAS_UNK:
    #colors = colors[1:]
    
    # 創(chuàng)建從predicted_image到32位整數(shù)顏色的映射。
    colorize = np.empty((len(colors), 3), np.uint8)
    colorize[:,0] = (colors & 0x0000FF)
    colorize[:,1] = (colors & 0x00FF00) >> 8
    colorize[:,2] = (colors & 0xFF0000) >> 16
    
    # 計(jì)算predicted_image中的類數(shù)。
    n_labels = len(set(labels.flat))
    #n_labels = len(set(labels.flat)) - int(HAS_UNK) ##如果有不確定區(qū)域,用這一行代碼替換上一行
    
    ###########################
    ###     設(shè)置CRF模型     ###
    ###########################
    use_2d = False               
#    use_2d = True   
    ###########################################################   
    ##不是很清楚什么情況用2D        
    ##作者說(shuō)“對(duì)于圖像,使用此庫(kù)的最簡(jiǎn)單方法是使用DenseCRF2D類”
    ##作者還說(shuō)“DenseCRF類可用于通用(非二維)密集CRF”
    ##但是根據(jù)我的測(cè)試結(jié)果一般情況用DenseCRF比較對(duì)
    #########################################################33
    if use_2d:                   
        # 使用densecrf2d類
        d = dcrf.DenseCRF2D(img.shape[1], img.shape[0], n_labels)
    
        # 得到一元?jiǎng)荩ㄘ?fù)對(duì)數(shù)概率)
        # U.shape為(2, 76800),即(n_labels,len(labels))
        U = unary_from_labels(labels, n_labels, gt_prob=0.2, zero_unsure=None)
        #U = unary_from_labels(labels, n_labels, gt_prob=0.2, zero_unsure=HAS_UNK)## 如果有不確定區(qū)域,用這一行代碼替換上一行
        d.setUnaryEnergy(U)
    
        # 增加了與顏色無(wú)關(guān)的術(shù)語(yǔ),只是位置-----會(huì)懲罰空間上孤立的小塊分割,即強(qiáng)制執(zhí)行空間上更一致的分割
        d.addPairwiseGaussian(sxy=(3, 3), compat=3, kernel=dcrf.DIAG_KERNEL,
                              normalization=dcrf.NORMALIZE_SYMMETRIC)
    
        # 增加了顏色相關(guān)術(shù)語(yǔ),即特征是(x,y,r,g,b)-----使用局部顏色特征來(lái)細(xì)化它們
        d.addPairwiseBilateral(sxy=(80, 80), srgb=(13, 13, 13), rgbim=img,compat=10,
                               kernel=dcrf.DIAG_KERNEL,
                               normalization=dcrf.NORMALIZE_SYMMETRIC)
        '''
        addPairwiseGaussian函數(shù)里的sxy為公式中的 $\theta_{\gamma}$, 
        addPairwiseBilateral函數(shù)里的sxy、srgb為$\theta_{\alpha}$ 和 $\theta_{\beta}$
        '''
    else:
        # 使用densecrf類
        d = dcrf.DenseCRF(img.shape[1] * img.shape[0], n_labels)
    
        # 得到一元?jiǎng)荩ㄘ?fù)對(duì)數(shù)概率)
        U = unary_from_labels(labels, n_labels, gt_prob=0.5, zero_unsure=None)  
        #U = unary_from_labels(labels, n_labels, gt_prob=0.7, zero_unsure=HAS_UNK)## 如果有不確定區(qū)域,用這一行代碼替換上一行
        d.setUnaryEnergy(U)
    
        # 這將創(chuàng)建與顏色無(wú)關(guān)的功能,然后將它們添加到CRF中
        feats = create_pairwise_gaussian(sdims=(3, 3), shape=img.shape[:2])
        d.addPairwiseEnergy(feats, compat=8,kernel=dcrf.DIAG_KERNEL,
                            normalization=dcrf.NORMALIZE_SYMMETRIC)
    
        # 這將創(chuàng)建與顏色相關(guān)的功能,然后將它們添加到CRF中
        feats = create_pairwise_bilateral(sdims=(80, 80), schan=(13, 13, 13),
                                          img=img, chdim=2)
        d.addPairwiseEnergy(feats, compat=10,
                            kernel=dcrf.DIAG_KERNEL,
                            normalization=dcrf.NORMALIZE_SYMMETRIC)
    
    ####################################
    ###         做推理和計(jì)算         ###
    ####################################
    
    # 進(jìn)行5次推理
    Q = d.inference(10)
    
    # 找出每個(gè)像素最可能的類
    MAP = np.argmax(Q, axis=0)
    
    # 將predicted_image轉(zhuǎn)換回相應(yīng)的顏色并保存圖像
    MAP = colorize[MAP,:]
    imwrite(CRF_image_path, MAP.reshape(img.shape))
    print("CRF圖像保存在",CRF_image_path,"!")

4、一元?jiǎng)莺瘮?shù) Unary potential

一元?jiǎng)菁淳W(wǎng)絡(luò)預(yù)測(cè)得到的結(jié)果,進(jìn)行-np.log(py)等操作

U = np.array(...)     # Get the unary in some way.
print(U.shape)        # -> (2, 240, 320)
print(U.dtype)        # -> dtype('float32')
U = U.reshape((5,-1)) # Needs to be flat.
d.setUnaryEnergy(U)
# Or alternatively: d.setUnary(ConstUnary(U))
#注意,nlabel維度是這里reshape之前的第一個(gè)維度;如果不是這樣的話,你可能需要在reshape之前把nlabel移到前面,即U.shape的結(jié)果應(yīng)該為(5, 480, 640),就像這樣:
print(U.shape)  # -> (480, 640, 5)
U = U.transpose(2, 0, 1).reshape((5,-1))

得到 unary potentials有兩種常見(jiàn)的方法:
1)由人類或其他過(guò)程產(chǎn)生的硬標(biāo)簽。該方法由from pydensecrf.utils import unary_from_labels實(shí)現(xiàn)
2)由概率分布計(jì)算得到,例如深度網(wǎng)絡(luò)的softmax輸出。即我們之前先對(duì)圖片使用訓(xùn)練好的網(wǎng)絡(luò)預(yù)測(cè)得到最終經(jīng)過(guò)softmax函數(shù)得到的分類結(jié)果,這里需要將這個(gè)結(jié)果轉(zhuǎn)成一元?jiǎng)?br> 對(duì)此,請(qǐng)參閱from pydensecrf.utils import unary_from_softmax

1)unary_from_labels(labels, n_labels, gt_prob, zero_unsure=True)函數(shù)的使用
簡(jiǎn)單分類器,該分類器50%確定注釋(即從訓(xùn)練好的網(wǎng)絡(luò)預(yù)測(cè)img后得到的結(jié)果)是正確的。(與推理示例中相同)。

參數(shù):
labels: numpy.array;標(biāo)簽label映射,即數(shù)據(jù)的形狀的數(shù)組,其中每個(gè)唯一值對(duì)應(yīng)于一個(gè)標(biāo)簽,一種像素值對(duì)應(yīng)一種標(biāo)簽。
n_labels: int;標(biāo)簽的總數(shù)。如果zero_unsure參數(shù)為True(默認(rèn)值),這個(gè)數(shù)字不應(yīng)該包括' 0 '標(biāo)簽,因?yàn)? 0 '不是一個(gè)標(biāo)簽!
gt_prob: float;基本事實(shí)的確定性(必須在(0,1)之內(nèi))。
zero_unsure: bool;如果“True”,則將標(biāo)簽值“0”視為“可能是任何東西”,即具有此值的項(xiàng)將得到一致的一元概率,不將其當(dāng)作標(biāo)簽。如果“False”,不要特別對(duì)待值“0”,而是像對(duì)待任何其他類一樣對(duì)待它。

2)unary_from_softmax(sm, scale=None, clip=1e-5)函數(shù)的使用
將softmax類概率轉(zhuǎn)換為一元?jiǎng)?每個(gè)節(jié)點(diǎn)的NLL),即我們之前先對(duì)圖片使用訓(xùn)練好的網(wǎng)絡(luò)預(yù)測(cè)得到最終經(jīng)過(guò)softmax函數(shù)得到的分類結(jié)果,這里需要將這個(gè)結(jié)果轉(zhuǎn)成一元?jiǎng)荨?/p>

參數(shù):
sm: numpy.array,第一個(gè)維度是類的softmax的輸出,其他所有維度都是flattend。這意味著“sm.shape[0] == n_classes”。
scale: float,softmax輸出的確定性(默認(rèn)為None),需要值在(0,1]。如果不為None,則softmax輸出被縮放到從[0,scale]概率的范圍。
clip: float,將概率裁剪到的最小值。這是因?yàn)橐辉瘮?shù)是概率的負(fù)對(duì)數(shù),而log(0) = inf,所以我們需要把0概率裁剪成正的值。
在這里因?yàn)?code>scale=None,clip=None,所以這個(gè)函數(shù)的作用其實(shí)只進(jìn)行了下面的操作:
-np.log(sm).reshape([num_cls, -1]).astype(np.float32)
構(gòu)建好一元?jiǎng)莺笮枰{(diào)用, 將該一元?jiǎng)萏砑拥紺RF中:
d.setUnaryEnergy(U)

5、參考

??[1] 如何輕松愉快地理解條件隨機(jī)場(chǎng)(CRF)?
??[2] 圖像語(yǔ)義分割之FCN和CRF
??[3] https://hit-computer.github.io/2017/06/10/CRF/
??[4] DeepLearning-500-questions第九章 圖像分割d
??[5] https://zhuanlan.zhihu.com/p/64854535
??[6] pydensecrf的使用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容