มีวิธีการตรวจสอบหรือไม่หากภาพไม่ชัด?


203

ฉันสงสัยว่ามีวิธีการตรวจสอบว่าภาพพร่ามัวหรือไม่โดยการวิเคราะห์ข้อมูลภาพ


7
คำถามที่เกี่ยวข้องที่มีคำตอบที่ดี แต่ยังรวมถึงการกำหนดคำถามที่เกี่ยวข้องมากขึ้น stackoverflow.com/questions/5180327/…
Lennart Rolland

1
นอกจากนี้ยังมีคำตอบที่แย่กว่านั้นอีกมาก
John Shedletsky

คำตอบ:


133

ใช่แล้ว. คำนวณการแปลงฟูริเยร์อย่างรวดเร็วและวิเคราะห์ผลลัพธ์ การแปลงฟูริเยร์จะบอกคุณว่ามีความถี่ใดบ้างในภาพ หากมีความถี่สูงในระดับต่ำภาพจะเบลอ

การกำหนดคำว่า 'ต่ำ' และ 'สูง' ขึ้นอยู่กับคุณ

แก้ไข :

ดังที่ระบุไว้ในความคิดเห็นหากคุณต้องการให้โฟลตหนึ่งอันแสดงถึงความพร่ามัวของภาพที่ระบุคุณต้องคำนวณเมตริกที่เหมาะสม

คำตอบของ nikieให้เมตริกเช่นนั้น สร้างภาพที่น่าเชื่อถือด้วยเคอร์เนล Laplacian:

   1
1 -4  1
   1

และใช้ตัวชี้วัดสูงสุดที่แข็งแกร่งในผลลัพธ์เพื่อรับตัวเลขที่คุณสามารถใช้สำหรับการกำหนดเกณฑ์ขั้นต่ำ พยายามหลีกเลี่ยงการปรับภาพให้เรียบเกินไปก่อนที่จะคำนวณ Laplacian เพราะคุณจะพบว่าภาพที่ราบเรียบนั้นพร่ามัวจริง ๆ :-)


9
ปัญหาเดียวที่ 'ต่ำ' และ 'สูง' ก็ขึ้นอยู่กับฉากด้วยเช่นกัน +1
kenny

4
ยกเว้นว่าภาพของคุณเป็นแบบวนซ้ำคุณมักจะมีขอบคมที่ขอบของภาพซึ่งนำไปสู่ความถี่ที่สูงมาก
Niki

2
คุณมักจะขยายภาพของคุณเพื่อหลีกเลี่ยงผลกระทบนี้ คุณยังสามารถใช้หน้าต่างเล็ก ๆ เพื่อคำนวณค่า FFT ในระบบได้
Simon Bergot

6
มีเพียงจุดเดียวที่สำคัญอย่างยิ่งคือคุณต้องรู้ (อย่างคร่าว ๆ ) ว่าเนื้อหา (ความถี่) ของภาพที่พร่ามัวล่วงหน้าของคุณคืออะไร สิ่งนี้เป็นจริงเนื่องจากสเปกตรัมความถี่จะเป็นของภาพต้นฉบับคูณด้วยตัวกรองเบลอ ดังนั้นหากภาพต้นฉบับมีความถี่ต่ำอยู่แล้วคุณจะบอกได้อย่างไรว่าภาพนั้นเบลอ
Chris A.

1
หากคุณถ่ายภาพแผนภูมิสีขาวที่ว่างเปล่าคุณไม่มีทางบอกได้ว่าภาพนั้นพร่ามัวหรือไม่ ฉันคิดว่า OP ต้องการการวัดความคมชัดที่แน่นอน ภาพที่ปรากฏล่วงหน้าอาจไม่ปรากฏเลย คุณต้องทำงานเล็กน้อยเพื่อให้ได้เมตริกที่ถูกต้อง แต่ fft สามารถช่วยแก้ไขปัญหานี้ได้ ในมุมมองนี้คำตอบของ Nickie ดีกว่าของฉัน
Simon Bergot

158

อีกวิธีที่ง่ายมากในการประมาณความคมชัดของภาพคือการใช้ฟิลเตอร์ Laplace (หรือ LoG) และเลือกค่าสูงสุด การใช้การวัดที่แข็งแกร่งเช่นควอไทล์ 99.9% น่าจะดีกว่าถ้าคุณคาดหวังว่าจะเกิดจุดรบกวน (เช่นการเลือกคอนทราสต์สูงสุด Nth แทนที่จะเป็นคอนทราสต์สูงสุด) หากคุณคาดหวังความสว่างของภาพที่แตกต่างกัน ความคมชัด (เช่นการทำให้เท่าเทียมกันฮิสโตแกรม)

