Existe uma maneira de detectar se uma imagem está tremida?

203

Fiquei me perguntando se existe uma maneira de determinar se uma imagem está embaçada ou não, analisando os dados da imagem.

Sam
fonte
7
Pergunta relacionada que tem uma boa resposta, mas também uma formulação de pergunta mais envolvida. stackoverflow.com/questions/5180327/…
Lennart Rolland
1
Também tem respostas muito piores.
John Shedletsky

Respostas:

133

Sim, ele é. Calcule a Transformada rápida de Fourier e analise o resultado. A transformação de Fourier informa quais frequências estão presentes na imagem. Se houver uma quantidade baixa de altas frequências, a imagem está tremida.

A definição dos termos 'baixo' e 'alto' depende de você.

Editar :

Conforme declarado nos comentários, se você quiser um único flutuador representando a desfocagem de uma determinada imagem, precisará elaborar uma métrica adequada.

a resposta da nikie fornece essa métrica. Convolve a imagem com um kernel da Lapônia:

   1
1 -4  1
   1

E use uma métrica máxima robusta na saída para obter um número que você pode usar para limiar. Tente evitar suavizar demais as imagens antes de calcular o Laplaciano, porque você descobrirá apenas que uma imagem suavizada está realmente borrada :-).

Simon Bergot
fonte
9
único problema, 'baixo' e 'alto' também são dependentes da cena. 1
kenny
4
A menos que sua imagem é cíclica, normalmente você vai ter bordas afiadas nas fronteiras da imagem que conduzem a frequências muito altas
Niki
2
você geralmente praticamente amplia sua imagem para evitar esse efeito. você também pode usar janelas pequenas para calcular o fft local.
Simon Bergot 14/10
6
Apenas um ponto extremamente importante é que você precisa saber (pelo menos aproximadamente) qual era o conteúdo esperado da imagem pré-desfocada (frequência). Isso é verdade, já que o espectro de frequência será o da imagem original multiplicado pelo filtro de desfoque. Portanto, se a imagem original já tinha frequências predominantemente baixas, como você pode saber se estava borrada?
Chris A.
1
Se você tirar uma foto de um quadro branco em branco, não terá como saber se a imagem está embaçada ou não. Eu acho que o OP quer alguma medição de nitidez absoluta. a imagem pré-desfocada pode não existir. Você precisa trabalhar um pouco para obter uma métrica correta, mas o fft pode ajudar com esse problema. Nesta perspectiva, a resposta de nickie é melhor que a minha.
Simon Bergot
158

Outra maneira muito simples de estimar a nitidez de uma imagem é usar um filtro Laplace (ou LoG) e simplesmente escolher o valor máximo. Usar uma medida robusta como um quantil de 99,9% é provavelmente melhor se você espera ruído (por exemplo, escolher o contraste N-mais alto em vez do contraste mais alto.) Se você espera um brilho variável da imagem, também deve incluir uma etapa de pré-processamento para normalizar o brilho da imagem / contraste (por exemplo, equalização do histograma).

Eu implementei a sugestão de Simon e essa no Mathematica, e tentei em algumas imagens de teste:

imagens de teste

O primeiro teste desfoca as imagens de teste usando um filtro Gaussiano com um tamanho variável do kernel, calcula a FFT da imagem desfocada e calcula a média das frequências mais altas de 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}]

Resultar em um gráfico logarítmico:

resultado fft

As 5 linhas representam as 5 imagens de teste, o eixo X representa o raio do filtro gaussiano. Os gráficos estão diminuindo, portanto a FFT é uma boa medida de nitidez.

Este é o código para o estimador de desfocagem "LoG mais alto": ele simplesmente aplica um filtro LoG e retorna o pixel mais brilhante no resultado do filtro:

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

Resultar em um gráfico logarítmico:

resultado laplace

A propagação para as imagens não desfocadas é um pouco melhor aqui (2,5 vs 3,3), principalmente porque esse método usa apenas o contraste mais forte na imagem, enquanto a FFT é essencialmente uma média sobre toda a imagem. As funções também estão diminuindo mais rapidamente, portanto, pode ser mais fácil definir um limite "embaçado".

