Детектирование объекта по шаблону может пригодиться во множестве случаев. Самый простой пример — поиск заранее заданного объекта.
В OpenCV для этого есть замечательная функция 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)
— сравнение шаблона и перекрывающего окна на исходном изображении
image — изображение для поиска (8-битное или 32F)
templ — шаблон для поиска (не должен превышать исходное изображение и иметь тот же тип)
result — карта результата сравнения (32FС1) если image WxH и templ wxh, то result = (W-w+1)x(H-h+1)
method — метод сравнения областей изображения:
Функцию поиска можно приблизительно представить следующим образом:
изображение шаблона templ последовательно накладывается на исходное изображение image и между ними вычисляется корреляция, результат которой заносится в результирующее изображение result.
Очевидно, что корреляцию между двумя изображениями можно считать разными способами.
Эти методы собраны выше в перечислении и просто меняют формулу рассчёта корреляции:
Посмотрим результаты работы поиска шаблона с разными методами.
Для этого используем следующий код:
//
// Несколько модифицированный пример 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<6; ++i){
ftmp[i] = cvCreateImage( cvSize(iwidth,iheight),32,1);
}
// сравнение шаблона с изображением
for(i=0; i<6; ++i){
cvMatchTemplate( src, templ, ftmp[i], i);
// double min,max;
// cvMinMaxLoc(ftmp,&min,&max);
cvNormalize(ftmp[i],ftmp[i],1,0,CV_MINMAX);
}
// показываем
cvNamedWindow( "Template");
cvShowImage( "Template", templ );
cvNamedWindow( "Image");
cvShowImage( "Image", src );
cvNamedWindow( "SQDIFF" );
cvShowImage( "SQDIFF", ftmp[0] );
cvNamedWindow( "SQDIFF_NORMED" );
cvShowImage( "SQDIFF_NORMED", ftmp[1] );
cvNamedWindow( "CCORR" );
cvShowImage( "CCORR", ftmp[2] );
cvNamedWindow( "CCORR_NORMED" );
cvShowImage( "CCORR_NORMED", ftmp[3] );
cvNamedWindow( "CCOEFF" );
cvShowImage( "CCOEFF", ftmp[4] );
cvNamedWindow( "CCOEFF_NORMED" );
cvShowImage( "CCOEFF_NORMED", ftmp[5] );
// ждём нажатия клавиши
cvWaitKey(0);
return 0;
}
В качестве исходного изображения возьмём изображение Чеширского Кота, а в качестве шаблона — скопированный из этой же картинки глаз:
Результат:
Следует обратить внимание, что для приведения результата корреляции в «видимый» формат (ведь некоторые методы могут возвращать отрицательные значения) используется нормировка изображения при помощи функции cvNormalize():
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) );
— нормировка массива
arr1 — первое исходное изображение
arr2 — второе исходное изображение (если NULL, то абсолютная нормировка arr1, иначе абсолютная или относительная arr1-arr2)
norm_type — тип нормировки:
Как видим, в зависимости от выбранного метода корреляции, местоположение заданного шаблона на целевом изображении можно обнаружить по минимуму или максимуму значения на результирующей картинке.
Для этого, очень удобно использовать OpenCV-ную функцию cvMinMaxLoc():
— определяет минимальное и максимальное значения массива, а так же их местоположение
arr — массив(изображение) для поиска (одноканальный или многоканальный с установленным COI)
min_val — указатель на переменную для сохранения минимального значения
max_val — указатель на переменную для сохранения максимального значения
min_loc — указатель на точку местоположения минимума
max_loc — указатель на точку местоположения максимума
mask — маска для выбора подмассива
Пример как можно определять местоположение шаблона — поиск максимума-минимума с помощью 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;
}
Обратите внимание, что т.к. размер результирующей картинки по ширине и высоте меньше исходного изображения на соответствующий размер шаблона +1 ( result = (W-w+1)x(H-h+1) ), то для выделения объекта на исходном изображении нужно, соответственно, прибавить эти величины.
Спасибо за статью.
Такой вопрос, искомое изображение на картинке и оно же в виде шаблона в пропорциях 1 к 1?
Или всё-таки шаблон глаза больше/меньше, чем глаз на целой картинке?
Очень интересно. Мне вообще нравится ваша серия статей OpenCV, легко читается.
Можно ли проводить сравнение, если изображения повернуты на угол? Для саможельного расстановочного PnP станка.
Нужно сравнить заранее отснятую фотографию микросхемы/smd детальки и определить угол/ориентацию (0,90,180 градусов) текущей детали. Съемка одной камерой, масштаб постоянный 1 к 1, яркость одна. Подскажите пожалуйста какие функции и алгоритмы можно использовать для сравнения повернутых изображений.
Другое решение ( как вижу):
— выравнивание угла до 0,90,180 положения (детали прямоугольные) -> угол на который нужно довернуть
— сравнение перебором с отснятыми картинками, для выяснения что за деталька и где у нее центр -> центр и 1я ножка детальки
Цель, программа запускаемая с командной строки с параметрами, результат выводится в echo.
Сейчас на самодельных станках все делается вслепую. Распознавания нет.
Возможно есть готовые утилиты сравнения изображений, но я ничего подобного не нашел. Да и не поэкспериментируешь…
Спасибо!
Думаю, для расстановочного станка лучше применять классические алгоритмы технического зрения (для надёжности лучше организовать для камеры постоянную подсветку). Т.е. искать контур, по геометрическим параметрам находить деталь и определять её ориентацию.
Если возникнут проблемы — пишите на форум, разберёмся :)
Фотографирование в красном свете дает картинку с четкими контурами выводов. Если искать по геометрии, придется для программы описывать каждый элемент. Что несколько сложнее, чем подготовленная фотография. А вообще практика покажет.
в википедии есть псевдокод, но обратите внимание, что тестировать его следует на очень маленьких картинках ;)
для ускорения процесса, обычно, корреляция считается через преобразование Фурье.
Доброго времени суток!
Спасибо за вашу статью, очень познавательно.
Скажите а есть ли метод, который способен автоматически определять доминирующий шаблон для нахождение его на выбранном изображении. К примеру представте себе фасад дома с повторающимися окнами. Задача будет определить доминирующее окно на фасаде(т.е шаблон) и найти все подобные окна попадающиеся под этот шаблон. Тоесть задача сводится к тому что-бы машина сама определила шаблон, а не использовать готовый, заранее вырезанный шаблон из картинки. Спасибо, надеюсь обьяснил достаточно внятно.
Комментарии (9)
RSS свернуть / развернутьТакой вопрос, искомое изображение на картинке и оно же в виде шаблона в пропорциях 1 к 1?
Или всё-таки шаблон глаза больше/меньше, чем глаз на целой картинке?
StaDi
noonv
Можно ли проводить сравнение, если изображения повернуты на угол? Для саможельного расстановочного PnP станка.
Нужно сравнить заранее отснятую фотографию микросхемы/smd детальки и определить угол/ориентацию (0,90,180 градусов) текущей детали. Съемка одной камерой, масштаб постоянный 1 к 1, яркость одна. Подскажите пожалуйста какие функции и алгоритмы можно использовать для сравнения повернутых изображений.
Другое решение ( как вижу):
— выравнивание угла до 0,90,180 положения (детали прямоугольные) -> угол на который нужно довернуть
— сравнение перебором с отснятыми картинками, для выяснения что за деталька и где у нее центр -> центр и 1я ножка детальки
Цель, программа запускаемая с командной строки с параметрами, результат выводится в echo.
Сейчас на самодельных станках все делается вслепую. Распознавания нет.
Возможно есть готовые утилиты сравнения изображений, но я ничего подобного не нашел. Да и не поэкспериментируешь…
marshallab
Думаю, для расстановочного станка лучше применять классические алгоритмы технического зрения (для надёжности лучше организовать для камеры постоянную подсветку). Т.е.
Если возникнут проблемы — пишите на
noonv
marshallab
а можно где-нибудь достать реализацию этого метода, или хотя бы псевдо-код?
crawter
для ускорения процесса, обычно, корреляция считается через преобразование Фурье.
noonv
Спасибо за вашу статью, очень познавательно.
Скажите а есть ли метод, который способен автоматически определять доминирующий шаблон для нахождение его на выбранном изображении. К примеру представте себе фасад дома с повторающимися окнами. Задача будет определить доминирующее окно на фасаде(т.е шаблон) и найти все подобные окна попадающиеся под этот шаблон. Тоесть задача сводится к тому что-бы машина сама определила шаблон, а не использовать готовый, заранее вырезанный шаблон из картинки. Спасибо, надеюсь обьяснил достаточно внятно.
jack_milles
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.