Apakah ada cara untuk mendeteksi jika gambar buram?

203

Saya bertanya-tanya apakah ada cara untuk menentukan apakah suatu gambar buram atau tidak dengan menganalisis data gambar.

Sam
sumber
7
Pertanyaan terkait yang memiliki jawaban yang baik, tetapi juga formulasi pertanyaan yang lebih terlibat. stackoverflow.com/questions/5180327/…
Lennart Rolland
1
Ini juga memiliki jawaban yang jauh lebih buruk.
John Shedletsky

Jawaban:

133

Ya itu. Hitung Fast Fourier Transform dan analisis hasilnya. Transformasi Fourier memberi tahu Anda frekuensi mana yang ada dalam gambar. Jika ada frekuensi rendah dalam jumlah rendah, maka gambarnya buram.

Menentukan istilah 'rendah' ​​dan 'tinggi' terserah Anda.

Edit :

Seperti yang dinyatakan dalam komentar, jika Anda ingin satu float mewakili kekaburan gambar tertentu, Anda harus membuat metrik yang sesuai.

Jawaban nikie memberikan metrik seperti itu. Gabungkan gambar dengan kernel Laplacian:

   1
1 -4  1
   1

Dan gunakan metrik maksimum yang kuat pada output untuk mendapatkan nomor yang dapat Anda gunakan untuk thresholding. Cobalah untuk menghindari merapikan terlalu banyak gambar sebelum menghitung Laplacian, karena Anda hanya akan menemukan bahwa gambar yang dihaluskan memang buram :-).

Simon Bergot
sumber
9
hanya masalah 'rendah' ​​dan 'tinggi' juga tergantung adegan. +1
kenny
4
Kecuali jika gambar Anda adalah siklik, Anda biasanya akan memiliki tepi tajam pada batas gambar yang mengarah ke frekuensi yang sangat tinggi
Niki
2
Anda biasanya memperluas gambar Anda untuk menghindari efek ini. Anda juga dapat menggunakan jendela kecil untuk menghitung fft lokal.
Simon Bergot
6
Hanya satu hal yang sangat penting adalah Anda harus tahu (setidaknya secara kasar) apa yang diharapkan dari konten gambar pra-kabur Anda (frekuensi). Ini benar karena spektrum frekuensi akan menjadi yang dari kali gambar asli dari filter kabur. Jadi, jika gambar aslinya sudah memiliki frekuensi yang sangat rendah, bagaimana Anda bisa tahu apakah itu kabur?
Chris A.
1
Jika Anda mengambil foto dari grafik putih kosong, Anda tidak memiliki cara untuk mengetahui apakah gambar tersebut buram atau tidak. Saya pikir OP ingin beberapa pengukuran ketajaman absolut. gambar yang sudah ada sebelumnya mungkin tidak ada sama sekali. Anda harus bekerja sedikit untuk menghasilkan metrik yang benar, tetapi fft dapat membantu mengatasi masalah ini. Dalam perspektif ini, jawaban nickie lebih baik daripada jawaban saya.
Simon Bergot
158

Cara lain yang sangat sederhana untuk memperkirakan ketajaman suatu gambar adalah dengan menggunakan filter Laplace (atau LoG) dan cukup memilih nilai maksimum. Menggunakan ukuran yang kuat seperti 99,9% kuantil mungkin lebih baik jika Anda mengharapkan noise (yaitu memilih kontras ke-N tertinggi daripada kontras tertinggi.) Jika Anda mengharapkan berbagai kecerahan gambar, Anda juga harus memasukkan langkah preprocessing untuk menormalkan kecerahan gambar / kontras (mis. pemerataan histogram).

Saya telah mengimplementasikan saran Simon dan yang ini di Mathematica, dan mencobanya pada beberapa gambar uji:

gambar uji

Tes pertama mengaburkan gambar uji menggunakan filter Gaussian dengan ukuran kernel yang bervariasi, kemudian menghitung FFT dari gambar buram dan mengambil rata-rata frekuensi tertinggi 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}]

Menghasilkan plot logaritmik:

hasil fft

5 garis mewakili 5 gambar uji, sumbu X mewakili jari-jari filter Gaussian. Grafik menurun, sehingga FFT adalah ukuran yang baik untuk ketajaman.

Ini adalah kode untuk penaksir keburaman "LoG tertinggi": Ini hanya menerapkan filter LoG dan mengembalikan piksel paling terang dalam hasil filter:

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

Menghasilkan plot logaritmik:

hasil laplace

Penyebaran untuk gambar yang tidak kabur sedikit lebih baik di sini (2,5 vs 3,3), terutama karena metode ini hanya menggunakan kontras terkuat dalam gambar, sedangkan FFT pada dasarnya adalah rata-rata di seluruh gambar. Fungsi-fungsinya juga menurun lebih cepat, jadi mungkin lebih mudah untuk menetapkan ambang batas "buram".

Niki
sumber
1
Bagaimana jika saya mengejar ukuran blur lokal. Yaitu, Foto memiliki area yang buram dan tajam. Saya ingin memiliki peta yang memperkirakan tingkat blur per piksel.
Royi
4
@Drazick: Saya tidak yakin apakah itu mungkin. Misalnya, lihat gambar Lena: Ada area besar di mana tidak ada kontras (misalnya kulit Lena) meskipun area tersebut dalam fokus. Saya tidak bisa memikirkan cara untuk mengetahui apakah area yang halus itu "buram", atau untuk membedakannya dari area yang tidak fokus. Anda harus menanyakan ini sebagai pertanyaan terpisah (mungkin pada DSP.SE). Mungkin orang lain punya ide yang lebih baik.
Niki
1
Apakah ini cocok untuk motion blur? atau hanya untuk blur seperti gaussian?
mrgloom
@pparescasellas Apakah Anda bersedia berbagi implementasi Anda. Saya ingin tahu melihat mereka.
chappjc
@ JohnBoe Saya pikir Anda bermaksud bertanya pparescasellas
chappjc
79

Selama beberapa pekerjaan dengan lensa fokus otomatis, saya menemukan serangkaian algoritma yang sangat berguna ini untuk mendeteksi fokus gambar . Ini diimplementasikan dalam MATLAB, tetapi sebagian besar fungsi cukup mudah untuk port ke OpenCV dengan filter2D .

Ini pada dasarnya merupakan implementasi survei dari banyak algoritma pengukuran fokus. Jika Anda ingin membaca makalah asli, referensi ke penulis algoritma disediakan dalam kode. Makalah 2012 oleh Pertuz, et al. Analisis operator ukuran fokus untuk bentuk dari fokus (SFF) memberikan ulasan yang baik dari semua ukuran ini serta kinerja mereka (baik dalam hal kecepatan dan akurasi seperti yang diterapkan pada SFF).

EDIT: Menambahkan kode MATLAB untuk berjaga-jaga jika tautannya mati.

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
%******************************************************************

Beberapa contoh versi 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;
}

Tidak ada jaminan apakah langkah-langkah ini adalah pilihan terbaik untuk masalah Anda, tetapi jika Anda melacak makalah yang terkait dengan tindakan ini, mereka mungkin memberi Anda wawasan lebih lanjut. Semoga kode ini bermanfaat! Saya tahu saya melakukannya.

mevatron
sumber
dalam algoritma tenengrad, apa yang akan menjadi nilai nominal untuk kSize?
mans
@mans Saya biasanya menggunakan 3, 5, atau 7 tergantung pada resolusi gambar. Jika Anda merasa harus lebih tinggi dari itu, Anda mungkin ingin melihat downsampling gambar.
mevatron
32

Membangun dari jawaban Nike. Sangat mudah untuk mengimplementasikan metode berbasis laplacian dengan 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;
}

Akan menampilkan pendek yang menunjukkan ketajaman maksimum yang terdeteksi, yang didasarkan pada pengujian saya pada sampel dunia nyata, merupakan indikator yang cukup baik jika kamera fokus atau tidak. Tidak mengherankan, nilai normal tergantung pada adegan tetapi jauh lebih sedikit daripada metode FFT yang memiliki tingkat positif palsu yang tinggi untuk berguna dalam aplikasi saya.

