Finding for convolution kernel if many 0's for FFT?

后端 未结 1 1719
梦谈多话
梦谈多话 2021-01-21 15:51

I know that original_image * filter = blur_image, where * is the convolution. Thus, filter = ifft(fft(blur)/fft(original))

I have

相关标签:
1条回答
  • 2021-01-21 16:06

    This is where the Wiener filter comes in handy. It is typically applied for deconvolution -- estimating the original, unfiltered image from the filtered image and the convolution kernel. However, because of the commutativity of the convolution, deconvolution is exactly the same problem you are trying to solve. That is, if g = f * h, then you can estimate f from g and h (deconvolution), or you can estimate h from g and f, in exactly the same manner.

    Deconvolution

    The Wiener filter Wikipedia page is heavy on the math, but in a simplistic way, you look for frequencies where your kernel has small values (compared to the noise in your image), and you don't apply the division at those frequencies. This is called regularization, where you impose some constraints to avoid noise dominating the results.

    This is the MATLAB code, using in for the blurred input image, and psf for the spatial-domain filter:

    % Create a PSF and a blurred image:
    original = imread('cameraman.tif');
    sz = size(original);
    psf = zeros(sz);
    psf(fix(sz(1)/2)+(-5:5),fix(sz(1)/2)+(-10:10)) = 1;
    psf = psf/sum(psf(:));
    % in = conv2(original,psf,'same'); % gives boundary issues, less of a problem for smaller psf
    in = uint8(ifft2(fft2(original).*fft2(ifftshift(psf))));
    
    % Input parameter:
    K = 1e-2; 
    
    % Compute frequency-domain PSF:
    H = fft2(ifftshift(psf));
    
    % Compute the Wiener filter:
    cH = conj(H);
    HcH = H .* cH;
    K = K * max(max(abs(HcH)));
    w = cH ./ (HcH + K);
    
    % Apply the Wiener filter in the Frequency domain:
    out = real(ifft2(w .* fft2(in)));
    

    Here is the image in and the output of the Wiener filter for three different values of K:

    As you can see, selecting the right K is very important. If it is too low, there is not sufficient regularization. If it is too high then there are too many artefacts (insufficient deconvolution). This parameter K depends on the input image, though there are tricks to estimate it. Also, a simple filter like this can never perfectly undo a harsh blur like I put on here. More advanced iterative approaches are necessary to obtain a better deconvolution.

    Estimating the kernel

    Let's turn this around, and estimate psf from original and in. It is possible to do the division directly (equivalent to the Wiener filter with K=0), but the output is quite noisy. Where the original image has very low frequency-domain values, you'll get poor estimates. Picking the right K leads to a better estimate of the kernel. With a K that is too large, the result is again a poor approximation.

    % Direct estimation by division
    psf1 = fftshift(ifft2(fft2(in)./fft2(original)));
    
    % Wiener filter approach
    K = 1e-7;
    H = fft2(original);
    cH = conj(H);
    HcH = H .* cH;
    K = K * max(max(abs(HcH)));
    w = cH ./ (HcH + K);
    psf2 = fftshift(real(ifft2(w .* fft2(in))));
    

    (zoom in to observe the noise)


    Edit

    I downloaded the images from the website you linked. I used the first result, without padding, and cropped the frames from the images as best as I could, to leave only the data and exactly the data:

    original = imread('original.png');
    original = original(33:374,120:460,1);
    
    in = imread('blur_nopad.png');
    in = in(33:374,120:460,1);
    

    Then I used the code exactly as above, with the same K and everything, and got a pretty good result, showing a slightly shifted Gaussian kernel.

    I then repeated the same with the second result (after padding) and got a worse result, but still very recognizable as a Gaussian.

    0 讨论(0)
提交回复
热议问题