Object detection – search for an object by template (Template matching)


Table of contents

1. OpenCV step by step. Introduction.
2. Installation.
3. Hello world.
4. Loading a picture.
Object detection – search for an object by template (Template matching)

Pattern detection can be useful in many cases. The simplest example is the search for a predefined object.
OpenCV has a great function for this. cvMatchTemplate()

C++: void matchTemplate(InputArray image, InputArray temp, OutputArray result, int method)
Python: cv2.matchTemplate(image, templ, method[, result ]) !result
C: void cvMatchTemplate(const CvArr* image, const CvArr* templ, CvArr* result, int method)
CVAPI(void)  cvMatchTemplate( const CvArr* image, const CvArr* templ,
                              CvArr* result, int method );

– comparison of the template and the overlapping window on the original image
image – image to search (8-bit or 32F)
templ – search template (should not exceed the original image and have the same type)
result – comparison result map (32FC1) if image WxH and templ wxh, then result = (W-w+1)x(H-h+1)
method – method for comparing image areas:

/* Template matching methods */
enum
{
    CV_TM_SQDIFF        =0,
    CV_TM_SQDIFF_NORMED =1,
    CV_TM_CCORR         =2,
    CV_TM_CCORR_NORMED  =3,
    CV_TM_CCOEFF        =4,
    CV_TM_CCOEFF_NORMED =5
};

(there used to be defines)

#define  CV_TM_SQDIFF        0
#define  CV_TM_SQDIFF_NORMED 1
#define  CV_TM_CCORR         2
#define  CV_TM_CCORR_NORMED  3
#define  CV_TM_CCOEFF        4
#define  CV_TM_CCOEFF_NORMED 5

The search function can be roughly represented as follows:
the templ template image is sequentially superimposed on the source image image and a correlation is calculated between them, the result of which is entered in the resulting image result.

Obviously, the correlation between two images can be considered in different ways.
These methods are listed above and simply change the formula for calculating the correlation:

Let’s see the results of the template search with different methods.
For this we use the following code:

//
// Несколько модифицированный пример Example 7-5. Сравнение шаблона
//
// использование: prog шаблон изображение
//
// из книги:
//   Learning OpenCV: Computer Vision with the OpenCV Library
//     by Gary Bradski and Adrian Kaehler
//     Published by O'Reilly Media, October 3, 2008

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <stdio.h>

