Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inverse convolution of image

I have source and result image. I know, that some convolution matrix has been used on source to get result. Can this convolution matrix be computed ? Or at least not exact one, but very similar.

like image 947
Martin Perry Avatar asked May 14 '13 11:05

Martin Perry


2 Answers

In principle, yes. Just convert both images to frequency space using an FFT and divide the FFT of the result image by that of the source image. Then apply the inverse FFT to get an approximation of the convolution kernel.

To see why this works, note that convolution in the spatial domain corresponds to multiplication in the frequency domain, and so deconvolution similarly corresponds to division in the frequency domain. In ordinary deconvolution, one would divide the FFT of the convolved image by that of the kernel to recover the original image. However, since convolution (like multiplication) is a commutative operation, the roles of the kernel and the source can be arbitrarily exchanged: convolving the source by the kernel is exactly the same as convolving the kernel by the source.

As the other answers note, however, this is unlikely to yield an exact reconstruction of your kernel, for the same reasons as ordinary deconvolution generally won't exactly reconstruct the original image: rounding and clipping will introduce noise into the process, and it's possible for the convolution to completely wipe out some frequencies (by multiplying them with zero), in which case those frequencies cannot be reconstructed.

That said, if your original kernel was of limited size (support), the reconstructed kernel should typically have a single sharp peak around the origin, approximating the original kernel, surrounded by low-level noise. Even if you don't know the exact size of the original kernel, it shouldn't be too hard to extract this peak and discard the rest of the reconstruction.

Example:

Here's the Lenna test image in grayscale, scaled down to 256×256 pixels and convolved with a 5×5 kernel in GIMP:

OriginalKernelResult

I'll use Python with numpy/scipy for the deconvolution:

from scipy import misc
from numpy import fft

orig = misc.imread('lena256.png')
blur = misc.imread('lena256blur.png')
orig_f = fft.rfft2(orig)
blur_f = fft.rfft2(blur)

kernel_f = blur_f / orig_f         # do the deconvolution
kernel = fft.irfft2(kernel_f)      # inverse Fourier transform
kernel = fft.fftshift(kernel)      # shift origin to center of image
kernel /= kernel.max()             # normalize gray levels
misc.imsave('kernel.png', kernel)  # save reconstructed kernel

The resulting 256×256 image of the kernel, and a zoom of the 7×7 pixel region around its center, are shown below:

Reconstructed kernelZoom of reconstructed kernel

Comparing the reconstruction with the original kernel, you can see that they look pretty similar; indeed, applying a cutoff anywhere between 0.5 and 0.68 to the reconstruction will recover the original kernel. The faint ripples surrounding the peak in the reconstruction are noise due to rounding and edge effects.

I'm not entirely sure what's causing the cross-shaped artifact that appears in the reconstruction (although I'm sure someone with more experience with these things could tell you), but off the top of my head, my guess would be that it has something to do with the image edges. When I convolved the original image in GIMP, I told it to handle edges by extending the image (essentially copying the outermost pixels), whereas the FFT deconvolution assumes that the image edges wrap around. This may well introduce spurious correlations along the x and y axes in the reconstruction.

like image 190
Ilmari Karonen Avatar answered Oct 04 '22 12:10

Ilmari Karonen


This is a classical problem of deconvolution. What you called a convolution matrix is usually called the "kernel". The convolution operation is often denoted with a star '*' (not to confuse with multiplication!). Using this notation

Result = Source * Kernel

The answers above using the FFT are correct, but you can't really use FFT based deconvolution in the presence of noise. The right way to do it is using Richardson-Lucy deconvolution (see https://en.wikipedia.org/wiki/Richardson%E2%80%93Lucy_deconvolution)

It is quite straightforward to implement. This answer also provides a sample Matlab implementation: Would Richardson–Lucy deconvolution work for recovering the latent kernel?

like image 37
yvoronen Avatar answered Oct 04 '22 12:10

yvoronen