Existe-t-il un moyen de détecter si une image est floue?


Réponses:


133

Oui, ça l'est. Calculez la transformée de Fourier rapide et analysez le résultat. La transformée de Fourier vous indique les fréquences présentes dans l'image. S'il y a une faible quantité de hautes fréquences, l'image est floue.

Il vous appartient de définir les termes «bas» et «haut».

Modifier :

Comme indiqué dans les commentaires, si vous voulez un seul flottant représentant le flou d'une image donnée, vous devez élaborer une métrique appropriée.

la réponse de nikie fournit une telle métrique. Convoluez l'image avec un noyau laplacien:

   1
1 -4  1
   1

Et utilisez une métrique maximale robuste sur la sortie pour obtenir un nombre que vous pouvez utiliser pour le seuillage. Essayez d'éviter de trop lisser les images avant de calculer le laplacien, car vous découvrirez seulement qu'une image lissée est en effet floue :-).


9
seul problème, le «bas» et le «haut» dépendent également de la scène. +1
kenny

4
À moins que votre image ne soit cyclique, vous aurez généralement des bords nets aux bords de l'image qui conduisent à des fréquences très élevées
Niki

2
vous étendez généralement virtuellement votre image pour éviter cet effet. vous pouvez également utiliser de petites fenêtres pour calculer le fft local.
Simon Bergot

6
Un seul point extrêmement important est que vous devez savoir (au moins grossièrement) quel était le contenu (fréquence) de votre image pré-floue attendue . Cela est vrai car le spectre de fréquence va être celui de l'image d'origine multiplié par celui du filtre de flou. Ainsi, si l'image d'origine avait déjà des fréquences principalement basses, comment savoir si elle était floue?
Chris A.

1
Si vous prenez une photo d'un tableau blanc vierge, vous n'avez aucun moyen de dire si l'image est floue ou non. Je pense que l'OP veut une mesure de netteté absolue. l'image pré-floue peut ne pas exister du tout. Vous devez travailler un peu pour obtenir une métrique correcte, mais fft peut vous aider à résoudre ce problème. Dans cette perspective, la réponse de Nickie est meilleure que la mienne.
Simon Bergot

158

Une autre façon très simple d'estimer la netteté d'une image consiste à utiliser un filtre de Laplace (ou LoG) et à sélectionner simplement la valeur maximale. L'utilisation d'une mesure robuste comme un quantile à 99,9% est probablement meilleure si vous vous attendez à du bruit (c.-à-d. Choisir le Nième contraste le plus élevé au lieu du contraste le plus élevé.) Si vous vous attendez à une luminosité variable de l'image, vous devez également inclure une étape de prétraitement pour normaliser la luminosité de l'image / contraste (par exemple égalisation d'histogramme).

J'ai implémenté la suggestion de Simon et celle-ci dans Mathematica, et je l'ai essayée sur quelques images de test:

tester les images

Le premier test brouille les images de test à l'aide d'un filtre gaussien avec une taille de noyau variable, puis calcule la FFT de l'image floue et prend la moyenne des 90% des fréquences les plus élevées:

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

Résultat en un tracé logarithmique:

résultat fft

Les 5 lignes représentent les 5 images de test, l'axe X représente le rayon du filtre gaussien. Les graphiques diminuent, la FFT est donc une bonne mesure de netteté.

Voici le code de l'estimateur de flou "LoG le plus élevé": il applique simplement un filtre LoG et renvoie le pixel le plus brillant dans le résultat du filtre:

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

Résultat en un tracé logarithmique:

résultat laplace

La répartition pour les images non floues est un peu meilleure ici (2,5 vs 3,3), principalement parce que cette méthode n'utilise que le contraste le plus fort de l'image, tandis que la FFT est essentiellement une moyenne sur toute l'image. Les fonctions diminuent également plus rapidement, il peut donc être plus facile de définir un seuil "flou".


1
Et si je suis à la mesure du flou local. A savoir, une photo a des zones où elle est floue et où elle est nette. Je veux avoir une carte qui estime le niveau de flou par pixel.
Royi

4
@Drazick: Je ne sais pas si c'est encore possible. Par exemple, regardez l'image de Lena: Il y a de grandes zones où il n'y a pas de contraste (par exemple la peau de Lena) bien que la zone soit nette. Je ne peux pas penser à un moyen de dire si une zone aussi lisse est "floue", ou de la distinguer d'une zone floue. Vous devez poser cette question séparément (peut-être sur DSP.SE). Peut-être que quelqu'un d'autre a de meilleures idées.
Niki

1
Convient-il au flou de mouvement? ou seulement pour un flou comme gaussien?
mrgloom

@pparescasellas Seriez-vous prêt à partager vos implémentations. Je serais curieux de les voir.
chappjc

@JohnBoe Je pense que vous vouliez demander à pparescasellas
chappjc

79

Lors de certains travaux avec un objectif à mise au point automatique, je suis tombé sur cet ensemble très utile d'algorithmes pour détecter la mise au point d'image . Il est implémenté dans MATLAB, mais la plupart des fonctions sont assez faciles à porter sur OpenCV avec filter2D .

Il s'agit essentiellement d'une implémentation d'enquête de nombreux algorithmes de mesure de focalisation. Si vous souhaitez lire les articles originaux, des références aux auteurs des algorithmes sont fournies dans le code. L'article de 2012 de Pertuz, et al. L'analyse des opérateurs de mesure de mise au point pour la forme à partir de la mise au point (SFF) donne un excellent aperçu de toutes ces mesures ainsi que de leurs performances (à la fois en termes de vitesse et de précision appliquées à SFF).

EDIT: Ajout du code MATLAB juste au cas où le lien mourrait.

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

Quelques exemples de versions d'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;
}

