參考:https://github.com/lucasb-eyer/pydensecrf
1.使用
對於圖像來說,最簡單的使用該庫的方法是使用DenseCRF2D類:
import numpy as np import pydensecrf.densecrf as dcrf d = dcrf.DenseCRF2D(640, 480, 5) # width, height, nlabels
2.一元勢 Unary potential
你可以使用下面的方法設置固定的一元勢
一元勢即網絡預測得到的結果,進行-np.log(py)等操作
U = np.array(...) # Get the unary in some way. print(U.shape) # -> (5, 480, 640) print(U.dtype) # -> dtype('float32') U = U.reshape((5,-1)) # Needs to be flat. d.setUnaryEnergy(U) # Or alternatively: d.setUnary(ConstUnary(U))
記住U應該是負的log概率,所以如果你用概率py,別忘了執行U = -np.log(py)
需要在一元勢上進行reshape是我想要修復的API缺陷,但是如果不引入對numpy的顯式依賴,我不知道如何解決這個問題。
注意,nlabel維度是這里reshape之前的第一個維度;如果不是這樣的話,你可能需要在reshape之前把nlabel移到前面,即U.shape的結果應該為(5, 480, 640),就像這樣:
print(U.shape) # -> (480, 640, 5) U = U.transpose(2, 0, 1).reshape((5,-1))
1)Getting a Unary
得到 unary potentials有兩種常見的方法:
1)由人類或其他過程產生的硬標簽。該方法由from pydensecrf.utils import unary_from_labels實現
2)由概率分布計算得到,例如深度網絡的softmax輸出。即我們之前先對圖片使用訓練好的網絡預測得到最終經過softmax函數得到的分類結果,這里需要將這個結果轉成一元勢
對此,請參閱from pydensecrf.utils import unary_from_softmax
1)unary_from_labels(labels, n_labels, gt_prob, zero_unsure=True)函數的使用
簡單分類器,該分類器50%確定注釋(即從訓練好的網絡預測img后得到的結果)是正確的。(與推理示例中相同)。
參數:
- labels: numpy.array;標簽label映射,即數據的形狀的數組,其中每個唯一值對應於一個標簽,一種像素值對應一種標簽。
- n_labels: int;標簽的總數。如果' zero_unsure'參數為True(默認值),這個數字不應該包括' 0 '標簽,因為' 0 '不是一個標簽!
- gt_prob: float;基本事實的確定性(必須在(0,1)之內)。
- zero_unsure: bool;如果“True”,則將標簽值“0”視為“可能是任何東西”,即具有此值的項將得到一致的一元概率,不將其當作標簽。如果“False”,不要特別對待值“0”,而是像對待任何其他類一樣對待它。
2)unary_from_softmax(sm, scale=None, clip=1e-5)函數的使用
將softmax類概率轉換為一元勢(每個節點的NLL)。
即我們之前先對圖片使用訓練好的網絡預測得到最終經過softmax函數得到的分類結果,這里需要將這個結果轉成一元勢
參數
- sm: numpy.array ,第一個維度是類的softmax的輸出,其他所有維度都是flattend。這意味着“sm.shape[0] == n_classes”。
- scale: float,softmax輸出的確定性(默認為None),需要值在(0,1]。如果不為None,則softmax輸出被縮放到從[0,scale]概率的范圍。
- clip: float,將概率裁剪到的最小值。這是因為一元函數是概率的負對數,而log(0) = inf,所以我們需要把0概率裁剪成正的值。
在這里因為scale=None,clip=None,所以這個函數的作用其實只進行了下面的操作:
-np.log(sm).reshape([num_cls, -1]).astype(np.float32)
構建好一元勢后需要調用:
d.setUnaryEnergy(U)
將該一元勢添加到CRF中
3.Pairwise potentials(二元勢)
二維情況下,增加最常見的二元勢有兩種實用方法:
二元勢即用於描述像素點和像素點之間的關系,鼓勵相似像素分配相同的標簽,而相差較大的像素分配不同的標簽。這個相似的定義與顏色值srgb和實際相對距離sxy相關,所以CRF能夠使圖片盡量在邊界處分割。
- d.addPairwiseGaussian這個函數創建的是顏色無關特征,這里只有位置特征(只有參數實際相對距離sxy),並添加到CRF中
- d.addPairwiseBilateral這個函數根據原始圖像img創建顏色相關和位置相關特征並添加到CRF中,特征為(x,y,r,g,b)
# This adds the color-independent term, features are the locations only. d.addPairwiseGaussian(sxy=(3,3), compat=3, kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC) # This adds the color-dependent term, i.e. features are (x,y,r,g,b). # im is an image-array, e.g. im.dtype == np.uint8 and im.shape == (640,480,3) d.addPairwiseBilateral(sxy=(80,80), srgb=(13,13,13), rgbim=im, compat=10, kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC)
這兩種方法都有快捷方式和默認參數,因此最常見的用例可以簡化為:
d.addPairwiseGaussian(sxy=3, compat=3) d.addPairwiseBilateral(sxy=80, srgb=13, rgbim=im, compat=10)
im即image
參數映射到本文中的參數如下:高斯情況下的sxy為$\theta_{\gamma}$(即Θγ),雙邊情況下,sxy和srgb分別映射到$\theta_{\alpha}$(即Θα)和$\theta_{\beta}$(即ΘΒ)。names是“x/y標准偏差”(x/y standard-deviation,sxy)和“rgb標准偏差”(rgb standard-deviation,srgb)的簡寫,公式為:

