C'è un modo per rilevare se un'immagine è sfocata?


Risposte:


133

Sì. Calcola la Trasformata di Fourier veloce e analizza il risultato. La trasformata di Fourier ti dice quali frequenze sono presenti nell'immagine. Se c'è una bassa quantità di alte frequenze, l'immagine è sfocata.

La definizione dei termini "basso" e "alto" dipende da te.

Modifica :

Come indicato nei commenti, se si desidera un singolo float che rappresenti la sfocatura di una determinata immagine, è necessario elaborare una metrica adeguata.

la risposta di Nikie fornisce una simile metrica. Convolgere l'immagine con un kernel Laplaciano:

   1
1 -4  1
   1

E utilizza una metrica massima robusta sull'output per ottenere un numero che puoi utilizzare per il limite. Cerca di evitare di smussare troppo le immagini prima di calcolare Laplacian, perché scoprirai solo che un'immagine levigata è davvero sfocata :-).


9
l'unico problema è che "basso" e "alto" dipendono anche dalla scena. +1
kenny,

4
A meno che la tua immagine non sia ciclica, di solito avrai bordi nitidi ai bordi dell'immagine che portano a frequenze molto alte
Niki,

2
di solito estendi virtualmente la tua immagine per evitare questo effetto. puoi anche usare piccole finestre per calcolare fft locale.
Simon Bergot,

6
Solo un punto estremamente importante è che devi sapere (almeno all'incirca) qual era il contenuto previsto per la tua immagine pre-offuscata (frequenza). Questo è vero poiché lo spettro di frequenza sarà quello dell'immagine originale moltiplicato per quello del filtro di sfocatura. Pertanto, se l'immagine originale aveva già frequenze prevalentemente basse, come si può sapere se era sfocata?
Chris A.

1
Se scatti una foto di un diagramma bianco vuoto non hai modo di dire se l'immagine è sfocata o meno. Penso che l'OP voglia una misura di nitidezza assoluta. l'immagine preblurred potrebbe non esistere affatto. Devi lavorare un po 'per arrivare con una metrica corretta, ma fft può aiutare con questo problema. In questa prospettiva, la risposta di Nickie è migliore della mia.
Simon Bergot,

158

Un altro modo molto semplice per stimare la nitidezza di un'immagine è utilizzare un filtro Laplace (o LoG) e selezionare semplicemente il valore massimo. L'uso di una misura robusta come un quantile del 99,9% è probabilmente migliore se si prevede un rumore (ovvero scegliere l'ennesimo contrasto più elevato anziché il contrasto più elevato). Se si prevede una variazione della luminosità dell'immagine, è necessario includere anche una fase di preelaborazione per normalizzare la luminosità dell'immagine / contrasto (ad es. equalizzazione dell'istogramma).

Ho implementato il suggerimento di Simon e questo in Mathematica, e l'ho provato su alcune immagini di prova:

immagini di prova

Il primo test sfoca le immagini del test usando un filtro gaussiano con una dimensione del kernel variabile, quindi calcola la FFT dell'immagine sfocata e prende la media delle frequenze più alte del 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}]

Risultato in un diagramma logaritmico:

risultato fft

Le 5 linee rappresentano le 5 immagini di prova, l'asse X rappresenta il raggio del filtro gaussiano. I grafici stanno diminuendo, quindi FFT è una buona misura per la nitidezza.

Questo è il codice per lo stimatore di sfocatura "più alto LoG": applica semplicemente un filtro LoG e restituisce il pixel più luminoso nel risultato del filtro:

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

Risultato in un diagramma logaritmico:

risultato laplace

La diffusione per le immagini non sfocate è un po 'migliore qui (2,5 vs 3,3), principalmente perché questo metodo utilizza solo il contrasto più forte nell'immagine, mentre la FFT è essenzialmente una media sull'intera immagine. Le funzioni stanno inoltre diminuendo più rapidamente, quindi potrebbe essere più semplice impostare una soglia "sfocata".


1
E se cercassi la misura della sfocatura locale. Vale a dire, una foto ha aree in cui è sfocata e in cui è nitida. Voglio avere una mappa che stima il livello di sfocatura per pixel.
Royi,

4
@Drazick: non sono sicuro che sia possibile. Ad esempio, guarda l'immagine di Lena: ci sono ampie aree in cui non c'è contrasto (ad esempio la pelle di Lena) sebbene l'area sia a fuoco. Non riesco a pensare a un modo per dire se un'area così liscia è "sfocata" o per distinguerla da un'area sfocata. Dovresti porlo come una domanda separata (forse su DSP.SE). Forse qualcun altro ha idee migliori.
Niki,

1
È adatto per il motion blur? o solo per sfocatura come gaussiana?
mrgloom,

@pparescasellas Saresti disposto a condividere le tue implementazioni. Sarei curioso di vederli.
Chappjc,

@JohnBoe Penso che volevi chiedere a Pparescasellas
Chappjc,

79

Durante alcuni lavori con un obiettivo con messa a fuoco automatica, mi sono imbattuto in questo utilissimo set di algoritmi per rilevare la messa a fuoco dell'immagine . È implementato in MATLAB, ma la maggior parte delle funzioni è abbastanza facile da portare su OpenCV con filter2D .

È fondamentalmente un'implementazione di rilievo di molti algoritmi di misurazione del focus. Se si desidera leggere i documenti originali, nel codice vengono forniti riferimenti agli autori degli algoritmi. L'articolo del 2012 di Pertuz, et al. L'analisi degli operatori di misure di messa a fuoco per la forma da messa a fuoco (SFF) offre una grande rassegna di tutte queste misure e delle loro prestazioni (sia in termini di velocità che di precisione applicate a SFF).

EDIT: aggiunto il codice MATLAB nel caso in cui il collegamento si interrompa.

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

Alcuni esempi di versioni 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;
}

Nessuna garanzia se queste misure siano o meno la scelta migliore per il tuo problema, ma se rintracci i documenti associati a queste misure, potrebbero fornirti maggiori informazioni. Spero che trovi utile il codice! So di averlo fatto.


nell'algoritmo tenengrad, quale sarebbe un valore nominale per kSize?
equipaggia il

@mans Normalmente uso 3, 5 o 7 a seconda della risoluzione dell'immagine. Se scopri che hai bisogno di andare più in alto di quello, potresti voler guardare il downsampling dell'immagine.
Mevatron,

32

Basandosi sulla risposta di Nike. È semplice implementare il metodo basato su laplacian con 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;
}

Restituirà un corto che indica la massima nitidezza rilevata, che sulla base dei miei test su campioni del mondo reale, è un ottimo indicatore del fatto che una fotocamera sia a fuoco o meno. Non sorprende che i valori normali dipendono dalla scena, ma molto meno del metodo FFT che deve avere un tasso di falsi positivi elevato per essere utile nella mia applicazione.


Quale sarebbe il valore di trebbia per dire che un'immagine è sfocata? L'ho provato. Ma sta mostrando alcuni risultati variabili. Potete per favore aiutarmi in questo per impostare la soglia?
2vision2

Ho anche provato il tuo suggerimento, ma i numeri che ottengo sono un po 'casuali. Se avessi una nuova domanda riguardo a questa particolare implementazione, ti andrebbe di dare un'occhiata? \
Stpn

@stpn La soglia giusta dipende dalla scena. Nella mia applicazione (CCTV) sto usando una soglia predefinita di 300. Per le telecamere che richiedono un supporto ridotto, il valore configurato per quella telecamera specifica.
Yaur,

perché è "maxLap = -32767;" ?
Clemente Prem,

Stiamo cercando il massimo contrasto e poiché stiamo lavorando con pantaloncini firmati -32767 è il valore più basso possibile. Sono passati 2,5 anni da quando ho scritto quel codice ma IIRC ho avuto problemi con l'utilizzo di 16U.
Yaur,

23

Ho trovato una soluzione totalmente diversa. Avevo bisogno di analizzare i fotogrammi fissi video per trovare il più nitido in ogni (X) fotogrammi. In questo modo, rileverei le sfocature e / o le immagini sfocate.

Ho finito con il rilevamento di Canny Edge e ho ottenuto risultati MOLTO MOLTO buoni con quasi tutti i tipi di video (con il metodo di Nikie, ho avuto problemi con video VHS digitalizzati e video interlacciati pesanti).

Ho ottimizzato le prestazioni impostando una regione di interesse (ROI) sull'immagine originale.

Utilizzando 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

Grazie Nikie per l'ottimo suggerimento di Laplace. I documenti OpenCV mi hanno indicato nella stessa direzione: usando python, cv2 (opencv 2.4.10) e numpy ...

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

il risultato è compreso tra 0-255. Ho scoperto che qualcosa di più di 200ish è molto a fuoco, e per 100 è notevolmente sfocato. il massimo non arriva mai molto meno di 20 anni anche se è completamente sfocato.


3
Ho ricevuto 255 per 3 delle mie foto. E per una foto perfettamente focalizzata ho ottenuto 108. Quindi, penso che l'efficacia del metodo dipenda da qualcosa.
WindRider,

Concordato con @WindWider. L'immagine di esempio in cui questo fallisce è questa immagine Penso che il motivo sia che, sebbene l'immagine sia traballante, il contrasto dell'immagine e le corrispondenti differenze di intensità tra i pixel è grande, a causa del quale i valori di Laplacian sono relativamente grandi. Perfavore, correggimi se sbaglio.
Resham Wadhwa,