Aucune garantie quant à savoir si ces mesures sont ou non le meilleur choix pour votre problème, mais si vous retrouvez les documents associés à ces mesures, elles peuvent vous donner plus d'informations. J'espère que vous trouverez le code utile! Je sais que je l'ai fait.


dans l'algorithme tenengrad, quelle serait la valeur nominale de kSize?
mans

@mans J'utilise normalement 3, 5 ou 7 selon la résolution de l'image. Si vous trouvez que vous devez aller plus haut que cela, vous voudrez peut-être regarder sous-échantillonner l'image.
mevatron

32

S'appuyant sur la réponse de Nike. Il est simple d'implémenter la méthode basée sur le laplacien avec 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;
}

Rendra un court indiquant la netteté maximale détectée, ce qui, d'après mes tests sur des échantillons du monde réel, est un assez bon indicateur de la mise au point ou non d'une caméra. Sans surprise, les valeurs normales dépendent de la scène mais beaucoup moins que la méthode FFT qui doit avoir un taux de faux positifs élevé pour être utile dans mon application.


Quelle serait la valeur seuil pour dire qu'une image est floue? Je l'ai testé. Mais ses résultats varient. Pouvez-vous m'aider à définir le seuil?
2vision2

J'ai également essayé votre suggestion, mais les chiffres que j'obtiens sont un peu aléatoires. Si je commence une nouvelle question concernant cette implémentation particulière, voudriez-vous y jeter un œil? \
Stpn

@stpn Le seuil de droite dépend de la scène. Dans mon application (CCTV), j'utilise un seuil par défaut de 300. Pour les caméras où c'est trop bas, quelqu'un du support changera la valeur configurée pour cette caméra particulière.
Yaur

pourquoi "maxLap = -32767;" ?
Clement Prem

Nous recherchons le contraste le plus élevé et puisque nous travaillons avec des shorts signés -32767 est la valeur la plus basse possible. Cela fait 2,5 ans que j'ai écrit ce code mais l'IIRC a eu des problèmes avec 16U.
Yaur

23

J'ai trouvé une solution totalement différente. J'avais besoin d'analyser des images fixes vidéo pour trouver la plus nette de chaque (X) images. De cette façon, je détecterais le flou de mouvement et / ou les images floues.

