有没有一种方法可以检测图像是否模糊?

230
我想知道是否有一种方法通过分析图像数据来确定图像是否模糊。

7
相关问题已有很好的答案,但问题表述较为复杂。https://dev59.com/Wm435IYBdhLWcg3w1z4t - Mr. Developerdude
12个回答

173

估计图像清晰度的另一种简单方法是使用Laplace(或LoG)滤波器,然后选择最大值。如果你预期有噪声(即选择第N高的对比度而不是最高对比度),则使用99.9%分位数等健壮性指标可能更好。如果你预期图像亮度会发生变化,则还应包括预处理步骤以归一化图像亮度/对比度(例如直方图均衡化)。

我已经在Mathematica中实现了Simon的建议和这个方法,并对几个测试图像进行了尝试:

test images

第一个测试使用变化的内核大小使用高斯滤波器模糊测试图像,然后计算模糊图像的FFT并取90%最高频率的平均值:

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}]

在对数坐标图中的结果:

fft result

这5条线代表着5个测试图片,X轴代表高斯滤波器的半径。随着半径增大,曲线逐渐下降,所以FFT是一个很好的锐度测量指标。

以下是“最高LoG”模糊度估计的代码:它只是应用了一个LoG滤波器并返回滤波结果中最亮的像素:

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

在对数图中的结果:

laplace result

针对未模糊的图像,该方法的扩散稍微好些(2.5 vs 3.3),主要是因为该方法仅使用图像中最强烈的对比度,而FFT基本上是整个图像的平均值。函数下降速度也更快,所以可能更容易设置“模糊”阈值。


1
如果我想要测量局部模糊程度怎么办?也就是说,一张照片有模糊和清晰的区域。我想要得到一个地图,可以估算每个像素的模糊程度。 - Royi
5
@Drazick:我不确定这是否可能。例如,看看Lena的图像:有很大的区域没有对比度(例如Lena的皮肤),即使该区域处于焦点中。我无法想出一种方法来判断这样一个平滑的区域是否“模糊”,或将其与失焦区域区分开来。你应该将这个问题作为一个单独的问题提出来(也许在DSP.SE上)。也许其他人有更好的想法。 - Niki
2
它适用于动态模糊吗?还是只适用于高斯模糊之类的模糊效果? - mrgloom
@pparescasellas,你愿意分享你的实现吗?我很好奇想看看。 - chappjc
@JohnBoe 我想你的意思是要问 pparescasellas。 - chappjc
显示剩余3条评论

147
是的。计算快速傅里叶变换并分析结果。傅里叶变换告诉您图像中存在哪些频率。如果高频率较少,则图像模糊。
定义 "低" 和 "高" 是由您决定的。
编辑:
如评论中所述,如果要获得表示给定图像模糊度的单个浮点数,则必须计算出合适的度量标准。nikie's answer 提供了这样一种度量标准。用拉普拉斯核卷积图像。
   1
1 -4  1
   1

使用强大的最大度量标准来获得一个数字,以便用于阈值处理。在计算拉普拉斯算子之前,尽量避免过度平滑图像,因为你只会发现经过平滑处理的图像确实模糊不清 :-).

16
唯一的问题是,“低”和“高”也取决于场景。+1 - kenny
4
除非你的图像是循环的,否则通常在图像边缘会有锐利的边缘,导致出现非常高的频率。 - Niki
2
通常,您可以通过虚拟扩展图像来避免这种效应。您还可以使用小窗口计算局部FFT。 - Simon Bergot
7
只有一个非常重要的点,那就是您必须知道(至少大致上)您预期的预模糊图像(频率)内容是什么。这是因为频谱将是原始图像频谱与模糊滤镜频谱的乘积。因此,如果原始图像已经具有主要低频率,那么您如何确定它是否被模糊? - Chris A.
3
如果你拍摄一张白色背景的图表照片,你无法确定图像是否模糊。我认为发帖者想要一些绝对的清晰度测量方法。预先模糊的图像可能根本不存在。你需要花点功夫来得出正确的度量标准,但傅里叶变换可以帮助解决这个问题。从这个角度来看,尼基的回答比我的更好。 - Simon Bergot
显示剩余2条评论

