画像がぼやけているかどうかを検出する方法はありますか?


回答:


133

はい、そうです。高速フーリエ変換を計算し、結果を分析します。フーリエ変換は、画像に存在する周波数を示します。高周波の量が少ない場合、画像はぼやけます。

「低」と「高」という用語の定義は自由です。

編集

コメントで述べたように、特定の画像のぼやけを表す単一のフロートが必要な場合は、適切なメトリックを計算する必要があります。

ニキーの答えはそのような測定基準を提供します。画像をラプラシアンカーネルでたたみ込みます。

   1
1 -4  1
   1

そして、出力で堅牢な最大メトリックを使用して、しきい値に使用できる数値を取得します。ラプラシアンを計算する前に、画像を平滑化しすぎないようにしてください。平滑化された画像は実際にぼやけていることがわかるだけです。


9
「低」と「高」の問題のみがシーンにも依存します。+1
ケニー

4
画像が周期的でない限り、通常、画像の境界に鋭いエッジがあり、非常に高い周波数になります
Niki

2
通常、この効果を回避するために画像を実質的に拡張します。小さなウィンドウを使用してローカルFFTを計算することもできます。
Simon Bergot、2011年

6
非常に重要な唯一のポイントは、予測される事前にぼかされた画像(周波数)の内容が(少なくともおおまかに)わかっている必要があることです。これは、周波数スペクトルが、元の画像の周波数スペクトルにぼかしフィルターの周波数を掛けたものになるためです。したがって、元の画像の周波数が主に低かった場合、それがぼやけていたかどうかをどうやって確認できますか?
クリスA.

1
空白の白いチャートの写真を撮った場合、画像がぼやけているかどうかを見分ける方法はありません。OPは、絶対的なシャープネス測定を必要としていると思います。事前にぼかした画像はまったく存在しない可能性があります。正しいメトリックを取得するには少し作業する必要がありますが、fftはこの問題を解決するのに役立ちます。この観点では、ニッキーの答えは私の答えよりも優れています。
Simon Bergot、2011年

158

画像のシャープネスを推定する別の非常に単純な方法は、ラプラス(またはLoG)フィルターを使用して、最大値を選択することです。ノイズが予想される場合(つまり、最高のコントラストではなくN番目に高いコントラストを選択する場合)は、99.9%の分位数などのロバストな指標を使用する方がおそらく良いでしょう。コントラスト(ヒストグラムの等化など)。

私はサイモンの提案とこれをMathematicaに実装し、いくつかのテスト画像で試してみました:

テスト画像

最初のテストでは、カーネルサイズを変えたガウスフィルターを使用してテスト画像をぼかし、次にぼかした画像の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つのテスト画像を表し、X軸はガウスフィルターの半径を表します。グラフは減少しているため、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は基本的に画像全体の平均です。関数もより速く減少しているので、「ぼやけた」しきい値を設定する方が簡単かもしれません。


1
局所的なぼかしを測定したらどうなるでしょうか。つまり、写真にはぼやけている部分とシャープな部分があります。ピクセルごとのぼかしレベルを推定するマップが必要です。
Royi

4
@Drazick:それが可能かどうかさえわかりません。たとえば、Lenaの画像を見てください。焦点が合っているものの、コントラストのない大きな領域があります(Lenaの皮膚など)。このような滑らかな領域が「ぼやけている」かどうかを判断したり、焦点が合っていない領域と区別したりする方法は考えられません。別の質問としてこれを尋ねる必要があります(おそらくDSP.SEで)。多分誰かがより良いアイデアを持っています。
Niki

1
モーションブラーに適していますか?またはガウスのようなぼかしのためだけですか?
mrgloom 2013年

@pparescasellas実装を共有してもよろしいですか。それらを見てみたいと思います。
chappjc 2014年

@JohnBoe私はあなたがpparescasellasに質問するつもりだったと思います
chappjc

79

オートフォーカスレンズを使った作業中に、画像の焦点検出するための非常に便利なアルゴリズムのセットに出会いました。これは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通常、画像の解像度に応じて3、5、または7を使用します。それより高くする必要がある場合は、画像のダウンサンプリングを確認することをお勧めします。
mevatron

32

ナイキの答えに基づいて構築。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メソッドよりもはるかに低いので、アプリケーションで役立つには偽陽性率を高くする必要があります。


画像がbluryyであると言うためのしきい値は何でしょうか?私はそれをテストしました。しかし、その結果はさまざまです。しきい値を設定するためにこれを手伝ってくれませんか?
2vision2 2013

また、あなたの提案を試みましたが、私が得る数字は少しランダムです。この特定の実装に関して新しい質問を開始する場合、確認してよろしいですか?\
Stpn

@stpn正しいしきい値はシーンに依存します。私のアプリケーション(CCTV)では、デフォルトのしきい値である300を使用しています。サポートが低いカメラでは、特定のカメラの構成値が変更されます。
Yaur

なぜ「maxLap = -32767;」なのか ?
クレメントプレム2015