J'ai fini par utiliser la détection Canny Edge et j'ai obtenu de TRÈS TRÈS bons résultats avec presque tous les types de vidéos (avec la méthode de nikie, j'ai eu des problèmes avec les vidéos VHS numérisées et les vidéos entrelacées lourdes).

J'ai optimisé les performances en définissant une région d'intérêt (ROI) sur l'image d'origine.

Utilisation d'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

Merci Nikie pour cette excellente suggestion de Laplace. Les documents OpenCV m'ont orienté dans la même direction: en utilisant python, cv2 (opencv 2.4.10) et numpy ...

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

le résultat est compris entre 0 et 255. J'ai trouvé que tout ce qui dépassait 200ish était très net et, par 100, c'était nettement flou. le max n'a jamais vraiment moins de 20 ans même s'il est complètement flou.


3
J'en ai eu 255 pour 3 de mes photos. Et pour une photo parfaitement mise au point, j'en ai obtenu 108. Donc, je pense que l'efficacité de la méthode dépend de quelque chose.
WindRider

D'accord avec @WindWider. Exemple d'image où cela échoue est cette image Je pense que la raison en est que même si l'image est fragile, le contraste de l'image et les différences d'intensité correspondantes entre les pixels sont grands, en raison de quoi les valeurs laplaciennes sont relativement grandes. S'il vous plait corrigez moi si je me trompe.
Resham Wadhwa

@ReshamWadhwa cc WindRider - idem - des idées sur la façon de résoudre ce problème ??
jtlz2

@ ggez44 C'est ma réponse préférée - mais la valeur est fonction du nombre de pixels dans l'image. Savez-vous comment cela évolue théoriquement? Je pourrais la poser comme une nouvelle question, mais elle risque de se faire abattre. Merci!
jtlz2

10

Une façon que j'utilise actuellement mesure la propagation des bords dans l'image. Recherchez ce document:

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

C'est généralement derrière un mur payant mais j'ai vu des copies gratuites autour. Fondamentalement, ils localisent les bords verticaux d'une image, puis mesurent la largeur de ces bords. La moyenne de la largeur donne le résultat final d'estimation du flou pour l'image. Des bords plus larges correspondent à des images floues et vice versa.

Ce problème appartient au domaine de l' estimation de la qualité d'image sans référence . Si vous le recherchez sur Google Scholar, vous obtiendrez de nombreuses références utiles.

ÉDITER

Voici un graphique des estimations de flou obtenues pour les 5 images dans le post de nikie. Des valeurs plus élevées correspondent à un plus grand flou. J'ai utilisé un filtre gaussien de taille fixe 11x11 et varié l'écart-type (en utilisant la convertcommande imagemagick pour obtenir les images floues).

entrez la description de l'image ici

Si vous comparez des images de différentes tailles, n'oubliez pas de normaliser par la largeur de l'image, car les images plus grandes auront des bords plus larges.

Enfin, un problème important est de faire la distinction entre le flou artistique et le flou indésirable (causé par un manque de mise au point, une compression, un mouvement relatif du sujet par rapport à la caméra), mais cela dépasse les approches simples comme celle-ci. Pour un exemple de flou artistique, regardez l'image de Lenna: le reflet de Lenna dans le miroir est flou, mais son visage est parfaitement net. Cela contribue à une estimation de flou plus élevée pour l'image Lenna.


5

J'ai essayé une solution basée sur le filtre laplacien de ce post. Ça ne m'a pas aidé. J'ai donc essayé la solution de ce post et c'était bon pour mon cas (mais c'est lent):

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

Une image moins floue a un maximum sum valeur !

Vous pouvez également régler la vitesse et la précision en changeant de pas, par exemple

cette partie

for x in range(width - 1):

vous pouvez remplacer par celui-ci

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

4

Les réponses ci-dessus ont élucidé beaucoup de choses, mais je pense qu'il est utile de faire une distinction conceptuelle.

Que faire si vous prenez une photo parfaitement nette d'une image floue?

Le problème de détection de flou n'est bien posé que lorsque vous avez une référence . Si vous devez concevoir, par exemple, un système de mise au point automatique, vous comparez une séquence d'images prises avec différents degrés de flou ou de lissage, et vous essayez de trouver le point de flou minimum dans cet ensemble. En d'autres termes, vous devez croiser les différentes images en utilisant l'une des techniques illustrées ci-dessus (essentiellement - avec différents niveaux de raffinement possibles dans l'approche - à la recherche de l'image avec le contenu haute fréquence le plus élevé).


2
En d'autres termes, c'est une notion relative, il est seulement possible de dire si une image est plus ou moins floue qu'une autre image similaire. c'est-à-dire s'il a un contenu plus ou moins haute fréquence dans sa FFT. Cas particulier: que faire si l'image a des pixels adjacents avec la luminosité maximale et minimale? Par exemple, un pixel complètement noir à côté d'un pixel complètement blanc. Dans ce cas, c'est une mise au point parfaite, sinon il y aurait une transition plus douce du noir au blanc. Mise au point parfaite peu probable en photographie, mais la question ne précise pas la source de l'image (elle pourrait être générée par ordinateur).
Ben

1

Le code Matlab de deux méthodes publiées dans des revues réputées (IEEE Transactions on Image Processing) est disponible ici: https://ivulab.asu.edu/software

vérifiez les algorithmes CPBDM et JNBM. Si vous vérifiez le code, il n'est pas très difficile à porter et, incidemment, il est basé sur la méthode de Marzialiano comme fonctionnalité de base.


1

j'ai implémenté utiliser fft dans matlab et vérifier l'histogramme de la moyenne de calcul fft et std mais aussi la fonction d'ajustement peut être effectuée

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

C'est ce que je fais à Opencv pour détecter la qualité de la mise au point dans une région:

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];
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.