pydensecrf的inference.py代碼的學習


https://github.com/lucasb-eyer/pydensecrf/blob/master/examples/inference.py

1.運行

先運行看看實現的結果:

(deeplearning) userdeMBP:examples user$ python inference.py im1.png anno1.png out1.png
Found a full-black pixel in annotation image, assuming it means 'unknown' label, and will thus not be present in the output!
If 0 is an actual label for you, consider writing your own code, or simply giving your labels only non-zero values.
2  labels  plus "unknown" 0:  {0, 1, 2}
Using generic 2D functions
KL-divergence at 0: -543957.3854815669
KL-divergence at 1: -890605.7866870646
KL-divergence at 2: -919933.3682610085
KL-divergence at 3: -921683.1852052805
KL-divergence at 4: -922674.4361045817

im1.pnganno1.png是輸入圖片,out1.png為進行crf處理后的輸出圖片

im1.png和anno1.png為:

得到的輸出結果是:

可見效果變得很好

 

2.代碼分析

"""
Adapted from the inference.py to demonstate the usage of the util functions.
"""

import sys
import numpy as np
import pydensecrf.densecrf as dcrf

# Get im{read,write} from somewhere.
try:
    from cv2 import imread, imwrite
except ImportError:
    # Note that, sadly, skimage unconditionally import scipy and matplotlib,
    # so you'll need them if you don't have OpenCV. But you probably have them.
    from skimage.io import imread, imsave
    imwrite = imsave
    # TODO: Use scipy instead.

from pydensecrf.utils import unary_from_labels, create_pairwise_bilateral, create_pairwise_gaussian

if len(sys.argv) != 4:
    print("Usage: python {} IMAGE ANNO OUTPUT".format(sys.argv[0]))
    print("")
    print("IMAGE and ANNO are inputs and OUTPUT is where the result should be written.")
    print("If there's at least one single full-black pixel in ANNO, black is assumed to mean unknown.")
    sys.exit(1)

fn_im = sys.argv[1]#輸入的圖片
print(fn_im)
fn_anno = sys.argv[2]#輸入的圖片fn_im經過訓練后的網絡進行預測得到的結果
print(fn_anno)
fn_output = sys.argv[3]#指定進行crf處理后的結果輸出
print(fn_output)

##############################################################
### Read images and annotation讀取輸入的兩個圖片fn_im和fn_anno###
##############################################################
img = imread(fn_im)

# Convert the annotation's RGB color to a single 32-bit integer color 0xBBGGRR
#將fn_anno的三個uint8表示的RGB像素值放到一個uint32像素值中表示
#[0,7]位為R層的值,[8,15]為G層的值,[16,23]為B層的值
anno_rgb = imread(fn_anno).astype(np.uint32)#shape為(240, 320, 3)
anno_lbl = anno_rgb[:,:,0] + (anno_rgb[:,:,1] << 8) + (anno_rgb[:,:,2] << 16)#shape變為了(240, 320)

# Convert the 32bit integer color to 1, 2, ... labels.
# Note that all-black, i.e. the value 0 for background will stay 0.
# np.unique該函數是去除數組中的重復數字,並進行排序之后輸出
# 這就得到了整張圖中有的像素值序列
# #colors返回為[0,16384,4227072],說明圖片fn_anno只有這三種像素值
# labels的shape為(76800,),其為anno_lbl中所有的像素值標上了對應的label
# 在這里color=0時,對應的label為0;color=16384時,對應的label為1;color=4227072時,對應的label為2
# 黑色的像素值為0
colors, labels = np.unique(anno_lbl, return_inverse=True)

# But remove the all-0 black, that won't exist in the MAP!
# 移除像素值為0,即黑色的值
HAS_UNK = 0 in colors#若0存在於colors中,則HAS_UNK為True
#在annotation圖像中的黑色像素,即color=0的像素,被假設為label='unknown',不會在output中輸出
#如果0是一個對你來說有意義的label,那么更改你的代碼,或者盡量讓你的label為非0的數值
if HAS_UNK:
    print("Found a full-black pixel in annotation image, assuming it means 'unknown' label, and will thus not be present in the output!")
    print("If 0 is an actual label for you, consider writing your own code, or simply giving your labels only non-zero values.")
    colors = colors[1:]#然后將color=0從數組中移除
#else:
#    print("No single full-black pixel found in annotation image. Assuming there's no 'unknown' label!")