94
在使用自动对焦镜头时,我发现了这组非常有用的算法用于检测图像对焦。它是用MATLAB实现的,但大多数函数很容易通过filter2D转换到OpenCV中。
它基本上是许多对焦测量算法的调查实现。如果您想阅读原始论文,则代码中提供了算法作者的参考文献。 由Pertuz等人于2012年发表的论文分析对焦测量算子以进行形状对焦(SFF)对所有这些测量以及它们在SFF中应用的速度和精度性能都进行了全面审查。 编辑:为防链接失效,添加了MATLAB代码。
function FM = fmeasure(Image, Measure, ROI)
%This function measures the relative degree of focus of 
%an image. It may be invoked as:
%
%   FM = fmeasure(Image, Method, ROI)
%
%Where 
%   Image,  is a grayscale image and FM is the computed
%           focus value.
%   Method, is the focus measure algorithm as a string.
%           see 'operators.txt' for a list of focus 
%           measure methods. 
%   ROI,    Image ROI as a rectangle [xo yo width heigth].
%           if an empty argument is passed, the whole
%           image is processed.
%
%  Said Pertuz
%  Abr/2010


if ~isempty(ROI)
    Image = imcrop(Image, ROI);
end

WSize = 15; % Size of local window (only some operators)

switch upper(Measure)
    case 'ACMO' % Absolute Central Moment (Shirvaikar2004)
        if ~isinteger(Image), Image = im2uint8(Image);
        end
        FM = AcMomentum(Image);
                
    case 'BREN' % Brenner's (Santos97)
        [M N] = size(Image);
        DH = Image;
        DV = Image;
        DH(1:M-2,:) = diff(Image,2,1);
        DV(:,1:N-2) = diff(Image,2,2);
        FM = max(DH, DV);        
        FM = FM.^2;
        FM = mean2(FM);
        
    case 'CONT' % Image contrast (Nanda2001)
        ImContrast = inline('sum(abs(x(:)-x(5)))');
        FM = nlfilter(Image, [3 3], ImContrast);
        FM = mean2(FM);
                        
    case 'CURV' % Image Curvature (Helmli2001)
        if ~isinteger(Image), Image = im2uint8(Image);
        end
        M1 = [-1 0 1;-1 0 1;-1 0 1];
        M2 = [1 0 1;1 0 1;1 0 1];
        P0 = imfilter(Image, M1, 'replicate', 'conv')/6;
        P1 = imfilter(Image, M1', 'replicate', 'conv')/6;
        P2 = 3*imfilter(Image, M2, 'replicate', 'conv')/10 ...
            -imfilter(Image, M2', 'replicate', 'conv')/5;
        P3 = -imfilter(Image, M2, 'replicate', 'conv')/5 ...
            +3*imfilter(Image, M2, 'replicate', 'conv')/10;
        FM = abs(P0) + abs(P1) + abs(P2) + abs(P3);
        FM = mean2(FM);
        
    case 'DCTE' % DCT energy ratio (Shen2006)
        FM = nlfilter(Image, [8 8], @DctRatio);
        FM = mean2(FM);
        
    case 'DCTR' % DCT reduced energy ratio (Lee2009)
        FM = nlfilter(Image, [8 8], @ReRatio);
        FM = mean2(FM);
        
    case 'GDER' % Gaussian derivative (Geusebroek2000)        
        N = floor(WSize/2);
        sig = N/2.5;
        [x,y] = meshgrid(-N:N, -N:N);
        G = exp(-(x.^2+y.^2)/(2*sig^2))/(2*pi*sig);
        Gx = -x.*G/(sig^2);Gx = Gx/sum(Gx(:));
        Gy = -y.*G/(sig^2);Gy = Gy/sum(Gy(:));
        Rx = imfilter(double(Image), Gx, 'conv', 'replicate');
        Ry = imfilter(double(Image), Gy, 'conv', 'replicate');
        FM = Rx.^2+Ry.^2;
        FM = mean2(FM);
        
    case 'GLVA' % Graylevel variance (Krotkov86)
        FM = std2(Image);
        
    case 'GLLV' %Graylevel local variance (Pech2000)        
        LVar = stdfilt(Image, ones(WSize,WSize)).^2;
        FM = std2(LVar)^2;
        
    case 'GLVN' % Normalized GLV (Santos97)
        FM = std2(Image)^2/mean2(Image);
        
    case 'GRAE' % Energy of gradient (Subbarao92a)
        Ix = Image;
        Iy = Image;
        Iy(1:end-1,:) = diff(Image, 1, 1);
        Ix(:,1:end-1) = diff(Image, 1, 2);
        FM = Ix.^2 + Iy.^2;
        FM = mean2(FM);
        
    case 'GRAT' % Thresholded gradient (Snatos97)
        Th = 0; %Threshold
        Ix = Image;
        Iy = Image;
        Iy(1:end-1,:) = diff(Image, 1, 1);
        Ix(:,1:end-1) = diff(Image, 1, 2);
        FM = max(abs(Ix), abs(Iy));
        FM(FM<Th)=0;
        FM = sum(FM(:))/sum(sum(FM~=0));
        
    case 'GRAS' % Squared gradient (Eskicioglu95)
        Ix = diff(Image, 1, 2);
        FM = Ix.^2;
        FM = mean2(FM);
        
    case 'HELM' %Helmli's mean method (Helmli2001)        
        MEANF = fspecial('average',[WSize WSize]);
        U = imfilter(Image, MEANF, 'replicate');
        R1 = U./Image;
        R1(Image==0)=1;
        index = (U>Image);
        FM = 1./R1;
        FM(index) = R1(index);
        FM = mean2(FM);
        
    case 'HISE' % Histogram entropy (Krotkov86)
        FM = entropy(Image);
        
    case 'HISR' % Histogram range (Firestone91)
        FM = max(Image(:))-min(Image(:));
        
           
    case 'LAPE' % Energy of laplacian (Subbarao92a)
        LAP = fspecial('laplacian');
        FM = imfilter(Image, LAP, 'replicate', 'conv');
        FM = mean2(FM.^2);
                
    case 'LAPM' % Modified Laplacian (Nayar89)
        M = [-1 2 -1];        
        Lx = imfilter(Image, M, 'replicate', 'conv');
        Ly = imfilter(Image, M', 'replicate', 'conv');
        FM = abs(Lx) + abs(Ly);
        FM = mean2(FM);
        
    case 'LAPV' % Variance of laplacian (Pech2000)
        LAP = fspecial('laplacian');
        ILAP = imfilter(Image, LAP, 'replicate', 'conv');
        FM = std2(ILAP)^2;
        
    case 'LAPD' % Diagonal laplacian (Thelen2009)
        M1 = [-1 2 -1];
        M2 = [0 0 -1;0 2 0;-1 0 0]/sqrt(2);
        M3 = [-1 0 0;0 2 0;0 0 -1]/sqrt(2);
        F1 = imfilter(Image, M1, 'replicate', 'conv');
        F2 = imfilter(Image, M2, 'replicate', 'conv');
        F3 = imfilter(Image, M3, 'replicate', 'conv');
        F4 = imfilter(Image, M1', 'replicate', 'conv');
        FM = abs(F1) + abs(F2) + abs(F3) + abs(F4);
        FM = mean2(FM);
        
    case 'SFIL' %Steerable filters (Minhas2009)
        % Angles = [0 45 90 135 180 225 270 315];
        N = floor(WSize/2);
        sig = N/2.5;
        [x,y] = meshgrid(-N:N, -N:N);
        G = exp(-(x.^2+y.^2)/(2*sig^2))/(2*pi*sig);
        Gx = -x.*G/(sig^2);Gx = Gx/sum(Gx(:));
        Gy = -y.*G/(sig^2);Gy = Gy/sum(Gy(:));
        R(:,:,1) = imfilter(double(Image), Gx, 'conv', 'replicate');
        R(:,:,2) = imfilter(double(Image), Gy, 'conv', 'replicate');
        R(:,:,3) = cosd(45)*R(:,:,1)+sind(45)*R(:,:,2);
        R(:,:,4) = cosd(135)*R(:,:,1)+sind(135)*R(:,:,2);
        R(:,:,5) = cosd(180)*R(:,:,1)+sind(180)*R(:,:,2);
        R(:,:,6) = cosd(225)*R(:,:,1)+sind(225)*R(:,:,2);
        R(:,:,7) = cosd(270)*R(:,:,1)+sind(270)*R(:,:,2);
        R(:,:,7) = cosd(315)*R(:,:,1)+sind(315)*R(:,:,2);
        FM = max(R,[],3);
        FM = mean2(FM);
        
    case 'SFRQ' % Spatial frequency (Eskicioglu95)
        Ix = Image;
        Iy = Image;
        Ix(:,1:end-1) = diff(Image, 1, 2);
        Iy(1:end-1,:) = diff(Image, 1, 1);
        FM = mean2(sqrt(double(Iy.^2+Ix.^2)));
        
    case 'TENG'% Tenengrad (Krotkov86)
        Sx = fspecial('sobel');
        Gx = imfilter(double(Image), Sx, 'replicate', 'conv');
        Gy = imfilter(double(Image), Sx', 'replicate', 'conv');
        FM = Gx.^2 + Gy.^2;
        FM = mean2(FM);
        
    case 'TENV' % Tenengrad variance (Pech2000)
        Sx = fspecial('sobel');
        Gx = imfilter(double(Image), Sx, 'replicate', 'conv');
        Gy = imfilter(double(Image), Sx', 'replicate', 'conv');
        G = Gx.^2 + Gy.^2;
        FM = std2(G)^2;
        
    case 'VOLA' % Vollath's correlation (Santos97)
        Image = double(Image);
        I1 = Image; I1(1:end-1,:) = Image(2:end,:);
        I2 = Image; I2(1:end-2,:) = Image(3:end,:);
        Image = Image.*(I1-I2);
        FM = mean2(Image);
        
    case 'WAVS' %Sum of Wavelet coeffs (Yang2003)
        [C,S] = wavedec2(Image, 1, 'db6');
        H = wrcoef2('h', C, S, 'db6', 1);   
        V = wrcoef2('v', C, S, 'db6', 1);   
        D = wrcoef2('d', C, S, 'db6', 1);   
        FM = abs(H) + abs(V) + abs(D);
        FM = mean2(FM);
        
    case 'WAVV' %Variance of  Wav...(Yang2003)
        [C,S] = wavedec2(Image, 1, 'db6');
        H = abs(wrcoef2('h', C, S, 'db6', 1));
        V = abs(wrcoef2('v', C, S, 'db6', 1));
        D = abs(wrcoef2('d', C, S, 'db6', 1));
        FM = std2(H)^2+std2(V)+std2(D);
        
    case 'WAVR'
        [C,S] = wavedec2(Image, 3, 'db6');
        H = abs(wrcoef2('h', C, S, 'db6', 1));   
        V = abs(wrcoef2('v', C, S, 'db6', 1));   
        D = abs(wrcoef2('d', C, S, 'db6', 1)); 
        A1 = abs(wrcoef2('a', C, S, 'db6', 1));
        A2 = abs(wrcoef2('a', C, S, 'db6', 2));
        A3 = abs(wrcoef2('a', C, S, 'db6', 3));
        A = A1 + A2 + A3;
        WH = H.^2 + V.^2 + D.^2;
        WH = mean2(WH);
        WL = mean2(A);
        FM = WH/WL;
    otherwise
        error('Unknown measure %s',upper(Measure))
end
 end
%************************************************************************
function fm = AcMomentum(Image)
[M N] = size(Image);
Hist = imhist(Image)/(M*N);
Hist = abs((0:255)-255*mean2(Image))'.*Hist;
fm = sum(Hist);
end

%******************************************************************
function fm = DctRatio(M)
MT = dct2(M).^2;
fm = (sum(MT(:))-MT(1,1))/MT(1,1);
end

%************************************************************************
function fm = ReRatio(M)
M = dct2(M);
fm = (M(1,2)^2+M(1,3)^2+M(2,1)^2+M(2,2)^2+M(3,1)^2)/(M(1,1)^2);
end
%******************************************************************

一些OpenCV版本的示例:

// OpenCV port of 'LAPM' algorithm (Nayar89)
double modifiedLaplacian(const cv::Mat& src)
{
    cv::Mat M = (Mat_<double>(3, 1) << -1, 2, -1);
    cv::Mat G = cv::getGaussianKernel(3, -1, CV_64F);

    cv::Mat Lx;
    cv::sepFilter2D(src, Lx, CV_64F, M, G);

    cv::Mat Ly;
    cv::sepFilter2D(src, Ly, CV_64F, G, M);

    cv::Mat FM = cv::abs(Lx) + cv::abs(Ly);

    double focusMeasure = cv::mean(FM).val[0];
    return focusMeasure;
}

// OpenCV port of 'LAPV' algorithm (Pech2000)
double varianceOfLaplacian(const cv::Mat& src)
{
    cv::Mat lap;
    cv::Laplacian(src, lap, CV_64F);

    cv::Scalar mu, sigma;
    cv::meanStdDev(lap, mu, sigma);

    double focusMeasure = sigma.val[0]*sigma.val[0];
    return focusMeasure;
}

// OpenCV port of 'TENG' algorithm (Krotkov86)
double tenengrad(const cv::Mat& src, int ksize)
{
    cv::Mat Gx, Gy;
    cv::Sobel(src, Gx, CV_64F, 1, 0, ksize);
    cv::Sobel(src, Gy, CV_64F, 0, 1, ksize);

    cv::Mat FM = Gx.mul(Gx) + Gy.mul(Gy);

    double focusMeasure = cv::mean(FM).val[0];
    return focusMeasure;
}

// OpenCV port of 'GLVN' algorithm (Santos97)
double normalizedGraylevelVariance(const cv::Mat& src)
{
    cv::Scalar mu, sigma;
    cv::meanStdDev(src, mu, sigma);

    double focusMeasure = (sigma.val[0]*sigma.val[0]) / mu.val[0];
    return focusMeasure;
}

不能保证这些措施是否是解决你问题的最佳选择,但如果你找到了与这些措施相关的论文,它们可能会给你更多的见解。希望你觉得这些代码有用!我知道我很满意。


在Tenengrad算法中,kSize的标准值是多少? - mans
@mans 我通常根据图像的分辨率使用3、5或7。如果你发现需要更高的值,可能需要考虑对图像进行降采样。 - mevatron

34

在 Nike 的回答基础上继续完善。使用 OpenCV 实现基于拉普拉斯算子的方法非常简单:

short GetSharpness(char* data, unsigned int width, unsigned int height)
{
    // assumes that your image is already in planner yuv or 8 bit greyscale
    IplImage* in = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);
    IplImage* out = cvCreateImage(cvSize(width,height),IPL_DEPTH_16S,1);
    memcpy(in->imageData,data,width*height);

    // aperture size of 1 corresponds to the correct matrix
    cvLaplace(in, out, 1);

    short maxLap = -32767;
    short* imgData = (short*)out->imageData;
    for(int i =0;i<(out->imageSize/2);i++)
    {
        if(imgData[i] > maxLap) maxLap = imgData[i];
    }

    cvReleaseImage(&in);
    cvReleaseImage(&out);
    return maxLap;
}

将返回一个short型数据,表示检测到的最大锐度,根据我的实际样本测试结果,这是相当不错的指示器,可以判断照相机是否处于对焦状态。毫不奇怪,正常值依赖于场景,但比FFT方法要少得多,而FFT方法误报率太高,在我的应用中没有用处。


什么阈值可以用来判断一张图片是否模糊?我已经进行了测试,但结果有些不稳定。你能帮我设置一个阈值吗?谢谢。 - 2vision2
我也尝试了你的建议,但是得到的数字有点随机。如果我就这个特定实现提出一个新问题,你愿意看一下吗? - Stpn
@stpn 合适的阈值与场景有关。在我的应用程序(CCTV)中,我使用默认阈值为300。对于那些该值过低的相机,支持团队将更改特定相机的配置值。 - Yaur
为什么是 "maxLap = -32767;"? - Clement Prem
我们正在寻找最高对比度,由于我们使用带符号短整型,-32767是最小的可能值。虽然我已经写了那段代码2.5年了,但我记得使用16U时会出问题。 - Yaur

31

我想出了一种完全不同的解决方案。我需要分析视频静止帧以找到每(X)帧中最清晰的帧,这样我可以检测到动态模糊和/或焦点不准确的图像。

最终我使用了Canny边缘检测,并且在几乎所有类型的视频中都取得了非常好的结果(使用nikie's方法时,在数字化的VHS视频和重度交错视频上存在问题)。

我通过在原始图像上设置兴趣区域(ROI)来优化性能。

使用EmguCV:

//Convert image using Canny
using (Image<Gray, byte> imgCanny = imgOrig.Canny(225, 175))
{
    //Count the number of pixel representing an edge
    int nCountCanny = imgCanny.CountNonzero()[0];

    //Compute a sharpness grade:
    //< 1.5 = blurred, in movement
    //de 1.5 à 6 = acceptable
    //> 6 =stable, sharp
    double dSharpness = (nCountCanny * 1000.0 / (imgCanny.Cols * imgCanny.Rows));
}

嘿,@Goladorak84,谢谢你。我可以问一下你为什么选择在dSharpness内乘以1000.0吗? - Roi Mulia
3
这个非常棒(在这个问题中是我测试过的最好的)。这里是Python实现,供需要的人使用。image_canny = cv2.Canny(image, 175, 225); nonzero_ratio = numpy.count_nonzero(image_canny) * 1000.0 / image_canny.size; return nonzero_ratio; - smttsp
如果我没记错的话,那是基于试错法的任意数字。我应该给它起个更好的名字 :) - Goldorak84

20

感谢nikie提供的优秀Laplace建议。OpenCV文档也指向了同一方向:使用Python、cv2(OpenCV 2.4.10)和NumPy...

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

结果介于0-255之间。 我发现超过200左右的任何东西都非常清晰,而到了100时,它就明显模糊了。 即使完全模糊,最大值也很少低于20。


5
我得到了三张照片的总分是255分。而对于一张完美对焦的照片,我得到了108分。因此,我认为这种方法的有效性取决于某些因素。 - WindRider
同意@WindWider的观点。这里失败的示例图像是此图像。 我认为原因是即使图像摇晃,图像的对比度和相应像素之间的强度差异很大,因此Laplacian值相对较大。如果我错了,请纠正我。 - Resham Wadhwa
@ReshamWadhwa cc WindRider - 同上 - 有什么解决方法吗? - jtlz2
1
@ggez44 这是我偏爱的答案 - 但价值取决于图像中的像素数量。你知道这在理论上如何扩展吗?我可以提出一个新问题,但很可能会被拒绝。谢谢! - jtlz2

10

我目前使用的一种方法是测量图像中边缘的扩散程度。请查看这篇论文:

@ARTICLE{Marziliano04perceptualblur,
    author = {Pina Marziliano and Frederic Dufaux and Stefan Winkler and Touradj Ebrahimi},
    title = {Perceptual blur and ringing metrics: Application to JPEG2000,” Signal Process},
    journal = {Image Commun},
    year = {2004},
    pages = {163--172} }

通常情况下,这是付费内容,但我已经看到有一些免费的副本。基本上,它们会在图像中定位垂直边缘,然后测量这些边缘的宽度。对宽度求平均值得出图像的最终模糊估计结果。更宽的边缘对应于模糊的图像,反之亦然。
这个问题属于“无参考图像质量评估”的领域。如果您在Google Scholar上查找,您将获得大量有用的参考资料。
编辑:这是nikie帖子中5张图片的模糊估计值的图表。更高的值对应着更大的模糊程度。我使用了一个固定尺寸的11x11高斯滤波器,并改变了标准偏差(使用imagemagick的convert命令获取模糊图像)。

enter image description here

如果您比较不同大小的图像,请不要忘记通过图像宽度进行归一化,因为较大的图像将具有更宽的边缘。
最后,一个重要的问题是区分艺术模糊和不需要的模糊(由于对焦失误、压缩、主体相对于相机的运动引起),但这超出了简单方法的范畴。例如,可以查看Lenna图像中的艺术模糊:Lenna在镜子里的反射是模糊的,但她的脸部完全清晰。这导致Lenna图像的模糊估计更高。

7

以上的回答解释了很多问题,但我认为有必要进行概念上的区分。

如果你拍摄一张清晰的模糊图像会怎样?

只有在有一个参考时,才能准确地检测模糊问题。例如,如果你需要设计自动对焦系统,你需要比较一系列不同程度模糊或平滑处理后的图像,并尝试找到其中模糊最小的点。换句话说,你需要使用上述技术之一来交叉参考各种图像(基本上是寻找高频内容最高的图像,具体方法可能有不同的细化级别)。


2
换句话说,这是一个相对的概念,只有通过比较两张相似图像的高频内容(FFT)才能确定一张图像是否更模糊或更清晰。特殊情况:如果图像存在最大亮度和最小亮度相邻的像素怎么办?例如,完全黑色像素旁边是完全白色像素。在这种情况下,这是一个完美的聚焦,否则黑色到白色的过渡将更加平滑。在摄影中很难实现完美聚焦,但问题没有指定图像的来源(它可以是计算机生成的)。 - Ben

6

我尝试了基于拉普拉斯滤波器的解决方案,来自这篇文章。但它对我没有帮助。所以,我尝试了这篇文章中的解决方案,它适用于我的情况(但速度较慢):

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))

更清晰的图像具有最大的sum值!

您还可以通过更改步骤来调整速度和精度,例如:

这一部分

for x in range(width - 1):

你可以用这个替换它

for x in range(0, width - 1, 10):

1
对于那些尝试使用这段代码的人:顺便说一下,它并不高效。据我所知,您将水平移动1个像素并将其减去。找到绝对差的总和。您可以这样做:gray_f = float(gray); diff = gray_f[:-1, :] - gray_f[1:, :]; sum(np.abs(diff));。我没有测试过,但应该是类似这样的东西,可以大大加快代码速度。 - smttsp

1

以下是我在Opencv中用于检测区域内焦点质量的方法:

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];

2
在这里稍微解释一下你正在做什么会很有帮助。 - sarfrazanwar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接