Why the local_binary_pattern function in a scikit image provides the same value for different patterns

I am using the local_binary_pattern function in the scikit-image package. I would like to calculate the rotation invariant of a uniform LBP of 8 neighbors in radius 1. Here is my Python code:

 import numpy as np from skimage.feature import local_binary_pattern image = np.array([[150, 137, 137, 146, 146, 148], [145, 144, 144, 144, 142, 144], [149, 144, 144, 143, 153, 147], [145, 144, 147, 150, 145, 150], [146, 146, 139, 148, 144, 148], [129, 139, 142, 150, 146, 140]]).astype(np.uint8) lbp = local_binary_pattern(image, 8, 1, "uniform") print "image =" print image print "lbp =" print lbp 

And here is the conclusion

 image = [[150 137 137 146 146 148] [145 144 144 144 142 144] [149 144 144 143 153 147] [145 144 147 150 145 150] [146 146 139 148 144 148] [129 139 142 150 146 140]] lbp = [[ 0. 5. 5. 1. 9. 0.] [ 9. 6. 9. 9. 8. 9.] [ 0. 8. 6. 8. 0. 3.] [ 9. 7. 1. 0. 7. 0.] [ 1. 1. 8. 9. 7. 1.] [ 3. 4. 9. 0. 2. 3.]] 

What confuses me is that the same values ​​in lbp do not match the same homogeneous pattern. For example, lbp[1,1] and lbp[2,2] are 6. But LBP image[1,1] is

 1 0 0 1 x 1 1 1 1 

LBP image[2,2] -

 1 1 1 1 x 0 1 1 1 

where, based on the values ​​in lbp , I assume that the local_binary_pattern function uses more than or equal to compare with neighbors.

LBPs image[1,1] and image[2,2] are the same. But how do image[1,1] and image[2,2] have the same LBP value?

+5
source share
2 answers

Rotation-independent LBP does not use pixel values ​​for neighbors directly, but rather, values ​​interpolated in a circle (for rotation invariance). See https://github.com/scikit-image/scikit-image/blob/master/skimage/feature/_texture.pyx#L156

Also see the original LBP paper http://vision.stanford.edu/teaching/cs231b_spring1415/papers/lbp.pdf , which mentions "Gray values ​​of neighbors that do not fall exactly in the center of the pixels are estimated by interpolation."

+3
source

To increase the rotation resistance of the LBP descriptor, the square neighborhood is replaced by a circular one. In a circular neighborhood formed by eight pixels, four neighbors on the diagonals do not coincide with the centers of the pixels. The intensity values ​​of these neighbors are usually calculated using bilinear interpolation. The following figure graphically explains why some sample LBP 3 and times; 3 are different from LBP 8.1 templates.

square and circular surroundings

Code

 w_cen = (1-1/np.sqrt(2))**2 # Weights w_diag = (1/np.sqrt(2))**2 w_orto = (1-1/np.sqrt(2))*(1/np.sqrt(2)) def bilinear_interpoplation(i_cen, i_diag, i_hor, i_ver): return i_cen*w_cen + i_diag*w_diag + i_hor*w_orto + i_ver*w_orto def circular_neighbourhood(x): [I7, I6, I5] = x[0, :] [I0, Ic, I4] = x[1, :] [I1, I2, I3] = x[2, :] I7i = bilinear_interpolation(Ic, I7, I0, I6) I5i = bilinear_interpolation(Ic, I5, I4, I6) I3i = bilinear_interpolation(Ic, I3, I4, I2) I1i = bilinear_interpolation(Ic, I1, I0, I2) interpolated = np.array([[I7i, I6, I5i], [ I0, Ic, I4], [I1i, I2, I3i]]) return interpolated def binary_pattern(x): return np.where(x >= x[1, 1], 1, 0) def display_lbps(patch): interpolated = circular_neighbourhood(patch) print('Patch =') print(patch) print('LBP of patch =') print(binary_pattern(patch)) print('Interpolated patch =') print(interpolated) print('LBP of interpolated patch =') print(binary_pattern(interpolated)) display_lbps(image[0:3, 0:3]) display_lbps(image[1:4, 1:4]) 
+3
source

All Articles