Asmastas Maz
Asmastas Maz

Reputation: 397

Removing pixels surrounded by white pixels OpenCV

I have a black and white image which has a lot of noise. I would like to remove only black pixels that are completely surrounded by white ones. I tried doing so with Filter2d, but I could not achieve it.

Upvotes: 4

Views: 4800

Answers (3)

arccoder
arccoder

Reputation: 57

4 years later, I ran into a similar task to weed out single pixel noise.

OpenCV's filterspeckles function from Camera Calibration module proved useful for the task.

Code:

import cv2
import numpy as np

data = np.array([[1, 1, 1, 1, 1, 1],
                 [1, 1, 1, 1, 1, 0],
                 [1, 0, 0, 0, 0, 1],
                 [1, 0, 1, 0, 0, 0],
                 [1, 0, 1, 0, 1, 0],
                 [1, 0, 0, 0, 0, 0]]).astype(np.uint8)

print('Input')
print(data)
cv2.filterSpeckles(data, 0, 1, 1)[0]

print('Output')
print(data)

Console:

Input
[[1 1 1 1 1 1]
 [1 1 1 1 1 0]
 [1 0 0 0 0 1]
 [1 0 1 0 0 0]
 [1 0 1 0 1 0]
 [1 0 0 0 0 0]]
Output
[[1 1 1 1 1 1]
 [1 1 1 1 1 0]
 [1 0 0 0 0 0]
 [1 0 1 0 0 0]
 [1 0 1 0 0 0]
 [1 0 0 0 0 0]]

Upvotes: 2

Oliver W.
Oliver W.

Reputation: 13459

I'd use a convolution (again) 1:

>>> import numpy as np
>>> from scipy.signal import convolve2d
>>> 
>>> kernel = np.ones((3,3))
>>> kernel[1,1] = 0
>>> print(kernel)
[[ 1.  1.  1.]
 [ 1.  0.  1.]
 [ 1.  1.  1.]]
>>> # Create a decent test array that shows the features
... test = np.array(
...     [[0,1,1,0,1,1],
...      [1,1,1,1,1,0],
...      [1,0,1,1,0,1],
...      [1,1,1,0,0,0],
...      [1,1,1,0,1,0],
...      [1,1,1,0,0,0]])
>>> 
>>> mask = convolve2d(test, kernel, mode='same', fillvalue=1)
>>> print(mask)
[[ 8.  7.  7.  8.  6.  7.]
 [ 6.  6.  6.  6.  5.  7.]
 [ 7.  8.  6.  5.  4.  4.]
 [ 7.  7.  5.  5.  3.  5.]
 [ 8.  8.  5.  4.  0.  4.]
 [ 8.  8.  6.  6.  4.  6.]]
>>> result = test.copy()
>>> result[np.logical_and(mask==8, test==0)] = 1
>>> print(result)
[[1 1 1 1 1 1]
 [1 1 1 1 1 0]
 [1 1 1 1 0 1]
 [1 1 1 0 0 0]
 [1 1 1 0 1 0]
 [1 1 1 0 0 0]]

As you can see, the result array has changed all "black" pixels (here represented by the value of 0) that were completely surrounded by white (represented by ones) on all 8 sides, even in the corners and on the edges.

Edit: Hugo Rune's answer is better though if you have "pepper" noise, which means you'd have small groups of black pixels that are surrounded by white pixels and not just single pixels. For single pixels, which is how I interpreted your question, the above will work fine.

Footnote:

1: Actually you'd need a correlation, but in this case it is the same, because the kernel is symmetric.

Upvotes: 3

HugoRune
HugoRune

Reputation: 13829

You have two possibilities:

Perform a morphological closing.

enter image description here

This will remove all single black pixels, but it will also remove some other shapes, such as one-pixel-thick black lines, or sharp black corners

This is the standard approach to remove "pepper-noise", noisy individual black pixels.


The other way, which will remove only lone black pixels:

  • invert the image
  • use findContours to find all connected components in the inverted image
  • select all found contours with an area of 1, and paint them white in the original image

This will however not work if two random black pixels are by chance neighbours, so perhaps paint over all areas of size 2 or 3.

Upvotes: 2

Related Questions