@ReshamWadhwa cc WindRider - idem - qualche idea su come risolvere questo ??
jtlz2,

@ ggez44 Questa è la mia risposta preferita, ma il valore è una funzione del numero di pixel nell'immagine. Sai come questa scala teoricamente? Potrei porlo come una nuova domanda ma è probabile che venga abbattuto. Grazie!
jtlz2,

10

Un modo che sto attualmente utilizzando misura la diffusione dei bordi nell'immagine. Cerca questo documento:

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

Di solito è dietro un paywall ma ho visto alcune copie gratuite in giro. Fondamentalmente, individuano i bordi verticali in un'immagine e quindi misurano la larghezza di tali bordi. La media della larghezza fornisce il risultato finale della stima della sfocatura per l'immagine. I bordi più ampi corrispondono alle immagini sfocate e viceversa.

Questo problema appartiene al campo della stima della qualità dell'immagine senza riferimento . Se lo cerchi su Google Scholar, otterrai molti riferimenti utili.

MODIFICARE

Ecco una trama delle stime di sfocatura ottenute per le 5 immagini nel post di nikie. Valori più alti corrispondono a una maggiore sfocatura. Ho usato un filtro gaussiano di dimensioni fisse 11x11 e ho variato la deviazione standard (usando il convertcomando imagemagick per ottenere le immagini sfocate).

inserisci qui la descrizione dell'immagine

Se si confrontano immagini di dimensioni diverse, non dimenticare di normalizzare in base alla larghezza dell'immagine, poiché le immagini più grandi avranno bordi più ampi.

Infine, un problema significativo è la distinzione tra sfocatura artistica e sfocatura indesiderata (causata da mancanza di messa a fuoco, compressione, movimento relativo del soggetto rispetto alla fotocamera), ma va oltre i semplici approcci come questo. Per un esempio di sfocatura artistica, dai un'occhiata all'immagine di Lenna: il riflesso di Lenna nello specchio è sfocato, ma il suo viso è perfettamente a fuoco. Ciò contribuisce a una stima della sfocatura più elevata per l'immagine di Lenna.


5

Da questo post ho provato una soluzione basata sul filtro Laplaciano . Non mi ha aiutato. Quindi, ho provato la soluzione da questo post ed è stato buono per il mio caso (ma è lento):

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

L'immagine meno sfocata ha il massimo sumvalore!

È inoltre possibile regolare la velocità e la precisione modificando il passo, ad es

questa parte

for x in range(width - 1):

puoi sostituirlo con questo

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

4

Le risposte sopra hanno chiarito molte cose, ma penso che sia utile fare una distinzione concettuale.

Cosa succede se si scatta una foto perfettamente a fuoco di un'immagine sfocata?

Il problema di rilevamento della sfocatura è ben posto solo quando si ha un riferimento . Se è necessario progettare, ad esempio, un sistema di messa a fuoco automatica, si confronta una sequenza di immagini scattate con diversi gradi di sfocatura o levigatura e si tenta di trovare il punto di sfocatura minima all'interno di questo set. In altre parole, è necessario fare un riferimento incrociato tra le varie immagini usando una delle tecniche illustrate sopra (sostanzialmente - con vari possibili livelli di raffinatezza nell'approccio - cercare l'immagine con il più alto contenuto ad alta frequenza).


2
In altre parole è una nozione relativa, è possibile solo dire se un'immagine è più o meno sfocata di un'altra immagine simile. cioè se ha un contenuto più o meno ad alta frequenza nella sua FFT. Caso particolare: cosa succede se l'immagine ha pixel adiacenti con la luminosità massima e minima? Ad esempio un pixel completamente nero accanto a un pixel completamente bianco. In questo caso è un focus perfetto, altrimenti ci sarebbe una transizione più fluida dal nero al bianco. Una messa a fuoco perfetta non è probabile nella fotografia, ma la domanda non specifica la fonte dell'immagine (potrebbe essere generata al computer).
Ben

1

Il codice Matlab di due metodi che sono stati pubblicati su riviste di alto livello (Transazioni IEEE sull'elaborazione delle immagini) sono disponibili qui: https://ivulab.asu.edu/software

controlla gli algoritmi CPBDM e JNBM. Se si controlla il codice non è molto difficile eseguire il porting e per inciso si basa sul metodo di Marzialiano come funzionalità di base.


1

l'ho implementato usando fft in matlab e controlla l'istogramma della media di calcolo fft e std ma si può anche fare la funzione di adattamento

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

Questo è ciò che faccio in Opencv per rilevare la qualità della messa a fuoco in una regione:

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];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.