I have read that if we have the PSF
of a given image, using deconvolution we can reverse the distortion and get the original image.
I tried to do the same thing, however, I’m getting an image that looks like complete noise!
def motion_blur(img, size=31, angle=11):
kernel = np.zeros((size,size), dtype=np.float32)
# set the middle row of the kernel array to be all ones.
kernel[size//2,:] = np.ones((size,),dtype=np.float32)
# now rotate the kernel
m = cv2.getRotationMatrix2D((size//2, size//2), angle=angle, scale=1.0)
kernel = cv2.warpAffine(kernel, m, dsize=(size,size))
kernel /= np.sum(kernel)
return cv2.filter2D(img, ddepth=-1, kernel=kernel), kernel
img = cv2.imread('./img/peppers.jpg')
# adding motion blur is akin to creating the PSF because
# its a distorting operator, and we are distorting the image using it!
img_blurred, kernel = motion_blur(img, size=31, angle=60)
# now we should be able to deconvolve the image with the PSF and get the deblurred version
# for this we can use the fourier transform and divide our blurred image from the psf
fft = np.fft.fftn(img_blurred[...,0)
# pad the kernel so its the same shape as our image so the division goes on without an issue
fft_psf = np.fft.fftn(kernel, s=fft.shape)
fft_result = fft/fft_psf
ifft_result = np.fft.ifft2(fft_result)
deblurred_image = np.abs(ifft_result).astype(np.uint8)
cv2.imshow('deblurred image',deblurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
this results in pure noise it seems:
I also tried Wiener deconvolution to no avail:
# Wiener deconvolution
fft_psf_mag = np.conj(fft_psf) / (np.abs(fft_psf)**2 + 10)
fft_result = fft / fft_psf_mag
It results in the same result it seems:
What am I missing here? I also tried fft/(fft_psf+1e-3)
as a way of regularizing the kernel’s small values, but this does not result in any improvement either!
sidenote:
These are the previous outputs belonging to the original image, the blurred version and the kernel used: