图像模板匹配算法的研究和实现

  这次写一下算法方面的,图像处理中模板匹配算法的研究和实现。

  一:  首先我们先上一下模板匹配的理论及其公式描述:

     模板匹配是通过在输入图像上滑动模板图像块对实际的图像块和输入图像进行匹配,并且可以利用函数cvMinMaxLoc()找到最佳匹配的位置。例如在工业应用中,可以锁定图像中零部件的位置,并根据具体的位置,进行具体的处理。匹配的过程中可以使用不同的method,通过最合适的method,进行最合适的匹配。

  MatchTemplate       比较模板和重叠的图像区域

void cvMatchTemplate( const CvArr* image,const CvArr* templ, CvArr* result, int method );  

image      欲搜索的图像。它应该是单通道、8-比特或32-比特 浮点数图像 templ      搜索模板,不能大于输入图像,且与输入图像具有一样的数据类型 result      比较结果的映射图像。单通道、32-比特浮点数. 如果图像是 W×H 而 templ 是 w×h ,则 result 一定是 (W-w+1)×(H-h+1). method   指定匹配方法:

       函数 cvMatchTemplate 与函数 cvCalcBackProjectPatch 类似。它滑动过整个图像 image, 用指定方法比较 templ 与图像尺寸为 w×h 的重叠区域,并且将比较结果存到 result 中。 下面是不同的比较方法,可以使用其中的一种 (I 表示图像,T - 模板, R - 结果. 模板与图像重叠区域 x'=0..w-1, y'=0..h-1 之间求和):

OpenCV模板匹配算法.可用的方法有6个:

平方差匹配method=CV_TM_SQDIFF,这类方法利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大.

标准平方差匹配method=CV_TM_SQDIFF_NORMED

相关匹配method=CV_TM_CCORR,这类方法采用模板和图像间的乘法操作,所以较大的数表示匹配程度较高,0标识最坏的匹配效果.


标准相关匹配method=CV_TM_CCORR_NORMED

相关系数匹配method=CV_TM_CCOEFF。这类方法将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列).

在这里

标准相关系数匹配method=CV_TM_CCOEFF_NORMED



     通常,随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价).最好的办法是对所有这些设置多做一些测试实验,以便为自己的应用选择同时兼顾速度和精度的最佳方案.

       通过使用 cvMinMaxLoc函数,我们确定结果矩阵 R 的最大值和最小值的位置。函数中的参数有:

    

二:   opencv 实现模板匹配

     这里调用 OPENCV 自带的模板匹配函数实现模板匹配  .具体代码如下:

     //outDataMat 中相邻扫描线进行匹配,模板矩阵大小为100,目标矩阵大小为200,结果矩阵大小为101     

   // 参数说明: winSize :100  ; stepSize :10 ;outDataMat :300*8196