Niki
fonte
1
E se eu estiver atrás da medida do desfoque local. Ou seja, uma foto tem áreas onde está desfocada e nítida. Quero ter um mapa que calcule o nível de desfoque por pixel.
Royi 2/11/12
4
@Drazick: Não tenho certeza se isso é possível. Por exemplo, observe a imagem de Lena: Existem grandes áreas onde não há contraste (por exemplo, a pele de Lena), embora a área esteja focada. Não consigo pensar em uma maneira de saber se uma área tão suave está "embaçada" ou para distingui-la de uma área fora de foco. Você deve fazer isso como uma pergunta separada (talvez no DSP.SE). Talvez alguém tenha idéias melhores.
Niki
1
É adequado para desfoque de movimento? ou apenas para desfocar como gaussiano?
mrgloom
@pparescasellas Você gostaria de compartilhar suas implementações. Eu ficaria curioso para vê-los.
Chappjc
@JohnBoe Eu acho que você queria perguntar pparescasellas
chappjc
79

Durante algum trabalho com uma lente de foco automático, deparei-me com um conjunto muito útil de algoritmos para detectar o foco da imagem . É implementado no MATLAB, mas a maioria das funções é bastante fácil de portar para o OpenCV com o filter2D .

É basicamente uma implementação de pesquisa de muitos algoritmos de medição de foco. Se você quiser ler os artigos originais, as referências aos autores dos algoritmos são fornecidas no código. O artigo de 2012 de Pertuz, et al. A análise dos operadores de medida de foco para a forma a partir do foco (SFF) fornece uma ótima revisão de todas essas medidas, bem como de seu desempenho (tanto em termos de velocidade quanto de precisão, conforme aplicado ao SFF).

EDIT: Adicionado código MATLAB, caso o link morra.

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

Alguns exemplos de versões do 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;
}

Não há garantias de que essas medidas sejam ou não a melhor escolha para o seu problema, mas se você localizar os documentos associados a essas medidas, eles poderão fornecer mais informações. Espero que você ache o código útil! Eu sei que sim.

mevatron
fonte
no algoritmo tenengrad, qual seria um valor nominal para o kSize?
mans
@mans Normalmente, uso 3, 5 ou 7, dependendo da resolução da imagem. Se você achar que precisa ir mais alto do que isso, convém observar a redução da amostra da imagem.
Mevatron #
32

Aproveitando a resposta da Nike. É simples implementar o método baseado em laplaciano com 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;
}

Retornará um breve, indicando a nitidez máxima detectada, que com base nos meus testes em amostras do mundo real, é um bom indicador de se a câmera está focada ou não. Não é de surpreender que os valores normais dependam da cena, mas muito menos do que o método FFT, que tem uma taxa alta de falsos positivos para ser útil na minha aplicação.

Yaur
fonte
Qual seria o valor do limiar de dizer que uma imagem é bluryy? Eu testei. Mas está mostrando alguns resultados variados. Você pode me ajudar nisso para definir o limite?
2vision2
Também tentei sua sugestão, mas os números que recebo são um pouco aleatórios. Se eu começar uma nova pergunta com relação a esta implementação particular, você se importaria de dar uma olhada \?
STPN
@stpn O limiar certo depende da cena. No meu aplicativo (CCTV), estou usando um limite padrão de 300. Para câmeras onde isso é baixo, alguém do suporte alterará o valor configurado para essa câmera em particular.
Yaur
por que "maxLap = -32767;" ?
Clement Prem
Estamos procurando o maior contraste e, como estamos trabalhando com shorts assinados, -32767 é o menor valor possível. Já faz 2,5 anos desde que escrevi esse código, mas no IIRC tive problemas usando 16U.
Yaur 28/02
23

Eu vim com uma solução totalmente diferente. Eu precisava analisar os quadros estáticos de vídeo para encontrar o mais nítido em todos os quadros (X). Dessa forma, eu detectaria desfoque de movimento e / ou imagens desfocadas.

Acabei usando a detecção do Canny Edge e obtive resultados MUITO MUITO BONS com quase todo tipo de vídeo (com o método da nikie, tive problemas com vídeos VHS digitalizados e vídeos entrelaçados pesados).

Otimizei o desempenho definindo uma região de interesse (ROI) na imagem original.

Usando o 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
fonte
17

Obrigado, Nikie, pela ótima sugestão de Laplace. Os documentos do OpenCV me apontaram na mesma direção: 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)))

resultado está entre 0-255. Descobri que algo acima de 200 está muito focado e, aos 100, está visivelmente embaçado. o máximo nunca fica muito abaixo dos 20, mesmo que esteja completamente desfocado.

