Reputation: 397
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
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
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
Reputation: 13829
You have two possibilities:
Perform a morphological closing.
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:
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