最高のコントラストを探しています。符号付きのショートパンツを使用しているため、-32767が最も低い値です。そのコードを書いてから2.5年になりますが、IIRCでは16Uの使用に問題がありました。
Yaur、2015

23

私はまったく異なる解決策を思いつきました。ビデオ静止フレームを分析して、すべての(X)フレームで最も鮮明なフレームを見つける必要がありました。このようにして、モーションブラーや焦点の外れた画像を検出します。

最終的にCanny Edge検出を使用し、ほぼすべての種類のビデオで非常に良い結果が得られました(ニキーの方法では、デジタル化された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));
}

17

その素晴らしいラプラスの提案をニキーに感謝します。 OpenCVドキュメントは私に同じ方向を示しました:python、cv2(opencv 2.4.10)、およびnumpyの使用...

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

結果は0〜255です。200ish以上のものは非常に焦点が合っており、100までにはっきりとぼやけています。完全にぼやけていても、maxが実際に20を大きく下回ることはありません。


3
3枚の写真で255を獲得しました。そして、完璧に焦点を合わせた1枚の写真で108枚を得ました。つまり、メソッドの有効性は何かに依存すると思います。
WindRider 2018年

@WindWiderに同意します。これが失敗するサンプル画像はこの画像です。画像が揺れても、画像のコントラストとピクセル間の対応する強度の差が大きいため、ラプラシアン値が比較的大きいためです。私が間違っていたら訂正してください。
Resham Wadhwa

@ReshamWadhwa cc WindRider-同上-これを修正する方法に関するアイデア?
jtlz2 2018年

@ ggez44これは私の好ましい答えですが、値は画像のピクセル数の関数です。これが理論的にどのようにスケーリングするか知っていますか?新しい質問として質問することもできますが、撃ち落とされる可能性があります。ありがとう!
jtlz2

10

私が現在使用している1つの方法は、画像のエッジの広がりを測定します。このペーパーを探してください:

@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で調べれば、役に立つ参照がたくさん得られます。

編集

これはニキーの投稿の5つの画像から得られたぼかし推定のプロットです。値が大きいほどぼかしが大きくなります。固定サイズの11x11ガウシアンフィルターを使用し、標準偏差を変化させました(imagemagickのconvertコマンドを使用してぼやけた画像を取得しました)。

ここに画像の説明を入力してください

異なるサイズの画像を比較する場合は、画像の幅によって正規化することを忘れないでください。大きい画像は幅が広くなるためです。

最後に、重要な問題は、芸術的なぼかしと望ましくないぼかし(フォーカスミス、圧縮、カメラに対する被写体の相対的な動きによって引き起こされる)を区別することですが、これはこのような単純なアプローチを超えています。芸術的なぼかしの例として、レナの画像を見てください。鏡の中のレナの反射はぼやけていますが、彼女の顔には完全に焦点が合っています。これは、Lennaイメージのより高いぼかし推定に貢献します。


5

私はこの投稿からラプラシアンフィルターに基づくソリューションを試しました。それは私を助けませんでした。だから、私はこの記事の解決策を試しましたが、それは私のケースには適していました(しかし遅い):

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

4

上記の答えは多くのことを解明しましたが、概念的な区別をすることは有用だと思います。

ぼやけた画像の完全に焦点の合った写真を撮るとどうなるでしょうか?

ぼやけ検出の問題は、リファレンスがある場合にのみ発生します。たとえばオートフォーカスシステムを設計する必要がある場合は、ぼかしまたは平滑化の程度を変えて撮影した一連の画像を比較し、このセット内で最小のぼかしのポイントを見つけようとします。つまり、上記の手法のいずれかを使用してさまざまな画像を相互参照する必要があります(基本的に、アプローチでさまざまなレベルの調整を行い、高周波コンテンツが最も高い1つの画像を探します)。


2
言い換えれば、それは相対的な概念であり、画像が他の類似した画像よりも多少ぼやけているかどうかを知ることだけが可能です。つまり、FFTに多かれ少なかれ高周波成分がある場合です。特定のケース:画像に最大輝度と最小輝度の隣接するピクセルがある場合はどうなりますか?たとえば、完全に白いピクセルの隣にある完全に黒いピクセル。この場合、それは完璧な焦点です。それ以外の場合は、黒から白への移行がよりスムーズになります。写真では完璧な焦点ではない可能性がありますが、質問では画像のソースを指定していません(コンピューターで生成される可能性があります)。
Ben

1

高く評価されているジャーナル(IEEE Transactions on Image Processing)で公開されている2つの方法のMatlabコードは、https//ivulab.asu.edu/softwareから入手できます。

CPBDMおよびJNBMアルゴリズムを確認してください。コードをチェックすると、移植するのはそれほど難しくなく、偶然にも、Marzialianoの方法を基本機能として使用しています。


1

私はそれをMATLABでFFTを使用して実装し、FFT計算平均と標準のヒストグラムをチェックしましたが、フィット関数も行うことができます

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

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];
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.