¿Hay alguna manera de detectar si una imagen está borrosa?

203

Me preguntaba si hay una manera de determinar si una imagen está borrosa o no analizando los datos de la imagen.

Sam
fuente
77
Pregunta relacionada que tiene una buena respuesta, pero también una formulación de preguntas más complicada. stackoverflow.com/questions/5180327/…
Lennart Rolland
1
También tiene respuestas mucho peores.
John Shedletsky

Respuestas:

133

Sí lo es. Calcule la Transformada rápida de Fourier y analice el resultado. La transformación de Fourier le dice qué frecuencias están presentes en la imagen. Si hay una baja cantidad de frecuencias altas, la imagen está borrosa.

Definir los términos 'bajo' y 'alto' depende de usted.

Editar :

Como se indicó en los comentarios, si desea un flotador único que represente el desenfoque de una imagen determinada, debe calcular una métrica adecuada.

La respuesta de Nikie proporciona esa métrica. Convolucione la imagen con un núcleo laplaciano:

   1
1 -4  1
   1

Y use una métrica máxima robusta en la salida para obtener un número que pueda usar para el umbral. Intente evitar suavizar demasiado las imágenes antes de calcular el Laplaciano, porque solo descubrirá que una imagen suavizada está borrosa :-).

Simon Bergot
fuente
9
El único problema es que 'bajo' y 'alto' también dependen de la escena. +1
kenny
44
A menos que su imagen sea cíclica, generalmente tendrá bordes afilados en los bordes de la imagen que conducen a frecuencias muy altas
Niki
2
Por lo general, prácticamente extiende su imagen para evitar este efecto. También puede usar ventanas pequeñas para calcular fft local.
Simon Bergot
66
Solo un punto que es de gran importancia es que debe saber (al menos aproximadamente) cuál era el contenido esperado de la imagen pre-borrosa (frecuencia). Esto es cierto ya que el espectro de frecuencia será el de la imagen original multiplicado por el del filtro borroso. Por lo tanto, si la imagen original ya tenía frecuencias predominantemente bajas, ¿cómo puede saber si estaba borrosa?
Chris A.
1
Si toma una foto de un cuadro blanco en blanco, no tiene forma de saber si la imagen está borrosa o no. Creo que el OP quiere una medición de nitidez absoluta. la imagen borrosa podría no existir en absoluto. Debe trabajar un poco para obtener una métrica correcta, pero fft puede ayudarlo con este problema. Desde esta perspectiva, la respuesta de Nickie es mejor que la mía.
Simon Bergot
158

Otra forma muy simple de estimar la nitidez de una imagen es usar un filtro de Laplace (o LoG) y simplemente elegir el valor máximo. Usar una medida robusta como un cuantil del 99.9% probablemente sea mejor si espera ruido (es decir, elegir el enésimo contraste más alto en lugar del contraste más alto). Si espera un brillo de imagen variable, también debe incluir un paso de preprocesamiento para normalizar el brillo de la imagen / contraste (por ejemplo, ecualización de histograma).

Implementé la sugerencia de Simon y esta en Mathematica, y la probé en algunas imágenes de prueba:

imágenes de prueba

La primera prueba difumina las imágenes de prueba usando un filtro gaussiano con un tamaño de núcleo variable, luego calcula la FFT de la imagen borrosa y toma el promedio de las frecuencias más altas 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}]

Resultado en una trama logarítmica:

resultado fft

Las 5 líneas representan las 5 imágenes de prueba, el eje X representa el radio del filtro gaussiano. Los gráficos están disminuyendo, por lo que la FFT es una buena medida de nitidez.

Este es el código para el estimador de borrosidad "LoG más alto": simplemente aplica un filtro LoG y devuelve el píxel más brillante en el resultado del filtro:

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

Resultado en una trama logarítmica:

resultado de laplace

La extensión de las imágenes no borrosas es un poco mejor aquí (2.5 frente a 3.3), principalmente porque este método solo usa el contraste más fuerte en la imagen, mientras que el FFT es esencialmente un promedio sobre toda la imagen. Las funciones también disminuyen más rápido, por lo que podría ser más fácil establecer un umbral "borroso".

Niki
fuente
1
¿Qué pasa si busco la medida del desenfoque local? A saber, una foto tiene áreas donde está borrosa y donde es nítida. Quiero tener un mapa que calcule el nivel de desenfoque por píxel.
Royi
44
@Drazick: No estoy seguro de si eso es posible. Por ejemplo, mire la imagen de Lena: hay grandes áreas donde no hay contraste (por ejemplo, la piel de Lena) aunque el área está enfocada. No se me ocurre una manera de saber si un área tan suave es "borrosa", o distinguirla de un área fuera de foco. Debe hacer esto como una pregunta separada (tal vez en DSP.SE). Quizás alguien más tenga mejores ideas.
Niki
1
¿Es adecuado para el desenfoque de movimiento? o solo para desenfoque como gaussiano?
mrgloom
@pparescasellas ¿Estaría dispuesto a compartir sus implementaciones? Me daría curiosidad verlos.
chappjc
@JohnBoe Creo que querías preguntarle a pparescasellas
chappjc
79