Yaur
sumber
Apa yang akan menjadi nilai ambang untuk mengatakan gambar itu buram? Saya sudah mengujinya. Tetapi ini menunjukkan beberapa hasil yang bervariasi. Bisakah Anda membantu saya dalam menetapkan ambang ini?
2vision2
Juga mencoba saran Anda, tetapi angka yang saya dapatkan agak acak. Jika saya memulai pertanyaan baru sehubungan dengan implementasi khusus ini, apakah Anda mau melihatnya? \
Stpn
@stpn Ambang kanan bergantung pada adegan. Dalam aplikasi saya (CCTV) saya menggunakan ambang batas standar 300. Untuk kamera di mana itu adalah untuk seseorang yang rendah dari dukungan akan mengubah nilai yang dikonfigurasi untuk kamera tertentu.
Yaur
mengapa "maxLap = -32767;" ?
Clement Prem
Kami mencari kontras tertinggi dan karena kami bekerja dengan celana pendek bertanda -32767 adalah nilai serendah mungkin. Sudah 2,5 tahun sejak saya menulis kode itu tetapi IIRC saya punya masalah menggunakan 16U.
Yaur
23

Saya datang dengan solusi yang sama sekali berbeda. Saya perlu menganalisis frame video untuk menemukan yang paling tajam di setiap frame (X). Dengan cara ini, saya akan mendeteksi gambar blur dan / atau tidak fokus.

Saya akhirnya menggunakan deteksi Canny Edge dan saya mendapatkan hasil yang SANGAT SANGAT bagus dengan hampir setiap jenis video (dengan metode nikie, saya memiliki masalah dengan video VHS digital dan video interlaced berat).

Saya mengoptimalkan kinerja dengan menetapkan wilayah minat (ROI) pada gambar asli.

Menggunakan 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));
}
Goldorak84
sumber
17

Terima kasih nikie untuk saran Laplace yang hebat itu. OpenCV docs menunjuk saya ke arah yang sama: menggunakan python, cv2 (opencv 2.4.10), dan numpy ...

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

hasilnya adalah antara 0-255. Saya menemukan sesuatu yang berusia lebih dari 200 tahun sangat fokus, dan pada usia 100, terlihat buram. maks tidak pernah benar-benar mendapat jauh di bawah 20 bahkan jika itu benar-benar kabur.

ggez44
sumber
3
Saya mendapat 255 untuk 3 foto saya. Dan untuk satu foto yang fokus sempurna saya dapatkan 108. Jadi, saya pikir efektivitas metode ini tergantung pada sesuatu.
WindRider
Setuju dengan @WindWider. Contoh gambar di mana ini gagal adalah gambar ini saya pikir alasannya adalah bahwa meskipun gambar itu goyah, kontras gambar dan perbedaan intensitas yang sesuai antara piksel besar, karena yang Nilai-nilai Laplacian relatif besar. Tolong koreksi saya jika saya salah.
Resham Wadhwa
@ReshamWadhwa cc WindRider - idem - ada ide tentang cara memperbaikinya ??
jtlz2
@ ggez44 Ini adalah jawaban yang saya sukai - tetapi nilainya adalah fungsi dari jumlah piksel dalam gambar. Apakah Anda tahu bagaimana skala ini secara teoritis? Saya bisa mengajukannya sebagai pertanyaan baru tetapi kemungkinan akan ditembak jatuh. Terima kasih!
jtlz2
10

Salah satu cara yang saya gunakan saat ini adalah mengukur penyebaran tepi pada gambar. Cari makalah ini:

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

Biasanya di balik paywall tetapi saya telah melihat beberapa salinan gratis di sekitar. Pada dasarnya, mereka menemukan tepi vertikal dalam gambar, dan kemudian mengukur seberapa lebar tepi tersebut. Rata-rata lebar memberikan hasil estimasi blur akhir untuk gambar. Tepi yang lebih luas berhubungan dengan gambar buram, dan sebaliknya.

Masalah ini milik bidang estimasi kualitas gambar tanpa referensi . Jika Anda mencarinya di Google Cendekia, Anda akan mendapatkan banyak referensi yang bermanfaat.

EDIT

