Search code examples
pythonimage-processingscikit-imageimage-thresholding

How to fix error running local Otsu threshold example on my own images?


I am basically trying to preprocess an image for a better OCR recognition. I've decided to use scikit-image (or should I use maybe something else)?

I am following the example shown here:

https://scikit-image.org/docs/stable/auto_examples/applications/plot_thresholding.html#id4

And, I have downloaded this script:

https://scikit-image.org/docs/stable/_downloads/939bd4a228ba1525a5e2896c819e2218/plot_thresholding.py

To test it with my own image, I've replaced this line

img = img_as_ubyte(data.page())

with this:

from skimage import io

img = img_as_ubyte(io.imread('test.jpg'))

But, I am getting this error:

File "/Users/janine/Downloads/test.py", line 207, in <module>
  local_otsu = rank.otsu(img, selem)
File "/usr/local/lib/python3.9/site-packages/skimage/filters/rank/generic.py", line 1399, in otsu
  return _apply_scalar_per_pixel_3D(generic_cy._otsu_3D, image,
File "/usr/local/lib/python3.9/site-packages/skimage/filters/rank/generic.py", line 278, in _apply_scalar_per_pixel_3D
  image, selem, out, mask, n_bins = _handle_input_3D(image, selem, out, mask,
File "/usr/local/lib/python3.9/site-packages/skimage/filters/rank/generic.py", line 199, in _handle_input_3D
  raise ValueError('Image dimensions and neighborhood dimensions'
    ValueError: Image dimensions and neighborhood dimensionsdo not match

I have tried with multiple images so the problem is not the image.


Solution

  • Inspecting data.page(), we notice, that this image is a single-channel (i.e. grayscale) image. Later in the linked example, you set up the structuring element selem like so:

    selem = disk(radius)
    

    Please notice, that skimage.morphology.disk is a "2D structuring element", which can only be used with a "2D image", i.e. a grayscale image.

    Most likely, your test.jpg now is a three-channel (i.e. color) image, thus a "3D image". When using a "2D structuring element" like disk with a "3D image", you get the given error.

    Now, you have two options:

    1. Convert your input color image to some grayscale image, simply by setting as_gray=True in skimage.io.imread. Then you can use the rest of the code as-is.
    2. Use some "3D structuring element" like skimage.morphology.ball, which would be the 3D equivalent to disk, to use your input image as-is.

    Here's some minimal code for reference:

    from matplotlib import pyplot as plt
    from skimage.filters import rank
    from skimage.io import imread
    from skimage.morphology import ball, disk
    from skimage.util import img_as_ubyte
    
    # Option #1: 2D image (e.g. grayscale input image), and 2D structuring element
    img = img_as_ubyte(imread('path/to/your/image.png', as_gray=True))
    radius = 15
    selem = disk(radius)
    local_otsu = rank.otsu(img, selem)
    plt.figure(1)
    plt.imshow(local_otsu, vmin=0, vmax=255, cmap='gray')
    
    # Option #2: 3D image (original input image), and 3D structuring element
    img = img_as_ubyte(imread('path/to/your/image.png'))
    radius = 15
    selem = ball(radius)
    local_otsu = rank.otsu(img, selem)
    plt.figure(2)
    plt.imshow(local_otsu, vmin=0, vmax=255)
    
    plt.show()
    

    And, the two resulting outputs:

    Option 1

    Option 2

    ----------------------------------------
    System information
    ----------------------------------------
    Platform:      Windows-10-10.0.19041-SP0
    Python:        3.9.1
    PyCharm:       2021.1.1
    Matplotlib:    3.4.1
    scikit-image:  0.18.1
    ----------------------------------------