1)Non-RGB bilateral
一個重要的警告是,addPairwiseBilateral只適用於RGB圖像,即三個通道。如果您的數據與這個簡單但常見的情況不同,則需要使用util .create_pairwise_bilateral函數計算你自己的二元能源;有關詳細信息,請參閱 generic non-2D case案例。
在examples文件夾中以筆記本的形式提供了一個example of working with Non-RGB data例子。
可見Example of DenseCRF with non-RGB data
2)Compatibilities
compat參數可以是以下任何一種:
- 一個數字,然后使用PottsCompatibility。
- 一個一維數組,然后使用對角兼容性。
- 一個二維數組,然后使用矩陣兼容性。
這些是label-compatibilites µ(xi, xj)的參數可能學到的東西。例如,他們可以指出把鳥的像素誤認為天空並不像把貓誤認為天空那么糟糕。數組應該有nlabel或(nlabel,nlabel)作為shape和一個float32數據類型。
3)Kernels
kenel參數的可能值有:
CONST_KERNELDIAG_KERNEL(the default)FULL_KERNEL
4)Normalizations
NO_NORMALIZATIONNORMALIZE_BEFORENORMALIZE_AFTERNORMALIZE_SYMMETRIC(the default)
5)Kernel weight權重
4.Inference推理
Q = d.inference(5)
然后MAP預測是:
map = np.argmax(Q, axis=0).reshape((640,480))
如果你對類概率Q感興趣,你會注意到Q是一個包裝好的特征矩陣。本項目的特征包裝器實現緩沖接口,可以簡單地轉換為numpy數組,如下:
proba = np.array(Q)
5.Step-by-step inference一步步推理
如果出於某種原因,你想手動運行推理循環,你可以這樣做:
Q, tmp1, tmp2 = d.startInference() for i in range(5): print("KL-divergence at {}: {}".format(i, d.klDivergence(Q))) d.stepInference(Q, tmp1, tmp2)
6.Generic non-2D
DenseCRF類可用於一般(非2d)denseCRFs。它的用法與上面完全一樣,只是缺少了特定於2d的二元勢addPairwiseGaussian和addPairwiseBilateral。
相反,您需要使用通用的addPairwiseEnergy方法,如下所示:
d = dcrf.DenseCRF(100, 5) # npoints, nlabels feats = np.array(...) # Get the pairwise features from somewhere. print(feats.shape) # -> (7, 100) = (feature dimensionality, npoints) print(feats.dtype) # -> dtype('float32') dcrf.addPairwiseEnergy(feats)
此外,你還可以傳遞兼容性、內核參數和標准化參數,就像在二維高斯和雙邊情況下一樣。
勢函數計算為w*exp(-0.5 * |f_i - f_j|^2)。
當然,首先你要先使用create_pairwise_gaussian和create_pairwise_bilateral,然后才能使用addPairwiseEnergy
1.create_pairwise_gaussian(sdims, shape)函數的使用
創建二元高斯勢的Util函數。這適用於所有的圖像尺寸。對於2D例子,他等價於DenseCRF2D.addPairwiseGaussian的操作
參數:
- sdims: list or tuple;每個維度的比例因子,等價於DenseCRF2D.addPairwiseGaussian中的sxy參數
- shape: list or tuple;CRF的形狀
2.create_pairwise_bilateral(sdims, schan, img, chdim=-1)
創造二元雙邊勢的Util函數。這適用於所有的圖像尺寸。對於2D例子,等價於DenseCRF2D.addPairwiseBilateral。
參數:
- sdims: list or tuple;每個維度的比例因子。即DenseCRF2D.addPairwiseBilateral中的“sxy”
- schan: list or tuple;圖像中每個通道的比例因子。即DenseCRF2D.addPairwiseBilateral中的“srgb”參數
- img: numpy.array;輸入的圖片
- chdim: int, optional;這指定了通道維度在圖像中的位置。例如,' chdim=2 '用於大小為(240,300,3)的RGB圖像,指定維度值3放在索引2的位置處。如果圖像沒有通道尺寸(例如只有一個通道),則使用' chdim=-1 '
d = dcrf.DenseCRF(img.shape[1] * img.shape[0], n_labels) # get unary potentials (neg log probability) # 得到一元勢(即去負對數),labels為對所有像素值標注label后的數組,label類型n_labels=2, U = unary_from_labels(labels, n_labels, gt_prob=0.7, zero_unsure=HAS_UNK) #U.shape為(2, 76800),即(n_labels,len(labels)) d.setUnaryEnergy(U) # This creates the color-independent features and then add them to the CRF feats = create_pairwise_gaussian(sdims=(3, 3), shape=img.shape[:2]) d.addPairwiseEnergy(feats, compat=3, kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC) # This creates the color-dependent features and then add them to the 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)
1)Pairwise potentials for N-D
用戶@markusnagel編寫了幾個numpy函數,將兩個經典的二維圖像二元勢(高斯和雙邊)推廣到任意維數:create_pairwise_gaussian和create_pairwise_bilateral。
你可以從from pydensecrf.utils import create_pairwise_gaussian訪問它們,然后查看它們的文檔去了解如何使用它們。
7.Learning
這里有一個供初學者參考的指針:第24期。我們需要包裝梯度和獲取/設置參數。但是,我們還需要對這些做一些事情,最有可能的是從optimization.cpp調用minimizeLBFGS。遵循原始代碼中包含的學習示例應該相對簡單。
