Saltar a contenido

Tutorial y ejercicios

En esta práctica se trabajan características que permiten describir y comparar imágenes. Algunas son globales, como los histogramas, porque resumen información de toda la imagen o de una región grande. Otras son más locales, como los vértices o las rectas detectadas, porque indican puntos o estructuras concretas. Todas ellas ayudan a convertir información visual en datos más fáciles de analizar.

Cargamos las imágenes que utilizaremos en la práctica.

lena = imread("Imagenes\lena_color_512.tif");
mandril = imread("Imagenes\mandril_color.tif");
malla = imread("Imagenes\patron_malla.jpg");
textura = imread("Imagenes\astablet.tif");
chessboard = imread("Imagenes\chessboardpattern.jpg");
chessboard_inclinado = imread("Imagenes\esquinas_perspectiva.jpg");

malla = rgb2gray(malla);
chessboard_inclinado = rgb2gray(chessboard_inclinado);

montage({lena,mandril,malla,textura,chessboard,chessboard_inclinado})

figure_0.png

Caracteristicas basadas en el histograma

Un histograma de color indica cómo se distribuyen los valores de los canales de color. Es útil para describir la apariencia general de una imagen, por ejemplo si predominan tonos oscuros, claros o determinados colores. Aun así, el histograma no conserva información espacial: dos imágenes pueden tener el mismo histograma y, al mismo tiempo, mostrar objetos dispuestos de forma completamente diferente.

Histograma del color

Primer ejemplo: Imagen Lena

Separamos la imagen en los tres canales de color

rojo = lena(:,:,1);
verde = lena(:,:,2);
azul = lena(:,:,3);

Y obtenemos los histogramas de cada canal

h_rojo = imhist(rojo);
h_verde = imhist(verde);
h_azul = imhist(azul);

bar(h_rojo)

figure_1.png

bar(h_verde)

figure_2.png

bar(h_azul)

figure_3.png

Otro ejemplo: Imagen mandril

rojo = mandril(:,:,1);
verde = mandril(:,:,2);
azul = mandril(:,:,3);

h_rojo = imhist(rojo);
h_verde = imhist(verde);
h_azul = imhist(azul);

bar(h_rojo)

figure_4.png

bar(h_verde)

figure_5.png

bar(h_azul)

figure_6.png

Calculamos las medidas de similitud para comparar histogramas. Para simplificar, vamos a comparar solo un histograma por imagen.

Comparar histogramas significa medir hasta qué punto dos distribuciones de intensidad o color se parecen. La distancia euclídea trata las diferencias de forma directa, la chi cuadrado da más importancia a diferencias relativas y la divergencia de Jeffrey compara distribuciones de forma más simétrica. Ninguna métrica es universalmente mejor; depende de qué se quiera considerar semejante.

lena_gris = rgb2gray(lena);
mandril_gris = rgb2gray(mandril);

h_lena = imhist(lena_gris);
h_mandril = imhist(mandril_gris);

Normalizamos el histograma

La normalización de los histogramas es necesaria cuando se quieren comparar imágenes de tamaño diferente o con distinto número de píxeles. Sin normalizar, una imagen más grande podría dar valores más altos simplemente porque contiene más píxeles. Al normalizar, la comparación se centra mejor en la forma de la distribución y no tanto en la cantidad absoluta de muestras.

h_lena_n = h_lena/numel(lena_gris);
h_mandril_n = h_mandril/numel(mandril_gris);
bar(h_lena_n)

figure_7.png

bar(h_mandril_n)

figure_8.png

Distancia Euclidea

dist_euclidea = sqrt(sum((h_lena_n - h_mandril_n).^2))
dist_euclidea = 0.0533

Distancia Xi-cuadrado

dist_xicuadrado = sum(((h_lena_n - h_mandril_n).^2) ./ (h_lena_n + h_mandril_n + eps))
dist_xicuadrado = 0.2997

Distancia de la divergencia de Jeffrey

divergence_jeffrey = sum(h_lena_n.*log((h_lena_n./(h_mandril_n + eps))+eps))
divergence_jeffrey = 2.1436

Histograma de los gradientes orientados

El histograma de gradientes orientados, o HOG, describe la distribución de las direcciones del gradiente en pequeñas zonas de la imagen. Como el gradiente es fuerte en los bordes, este descriptor resume información sobre contornos y formas locales. Durante muchos años fue un descriptor muy utilizado en detección de objetos, especialmente antes de que las redes convolucionales fueran tan habituales.

Primer ejemplo: Imagen Lena

Comando: extractHOGFeatures