ฉันได้ใช้คำแนะนำของ Simon และอันนี้ใน Mathematica แล้วลองทดสอบในภาพทดสอบสองสามภาพ:

ทดสอบภาพ

การทดสอบครั้งแรกทำให้ภาพทดสอบเบลอโดยใช้ตัวกรอง Gaussian ที่มีขนาดเคอร์เนลที่แตกต่างกันจากนั้นคำนวณค่า 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 vs 3.3) ส่วนใหญ่เป็นเพราะวิธีนี้ใช้ความเปรียบต่างที่รุนแรงที่สุดในภาพในขณะที่ FFT นั้นมีความหมายโดยรวมมากกว่าภาพทั้งหมด ฟังก์ชั่นยังลดลงเร็วขึ้นด้วยดังนั้นจึงอาจง่ายกว่าในการตั้งค่าเกณฑ์ "เบลอ"


1
ถ้าฉันทำตามการวัดความเบลอของท้องที่ กล่าวคือภาพถ่ายมีพื้นที่ที่เบลอและมีความคมชัด ฉันต้องการแผนที่ที่ประมาณระดับเบลอต่อพิกเซล
Royi

4
@Drazick: ฉันไม่แน่ใจว่าเป็นไปได้ ตัวอย่างเช่นดูที่ภาพ Lena: มีพื้นที่ขนาดใหญ่ที่ไม่มีความเปรียบต่าง (เช่นผิวหนังของ Lena) แม้ว่าพื้นที่นั้นจะอยู่ในโฟกัส ฉันไม่สามารถคิดวิธีที่จะบอกได้ว่าพื้นที่ที่ราบเรียบดังกล่าวเป็น "พร่ามัว" หรือแยกแยะจากพื้นที่ที่อยู่นอกโฟกัส คุณควรถามคำถามนี้เป็นคำถามแยกต่างหาก (อาจเป็นใน DSP.SE) บางทีคนอื่นมีความคิดที่ดีกว่า
Niki

1
มันเหมาะกับการเคลื่อนไหวเบลอหรือไม่? หรือเพียงเพื่อเบลอเช่น Gaussian?
mrgloom

@pparescasellas คุณยินดีที่จะแบ่งปันการใช้งานของคุณ ฉันอยากรู้อยากเห็นพวกเขา
chappjc

@ JohnBoe ฉันคิดว่าคุณตั้งใจจะถาม pparescasellas
chappjc

79

ในระหว่างการทำงานบางอย่างกับเลนส์ออโต้โฟกัสผมมาในชุดนี้มีประโยชน์มากของอัลกอริทึมสำหรับการตรวจจับโฟกัสภาพ ก็ดำเนินการใน MATLAB แต่ส่วนมากของฟังก์ชั่นที่ค่อนข้างง่ายที่จะพอร์ตไป OpenCV กับfilter2D

โดยพื้นฐานแล้วเป็นการสำรวจโดยใช้อัลกอริทึมการวัดโฟกัส หากคุณต้องการอ่านเอกสารต้นฉบับการอ้างอิงถึงผู้แต่งอัลกอริทึมนั้นมีอยู่ในรหัส กระดาษ 2012 โดย Pertuz และคณะ การวิเคราะห์ผู้ประกอบการวัดโฟกัสสำหรับรูปร่างจากโฟกัส (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

ตัดคำตอบของ Nike ออก มันตรงไปตรงมาที่จะใช้วิธีการตาม laplacian กับ 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;
}

จะคืนค่าสั้น ๆ เพื่อระบุความคมชัดสูงสุดที่ตรวจพบซึ่งจากการทดสอบของฉันสำหรับตัวอย่างจริงเป็นตัวบ่งชี้ที่ดีว่ากล้องอยู่ในโฟกัสหรือไม่ ไม่น่าแปลกใจค่าปกติที่เกิดเหตุขึ้น แต่มากน้อยกว่าวิธีการ FFT ซึ่งมีระดับสูงของอัตราบวกปลอมที่จะเป็นประโยชน์ในการประยุกต์ใช้ของฉัน


มูลค่า threshhold จะบอกว่าภาพเป็น bluryy? ฉันได้ทำการทดสอบแล้ว แต่มันแสดงผลลัพธ์ที่แตกต่างกันบ้าง คุณช่วยฉันออกจากสิ่งนี้เพื่อกำหนดเกณฑ์ได้หรือไม่?
2vision2

