3

I have a white and black image. I try to remove noise by remove_small_objects.

import cv2 as cv
import numpy as np
from skimage import morphology

img = np.array([[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
                [255, 255,   0, 255,   0,   0,   0,   0, 255, 255, 255],
                [255, 255, 255, 255,   0,   0,   0,   0, 255,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0, 255,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0]])

cleaned = morphology.remove_small_objects(img, min_size=10, connectivity=1)
print(cleaned)

while True:
    cv.imshow('Demo', cleaned.astype(np.uint8))
    if cv.waitKey(1) & 0xFF == 27:
        break

cv.destroyAllWindows()

However, it didn't work as I expected. The white pixel 255 in the middle is still there.

Did I do something wrong? Thanks

enter image description here

Tonechas
  • 13,398
  • 16
  • 46
  • 80
Hongbo Miao
  • 45,290
  • 60
  • 174
  • 267

1 Answers1

7

From the docs (emphasis mine):

skimage.morphology.remove_small_objects(ar, min_size=64, connectivity=1, in_place=False)

Remove objects smaller than the specified size.

Expects ar to be an array with labeled objects, and removes objects smaller than min_size. If ar is bool, the image is first labeled. This leads to potentially different behavior for bool and 0-and-1 arrays.

import numpy as np
from skimage import io, morphology
import matplotlib.pyplot as plt

img = np.array([[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
                [255, 255,   0, 255,   0,   0,   0,   0, 255, 255, 255],
                [255, 255, 255, 255,   0,   0,   0,   0, 255,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0, 255,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255, 255,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0],
                [255, 255,   0,   0,   0,   0,   0,   0,   0,   0,   0]])

arr = img > 0
cleaned = morphology.remove_small_objects(arr, min_size=2)
cleaned = morphology.remove_small_holes(cleaned, min_size=2)

fig, axs = plt.subplots(1, 2)
axs[0].imshow(img, cmap='gray')
axs[0].set_title('img')
axs[1].imshow(cleaned, cmap='gray')
axs[1].set_title('cleaned')
plt.show(fig)

plot

Tonechas
  • 13,398
  • 16
  • 46
  • 80
  • It works! I am wondering why when `ndarray` is int array, it is not working.. The doc says It can be `arbitrary shape, int or bool type. The array containing the objects of interest. If the array type is int, the ints must be non-negative.` – Hongbo Miao Mar 08 '19 at 19:56
  • 4
    The point is that if the array is bool, it is first labeled. If it is int, then each value is considered a different object. In this case, the function assumes that the small blob is still part of the object called "255". Other than converting to bool, you could also run `skimage.measure.label` (or `scipy.ndimage.label`) on your image, and then use that as input. – Juan Mar 09 '19 at 14:59