6

I would like to remove noise exists in the background. the noise isn't in a standard pattern. I would like to remove the background noise and keep the text on white background.

This an image sample :

enter image description here

I used the below code very simple processing steps.

import cv2 
import numpy as np

img = cv2.imread("noisy.PNG")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.subtract(255,gray)
ret,thresh = cv2.threshold(gray,5,255,cv2.THRESH_TOZERO)


noisy_removal = cv2.fastNlMeansDenoising(thresh, None, 65, 5, 21)
cv2.imwrite("finalresult.jpg",255-noisy_removal)

Here is the output image:

enter image description here

How I can enhance this result

ahmed osama
  • 621
  • 2
  • 12
  • 21

2 Answers2

5

You can play around with contrast/brightness to remove background pixels as discussed in this post.

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

alpha = 2.5
beta = -0.0

denoised = alpha * gray + beta
denoised = np.clip(denoised, 0, 255).astype(np.uint8)

denoised = cv2.fastNlMeansDenoising(denoised, None, 31, 7, 21)

result

zindarod
  • 6,328
  • 3
  • 30
  • 58
  • 1
    It's a good suggestion but its manual task need an intervention to see every image and try the best fit `alpha ` and `beta` – ahmed osama Jul 15 '18 at 09:17
2

This is also based on the difference of gray levels of noise pixels and the text. You can adjust threshold manually. May be you can arrive at a reasonable auto-threshold by taking into account the distribution of the noise and text pixels values. Below I use such threshold, which is the mean - std. It works for the given image, but not sure if it'll work in general.

im = cv2.imread('XKRut.jpg')
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

# calculate auto-threshold value
# noise and text pixels
_, bw = cv2.threshold(cv2.GaussianBlur(gray, (3, 3), 0), 0, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)
# find mean and std of noise and text pixel values
mu, sd = cv2.meanStdDev(gray, mask=bw)

simple = gray.copy()
# apply the auto-threshold to clean the image
thresh = mu - sd
simple[simple > thresh] = 255
simple[simple <= thresh] = 0

simple2 = simple.copy()
# clean it further considering text-like pixel density in a 3x3 window
# using avg = ~cv2.blur(simple, (3, 3)) is more intuitive, but Gaussian
# kernel gives more weight to center pixel
avg = ~cv2.GaussianBlur(simple, (3, 3), 0)
# need more than 3 text-like pixels in the 3x3 window to classify the center pixel
# as text. otherwise it is noise. this definition is more relevant to box kernel
thresh2 = 255*3/9
simple2[avg < thresh2] = 255

Cleaned image:

simple

Clean image taking into account the pixel density:

simple2

If your images don't have a huge variation in their pixel values, you can pre-calculate a best threshold, or an alpha, beta pair for zindarod's solution.

dhanushka
  • 10,492
  • 2
  • 37
  • 47
  • This solution looks good but the problem it works on this image only. I think will try to generalize the solution. – ahmed osama Jul 16 '18 at 16:37