ลองข้อเสนอแนะของคุณด้วย แต่ตัวเลขที่ฉันได้รับนั้นค่อนข้างสุ่ม หากฉันเริ่มคำถามใหม่เกี่ยวกับการใช้งานเฉพาะนี้คุณสนใจที่จะดูหรือไม่ \
Stpn

@stpn เกณฑ์ที่เหมาะสมขึ้นอยู่กับฉาก ในแอปพลิเคชันของฉัน (กล้องวงจรปิด) ฉันใช้ขีด จำกัด เริ่มต้นที่ 300 สำหรับกล้องที่มีผู้สนับสนุนน้อยจะเปลี่ยนค่าที่กำหนดสำหรับกล้องนั้น
Yaur

ทำไม "maxLap = -32767;" ?
ผ่อนผันเปรม

เรากำลังมองหาความคมชัดสูงสุดและเนื่องจากเรากำลังทำงานกับกางเกงขาสั้นที่มีลายเซ็น -32767 จึงเป็นค่าที่ต่ำที่สุด 2.5 ปีแล้วที่ฉันเขียนโค้ดนั้น แต่ IIRC ฉันมีปัญหาในการใช้ 16U
Yaur

23

ฉันคิดวิธีแก้ปัญหาที่แตกต่างออกไปโดยสิ้นเชิง ฉันต้องการวิเคราะห์เฟรมภาพนิ่งของวิดีโอเพื่อค้นหาเฟรมที่คมชัดที่สุดในทุกเฟรม (X) ด้วยวิธีนี้ฉันจะตรวจจับการเคลื่อนไหวเบลอและ / หรือภาพไม่ชัด

ฉันลงเอยด้วยการใช้การตรวจจับ Canny Edge และฉันได้ผลลัพธ์ที่ดีมาก ๆ กับวิดีโอเกือบทุกชนิด (ด้วยวิธีของ nikie ฉันมีปัญหากับวิดีโอ VHS แบบดิจิทัลและวิดีโอ interlaced จำนวนมาก)

