有没有办法来检测图像是否模糊?

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

是的。 计算fft并分析结果。 傅里叶变换可以告诉您图像中存在哪些频率。 如果频率较低,则图像模糊。

定义术语“低”和“高”取决于你。

编辑 :如评论所述,如果你想要一个单一的浮点数表示一个给定的图像的模糊性,你必须制定一个合适的度量。

nikie的答案提供了这样一个指标。 使用拉普拉斯内核来卷积图像:

1 1 -4 1 1 

在输出上使用一个可靠的最大度量标准来得到一个可以用于阈值处理的数字。 尽量避免在计算拉普拉斯算子之前平滑过多的图像,因为您只会发现平滑的图像确实是模糊的:-)。

估计图像清晰度的另一种非常简单的方法是使用拉普拉斯(或LoG)滤镜,并简单地选取最大值。 如果您期望噪点(例如,select第N高的对比度,而不是最高的对比度),则使用像99.9%分位点这样的可靠措施可能会更好。如果您期望图像亮度不同,则还应包括预处理步骤,以使图像亮度/对比度(例如直方图均衡)。

我已经在Mathematica中实现了Simon的build议和这个build议,并且在一些testing图像上尝试了这个build议:

测试图像

第一个testing使用具有变化的内核大小的高斯滤波器使testing图像变模糊,然后计算模糊图像的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结果

5行代表5个testing图像,X轴代表高斯滤波半径。 图表正在减less,所以FFT是一个很好的度量清晰度。

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

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

导致对数图:

拉结结果

对于非模糊图像的散布在这里稍微好一些(2.5对3.3),主要是因为这种方法只使用图像中最强烈的对比度,而FFT本质上是整个图像的平均值。 function也下降得更快,所以设置一个“模糊”的阈值可能会更容易。

在使用自动对焦镜头的一些工作中,我遇到了这个非常有用的检测图像焦点的algorithm。 它在MATLAB中实现,但是大多数函数都很容易通过filter2D移植到OpenCV。

这基本上是许多重点测量algorithm的调查实施。 如果您想阅读原始论文,请在代码中提供对algorithm作者的引用。 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) [MN] = 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) [MN] = 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; } 

不能保证这些措施是否是您的问题的最佳select,但如果您追踪与这些措施相关的文件,可能会给您更多的见解。 希望你find有用的代码! 我知道我做到了。

基于耐克的答案。 使用opencv实现基于laplacian的方法很简单:

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

将返回一个短的指示最大的锐度检测,根据我对现实世界样品的testing,是一个相当好的指标,如果一个摄像头是否焦点或没有。 毫不奇怪,正常值是场景相关的,但是比FFT方法less得多,因为这个方法在我的应用中有很高的假阳性率。

我想出了一个完全不同的解决scheme。 我需要分析video静帧以find每个(X)帧中最清晰的帧。 这样,我会检测到运动模糊和/或聚焦图像。

我结束了使用Canny边缘检测和几乎所有types的video(用nikie的方法,我有数字化的VHSvideo和繁重的隔行video问题),我得到了非常好的结果。

我通过在原始图像上设置感兴趣区域(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)); } 

感谢nikie拉普拉斯的伟大build议。 OpenCV的文档指出我在相同的方向:使用Python,CSV(OPENCV 2.4.10),和numpy …

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

结果在0-255之间。 我发现任何超过二十岁的人都非常关注,到了一百岁,这显然是模糊的。 即使完全模糊,最大值也不会超过20。

我目前使用的一种方法是测量图像边缘的扩散。 看这篇文章:

 @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学术search中查找,您将获得大量有用的参考资料。

编辑

下面是nikie的post中5张图片的模糊估计图。 较高的值对应较大的模糊。 我使用了固定大小的11×11高斯滤波器,并改变了标准偏差(使用imagemagick的convert命令来获得模糊的图像)。

在这里输入图像描述

如果比较不同尺寸的图像,请不要忘记按图像宽度进行标准化,因为较大的图像将具有较宽的边缘。

最后,一个重要的问题是区分艺术模糊和不希望的模糊(由焦点错位,压缩,主体相对于相机的相对运动引起),但是这不是简单的方法。 举一个艺术模糊的例子,看一下Lenna的图像:Lenna在镜子里的倒影是模糊的,但是她的脸部完全是焦点。 这有助于对Lenna图像进行更高的模糊估计。

在高度重视的期刊(IEEE Transactions on Image Processing)上发表的两种方法的Matlab代码可以在这里find: https : //ivulab.asu.edu/software

检查CPBDM和JNBMalgorithm。 如果你检查这个代码,这个代码并不是很难被移植,而且它是基于Marzialiano的方法作为基本特征。

我实现它在matlab中使用fft并检查fft计算均值和std的直方图,但也可以完成拟合函数

 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(:)); 

上面的答案阐明了许多事情,但我认为这是有用的概念上的区别。

如果拍摄模糊图像的完美对焦照片,该怎么办?

模糊检测问题只有在您有参考的时候才会出现。 如果您需要devise一个自动对焦系统,您可以比较一系列不同模糊程度或平滑的图像,并尝试在该组内find最小模糊点。 换言之,您需要使用上述技术之一(基本上 – 在方法中有各种可能的细化级别 – 查找具有最高高频内容的一个图像)来交叉引用各种图像。

从这篇文章中我尝试了基于拉普拉斯滤波器的解决scheme。 它没有帮助我。 所以,我尝试了这个post的解决scheme, 这对我的情况是好的(但是很慢):

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

你可以用这个replace

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