# And create a mapping back from the labels to 32bit integer colors.
# np.empty()返回一個隨機元素的矩陣,值類型為uint8,大小按照參數定義,這里
colorize = np.empty((len(colors), 3), np.uint8)#colorize.shape為(2,3)
#下面將之前合並成0xBBGGRR格式的像素值又分成三層,得到各層像素值的值
colorize[:,0] = (colors & 0x0000FF)#得到R層的值,為[0,0], dtype=uint8
colorize[:,1] = (colors & 0x00FF00) >> 8#得到G層的值,為[ 64, 128], dtype=uint8
colorize[:,2] = (colors & 0xFF0000) >> 16#得到B層的值,[ 0, 64]

# Compute the number of classes in the label image.
# We subtract one because the number shouldn't include the value 0 which stands
# for "unknown" or "unsure".
# set(labels.flat)返回{0, 1, 2}
# flat將數組變為一個迭代器,可以用for訪問數組每一個元素,可以使用索引labels.flat[0]來訪問第一個元素
# set(迭代對象) 函數創建一個無序不重復元素集,可進行關系測試,刪除重復數據
n_labels = len(set(labels.flat)) - int(HAS_UNK) #返回2,得到除去了label=0后還有兩個label
print(n_labels, " labels", (" plus \"unknown\" 0: " if HAS_UNK else ""), set(labels.flat))

###########################
### Setup the CRF model ###
###########################
#上面處理完圖片fn_anno,得到labels和colors
#接下來就是設置CRF模型了

use_2d = False #是否使用二維指定函數DenseCRF2D,這里設置為False,則說明使用的是一般函數DenseCRF
# use_2d = True
if use_2d:
    print("Using 2D specialized functions")

    # Example using the DenseCRF2D code
    d = dcrf.DenseCRF2D(img.shape[1], img.shape[0], n_labels)

    # get unary potentials (neg log probability)
    U = unary_from_labels(labels, n_labels, gt_prob=0.7, zero_unsure=HAS_UNK)
    d.setUnaryEnergy(U)

    # This adds the color-independent term, features are the locations only.
    # 創建顏色無關特征,這里只有位置特征,並添加到CRF中
    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).
    # 根據原始圖像img創建顏色相關特征和位置相關並添加到CRF中,特征為(x,y,r,g,b)
    d.addPairwiseBilateral(sxy=(80, 80), srgb=(13, 13, 13), rgbim=img,
                           compat=10,
                           kernel=dcrf.DIAG_KERNEL,
                           normalization=dcrf.NORMALIZE_SYMMETRIC)
else:
    print("Using generic 2D functions")

    # Example using the DenseCRF class and the util functions
    # 使用DenseCRF類和util函數
    # n_labels為2,從上面對fn_anno的分析可知有兩個label
    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) #將一元勢添加到CRF中

    # This creates the color-independent features and then add them to the CRF
    # 創建顏色無關特征,這里只有位置特征,並添加到CRF中
    feats = create_pairwise_gaussian(sdims=(3, 3), shape=img.shape[:2]) #shape為(240, 320)
    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
    # 根據原始圖像img創建顏色相關和位置相關特征並添加到CRF中,特征為(x,y,r,g,b)
    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)


####################################
### Do inference and compute MAP ###
####################################
#上面就將相應的CRF構建好了
#然后要做的就是對img根據fn_anno得到的label和colors結果進行CRF推理
#然后得到輸出值fn_output了

# Run five inference steps.迭代5次
Q = d.inference(5)

# Find out the most probable class for each pixel.
# 找出每個像素最可能的類
# np.argmax取出Q元素中最大的值對應的索引,axis=0按列查找
MAP = np.argmax(Q, axis=0)
# MAP,MAP.shape返回
# (array([1, 1, 1, ..., 1, 1, 1]), (76800,))

# 將MAP(標簽)轉換回相應的顏色並保存圖像。
#注意,這里不再有“unknown”標簽,不管我們一開始擁有什么。
#colorize返回兩個label的color[16384,4227072]對應的RGB的值
#16384對應[  0,  64,   0],4227072對應[  0, 128,  64]
#array([[  0,  64,   0],
#       [  0, 128,  64]], dtype=uint8)
#MAP中1值對應的是4227072即[  0, 128,  64]
MAP = colorize[MAP,:] #MAP.shape為(76800, 3),這就是最后的結果

#將MAP轉成img相同的大小,就能夠得到最后的結果了
imwrite(fn_output, MAP.reshape(img.shape))

# Just randomly manually run inference iterations
# 這里是手動實現迭代推理
Q, tmp1, tmp2 = d.startInference()
for i in range(5):
    print("KL-divergence at {}: {}".format(i, d.klDivergence(Q)))
    d.stepInference(Q, tmp1, tmp2)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM