martes, 19 de agosto de 2014

Buscando a Waldo con Matlab

Una aplicación entretenida de la correlación cruzada normalizada es la detección de una imagen patrón en una imagen de mayor tamaño. Esta correlación está definida matemáticamente como 

dónde f(x,y) representa a la función de imagen y t(x,y) la función de templete o imagen patrón que se desea detectar. En nuestro programa ese templete será este segmento de imagen dónde aparece Waldo:


Nuestra función principal será el siguiente mapa en el que habrá que encontrar a Waldo:


Para encontrarlo utilizaremos la función normxcorr2(). Esta función retornará un arreglo bidimensional resultado de la correlación cruzada del templete y la imagen. Para encontrar la posposición de Waldo en la imagen bastará con encontrar el punto donde la función alcanza su máximo. El arreglo resultante será tan grande como la imagen del mapa por lo que habrá que seleccionar una pequeña región alrededor del pico para poder visualizarlo mejor:

 Para encontrar la posición del pico utilizamos la función max() con la siguiente sintaxis:

[pico,indice] = max(c(:)); % Obtener valor del pico y su índice

El arreglo c representa a la función de de correlación. Hasta aquí la variable pico contiene el valor del máximo y la variable indice contiene la posición del valor máximo como si la matriz c estuviera distribuida en un arreglo vectorial. Para conocer la verdadera poción del pico en la imagen se necesita la función  ind2sub():

[y,x] = ind2sub(size(c),indice); % Obtener posición en la imagen 

Teniendo ahora la posición de Waldo solo queda mostrar la imagen completa con un rectángulo superpuesto para señalarlo:


 El programa completo es quizá más compacto de lo que pudieron haber pensado

clc,clear
mapa = imread('Waldo.jpg'); %Carga imagen del mapa
waldokernel = imread('waldok.jpg'); % carga templete de Waldo
c = normxcorr2(waldokernel(:,:,1),mapa(:,:,1)); % Correlación cruzada normalizada
[pico,indice] = max(c(:)); % Obtener valor del pico y su índice
[y,x] = ind2sub(size(c),indice); % Obtener posición en la imagen
ccut = c(y-45:y+45,x-45:x+45); % Recortar región alrededor del pico
imshow(mapa)
hold on
rectangle('Position',[x-50,y-43,70,70], 'LineWidth',2)
figure(2),surf(ccut), shading flat, title('Pico en Correlación Cruzada')