[feature_vector,hog] = extractHOGFeatures(lena);

imshow(lena); 
hold on;
plot(hog);
hold off

figure_9.png

Otro ejemplo: Imagen mandril

[feature_vector_mandril,hog_mandril] = extractHOGFeatures(mandril);
imshow(mandril);
hold on
plot(hog_mandril);
hold off

figure_10.png

Caracteristicas basadas en la transformada de Hough

La transformada de Hough es una técnica para detectar formas geométricas simples, como rectas o círculos. La idea es que cada punto de borde vota por las formas que podrían pasar por él. Cuando muchos puntos votan por el mismo conjunto de parámetros, es probable que haya una forma real en la imagen. Esto permite detectar estructuras aunque los bordes no sean perfectos o estén parcialmente interrumpidos.

Obtención de rectas vía la transformada de Hough

Primero obtenemos los bordes de la imagen

La transformada de Hough no se aplica normalmente sobre toda la imagen, sino sobre una imagen de bordes. Esto reduce el número de puntos que votan y concentra el proceso en los píxeles que probablemente forman parte de rectas o contornos.

malla_edge = edge(malla,"canny");

Comando: hough. Da como input la discretización del plano de Hough H, con los valores de theta T y rho R

[H,T,R] = hough(malla_edge);

Calculamos los picos (puntos con más valor) en dicha discretización del plano de Hough. En particular, nos quedamos con los 16 picos de más valor que esten por encima del 35% del valor máximo.

Un pico en el espacio de Hough indica que muchos puntos de borde son compatibles con la misma recta. Seleccionar solo los picos más fuertes evita considerar rectas débiles o causadas por ruido. El umbral controla cuántas estructuras se conservan.

P = houghpeaks(H, 16,'threshold',ceil(0.35*max(H(:))));

Calculamos las rectas con dichos picos y sus valores theta y rho asociados (que definen las correspondientes rectas).

lines = houghlines(malla_edge,T,R,P);

imshow(malla)
hold on

for k = 1:length(lines)

    xy = [lines(k).point1; lines(k).point2];
    plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','red');

end
hold off

figure_11.png

Obtenemos los círculos en la imagen vía la transformada de Hough. Para ello, usamos el comando imfindcircles que busca círculos con un radio de valor comprendido en el rango que se define como segundo input.

Para detectar círculos, el método busca acumulaciones de votos compatibles con un centro y un radio. El rango de radios es importante: si es demasiado amplio, aumentan los falsos positivos; si es demasiado restrictivo, se pueden perder círculos reales. Por eso hay que relacionar este rango con el tamaño esperado de los objetos.

[centers, radii] = imfindcircles(textura,[10 30]);
imshow(textura)
viscircles(centers, radii,'EdgeColor','b');

figure_12.png

Vértices

Un vértice o esquina es un punto donde la imagen cambia de forma significativa en más de una dirección. Este tipo de punto es más fácil de localizar con precisión que un borde recto, porque un borde puede desplazarse a lo largo de su dirección sin cambiar demasiado. Por eso las esquinas son útiles como puntos de interés en registro de imágenes, seguimiento y comparación entre imágenes.

Se utiliza el detector de Harris para identificar esquinas y vértices en las imágenes.

El detector de Harris analiza cómo cambia la intensidad dentro de una pequeña ventana cuando esta se desplaza. Si el cambio es grande en todas las direcciones, el punto central se considera una buena esquina. Si el cambio es grande solo en una dirección, probablemente se trata de un borde. Para obtener resultados más fiables, normalmente se conservan solo los puntos con una respuesta más fuerte.

corners = detectHarrisFeatures(chessboard);

imshow(chessboard); 
hold on
plot(corners.Location(:,1),corners.Location(:,2),'o','Color','r','LineWidth',2);
hold off

figure_13.png

Otro ejemplo. Notad que en este caso se detectan varios falsos positivos. Un análisis más detallado muestra que la métrica de estos es muy baja, con lo que se pueden eliminar fácilmente mediante seleccionar los más fuertes, es decir, los que tienen una detección más robusta.

corners_alt = detectHarrisFeatures(chessboard_inclinado);

imshow(chessboard_inclinado); 
hold on
plot(corners_alt.Location(:,1),corners_alt.Location(:,2),'o',"color",'r','LineWidth',2);
hold off

figure_14.png

imshow(chessboard_inclinado)

strongest = corners_alt.selectStrongest(20);

hold on
plot(strongest.Location(:,1),strongest.Location(:,2),'o','color','r','LineWidth',2)
hold off

figure_15.png