How do we remove chessboard-like noise from an input image

Viewed 633

I'm working on something which requires me to enhance an input image which has consistent chessboard-like noise all over it projected uniformly input image

and this is the expected output image output image

2 Answers

Here is one way using notch filtering in Python/OpenCV.

  • Read the input as grayscale
  • Do DFT to complex real and imaginary components
  • Shift the DC point to the center
  • Convert the real and imaginary components to magnitude and phase
  • Compute the spectrum image from the magnitude
  • Threshold the spectrum image to extract the grid lines corresponding to the regular checkerboard pattern
  • Blacken out the white region around the DC point in the center
  • Invert the mask
  • Multiply the magnitude by the mask
  • Convert the new magnitude and old phase to real and imaginary components
  • Combine real and imaginary components
  • Shift the DC point to the top left corner
  • Do the DIFT and convert to 8-bit range as the notched filter result
  • Stretch the dynamic range to improve visibility
  • Save results

Input:

enter image description here

import numpy as np
import cv2
import skimage.exposure

# read input as grayscale
# opencv fft only works on grayscale
img = cv2.imread('checkerboard_noise.jpg', 0)
hh, ww = img.shape[:2]

# convert image to floats and do dft saving as complex output
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)

# apply shift of origin from upper left corner to center of image
dft_shift = np.fft.fftshift(dft)

# extract magnitude and phase images
mag, phase = cv2.cartToPolar(dft_shift[:,:,0], dft_shift[:,:,1])

# get spectrum for viewing only
spec = (np.log(mag) / 20)

# threshold spectrum as mask
mask = cv2.threshold(spec, 0.5, 1, cv2.THRESH_BINARY)[1]

# blacken out center DC region from mask
cx = ww // 2
cy = hh // 2
mask = cv2.circle(mask, (cx,cy), 10, 0, -1)

# invert mask
mask = 1 - mask

# apply mask to magnitude image
mag_notch = mask*mag

# convert magnitude and phase into cartesian real and imaginary components
real, imag = cv2.polarToCart(mag_notch, phase)

# combine cartesian components into one complex image
complex = cv2.merge([real, imag])

# shift origin from center to upper left corner
complex_ishift = np.fft.ifftshift(complex)

# do idft with normalization saving as real output
img_notch = cv2.idft(complex_ishift, flags=cv2.DFT_SCALE+cv2.DFT_REAL_OUTPUT)
img_notch = img_notch.clip(0,255).astype(np.uint8)

# stretch contrast
img_notch_stretched = skimage.exposure.rescale_intensity(img_notch, in_range=(75,150), out_range=(0,255))

# write result to disk
cv2.imwrite("checkerboard_noise_spectrum.png", (255*spec).clip(0,255).astype(np.uint8))
cv2.imwrite("checkerboard_noise_mask.png", (255*mask).clip(0,255).astype(np.uint8))
cv2.imwrite("checkerboard_noise_notched.png", img_notch)
cv2.imwrite("checkerboard_noise_notched_stretched.png", img_notch_stretched)

# show results
cv2.imshow("ORIGINAL", img)
cv2.imshow("MAG", mag)
cv2.imshow("PHASE", phase)
cv2.imshow("SPECTRUM", spec)
cv2.imshow("MASK", mask)
cv2.imshow("NOTCH", img_notch)
cv2.imshow("NOTCH_STRETCHED", img_notch_stretched)
cv2.waitKey(0)
cv2.destroyAllWindows()

Spectrum:

enter image description here

Mask:

enter image description here

Notched Filter Result:

enter image description here

Notched Filter Contrast Enhanced:

enter image description here

You can try using a Weiner filter. It won't give you as sharp a result you have shown in the question but it can remove the chessboard noise.

from skimage import color, data, restoration
from scipy.signal import convolve2d
import matplotlib.pyplot as plt

img = cv2.imread('chessboard.jpg', 0)
psf = np.ones((9, 9)) / 81
img = convolve2d(img, psf, 'same')
img += 0.1 * img.std() * np.random.standard_normal(img.shape)
deconvolved_img = restoration.wiener(img, psf, 1, clip=False)

plt.imshow(deconvolved_img, cmap='gray')

Result

If you want to use OpenCV further on this result convert it to uint8 using res = deconvolved_img.astype(np.uint8)

Related