一. LBP特徵
LBP(Local Binary Pattern),局部二值模式,主要用於提取紋理特徵,根據文獻[1]我們可以瞭解到LBP及其變體。一般的使用方法是,先將圖像轉換爲灰度圖,接着計算LBP特徵圖,最後計算其直方圖作爲特徵向量。0.如何描述紋理信息
不多說,看圖。LBP特徵可以表示平坦、邊緣、角點等區域。1.original LBP
最經典的LBP特徵,對於某像素的8-鄰域,大於該像素值的置1,小於該像素值的置0,最後組成八位二進制碼。
2.採樣方式及角空間
圓形鄰域的像素採樣方式會比8-鄰域的方式要更靈活,可以通過改變圓形的半徑R來調整鄰域大小。但半徑R越大,採樣點的數目P也越多。對於沒有落到像素格子中央的點的灰度值,一般採用插值法得到。除此之外,通過對採樣角度設置更高的量化等級,可以得到更精細的角度分辨率。
3.灰度不變性
由於各鄰域像素的灰度值需要減去中心像素的灰度值,可以實現針對平均光源的灰度不變性。4.旋轉不變性
由於編碼的起始點是一定的,每一種二值編碼模式經旋轉(循環位移)後會產生不同的編碼結果。爲了形成旋轉不變的編碼模式,我們讓有同一編碼模式經旋轉後產生的編碼結果編碼爲同一值,定義二值編碼爲這些旋轉結果中的最小值。在具體代碼實現時,通過使用計算映射(mapping)的方式來將不同的旋轉二值編碼映射爲旋轉不變的二值編碼。
5.uniform LBP
首先,我們將LBP的二值編碼看作是頭尾相接的,接着定義計數U爲二值編碼中0-1變化的次數(即0變成1,或者1變成0,記做一次),公式表達如下:而對於其它的非uniform編碼,我們將其歸爲一類。之所以這樣定義,是因爲這類編碼易受噪聲影響,變化頻率非常大。
最終的uniform LBP計算公式如下:
6.結合對比度的LBP
根據灰度不變LBP的定義,我們直接捨棄了像素點間的灰度幅值差異,進而丟失了對比度的信息(即灰度值的方差)。因此,我們考慮結合對比度Var和LBP作爲聯合特徵. 對比度計算公式如下:二. Python實現
在研究了網上LBP的代碼實現後,我認爲使用ski-image包的LBP特徵提取函數比較好,因爲它封裝了多種LBP的方法,非常簡單易用。官網上的參考文檔如下:Parameters: | image : (N, M) array
P : int
R : float
method : {‘default’, ‘ror’, ‘uniform’, ‘var’}
|
---|---|
Returns: | output : (N, M) array
|
# settings for LBP
radius = 2
n_points = 8 * radius
def kullback_leibler_divergence(p, q):
p = np.asarray(p)
q = np.asarray(q)
filt = np.logical_and(p != 0, q != 0)
return np.sum(p[filt] * np.log2(p[filt] / q[filt]))
def match(refs, img):
best_score = 10
best_name = None
lbp = local_binary_pattern(img, n_points, radius, METHOD)
n_bins = int(lbp.max() + 1)
hist, _ = np.histogram(lbp, normed=True, bins=n_bins, range=(0, n_bins))
for name, ref in refs.items():
ref_hist, _ = np.histogram(ref, normed=True, bins=n_bins,
range=(0, n_bins))
score = kullback_leibler_divergence(hist, ref_hist)
if score < best_score:
best_score = score
best_name = name
return best_name
brick = data.load('brick.png')
grass = data.load('grass.png')
wall = data.load('rough-wall.png')
refs = {
'brick': local_binary_pattern(brick, n_points, radius, METHOD),
'grass': local_binary_pattern(grass, n_points, radius, METHOD),
'wall': local_binary_pattern(wall, n_points, radius, METHOD)
}
# classify rotated textures
print('Rotated images matched against references using LBP:')
print('original: brick, rotated: 30deg, match result: ',
match(refs, rotate(brick, angle=30, resize=False)))
print('original: brick, rotated: 70deg, match result: ',
match(refs, rotate(brick, angle=70, resize=False)))
print('original: grass, rotated: 145deg, match result: ',
match(refs, rotate(grass, angle=145, resize=False)))
# plot histograms of LBP of textures
fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(nrows=2, ncols=3,
figsize=(9, 6))
plt.gray()
ax1.imshow(brick)
ax1.axis('off')
hist(ax4, refs['brick'])
ax4.set_ylabel('Percentage')
ax2.imshow(grass)
ax2.axis('off')
hist(ax5, refs['grass'])
ax5.set_xlabel('Uniform LBP values')
ax3.imshow(wall)
ax3.axis('off')
hist(ax6, refs['wall'])
plt.show()
結果如下:網站參考:
官方例程
參考文獻:
[1] Ojala T, Pietikäinen M, Mäenpää T. Multiresolution Gray-Scale and Rotation Invariant Texture Classification with Local Binary Patterns[C]// European Conference on Computer Vision. Springer-Verlag, 2000:404-420.
[2] Walt S V D, Schönberger J L, Nuneziglesias J, et al. scikit-image: image processing in Python[J]. Peerj, 2014, 2(2):e453.