Durante algunos trabajos con una lente de enfoque automático, me encontré con este conjunto muy útil de algoritmos para detectar el enfoque de la imagen . Está implementado en MATLAB, pero la mayoría de las funciones son bastante fáciles de portar a OpenCV con filter2D .

Básicamente es una implementación de encuestas de muchos algoritmos de medición de enfoque. Si desea leer los documentos originales, en el código se proporcionan referencias a los autores de los algoritmos. El artículo de 2012 de Pertuz, et al. El análisis de los operadores de medidas de enfoque para la forma desde el foco (SFF) ofrece una excelente revisión de todas estas medidas, así como de su rendimiento (tanto en términos de velocidad como de precisión aplicadas a SFF).

EDITAR: se agregó código MATLAB en caso de que el enlace muera.

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

Algunos ejemplos de versiones de 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;
}

No hay garantías de si estas medidas son o no la mejor opción para su problema, pero si rastrea los documentos asociados con estas medidas, pueden darle más información. ¡Espero que encuentres útil el código! Sé que lo hice.

mevatron
fuente
en el algoritmo tenengrad, ¿cuál sería un valor nominal para kSize?
Mans
@mans Normalmente uso 3, 5 o 7 dependiendo de la resolución de la imagen. Si encuentra que necesita ir más alto que eso, es posible que desee ver la disminución de la imagen.
mevatron
32

Partiendo de la respuesta de Nike. Es sencillo implementar el método basado en 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;
}

Devolverá un breve indicando la máxima nitidez detectada, que según mis pruebas en muestras del mundo real, es un indicador bastante bueno de si una cámara está enfocada o no. No es sorprendente que los valores normales dependan de la escena, pero mucho menos que el método FFT, que tiene una tasa de falsos positivos alta para ser útil en mi aplicación.

Yaur
fuente
¿Cuál sería el valor umbral para decir que una imagen es borrosa? Lo he probado Pero está mostrando algunos resultados variables. ¿Me pueden ayudar en esto para establecer el umbral?
2vision2
También probé tu sugerencia, pero los números que obtengo son un poco aleatorios. Si comienzo una nueva pregunta con respecto a esta implementación en particular, ¿le gustaría echar un vistazo? \
Stpn
@stpn El umbral derecho depende de la escena. En mi aplicación (CCTV) estoy usando un umbral predeterminado de 300. Para las cámaras en las que eso es muy bajo, alguien de soporte cambiará el valor configurado para esa cámara en particular.
Yaur
¿Por qué es "maxLap = -32767;" ?
Clement Prem
Estamos buscando el mayor contraste y dado que estamos trabajando con cortos firmados -32767 es el valor más bajo posible. Han pasado 2.5 años desde que escribí ese código, pero IIRC tuve problemas al usar 16U.
Yaur
23

Se me ocurrió una solución totalmente diferente. Necesitaba analizar cuadros fijos de video para encontrar el más nítido en cada (X) cuadros. De esta manera, detectaría imágenes borrosas y / o desenfocadas.

Terminé usando la detección de Canny Edge y obtuve MUY MUY buenos resultados con casi todos los tipos de video (con el método de Nikie, tuve problemas con los videos VHS digitalizados y los videos entrelazados pesados).

Optimicé el rendimiento estableciendo una región de interés (ROI) en la imagen original.

Usando 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
fuente
17

Gracias nikie por esa gran sugerencia de Laplace. Los documentos de OpenCV me apuntaron en la misma dirección: usando python, cv2 (opencv 2.4.10) y numpy ...

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

El resultado es entre 0-255. Encontré que cualquier cosa superior a 200ish está muy enfocada, y para 100, es notablemente borrosa. el máximo nunca tiene mucho menos de 20 incluso si está completamente borroso

