image-processing - para - corregir fotos borrosas y desenfocadas online
¿Hay alguna manera de detectar si una imagen es borrosa? (11)
Me preguntaba si hay una manera de determinar si una imagen es borrosa o no mediante el análisis de los datos de imagen.
Aprovechando 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 nitidez máxima 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 de extrañar que los valores normales dependan de la escena, pero mucho menos que el método FFT, que tiene un alto índice de falsos positivos para ser útil en mi aplicación.
Durante algún trabajo con un lente de enfoque automático, me encontré con este útil conjunto de algoritmos para detectar el foco de la imagen . Está implementado en MATLAB, pero la mayoría de las funciones son bastante fáciles de filter2D a OpenCV con filter2D .
Básicamente es una implementación de encuesta de muchos algoritmos de medición de enfoque. Si desea leer los documentos originales, las referencias a los autores de los algoritmos se proporcionan en el código. El documento de 2012 de Pertuz, et al. El análisis de los operadores de medida de enfoque para la forma del enfoque (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, tal como se aplica a SFF).
EDITAR: se agregó el 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 sobre si estas medidas son o no la mejor opción para su problema, pero si rastrea los documentos relacionados con estas medidas, es posible que le brinden más información. Espero que encuentres útil el código! Sé que lo hice.
El código de Matlab de dos métodos que se han publicado en revistas de gran prestigio (Transacciones IEEE sobre procesamiento de imágenes) está disponible aquí: https://ivulab.asu.edu/software
verifique los algoritmos CPBDM y JNBM. Si revisas el código, no es muy difícil ser portado y, por cierto, se basa en el método de Marzialiano como característica básica.
Gracias nikie por esa gran sugerencia de Laplace. Los documentos de OpenCV me apuntaban 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 está entre 0-255. Encontré que algo más de 200 mil está muy enfocado, y por 100, es notablemente borroso. el máximo nunca llega a ser muy por debajo de 20, incluso si está completamente borroso.
Intenté una solución basada en el filtro laplaciano de this publicación. No me ayudó. Entonces, probé la solución de this 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 valor de sum
máxima!
También puede ajustar la velocidad y la precisión cambiando el paso, por ejemplo
esta parte
for x in range(width - 1):
puedes reemplazar con este
for x in range(0, width - 1, 10):
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 borrosidad solo se plantea correctamente cuando tiene una referencia . Si necesita diseñar, por ejemplo, un sistema de enfoque automático, compare una secuencia de imágenes tomadas con diferentes grados de borrosidad o suavizado, e intente encontrar el punto de desenfoque mínimo dentro de este conjunto. En otras palabras, necesitas cruzar las distintas imágenes usando una de las técnicas ilustradas arriba (básicamente, con varios niveles posibles de refinamiento en el enfoque, buscando la imagen con el mayor contenido de alta frecuencia).
Lo implementé use fft en matlab y verifique el histograma de la media de FFT Compute 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(:));
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 99.9% es probablemente mejor si espera ruido (es decir, selecciona el N-alto contraste en lugar del contraste más alto). Si espera un brillo de imagen variable, también debe incluir un paso de preproceso 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:
La primera prueba difumina las imágenes de prueba usando un filtro gaussiano con un tamaño de kernel variable, luego calcula la FFT de la imagen borrosa y toma el promedio del 90% de las frecuencias más altas:
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:
Las 5 líneas representan las 5 imágenes de prueba, el eje X representa el radio de filtro gaussiano. Los gráficos están disminuyendo, por lo que la FFT es una buena medida para la 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:
La dispersión para las imágenes no borrosas es un poco mejor aquí (2.5 vs 3.3), principalmente porque este método solo usa el contraste más fuerte en la imagen, mientras que la FFT es esencialmente una media sobre toda la imagen. Las funciones también están disminuyendo más rápido, por lo que podría ser más fácil establecer un umbral "borroso".
Se me ocurrió una solución totalmente diferente. Necesitaba analizar cuadros de video fijos para encontrar el más nítido en cada fotograma (X). De esta forma, detectaría el desenfoque de movimiento y / o las imágenes fuera de foco.
Terminé usando detección Canny Edge y obtuve MUY muy buenos resultados con casi todo tipo de video (con el método de Nikki, tuve problemas con videos VHS digitalizados y 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));
}
Una manera que estoy usando actualmente mide la extensión de los bordes en la imagen. Busque este papel:
@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, ubican los bordes verticales en una imagen y luego miden qué tan amplios son esos bordes. Al promediar el ancho se obtiene el resultado final de estimación de desenfoque de la imagen. Los bordes más amplios 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 gráfica de las estimaciones de desenfoque obtenidas para las 5 imágenes en la publicación de Nikki. Los valores más altos corresponden a un mayor desenfoque. Utilicé un filtro gaussiano 11x11 de tamaño fijo y varié la desviación estándar (usando el comando de convert
de imagemagick para obtener las imágenes borrosas).
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 borrosidad artística y borrosidad no deseada (causada 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 mayor estimación de desenfoque para la imagen de Lenna.
sí lo es. calcule el fft y analice el resultado. La transformada de Fourier te dice qué frecuencias están presentes en la imagen. Si hay una baja cantidad de altas frecuencias, entonces la imagen es borrosa.
La definición de los términos "bajo" y "alto" depende de usted.
editar : como se indica en los comentarios, si desea una flotación única que represente la borrosidad de una imagen determinada, debe calcular una medida adecuada.
La respuesta de nikie proporciona tal métrica. Convolve la imagen con un kernel 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. Intenta evitar suavizar demasiado las imágenes antes de calcular el Laplaciano, porque solo descubrirás que una imagen suavizada es realmente borrosa :-).