#include "template_match.h" #include "highgui.h" void* init_template_match(void) { void *ptm = (void*) new TemplateMatch(); return ptm; } void release_template_match(void* ptemplate_match) { if(!ptemplate_match) return; TemplateMatch *ptm = (TemplateMatch*) ptemplate_match; delete ptm; return; } void* init_image_feature(void* ptemplate_match, const char* img_path) { if(!ptemplate_match || !img_path) return NULL; TemplateMatch *ptm = (TemplateMatch*) ptemplate_match; string imgName; imgName.assign(img_path); return (void*)ptm->ExtractImageContour(imgName); } void release_image_feature(void* pimage_feature) { if(!pimage_feature) return; Mat* pfeature = (Mat*) pimage_feature; delete pfeature; return; } int add_image_template(void* ptemplate_match, const char* template_img_path, const char* label, int x, int y, int width, int height) { if(!ptemplate_match || !template_img_path || !label) return -1; TemplateMatch *ptm = (TemplateMatch*) ptemplate_match; Rect roi = Rect(x, y, width, height); string imgName, strlabel; imgName.assign(template_img_path); strlabel.assign(label); return ptm->AddImageTemplate(imgName, strlabel, roi); } float match_image(void* ptemplate_match, void* pimage_feature, char* label) { if(!ptemplate_match || !pimage_feature || !label) return NO_MATCH_SCORE; TemplateMatch *ptm = (TemplateMatch*) ptemplate_match; string templateLabel; templateLabel.assign(label); return ptm->MatchOneTemplate( *(Mat*)pimage_feature, templateLabel); } Rect TemplateMatch::DefaultROI = Rect(DEFAULT_X, DEFAULT_Y, DEFAULT_COLS, DEFAULT_ROWS); TemplateMatch::TemplateMatch(void) : mMatchThresh(0.4) { } TemplateMatch::~TemplateMatch(void) { } Mat* TemplateMatch::ExtractImageContour(string& imgName) { if( imgName == "") return NULL; Rect roi = DefaultROI; Mat *pfMat = new Mat(roi.height, roi.width, CV_32FC1); if(!pfMat) return NULL; Mat imgMat = imread(imgName, 0); Mat imgROI = imgMat(Range(roi.y, roi.height + roi.y), Range(roi.x, roi.width + roi.x) ); GaussianBlur(imgROI, imgROI, Size(7, 7), 0, 0); /*these two threshold are small than threshold used when calculate template contour.*/ Canny(imgROI, imgROI, 20, 80, 3); imgROI.convertTo(*pfMat, CV_32FC1, 1, 0); normalize(*pfMat, *pfMat, 1.0, 0, NORM_MINMAX); return pfMat; } int TemplateMatch::AddImageTemplate(string& imgName, string& label, Rect& roi) { if( imgName == "") return -1; Mat imgMat = imread(imgName, 0); Mat imgROI = imgMat(Range(roi.y, roi.height + roi.y), Range(roi.x, roi.width + roi.x) ); Mat tplMat = imgROI.clone(); Mat fROI(roi.height, roi.width, CV_32FC1); GaussianBlur(imgROI, imgROI, Size(7, 7), 0, 0); //Canny(imgROI, imgROI, 50, 120, 3); Canny(imgROI, imgROI, 50, 110, 3); imgROI.convertTo(fROI, CV_32FC1, 1, 0); normalize(fROI, fROI, 1.0, 0, NORM_MINMAX); slogo logo; logo.name = label; logo.contourMat = fROI; logo.templateMat = tplMat; logo.contourRect = roi; AddLogoTemplate(logo); return 0; } int TemplateMatch::AddLogoTemplate(slogo logo) { mslogoArray.push_back(logo); return 0; } int TemplateMatch::AddLogoTemplate(string& lgName, Mat& ctMat, Mat& tplMat) { slogo logo; logo.name = lgName; logo.contourMat = ctMat; logo.templateMat = tplMat; mslogoArray.push_back(logo); return 0; } float TemplateMatch::MatchOneTemplate(Mat& dstContourMat, string label) { int i, length; length = mslogoArray.size(); for(i=0; i < mslogoArray.size(); i++) { if(mslogoArray[i].name == label) break; } if( i == length ) return NO_MATCH_SCORE; slogo logo = mslogoArray.at(i); Rect r = logo.contourRect; Mat dstct_roi = dstContourMat(Range(r.y - DefaultROI.y, r.y - DefaultROI.y + r.height), Range(r.x - DefaultROI.x, r.x - DefaultROI.x + r.width) ); return BilateralMatch(logo.contourMat, dstct_roi, TemplateMatch::INTERSECT); } string TemplateMatch::MatchImage(string& imgName, float* score) { if(imgName == "" || !score) return "image not found"; Rect roi = DefaultROI; Mat imgMat = imread(imgName, 0); Mat imgROI = imgMat(Range(roi.y, roi.height + roi.y), Range(roi.x, roi.width + roi.x) ); Mat tplMat = imgROI.clone(); Mat fROI(roi.height, roi.width, CV_32FC1); GaussianBlur(imgROI, imgROI, Size(7, 7), 0, 0); //these two threshold are small than threshold used when calculate template contour. Canny(imgROI, imgROI, 20, 80, 3); imgROI.convertTo(fROI, CV_32FC1, 1, 0); normalize(fROI, fROI, 1.0, 0, NORM_MINMAX); return RetrievebyScore(fROI, tplMat, score); } string TemplateMatch::RetrievebyScore(Mat& dstContourMat, Mat& dstMat, float* score) { float difRatio; int pos; int flag=1; mMatchResult.clear(); for(int i = 0; i < mslogoArray.size(); i++) { slogo logo = mslogoArray.at(i); Rect r = logo.contourRect; Mat dstct_roi = dstContourMat(Range(r.y - DefaultROI.y, r.y - DefaultROI.y + r.height), Range(r.x - DefaultROI.x, r.x - DefaultROI.x + r.width) ); difRatio = BilateralMatch(logo.contourMat, dstct_roi, TemplateMatch::INTERSECT); InsertMatchResult(logo.name, difRatio); } SortMatchResult(); *score = mMatchResult[0].second; return mMatchResult[0].first; } float TemplateMatch::BilateralMatch(Mat& srcMat, Mat& dstMat, enum method m) { if(srcMat.rows != dstMat.rows || srcMat.cols != dstMat.cols || srcMat.depth() != dstMat.depth() || srcMat.channels() != dstMat.channels() ) return NO_MATCH_SCORE; float score, difRatio, count; if(m == TemplateMatch::MINUSDIST) { Mat difMat(srcMat.rows, srcMat.cols, CV_32FC1); difMat = abs(srcMat - dstMat); score = sum(difMat)[0]; difRatio = score/(srcMat.rows * srcMat.cols); } else if(m == TemplateMatch::INTERSECT) { Mat scoreMat(srcMat.rows, srcMat.cols, CV_32FC1); scoreMat = dstMat.mul(srcMat); score = sum(scoreMat)[0]; count = sum(srcMat)[0]; difRatio = (count - score)/count; } return difRatio; } float TemplateMatch::CalcHistScore(Mat& srcMat, Mat& dstMat) { IplImage *srcImg; IplImage *dstImg; *srcImg = (IplImage(srcMat));//&(IplImage(srcMat)); *dstImg = (IplImage(dstMat));//&(IplImage(dstMat)); int hist_size = 256; float range[] = {0, 255}; float *ranges[] = {range}; CvHistogram *srcHist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1); cvCalcHist(&srcImg, srcHist, 0, 0); CvHistogram *dstHist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1); cvCalcHist(&dstImg, dstHist, 0, 0); float com1 = cvCompareHist(srcHist, dstHist, CV_COMP_BHATTACHARYYA); return com1; } Rect TemplateMatch::GetContourRect(Mat& ctMat) { Rect r; int min_x, min_y, max_x, max_y; max_x = max_y = 0; min_x = ctMat.cols; min_y = ctMat.rows; for(int i = 0 ; i < ctMat.rows ; i++) for(int j = 0; j < ctMat.cols ; j++) { float element = ctMat.at(i, j); if(element > 0.0) { if( j < min_x ) min_x = j; if( i < min_y) min_y = i; if( j > max_x ) max_x = j; if( i > max_y ) max_y = i; } } r.x = min_x; r.y = min_y; r.width = max_x - min_x ; r.height = max_y - min_y; return r; } int TemplateMatch::SortMatchResult(bool bAscend) { //sort mMatchResult with bubble sort int length = mMatchResult.size(); if(bAscend) { for(int i = 0; i < length; i++) for(int j = 0; j< length -i -1; j++) { if( mMatchResult.at(j).second > mMatchResult.at(j+1).second ) { pair temp = mMatchResult.at(j+1); mMatchResult.at(j+1) = mMatchResult.at(j); mMatchResult.at(j) = temp; } } } else { for(int i = 0; i < length; i++) for(int j = length -1; j> i; j--) { if( mMatchResult.at(j).second < mMatchResult.at(j-1).second ) { pair temp = mMatchResult.at(j-1); mMatchResult.at(j-1) = mMatchResult.at(j); mMatchResult.at(j) = temp; } } } return 0; } int TemplateMatch::InsertMatchResult(string label, float ratio) { mMatchResult.push_back(pair(label, ratio)); return mMatchResult.size(); }