ggez44
fuente
3
Tengo 255 por 3 de mis fotos. Y para una foto perfectamente enfocada obtuve 108. Entonces, creo que la efectividad del método depende de algo.
WindRider
De acuerdo con @WindWider. La imagen de muestra donde esto falla es esta imagen. Creo que la razón es que, aunque la imagen es inestable, el contraste de la imagen y las diferencias de intensidad correspondientes entre píxeles es grande, debido a que los valores laplacianos son relativamente grandes. Por favor, corríjame si estoy equivocado.
Resham Wadhwa
@ReshamWadhwa cc WindRider - lo mismo - ¿alguna idea sobre cómo solucionar esto?
jtlz2
@ ggez44 Esta es mi respuesta preferida, pero el valor es una función del número de píxeles en la imagen. ¿Sabes cómo se escala teóricamente? Podría formularla como una nueva pregunta, pero es probable que me derriben. ¡Gracias!
jtlz2
10

Una forma que estoy usando actualmente mide la extensión de los bordes en la imagen. Busque este 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} }

Por lo general, está detrás de un muro de pago, pero he visto algunas copias gratuitas. Básicamente, localizan bordes verticales en una imagen y luego miden qué tan anchos son esos bordes. Al promediar el ancho se obtiene el resultado final de estimación de desenfoque para la imagen. Los bordes más anchos corresponden a imágenes borrosas, y viceversa.

Este problema pertenece al campo de la estimación de calidad de imagen sin referencia . Si lo busca en Google Scholar, obtendrá muchas referencias útiles.

EDITAR

Aquí hay una trama de las estimaciones de desenfoque obtenidas para las 5 imágenes en la publicación de Nikie. Los valores más altos corresponden a un mayor desenfoque. Utilicé un filtro gaussiano de tamaño fijo 11x11 y varié la desviación estándar (usando el convertcomando de imagemagick para obtener las imágenes borrosas).

ingrese la descripción de la imagen aquí

Si compara imágenes de diferentes tamaños, no olvide normalizar por el ancho de la imagen, ya que las imágenes más grandes tendrán bordes más anchos.

Finalmente, un problema importante es distinguir entre el desenfoque artístico y el desenfoque no deseado (causado por falta de enfoque, compresión, movimiento relativo del sujeto hacia la cámara), pero eso está más allá de enfoques simples como este. Para ver un ejemplo de desenfoque artístico, eche un vistazo a la imagen de Lenna: el reflejo de Lenna en el espejo es borroso, pero su rostro está perfectamente enfocado. Esto contribuye a una estimación de desenfoque más alta para la imagen de Lenna.

mpenkov
fuente
5

Probé una solución basada en el filtro laplaciano de esta publicación. No me ha ayudado. Entonces, probé la solución de esta publicación y fue buena para mi caso (pero es lenta):

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

¡La imagen menos borrosa tiene el sumvalor máximo !

También puede ajustar la velocidad y la precisión cambiando el paso, p. Ej.

esta parte

for x in range(width - 1):

puedes reemplazar con este

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

Las respuestas anteriores aclararon muchas cosas, pero creo que es útil hacer una distinción conceptual.

¿Qué sucede si toma una imagen perfectamente enfocada de una imagen borrosa?

El problema de detección de desenfoque solo está bien planteado cuando tiene una referencia . Si necesita diseñar, por ejemplo, un sistema de enfoque automático, compara una secuencia de imágenes tomadas con diferentes grados de desenfoque o suavizado e intenta encontrar el punto de desenfoque mínimo dentro de este conjunto. En otras palabras, debe hacer una referencia cruzada de las diversas imágenes utilizando una de las técnicas ilustradas anteriormente (básicamente, con varios niveles posibles de refinamiento en el enfoque, buscando la única imagen con el mayor contenido de alta frecuencia).

Arma esmeralda
fuente
2
En otras palabras, es una noción relativa, solo es posible saber si una imagen está más o menos borrosa que otra imagen similar. es decir, si tiene más o menos contenido de alta frecuencia en su FFT. Caso particular: ¿qué pasa si la imagen tiene píxeles adyacentes con la luminosidad máxima y mínima? Por ejemplo, un píxel completamente negro junto a un píxel completamente blanco. En este caso es un enfoque perfecto, de lo contrario habría una transición más suave del negro al blanco. El enfoque perfecto no es probable en la fotografía, pero la pregunta no especifica la fuente de la imagen (podría ser generada por computadora).
Ben
1

El código Matlab de dos métodos que se han publicado en revistas de gran prestigio (Transacciones IEEE sobre procesamiento de imágenes) están disponibles aquí: https://ivulab.asu.edu/software

verifique los algoritmos CPBDM y JNBM. Si revisa el código, no es muy difícil portarlo y, por cierto, se basa en el método de Marzialiano como característica básica.

Marco
fuente
1

Lo implementé, use fft en matlab y verifique el histograma de la media de cálculo de fft y std, pero también se puede hacer la función de ajuste

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

Eso es lo que hago en Opencv para detectar la calidad del enfoque en una región:

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
fuente