Is there a way to detect if an image is blurry?

后端 未结 12 1775
予麋鹿
予麋鹿 2020-11-22 14:48

I was wondering if there is a way to determine if an image is blurry or not by analyzing the image data.

相关标签:
12条回答
  • 2020-11-22 15:04

    That's what I do in Opencv to detect focus quality in a region:

    Mat grad;
    int scale = 1;
    int delta = 0;
    int ddepth = CV_8U;
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;
    /// Gradient X
    Sobel(matFromSensor, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
    /// Gradient Y
    Sobel(matFromSensor, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
    convertScaleAbs(grad_x, abs_grad_x);
    convertScaleAbs(grad_y, abs_grad_y);
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
    cv::Scalar mu, sigma;
    cv::meanStdDev(grad, /* mean */ mu, /*stdev*/ sigma);
    focusMeasure = mu.val[0] * mu.val[0];
    
    0 讨论(0)
  • 2020-11-22 15:05

    Thanks nikie for that great Laplace suggestion. OpenCV docs pointed me in the same direction: using python, cv2 (opencv 2.4.10), and numpy...

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) numpy.max(cv2.convertScaleAbs(cv2.Laplacian(gray_image,3)))

    result is between 0-255. I found anything over 200ish is very in focus, and by 100, it's noticeably blurry. the max never really gets much under 20 even if it's completely blurred.

    0 讨论(0)
  • 2020-11-22 15:09

    I tried solution based on Laplacian filter from this post. It didn't help me. So, I tried the solution from this post and it was good for my case (but is slow):

    import cv2
    
    image = cv2.imread("test.jpeg")
    height, width = image.shape[:2]
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
    def px(x, y):
        return int(gray[y, x])
    
    sum = 0
    for x in range(width-1):
        for y in range(height):
            sum += abs(px(x, y) - px(x+1, y))
    

    Less blurred image has maximum sum value!

    You can also tune speed and accuracy by changing step, e.g.

    this part

    for x in range(width - 1):
    

    you can replace with this one

    for x in range(0, width - 1, 10):
    
    0 讨论(0)
  • 2020-11-22 15:11

    i implemented it use fft in matlab and check histogram of the fft compute mean and std but also fit function can be done

    fa =  abs(fftshift(fft(sharp_img)));
    fb = abs(fftshift(fft(blured_img)));
    
    f1=20*log10(0.001+fa);
    f2=20*log10(0.001+fb);
    
    figure,imagesc(f1);title('org')
    figure,imagesc(f2);title('blur')
    
    figure,hist(f1(:),100);title('org')
    figure,hist(f2(:),100);title('blur')
    
    mf1=mean(f1(:));
    mf2=mean(f2(:));
    
    mfd1=median(f1(:));
    mfd2=median(f2(:));
    
    sf1=std(f1(:));
    sf2=std(f2(:));
    
    0 讨论(0)
  • 2020-11-22 15:15

    Yes, it is. Compute the Fast Fourier Transform and analyse the result. The Fourier transform tells you which frequencies are present in the image. If there is a low amount of high frequencies, then the image is blurry.

    Defining the terms 'low' and 'high' is up to you.

    Edit:

    As stated in the comments, if you want a single float representing the blurryness of a given image, you have to work out a suitable metric.

    nikie's answer provide such a metric. Convolve the image with a Laplacian kernel:

       1
    1 -4  1
       1
    

    And use a robust maximum metric on the output to get a number which you can use for thresholding. Try to avoid smoothing too much the images before computing the Laplacian, because you will only find out that a smoothed image is indeed blurry :-).

    0 讨论(0)
  • 2020-11-22 15:16

    Another very simple way to estimate the sharpness of an image is to use a Laplace (or LoG) filter and simply pick the maximum value. Using a robust measure like a 99.9% quantile is probably better if you expect noise (i.e. picking the Nth-highest contrast instead of the highest contrast.) If you expect varying image brightness, you should also include a preprocessing step to normalize image brightness/contrast (e.g. histogram equalization).

    I've implemented Simon's suggestion and this one in Mathematica, and tried it on a few test images:

    test images

    The first test blurs the test images using a Gaussian filter with a varying kernel size, then calculates the FFT of the blurred image and takes the average of the 90% highest frequencies:

    testFft[img_] := Table[
      (
       blurred = GaussianFilter[img, r];
       fft = Fourier[ImageData[blurred]];
       {w, h} = Dimensions[fft];
       windowSize = Round[w/2.1];
       Mean[Flatten[(Abs[
           fft[[w/2 - windowSize ;; w/2 + windowSize, 
             h/2 - windowSize ;; h/2 + windowSize]]])]]
       ), {r, 0, 10, 0.5}]
    

    Result in a logarithmic plot:

    fft result

    The 5 lines represent the 5 test images, the X axis represents the Gaussian filter radius. The graphs are decreasing, so the FFT is a good measure for sharpness.

    This is the code for the "highest LoG" blurriness estimator: It simply applies an LoG filter and returns the brightest pixel in the filter result:

    testLaplacian[img_] := Table[
      (
       blurred = GaussianFilter[img, r];
       Max[Flatten[ImageData[LaplacianGaussianFilter[blurred, 1]]]];
       ), {r, 0, 10, 0.5}]
    

    Result in a logarithmic plot:

    laplace result

    The spread for the un-blurred images is a little better here (2.5 vs 3.3), mainly because this method only uses the strongest contrast in the image, while the FFT is essentially a mean over the whole image. The functions are also decreasing faster, so it might be easier to set a "blurry" threshold.

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