Berikut plot perkiraan blur yang diperoleh untuk 5 gambar di pos nikie. Nilai yang lebih tinggi sesuai dengan kekaburan yang lebih besar. Saya menggunakan filter Gaussian ukuran 11x11 ukuran tetap dan memvariasikan standar deviasi (menggunakan convertperintah imagemagick untuk mendapatkan gambar buram).

masukkan deskripsi gambar di sini

Jika Anda membandingkan gambar dengan ukuran berbeda, jangan lupa untuk menormalkan dengan lebar gambar, karena gambar yang lebih besar akan memiliki tepi yang lebih lebar.

Akhirnya, masalah yang signifikan adalah membedakan antara blur artistik dan blur yang tidak diinginkan (disebabkan oleh kehilangan fokus, kompresi, gerakan relatif subjek ke kamera), tetapi itu di luar pendekatan sederhana seperti ini. Sebagai contoh kekaburan artistik, lihatlah gambar Lenna: Refleksi Lenna di cermin buram, tetapi wajahnya benar-benar fokus. Ini berkontribusi pada perkiraan blur yang lebih tinggi untuk gambar Lenna.

mpenkov
sumber
5

Saya mencoba solusi berdasarkan filter Laplacian dari posting ini . Itu tidak membantu saya. Jadi, saya mencoba solusi dari posting ini dan itu bagus untuk kasus saya (tetapi lambat):

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

Gambar yang kurang buram memiliki maksimum sum nilai !

Anda juga dapat mengatur kecepatan dan akurasi dengan mengubah langkah, misalnya

bagian ini

for x in range(width - 1):

Anda dapat mengganti dengan yang ini

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

Jawaban di atas menjelaskan banyak hal, tetapi saya pikir berguna untuk membuat perbedaan konseptual.

Bagaimana jika Anda mengambil gambar yang benar-benar fokus pada gambar yang buram?

Masalah deteksi kabur hanya diajukan dengan baik ketika Anda memiliki referensi . Jika Anda perlu merancang, misalnya, sistem fokus otomatis, Anda membandingkan urutan gambar yang diambil dengan berbagai tingkat kekaburan, atau menghaluskan, dan Anda mencoba menemukan titik kekaburan minimum dalam set ini. Saya kata lain Anda perlu referensi silang berbagai gambar menggunakan salah satu teknik yang diilustrasikan di atas (pada dasarnya - dengan berbagai tingkat penyempurnaan dalam pendekatan - mencari satu gambar dengan konten frekuensi tinggi tertinggi).

Senjata Zamrud
sumber
2
Dengan kata lain itu adalah gagasan relatif, hanya mungkin untuk mengetahui apakah suatu gambar lebih atau kurang kabur daripada gambar serupa lainnya. yaitu jika memiliki konten frekuensi lebih atau lebih tinggi dalam FFT-nya. Kasus khusus: bagaimana jika gambar memiliki piksel yang berdekatan dengan luminositas maksimum dan minimum? Misalnya piksel yang benar-benar hitam di sebelah piksel yang sepenuhnya putih. Dalam hal ini, ini adalah fokus yang sempurna, jika tidak, akan ada transisi yang lebih mulus dari hitam ke putih. Fokus sempurna tidak mungkin dalam fotografi, tetapi pertanyaannya tidak menentukan sumber gambar (bisa dihasilkan oleh komputer).
Ben
1

Kode Matlab dari dua metode yang telah diterbitkan dalam jurnal yang sangat dihormati (Transaksi IEEE pada Pemrosesan Gambar) tersedia di sini: https://ivulab.asu.edu/software

periksa algoritma CPBDM dan JNBM. Jika Anda memeriksa kode itu tidak terlalu sulit untuk porting dan kebetulan itu didasarkan pada metode Marzialiano sebagai fitur dasar.

Marco
sumber
1

saya menerapkannya menggunakan fft di matlab dan memeriksa histogram dari rata-rata menghitung fft dan std tetapi juga fungsi fit dapat dilakukan

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

Itulah yang saya lakukan di Opencv untuk mendeteksi kualitas fokus di suatu wilayah:

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];
Nadav B
sumber