int main( int argc, char* argv[] )
{
	IplImage *src, *templ,*ftmp[6]; //ftmp is what to display on
	int i;

	char* filename = argc >= 2 ? argv[1] : "Image0.jpg";
	char* filename0 = argc >= 3 ? argv[2] : "templ.bmp";


	// загрузка изображения
	if((src=cvLoadImage(filename, 1))== 0) {
		printf("Error on reading src image %s\n",argv[1]);
		return(-1);
	}

	// загрузка шаблона
	if((templ=cvLoadImage(filename0, 1))== 0) {
		printf("Error on reading template %s\n",argv[2]);
		return(-1);
	}

	int patchx = templ->width;
	int patchy = templ->height;
	int iwidth = src->width - patchx + 1;
	int iheight = src->height - patchy + 1;
	for(i=0; i

cvMatchTemplate.cpp

В качестве исходного изображения возьмём изображение Чеширского Кота, а в качестве шаблона – скопированный из этой же картинки глаз:

Результат:

Следует обратить внимание, что для приведения результата корреляции в “видимый” формат (ведь некоторые методы могут возвращать отрицательные значения) используется нормировка изображения при помощи функции cvNormalize():

C++: double norm(InputArray src1, int normType=NORM_L2, InputArray mask=noArray())
C++: double norm(InputArray src1, InputArray src2, int normType, InputArray mask=noArray())
C++: double norm(const SparseMat& src, int normType)
Python: cv2.norm(src1[, normType[, mask ]]) !retval
Python: cv2.norm(src1, src2[, normType[, mask ]]) !retval
C: double cvNorm(const CvArr* arr1, const CvArr* arr2=NULL, int normType=CV_L2, const CvArr*
mask=NULL)
CVAPI(double)  cvNorm( const CvArr* arr1, const CvArr* arr2 CV_DEFAULT(NULL),
                       int norm_type CV_DEFAULT(CV_L2),
                       const CvArr* mask CV_DEFAULT(NULL) );

CVAPI(void)  cvNormalize( const CvArr* src, CvArr* dst,
                          double a CV_DEFAULT(1.), double b CV_DEFAULT(0.),
                          int norm_type CV_DEFAULT(CV_L2),
                          const CvArr* mask CV_DEFAULT(NULL) );

– array normalization

arr1 – first source image
arr2 – second source image (if NULL, then absolute normalization of arr1, otherwise absolute or relative arr1-arr2)
norm_type – normalization type:

#define CV_C            1
#define CV_L1           2
#define CV_L2           4
#define CV_NORM_MASK    7
#define CV_RELATIVE     8
#define CV_DIFF         16
#define CV_MINMAX       32

#define CV_DIFF_C       (CV_DIFF | CV_C)
#define CV_DIFF_L1      (CV_DIFF | CV_L1)
#define CV_DIFF_L2      (CV_DIFF | CV_L2)
#define CV_RELATIVE_C   (CV_RELATIVE | CV_C)
#define CV_RELATIVE_L1  (CV_RELATIVE | CV_L1)
#define CV_RELATIVE_L2  (CV_RELATIVE | CV_L2)

mask – mask

Without normalization, we would see the following:

As you can see, depending on the chosen correlation method, the location of the given template on the target image can be found by the minimum or maximum value in the resulting image.

For this, it is very convenient to use the OpenCV cvMinMaxLoc() function:

C++: void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point*
maxLoc=0, InputArray mask=noArray())
C++: void minMaxLoc(const SparseMat& src, double* minVal, double* maxVal, int* minIdx=0, int*
maxIdx=0)
Python: cv2.minMaxLoc(src[, mask ]) !minVal, maxVal, minLoc, maxLoc
C: void cvMinMaxLoc(const CvArr* arr, double* minVal, double* maxVal, CvPoint* minLoc=NULL, Cv-
Point* maxLoc=NULL, const CvArr* mask=NULL)
CVAPI(void)  cvMinMaxLoc( const CvArr* arr, double* min_val, double* max_val, CvPoint* min_loc CV_DEFAULT(NULL), CvPoint* max_loc CV_DEFAULT(NULL), const CvArr* mask CV_DEFAULT(NULL) );

– determines the minimum and maximum values ​​of the array, as well as their location
arr – array (image) to search (single-channel or multi-channel with COI set)
min_val – pointer to a variable to store the minimum value
max_val – pointer to a variable to store the maximum value
min_loc – pointer to the minimum location point
max_loc – pointer to the maximum location point
mask – mask for subarray selection

An example of how you can determine the location of the pattern – finding the maximum-minimum using cvMinMaxLoc():

//
// пример cvMatchTemplate()
// сравнение изображение с шаблоном
//

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* templ = 0;

int main(int argc, char* argv[])
{
	// имя картинки задаётся первым параметром
	char* filename = argc >= 2 ? argv[1] : "Image0.jpg";
	// получаем картинку
	image = cvLoadImage(filename,1);

	printf("[i] image: %s\n", filename);
	assert( image != 0 );

	// шаблон
	char* filename2 = argc >= 3 ? argv[2] : "eye.jpg";
	printf("[i] template: %s\n", filename2);

	templ = cvLoadImage(filename2,1);
	assert( templ != 0 );

	cvNamedWindow("origianl", CV_WINDOW_AUTOSIZE);
	cvNamedWindow("template", CV_WINDOW_AUTOSIZE);
	cvNamedWindow("Match", CV_WINDOW_AUTOSIZE);
	cvNamedWindow("res", CV_WINDOW_AUTOSIZE);

	// размер шаблона
	int width = templ->width;
	int height = templ->height;

	// оригинал и шаблон
	cvShowImage( "origianl", image);
	cvShowImage( "template", templ);

	// изображение для хранения результата сравнения
	// размер результата: если image WxH и templ wxh, то result = (W-w+1)x(H-h+1)
	IplImage *res = cvCreateImage( cvSize( (image->width-templ->width+1), (image->height-templ->height+1)), IPL_DEPTH_32F, 1 );

	// сравнение изображения с шаблоном
	cvMatchTemplate(image, templ, res, CV_TM_SQDIFF);

	// покажем что получили
	cvShowImage( "res", res);

	// определение лучшее положение для сравнения
	// (поиск минимумов и максимумов на изображении)
	double    minval, maxval;
	CvPoint    minloc, maxloc;
	cvMinMaxLoc(res, &minval, &maxval, &minloc, &maxloc, 0);

	// нормализуем
	cvNormalize(res,res,1,0,CV_MINMAX);
	cvNamedWindow("res norm", CV_WINDOW_AUTOSIZE);
	cvShowImage( "res norm", res);

	// выделим область прямоугольником
	cvRectangle(image, cvPoint(minloc.x, minloc.y), cvPoint(minloc.x+templ->width-1, minloc.y+templ->height-1), CV_RGB(255, 0, 0), 1, 8);

	// показываем изображение
	cvShowImage("Match", image);

	// ждём нажатия клавиши
	cvWaitKey(0);

	// освобождаем ресурсы
	cvReleaseImage( &image );
	cvReleaseImage( &templ );
	cvReleaseImage( &res );
	cvDestroyAllWindows();
	return 0;
}

cvMatchTemplate_2.cpp

Result:

Please note that since the size of the resulting image in width and height is less than the original image by the corresponding template size +1 ( result = (W-w+1)x(H-h+1) ), then to select an object in the original image, you need to add these values, respectively .

Links

http://en.wikipedia.org/wiki/Template_matching

Object detection – search for an object by template (Template matching)

Leave a Reply

Your email address will not be published.

Scroll to top