Search code examples
pythonimage-processingscikit-imagelbph-algorithm

Unexpected behavior in local binary pattern - python skimage


I've been running into problems recently where the local binary pattern method in python skimage is producing unexpected results.

Have a look at the cartoon example below. It shows two flat color circles on a flat color background.

circles

The local binary pattern (P=8 samples, Radius=1) output is:

lbp

(Image is color coded in jet colors). The gray color correctly represents 255. However, the blue color is 85 (binary 01010101).

So while the method correctly shows the background and the circle on the right as 255, it shows the left circle as 85. Apparently, the local binary pattern method in skimage thinks the region is completely noisy (hence the alternating binary pattern 01010101). This is not true, however, as I have double checked the individual pixels in the region shown in blue above and their values are identical (i.e. its flat color, just like the flat color background and other flat color circle).

Has anyone experienced a similar problem before?

Here is the code if you want to replicate this:

from skimage.feature import local_binary_pattern
from skimage.color import rgb2gray
import matplotlib.pyplot as plt

img = plt.imread('circles.png')
img = rgb2gray(img)

lbp = local_binary_pattern(img, 8, 1, 'default')
plt.imshow(lbp, cmap='nipy_spectral')
plt.title('Standard lbp (8,1)')

Solution

  • I guess the issue is due to numeric errors. When the color image is read using

    img = plt.imread('circles.png')
    

    you get an array of type float32 and in the subsequent conversion to grayscale

    img = skimage.color.rgb2gray(img)
    

    the resulting image is of type float64.

    I recommend you to avoid the intermediate step. You could read the image with double precision (i.e. float64) from the very beginning like this:

    In [63]: from skimage.feature import local_binary_pattern
    
    In [64]: from skimage import io
    
    In [65]: img = io.imread('circles.png', as_grey=True)
    
    In [66]: img.dtype
    Out[66]: dtype('float64')
    
    In [67]: lbp = local_binary_pattern(img, 8, 1, 'default')
    
    In [68]: io.imshow(lbp/255., cmap='nipy_spectral')
    Out[68]: <matplotlib.image.AxesImage at 0x10bdd780>
    

    results