ggez44
fonte
3
Eu tenho 255 para 3 das minhas fotos. E para uma foto perfeitamente focada, consegui 108. Então, acho que a eficácia do método depende de algo.
WindRider
Concordou com @WindWider. Imagem de exemplo em que isso falha é essa imagem. Acho que a razão é que, embora a imagem esteja tremida, o contraste da imagem e as diferenças de intensidade correspondentes entre os pixels são grandes, devido aos valores dos Laplacianos serem relativamente grandes. Por favor corrija-me se eu estiver errado.
Resham Wadhwa
@ReshamWadhwa cc WindRider - idem - alguma idéia de como consertar isso ??
Jtlz2
@ ggez44 Esta é a minha resposta preferida - mas o valor é uma função do número de pixels na imagem. Você sabe como isso escala teoricamente? Eu poderia fazer isso como uma nova pergunta, mas provavelmente será derrubado. Obrigado!
jtlz2 17/02
10

Uma maneira que estou usando atualmente mede a propagação de bordas na imagem. Procure este artigo:

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

Geralmente fica atrás de um paywall, mas já vi algumas cópias gratuitas por aí. Basicamente, eles localizam bordas verticais em uma imagem e medem a largura dessas bordas. A média da largura fornece o resultado final da estimativa de desfoque para a imagem. Bordas mais amplas correspondem a imagens tremidas e vice-versa.

Esse problema pertence ao campo de estimativa da qualidade da imagem sem referência . Se você procurar no Google Scholar, terá muitas referências úteis.

EDITAR

Aqui está um gráfico das estimativas de desfoque obtidas para as 5 imagens no post da nikie. Valores mais altos correspondem a maior desfocagem. Usei um filtro Gaussiano de tamanho fixo 11x11 e variei o desvio padrão (usando o convertcomando imagemagick para obter as imagens borradas).

insira a descrição da imagem aqui

Se você comparar imagens de tamanhos diferentes, não se esqueça de normalizar pela largura da imagem, pois as imagens maiores terão bordas mais amplas.

Finalmente, um problema significativo é distinguir entre desfoque artístico e desfoque indesejado (causado por falta de foco, compressão, movimento relativo do objeto para a câmera), mas isso está além de abordagens simples como esta. Para um exemplo de desfoque artístico, dê uma olhada na imagem de Lenna: o reflexo de Lenna no espelho está embaçado, mas seu rosto está perfeitamente focado. Isso contribui para uma estimativa de desfoque mais alta da imagem Lenna.

mpenkov
fonte
5

Eu tentei solução com base no filtro Laplacian deste post. Isso não me ajudou. Então, tentei a solução deste post e foi bom para o meu caso (mas é 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))

Uma imagem menos desfocada tem um sumvalor máximo !

Você também pode ajustar a velocidade e a precisão alterando a etapa, por exemplo

esta parte

for x in range(width - 1):

você pode substituir por este

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

As respostas acima elucidaram muitas coisas, mas acho que é útil fazer uma distinção conceitual.

E se você tirar uma foto perfeitamente focada de uma imagem borrada?

O problema de detecção de desfoque só é bem colocado quando você tem uma referência . Se você precisar projetar, por exemplo, um sistema de foco automático, compare uma sequência de imagens tiradas com diferentes graus de desfoque ou suavização e tente encontrar o ponto de desfoque mínimo nesse conjunto. Em outras palavras, você precisa fazer referência cruzada das várias imagens usando uma das técnicas ilustradas acima (basicamente - com vários níveis possíveis de refinamento na abordagem - procurando a imagem com o maior conteúdo de alta frequência).

Arma Esmeralda
fonte
2
Em outras palavras, é uma noção relativa, só é possível saber se uma imagem está mais ou menos desfocada do que outra imagem semelhante. ou seja, se tiver mais ou menos conteúdo de alta frequência em sua FFT. Caso particular: e se a imagem tiver pixels adjacentes com a luminosidade máxima e mínima? Por exemplo, um pixel completamente preto ao lado de um pixel completamente branco. Nesse caso, é um foco perfeito; caso contrário, haveria uma transição mais suave do preto para o branco. O foco perfeito não é provável na fotografia, mas a pergunta não especifica a fonte da imagem (pode ser gerada por computador).
Ben Ben
1

O código Matlab de dois métodos que foram publicados em periódicos conceituados (IEEE Transactions on Image Processing) estão disponíveis aqui: https://ivulab.asu.edu/software

verifique os algoritmos CPBDM e JNBM. Se você verificar o código, não é muito difícil ser portado e, aliás, é baseado no método de Marzialiano como recurso básico.

Marco
fonte
1

Eu o implementei use fft no matlab e verifique o histograma da média de computação fft e std, mas também a função de ajuste pode ser feita

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

É o que faço no Opencv para detectar a qualidade do foco em uma região:

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
fonte