I am using the local_binary_pattern
function in the scikit-image package. I would like to compute the rotation invariant uniform LBP of 8 neighbors within 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 output
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 some same values in lbp
do not correspond to the same uniform pattern. E.g., lbp[1, 1]
and lbp[2, 2]
are both 6
, but the LBP of image[1, 1]
is:
1 0 0
1 x 1
1 1 1
The LBP of image[2, 2]
is:
1 1 1
1 x 0
1 1 1
where based on the values in lbp
, I assume the local_binary_pattern
function uses 'greater or equal to' to compare with neighbors.
The LBPs of image[1, 1]
and image[2, 2]
are both uniform. But how could image[1, 1]
and image[2, 2]
have the same LBP value?
In order to improve robustness against rotation of the LBP descriptor the square neighbourhood is replaced by a circular one. In a circular neighbourhood formed by eight pixels the four neighbours on the diagonals do not coincide with pixel centers. The intensity values of those neighbours are commonly computed through bilinear interpolation. The following figure graphically explains why in your sample image some LBP3×3 patterns are different to the LBP8,1 patterns.
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])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With