void CDisplacement::displacementAlgorithm(   CvMat * outDataMat,int winSize  , int   stepSize  )
{
     int multiWin         = 2;                                                                                                                               //大窗口对小窗口的倍数
    int winNum           = static_cast<int>(outDataMat->cols - multiWin * winSize) / stepSize;                                //计算需要匹配的段数
  CvMat *disMat        = cvCreateMat(outDataMat->rows - 1, winNum, CV_32FC1);                                             //用于保存位移的矩阵,匹配得出的整数位移经过插值后应该为浮点数

CvMat *templateMat = cvCreateMatHeader(1, winSize, CV_32FC1);                                                                 //用于匹配的模板

CvMat *objectMat    = cvCreateMatHeader(1, multiWin * winSize, CV_32FC1);                                                 //用于匹配的目标

CvMat *resultMat    = cvCreateMat(1, (multiWin - 1) * winSize + 1, CV_32FC1);                                             //用于存放匹配结果

double min, max;                                                                                                                                     //匹配结果中的最大值
CvPoint max_loc;                                                                                                                                    //匹配结果最大值所在位置
double pmax, nmax;                                                                                                                              //最大值的前后两个值
double displacement;                                                                                                                             //存储位移值

float temp_result[101];

for (int i = 0; i < disMat->rows; ++i)                                                                                                      //求位移
{
for (int j = 0; j < disMat->cols; ++j)
{

                                                                                                                                                     /* ->data.ptr表示数据的起始位置 */


templateMat->data.ptr = outDataMat->data.ptr + i * outDataMat->step
+ static_cast<int>(sizeof(float) * ((multiWin - 1) * winSize / 2 + j * stepSize));


objectMat->data.ptr = outDataMat->data.ptr + (i + 1) * outDataMat->step + static_cast<int>(sizeof(float) * (j * stepSize)/* + 0.5*/);               //相邻扫描线

cvMatchTemplate(objectMat, templateMat, resultMat, CV_TM_CCORR_NORMED);                                                                                              //匹配

 

cvMinMaxLoc(resultMat, &min, &max, NULL, &max_loc);                                                                                                                               //查找最大值

pmax = *static_cast<float*>(static_cast<void*>(resultMat->data.ptr + sizeof(float)*max_loc.x - sizeof(float)));                                            //取最大值的前一个值

nmax = *static_cast<float*>(static_cast<void*>(resultMat->data.ptr + sizeof(float)*max_loc.x + sizeof(float)));                                          //取最大值的后一个值

displacement = (multiWin - 1) * winSize / 2 - max_loc.x - (pmax - nmax) / (2 * (pmax - 2 * max + nmax));                                                //插值得到位移

CV_MAT_ELEM(*disMat,float, i, j) = static_cast<float>(displacement);                                                                                                       //结果存放到位移矩阵中

}

 

//test for wong 2016/06/24

SaveDispDataFileFilter_1("weiyi_cpu.dat", disMat);                                                                                                                                  //保存位移值                

 

  }   

 

 

 三: CUDA实现模板匹配

    这里采用CUDA实现模板匹配功能

     

   

void CudaMain::computeDisplacement_cuda(CvMat* filtOutMat, int multiWin, int winSize, int stepSize, CvMat*outputMat){

 

int WinNum = (filtOutMat->cols - multiWin*winSize) / stepSize;                                                                         // 一维位移矩阵

Complex* hInput = (Complex*)filtOutMat->data.fl;                                                                                       // 数据位置;

Complex*hOutput = (Complex*)outputMat->data.fl;                                                                                    // 数据位置;


cudaMemcpy(inputMat, hInput, filtOutMat->cols*filtOutMat->rows*sizeof(Complex), cudaMemcpyHostToDevice); // CPU-GPU

dim3 dBlock;

dim3 dThread;

dBlock.x = filtOutMat->rows - 1;                                                                                                              // 输出矩阵行数 ,块数 299

 

dThread.x = WinNum;                                                                                                                           // 输出矩阵列数 , 线程数 799




templateMat*templateMatShare;                                                                                                               // 模板内存在GPU分配


objectMat* objectMatShare;                                                                                                                    // 目标内存在GPU分配

 

resultMat*resultMatShare;                                                                                                                        // 匹配结果在GPU分配

 

Complex* min;


Complex* max;

int* max_location;


Complex* displacement;

 

 

 


cudaMalloc(&templateMatShare, dBlock.x*dThread.x* sizeof(templateMat));                                          //模板矩阵在GPU全局内存分配


cudaMalloc(&objectMatShare, dBlock.x*dThread.x* sizeof(objectMat));                                                 //目标矩阵在GPU全局内存分配


cudaMalloc(&resultMatShare, dBlock.x*dThread.x* sizeof(resultMat));                                                  //结果矩阵在GPU全局内存分配

 

cudaMalloc(&min, dBlock.x*dThread.x* sizeof(Complex));                                                                   // min在GPU全局内存分配


cudaMalloc(&max, dBlock.x*dThread.x* sizeof(Complex));                                                                 // max在GPU全局内存分配


cudaMalloc(&max_location, dBlock.x*dThread.x* sizeof(int));                                                            // max_location在GPU全局内存分配


cudaMalloc(&displacement, dBlock.x*dThread.x* sizeof(Complex));                                                  // max_location在GPU全局内存分配

 

                                                                                                                                                //求位移矩阵

displacement_api_cuda << < dBlock, dThread >> > (inputMat, filtOutMat->rows, filtOutMat->cols, multiWin, winSize, stepSize, templateMatShare, objectMatShare, resultMatShare, min, max, max_location, displacement);

 

cudaThreadSynchronize();

cudaMemcpy(hOutput, displacement, sizeof(Complex)*outputMat->cols*outputMat->rows, cudaMemcpyDeviceToHost);       //拷贝GPU处理后数据到 CPU

SaveDataFile("weiyi_gpu.dat", outputMat);                                                                                                                    //保存数据

 

cudaFree(templateMatShare);

cudaFree(objectMatShare);

cudaFree(resultMatShare);

cudaFree(min);

cudaFree(max);

cudaFree(max_location);

 }

 

其中核函数:

   

__global__ void displacement_api_cuda(Complex*disInputCuda, int rows, int cols, int multiWin, int winSize, int stepSize, templateMat*templateMatShare, objectMat* objectMatShare, resultMat*resultMatShare, Complex*min, Complex*max, int*max_location, Complex* displacement ) {


int out_offset = blockIdx.x *blockDim.x + threadIdx.x; 

int bid = blockIdx.x ; 

int tid = threadIdx.x; 

Complex*templateMatID; //ID


Complex*objectMatID; //ID

 

 

templateMatID = (Complex*)(disInputCuda + blockIdx.x*cols + (multiWin - 1) * winSize / 2 + threadIdx.x * stepSize);

 


for (int i = 0; i < 100;i++) {

if (i < 64) {

templateMatShare[out_offset].tempData.elem[i]= *(templateMatID + i);

}

else

templateMatShare[out_offset].tempData.atom[i-64] = *(templateMatID + i);


}

 


objectMatID = (Complex*)(disInputCuda + (blockIdx.x + 1)*cols + threadIdx.x * stepSize);



for (int i = 0; i < 200; i++) {

if (i<64)
objectMatShare[out_offset].objData.elem_0[i] = *(objectMatID + i);
else if (i<128)
objectMatShare[out_offset].objData.elem_1[i - 64] = *(objectMatID + i);

else if (i<192)
objectMatShare[out_offset].objData.elem_2[i - 128] = *(objectMatID + i);
else
objectMatShare[out_offset].objData.atom[i - 192] = *(objectMatID + i);

 

}

 

 

for (int i = 0; i < 101; i++) {

if (i<64)
resultMatShare[out_offset].resData.elem[i] = 0;

else
resultMatShare[out_offset].resData.atom[i-64] = 0;

}

 

 

 

for (int i = 0; i < 192; i++) {

if (i<64)
objectMatShare[out_offset].elem_0[i] = *(objectMatID+i);
else if (i<128)
objectMatShare[out_offset].elem_1[i-64] = *(objectMatID + i);

else
objectMatShare[out_offset].elem_2[i - 128] = *(objectMatID + i);



}


for (int j = 0; j < 8; j++) {

objectMatShare[out_offset].atom[j] = *(templateMatID + j + 192);



xcorr_cuda(templateMatShare[out_offset].tempData.elem, objectMatShare[out_offset].objData.elem_0, resultMatShare[out_offset].resData.elem);

 

 

minMax_cuda(resultMatShare[out_offset].resData.elem, &min[out_offset], &max[out_offset], &max_location[out_offset]);



 

interp_cuda(resultMatShare[out_offset].resData.elem, &max_location[out_offset], &max[out_offset], &multiWin, &winSize, &displacement[out_offset]);

  __syncthreads();

 

}

 

  

__device__ void xcorr_cuda(const Complex* templateMat_startID, const Complex* objectMat_startID, Complex*resultMat_startID) {


for (int i = 0; i < 101; i++) {


Complex sum_object = 0;

Complex frac_object = 0;


Complex pow_template = 0;


Complex pow_object = 0;


Complex result = 0;


//sum_object

for (int j = 0; j < 100; j++) {


sum_object += *(objectMat_startID + i + j);


}

// ave

Complex ave_object = sum_object / 100;


//fraction

for (int j = 0; j < 100; j++) {

Complex tmp = *(templateMat_startID + j) * (*(objectMat_startID + i + j) - ave_object);


frac_object += tmp;

}


//pow temp

for (int j = 0; j < 100; j++) {


pow_template += *(templateMat_startID + j) * *(templateMat_startID + j);

}

//pow objectMat

for (int j = 0; j < 100; j++) {


pow_object += *(objectMat_startID + i + j)* * (objectMat_startID + i + j);

}

//result

result = sqrt(pow_template*pow_object);

//output

*(resultMat_startID + i) = frac_object / result;

}


}

 

__device__ void minMax_cuda(Complex*resultMat_startID, Complex* min_value, Complex* max_value, int * max_location) {

 

//求最大值及位置

for (int i = 0; i < 101; i++) {

if (*(resultMat_startID + i) >= *max_value) {

*max_location = i;

*max_value = *(resultMat_startID + i);

 

}

}

 

}

 

 

__device__ void interp_cuda(Complex*resultMat_startID, int * max_loc, Complex*max_value, int * multiWin, int * winSize, Complex* displace) {

Complex*pre = (Complex*)resultMat_startID + *max_loc - 1;

Complex*next = (Complex*)resultMat_startID + *max_loc + 1;


*displace = (*multiWin - 1) * *winSize / 2 - *max_loc - (*pre - *next) / (2 * (*pre - 2 * *max_value + *next));


}

 

 

 

四:  结果比较

  这里贴一下采用CPU计算的和GPU计算的结果吧:

 采用CPU计算的结果:

    0.009192 0.008164 0.007095 0.011042 0.011536 0.011247 0.016015 0.010360 0.001595 -0.000845 -0.002765 -0.000039 0.007204 0.005229 0.002261 0.003771 0.002982 0.010227 0.017885 0.016466 0.017094 0.017613 -0.000961 -0.003701 0.015722 0.016839 0.013439 0.007723 0.002980 0.010488 0.012283 0.006072 0.001040 -0.003270 -0.003462 0.004596 0.008017 0.010673 0.020252 0.002328 -0.001016 0.009833 0.011129 0.009137 0.012297 0.014499 0.017363 0.013004 0.003839 0.008114 0.014437 0.007309 0.004949 0.004221 0.002466 -0.001996 -0.015309 -0.020181 -0.013732 -0.012274 0.003202 

 

采用CUDA计算的结果:

  0.013173 0.015335 0.011267 0.008420 0.004566 0.006342 0.014983 0.010390 0.001600 -0.000754 -0.002277 0.001073 0.007668 0.005285 0.002635 0.004263 0.003369 0.010357 0.018863 0.017140 0.017338 0.019080 0.000751 -0.004420 0.017763 0.020394 0.015874 0.007988 0.000732 0.010925 0.016618 0.013930 0.008934 -0.004655 -0.013801 -0.003829 0.004890 0.014446 0.028133 -0.001455 -0.005051 0.008987 0.009782 0.003444 0.006536 0.009789 0.012227 0.010090 0.003550 -0.000100 0.000534 -0.005920 -0.008974 -0.008588 -0.002132 -0.002369 -0.017581 -0.032293 -0.021036 -0.009534 0.013279 0.025665 0.012573 0.006627 

  

 

转载于:https://www.cnblogs.com/colorful-days/p/5586206.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#模板匹配 import cv2 as cv import numpy as np def template_demo(): dog = cv.imread("E:/opencv/picture/dog.jpg") dog_nose = cv.imread("E:/opencv/picture/nose.jpg") cv.imshow("dog",dog) result = cv.matchTemplate(dog,dog_nose,cv.TM_CCORR_NORMED) h,w =dog_nose.shape[:2] min_val,max_val,min_loc,max_loc=cv.minMaxLoc(result) pt1 = max_loc pt2 = (pt1[0]+w,pt1[1]+h) cv.rectangle(dog,pt1,pt2,(0,255,0),2) cv.imshow("match",dog) print(result) #src = cv.imread("E:/opencv/picture/dog.jpg") #cv.imshow("inital_window",src) template_demo() cv.waitKey(0) cv.destroyAllWindows() 分析: 模板匹配通常用于目标检测。本文我们检测狗图片的鼻子。 • 我们需要两个主要组件: 1. 源图像(I):我们期望找到与模板图像匹配的图像 2. 模板图像(T):将与模板图像进行比较的补丁图像 1. result = cv.matchTemplate(dog,dog_nose,cv.TM_CCORR_NORMED) void cv::matchTemplate( cv::InputArray image, // 待匹配图像W*H cv::InputArray templ, // 模板图像,和image类型相同, 大小 w*h cv::OutputArray result, // 匹配结果图像, 类型 32F, 大小 (W-w+1)*(H-h+1) int method // 用于比较的方法 ); 其中method有: TM_SQDIFF_NORMED匹配数值越低表示匹配效果越好 TM_CCORR_NORMED,TM_CCOEFF_NORMED匹配数值越大表示匹配效果越好 result参数:(保存各个点匹配结果的参数) 模板匹配函数cvMatchTemplate依次计算模板与待测图片的重叠区域的相似度,并将结果存入映射图像result当中,也就是说result图像中的每一个点的值代表了一次相似度比较结果 模板在待测图像上每次在横向或是纵向上移动一个像素,并作一次比较计算 我们可以通过cv.minMaxLoc函数来确定结果矩阵的最大值和最小值的位置。 2. cv.minMaxLoc(result) 返回result数值中最小值以及最小值所在的位置和最大值以及最大值所在的位置。 3. 当知道哪个点匹配度最高时这个时候我们需要用矩阵把模板给标出来 C++: void rectangle(Mat& img, Point pt1,Point pt2,const Scalar& color, int thickness=1, int lineType=8, int shift=0) 第一个参数:要在哪个图像上画? 第二个参数:矩阵的左上角点坐标 第三个参数:矩阵的右下角点坐标 第四个参数:颜色
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值