OpenCV Búsqueda de Patrones (Template Matching)
La búsqueda de patrones es una técnica de análisis de imágenes que podemos utilizar para buscar una imagen dada (patrón o template) dentro de una imagen de mayor tamaño, no solo buscamos apariciones exactas del patrón también se permite un grado de variación respecto al patrón original.
Template matching (Comparación de plantillas) es uno de los métodos más utilizados en la búsqueda de patrones, con la biblioteca de computación visual OpenCV esta tarea la realiza la función cv::matchTemplate()
la cual implementa con distintos métodos de comparación, puedes indicar estos métodos usando la enumeración cv::TemplateMatchModes
.
Si la imagen fuente tiene la dimensión (W, H) y la imagen patrón (w, h) el tamaño de la imagen resultado será: (W – w + 1, H – h + 1), esta imagen estará a escala de grises, utilizamos la función cv::minMaxLoc()
para obtener los valores máximos y mínimos, esta función nos devuelve también la posición de dichos valores.
Lo valores más claros indican una alta probabilidad de que el patrón se encuentre en esa posición, entre mas oscuro sea el área la probabilidad es menor, esto puede ser al inverso según el modo que estemos utilizando.
Búsqueda de patrones con OpenCV
Implementar la búsqueda de patrones con biblioteca de análisis de imágenes OpenCV es fácil ya que disponemos de todas las funciones necesarias para la tarea, veamos como se hace.
Preparar el cv::Mat para guardar el resultado de la operación.
// obtener las dimensiones para el cv::Mat resultado int result_cols = img_src.cols - templ.cols + 1; int result_rows = img_src.rows - templ.rows + 1; Mat result(result_rows, result_cols, CV_32FC1);
Para aplicar la comparación de plantillas (match template), debemos indicar la imagen fuente (img_src), la imagen template o patrón (templ), el cv::Mat donde se almacenará el resultado (result), además de el modo (match_mode) utilizado por la función.
cv::TemplateMatchModes match_mode = cv::TemplateMatchModes::TM_CCOEFF_NORMED; // aplicar match template y normalizar el resultado. matchTemplate(img_src, templ, result, match_mode); normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
Usamos la función cv::minMaxLoc()
para determinar los valores máximos o mínimos, junto con la posición de los mismos, según el modo que usemos nos interesarán los valores más claros o los más oscuros.
// obtener max y min junto con sus ubicaciones minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat()); if (match_mode == TM_SQDIFF || match_mode == TM_SQDIFF_NORMED) matchLoc = minLoc; else matchLoc = maxLoc;
Cuando obtenemos la ubicación del área deseada la marcamos dibujando un rectángulo en dicha posición, esto se hace de la siguiente manera:
// dibujar el rectangulo en la posicion encontrada rectangle(img_src, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, CV_AA, 0); // mostrar las imagenes imshow(result_window, result); imshow(image_window, img_src);
Ejecutando el código con las siguientes imágenes, la imagen pequeña en la parte superior izquierda es la deseamos localizar:
Aplicando la función cv::matchTemplate()
usando el modo TM_CCOEFF_NORMED:
Al usar los modos TM_SQDIFF_NORMED o TM_SQDIFF nos interesa el punto mínimo, el contrario de los demás modos.
Si deseamos ser mas específicos al definir el patrón a buscar podemos utilizar una máscara, esta nos permite establecer de una manera más precisa el patrón que deseamos ubicar, la función cv::matchTemplate()
en su último parámetro nos permite indicar la máscara a utilizar.
Debemos tener presente que no todos los modos soportan máscaras, además las imágenes patrón y máscara deben tener el mismo tamaño y tipo.
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char** argv)
{
const char* image_window = "Source Image";
const char* result_window = "Result window";
Mat img_src = imread("../image.png", CV_LOAD_IMAGE_COLOR);
Mat templ = imread("../banana.png", CV_LOAD_IMAGE_COLOR);
Mat mask = imread("../mascara.png", CV_LOAD_IMAGE_COLOR);
// obtener las dimensiones para el cv::Mat resultado
int result_cols = img_src.cols - templ.cols + 1;
int result_rows = img_src.rows - templ.rows + 1;
Mat result(result_rows, result_cols, CV_32FC1);
// establecer el match template mode
cv::TemplateMatchModes match_mode = cv::TemplateMatchModes::TM_SQDIFF;
// aplicar match template con el modo indicado y normalizar el resultado
matchTemplate(img_src, templ, result, match_mode, mask);
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
double minVal, maxVal;
Point minLoc, maxLoc, matchLoc;
// obtener max y min junto con sus ubicaciones
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
if (match_mode == TM_SQDIFF || match_mode == TM_SQDIFF_NORMED)
matchLoc = minLoc;
else
matchLoc = maxLoc;
// dibujar el rectangulo en la posicion encontrada
rectangle(img_src, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, CV_AA, 0);
imshow(image_window, img_src);
waitKey(0);
return 0;
}
- Descargar el proyecto completo en GitHub: OpenCV Template Matching
- Puedes ver más en: Tutoriales Análisis de Imágenes con OpenCV
Comentarios
Publicar un comentario