ฉันปรับประสิทธิภาพให้เหมาะสมด้วยการตั้งค่าภูมิภาคที่น่าสนใจ (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

ขอบคุณ nikie สำหรับคำแนะนำที่ดีเยี่ยมของ Laplace เอกสาร 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 มันเบลออย่างเห็นได้ชัด ค่าสูงสุดไม่เคยต่ำกว่า 20 ถึงแม้ว่ามันจะเบลออย่างสมบูรณ์


3
ฉันได้ 255 จาก 3 รูป และสำหรับหนึ่งภาพที่โฟกัสได้อย่างสมบูรณ์แบบฉันได้ 108 ดังนั้นฉันคิดว่าประสิทธิภาพของวิธีการนั้นขึ้นอยู่กับบางสิ่ง
WindRider

เห็นด้วยกับ @WindWider ภาพตัวอย่างที่สิ่งนี้ล้มเหลวคือภาพนี้ฉันคิดว่าเหตุผลคือแม้ว่าภาพสั่นคลอนความแตกต่างของภาพและความแตกต่างของความเข้มที่สอดคล้องกันระหว่างพิกเซลมีขนาดใหญ่เนื่องจากค่า Laplacian มีขนาดค่อนข้างใหญ่ โปรดแก้ไขฉันหากฉันผิด
Resham Wadhwa

@ReshamWadhwa cc WindRider - เหมือนกัน - ความคิดใด ๆ ในการแก้ไขปัญหานี้ ??
jtlz2

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

มันมักจะอยู่หลัง paywall แต่ฉันได้เห็นบางสำเนาฟรี โดยทั่วไปแล้วพวกเขาจะหาขอบแนวตั้งในภาพแล้ววัดความกว้างของขอบเหล่านั้น การเฉลี่ยความกว้างจะให้ผลลัพธ์การประมาณเบลอสุดท้ายของภาพ ขอบที่กว้างขึ้นสอดคล้องกับภาพที่เบลอและในทางกลับกัน

ปัญหานี้เป็นเขตของไม่มีการอ้างอิงการประมาณค่าคุณภาพของภาพ หากคุณค้นหาใน Google Scholar คุณจะได้รับการอ้างอิงที่มีประโยชน์มากมาย

แก้ไข

นี่คือพล็อตของการประมาณการเบลอที่ได้รับจาก 5 ภาพในโพสต์ของ nikie ค่าที่สูงกว่านั้นสอดคล้องกับความพร่ามัวมากขึ้น ฉันใช้ตัวกรอง Gaussian 11x11 ขนาดคงที่และเปลี่ยนค่าเบี่ยงเบนมาตรฐาน (ใช้convertคำสั่งของ imagemagick เพื่อให้ได้ภาพเบลอ)

ป้อนคำอธิบายรูปภาพที่นี่

หากคุณเปรียบเทียบภาพที่มีขนาดต่างกันอย่าลืมที่จะทำให้ปกติด้วยความกว้างของภาพเนื่องจากภาพที่มีขนาดใหญ่กว่าจะมีขอบที่กว้างขึ้น

ในที่สุดปัญหาที่สำคัญคือการแยกความแตกต่างระหว่างความเบลอของภาพและเบลอที่ไม่ต้องการ (เกิดจากการพลาดโฟกัส, การบีบอัด, การเคลื่อนที่สัมพัทธ์ของตัวแบบกับกล้อง) แต่นั่นไม่ใช่วิธีง่าย ๆ เช่นนี้ สำหรับตัวอย่างของการเบลอทางศิลปะให้ดูที่ภาพของ Lenna: การสะท้อนของ Lenna ในกระจกนั้นพร่ามัว แต่ใบหน้าของเธออยู่ในโฟกัสอย่างสมบูรณ์แบบ สิ่งนี้มีส่วนช่วยในการประมาณการเบลอที่สูงขึ้นสำหรับภาพ Lenna


5

ฉันพยายามแก้ปัญหาขึ้นอยู่กับตัวกรอง Laplacian จากนี้โพสต์ มันไม่ได้ช่วยอะไรฉัน ดังนั้นฉันลองวิธีแก้ปัญหาจากโพสต์นี้และมันก็ดีสำหรับกรณีของฉัน (แต่ช้า):

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

คำตอบข้างต้นอธิบายหลายสิ่งหลายอย่าง แต่ฉันคิดว่ามันมีประโยชน์ที่จะทำให้ความแตกต่างทางความคิด

ถ้าคุณถ่ายภาพโฟกัสที่สมบูรณ์แบบของภาพเบลอ

ปัญหาการตรวจจับการเบลอนั้นเกิดขึ้นเมื่อคุณมีการอ้างอิงเท่านั้น หากคุณต้องการออกแบบเช่นระบบโฟกัสอัตโนมัติคุณเปรียบเทียบลำดับของภาพที่ถ่ายโดยมีระดับการเบลอหรือการปรับให้เรียบและคุณพยายามหาจุดเบลอขั้นต่ำภายในชุดนี้ คำอื่น ๆ ที่คุณต้องอ้างอิงภาพต่าง ๆ โดยใช้หนึ่งในเทคนิคที่แสดงด้านบน (โดยทั่วไป - ด้วยวิธีการปรับแต่งระดับต่างๆที่เป็นไปได้ - มองหาภาพหนึ่งภาพที่มีเนื้อหาความถี่สูงที่สุด)


2
กล่าวอีกนัยหนึ่งมันเป็นความคิดสัมพัทธ์มันเป็นไปได้ที่จะบอกได้ว่าภาพนั้นเบลอมากหรือน้อยกว่าภาพที่คล้ายกันอื่น เช่นถ้ามันมีเนื้อหาความถี่สูงหรือต่ำกว่าใน FFT กรณีเฉพาะ: จะเกิดอะไรขึ้นถ้าภาพมีพิกเซลที่อยู่ติดกันซึ่งมีความส่องสว่างสูงสุดและต่ำสุด? ตัวอย่างเช่นพิกเซลสีดำสนิทถัดจากพิกเซลสีขาวทั้งหมด ในกรณีนี้มันเป็นจุดโฟกัสที่สมบูรณ์แบบมิฉะนั้นจะมีการเปลี่ยนแปลงที่ราบรื่นจากสีดำเป็นสีขาว โฟกัสที่สมบูรณ์แบบไม่น่าจะมีในการถ่ายภาพ แต่คำถามไม่ได้ระบุแหล่งที่มาของภาพ (อาจเป็นคอมพิวเตอร์ที่สร้างขึ้น)
Ben

1

รหัส Matlab ของสองวิธีที่ได้รับการตีพิมพ์ในวารสารที่ได้รับการยอมรับอย่างสูง (IEEE ธุรกรรมในการประมวลผลภาพ) มีให้ที่นี่: https://ivulab.asu.edu/software

ตรวจสอบอัลกอริทึม CPBDM และ JNBM หากคุณตรวจสอบรหัสมันไม่ยากมากที่จะทำการพอร์ตและบังเอิญว่ามันขึ้นอยู่กับวิธีการของ Marzialiano เป็นคุณสมบัติพื้นฐาน


1

ฉันใช้มันใช้ fft ใน MATLAB และตรวจสอบฮิสโตแกรมของค่าเฉลี่ยคำนวณ 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(:));

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.