资源描述
智能系统平台专业实验报告
基于模板匹配的运动目标跟踪
一、实验目的
通过该实验,初步了解模板匹配算法,体会并学习如何用该算法实现视频跟踪。
二、算法概要
模板就是一幅已知的小图片。模板匹配就是在一幅大图像中搜寻目标。已知在该图中有要寻找的目标,且该目标与模板有相同的尺寸、方向和图像,通过一定的算法可以在图中找到目标,确定其坐标位置。
如图所示,设模板T叠放在搜索图S上平移,模板覆盖下的那块搜索图叫做子图,这块子图的左上角像素点在S图中的坐标,叫参考点,从图中可知和的取值范围为:, 其中,为被搜索图的大小,为模板的大小。
图1 被搜索图 图2 模板
现在可以比较与的内容,如两者一致,则和之差为零,所以我们可以用下式来衡量和的相似程度:
(1-1)
展开上式,则有:
(1-2)
上式等号右边第三项表示模板的总能量,是一个常数与坐标位置无关,第一项是模板覆盖下那块子图的能量,它随坐标位置的改变而缓慢改变,这两项都与模板匹配无关。第二项是子图像和模板的互相关,随而改变,和匹配时该项有最大值。
上式第二项的计算是通过将图像元素和模板图像元素联系起来获得的,将相关元素相乘后累加。现在我们完全可以将模板图像视为一个按行或者按列存储的向量,将被覆盖的图像区域视为另一个按照同样的方式存储的向量。这样,相似程度的计算就转换成了向量之间的点积运算。
(1-3)
显然,当和方向相同时,=1(为向量、的夹角),此时上式取得最大值,即当模板和子图匹配时,相关运算产生最大的响应。但是,上式最终的取值还与向量、自身的模值有关,比如说由于自身较大而同样能产生一个很高的响应。因此我们需要用向量模值的归一化解决这一问题。
改进的用于匹配的相关系数计算公式如下:
(1-4)
当模板和子图完全一样时,相关系数=1。在被搜索图中逐个像素点地移动模板图像,同时计算每处子图与模板的相关系数,当移过整幅图像S之后,找出的最大值,最大响应点坐标即为最佳匹配的左上角点。以该坐标为起始点,范围大小就以模板的大小为准就可以锁定目标。
三、算法步骤
(1)首先取得待跟踪的目标图像,该目标图像常较小,称该图像为模板,以代表;
(2)然后,定义匹配公式以备在移动模板时得到匹配度;
(3)把模板在待检测的图像(往往是视频中的一帧帧图像)中移动,在模板覆盖下那块搜索图叫做子图,每移动到一个位置就按定义的匹配公式计算匹配度,直至移动完整幅图像为止;
(4)按照匹配度的大小,选择匹配度最大(即最匹配)的位置,此位置即为最佳匹配位置,以此点为起始点,范围的大小就以模板的大小为准,即可锁定目标;
(5)针对视频中的每一帧图像执行步骤(3)~(4),这样就达到了跟踪的目的。
四、程序使用说明
例程给出了BMP_Display,内部函数实现了读图片和显示图片的功能。请同学们自行编写函数实现基于模板匹配的视频跟踪。
五、实验程序
#include <cdefBF561.h>
#include <sys\exception.h>
#include <ccblkfn.h>
#include "..\D_image_API\D_image_API.h"
#include "common.h"
#include "..\sys_res.h"
#include "..\sml2\sml2.h"
#include "dip_algorithm.h"
#include "math.h"
//最大响应出现位置
int nMaxX=0;
int nMaxY=0;
#define TEMPLATE_END_ADDRESS "..\\end_flag.bmp"
#define TEMPLATE_ADDRESS "..\\template.bmp"
BMPIMAGE bmpimage; //原始图像
BMPIMAGE bmptemplate; //模板图像
void TemplateMatch(unsigned char *pTo,unsigned char *pTemplate)
{
//循环变量
int i,j,m,n;
int nGraySrc=0;
int nGrayTpl=0;
double dSumT; //模板元素的平方和
double dSumS; // 图像子区域元素的平方和
double dSumST; //图像子区域和模板的点积
double R; //响应值
double MaxR; //记录当前的最大响应
//计算dSumT
dSumT=0;
for(m=0;m<bmptemplate.infohead.biHeight;m++)
{
for(n=0;n<bmptemplate.infohead.biWidth;n++)
{
//模板图像第m行,第n个像素的灰度值
int nGray=*(pTemplate+m*bmptemplate.infohead.biWidth+n);
dSumT+=(double)nGray*nGray;
}
}
//找到图像最大响应的现位置
MaxR=0;
for(i=0;i<bmpimage.infohead.biHeight-bmptemplate.infohead.biHeight+1;i++)
{
for(j=0;j<bmpimage.infohead.biWidth-bmptemplate.infohead.biWidth+1;j++)
{
dSumST=0;
dSumS=0;
for(m=0;m<bmptemplate.infohead.biHeight;m++)
{
for(n=0;n<bmptemplate.infohead.biWidth;n++)
{
//原图像第i+m行,第j+n列像素的灰度值
nGraySrc=*(pTo+(i+m)*bmpimage.infohead.biWidth+j+n);
//模板图像第m行,第n列像素的灰度值
nGrayTpl=*(pTemplate+m*bmptemplate.infohead.biWidth+n);
dSumS +=(double)nGraySrc*nGraySrc;
dSumST +=(double)nGraySrc*nGrayTpl;
}
}
R=dSumST/(sqrt(dSumS)*sqrt(dSumT)); //计算相关响应
if(R>MaxR)
{ //与最大相似性比较
MaxR=R;
nMaxX=j;
nMaxY=i;
}
}
}
}
void draw_rectangle(int a)
{
char i=0;
char j=0;
for(i=0;i<bmptemplate.infohead.biHeight;i++)
{
*(bmpimage.imgbuf + (nMaxY + i)*bmpimage.infohead.biWidth + nMaxX) = a;// 矩形左边 画黑线
}
for(i=0;i<bmptemplate.infohead.biHeight;i++)
{
*(bmpimage.imgbuf + (nMaxY + i)*bmpimage.infohead.biWidth + nMaxX + bmptemplate.infohead.biWidth) = a;
// 矩形右边 画黑线
}
for(j=0;j<bmptemplate.infohead.biWidth;j++)
{
*(bmpimage.imgbuf + nMaxY*bmpimage.infohead.biWidth + nMaxX +j) = a;// 矩形上边 画黑线
}
for(j=0;j<bmptemplate.infohead.biWidth;j++)
{
*(bmpimage.imgbuf + (nMaxY+ bmptemplate.infohead.biHeight)*bmpimage.infohead.biWidth + nMaxX +j) = a;
// 矩形下边 画黑线
}
}
int main(void)
{
char filename[15];
int m=0;
unsigned int state;
unsigned char tempData, *pGrayData,*pRGBData;
unsigned int index_data;
*pSICA_SYSCR &= 0xFFDF; // clear bit 5 to unlock core b
//Set_PLL((short)(CCLK/CLK_IN), (short)(CCLK/SCLK));
D_image_init();
// 加载__模板图像数据 bmptemplate;
if(!OpenBmpFile(TEMPLATE_ADDRESS,&bmptemplate))
{
return FALSE;
}
if(!GetBmpHeader(&bmptemplate))
{
return FALSE;
}
if(!Allocbuf(&bmptemplate))
{
return FALSE;
}
if(!ReadBMPData(&bmptemplate))
{
return FALSE;
}
//对27帧图像进行跟踪
for(m=1;m<28;m++)
{
sprintf(filename,"..\\%d.bmp",m);
if(!OpenBmpFile(filename,&bmpimage))
{
return FALSE;
}
if(!GetBmpHeader(&bmpimage))
{
return FALSE;
}
if(!Allocbuf(&bmpimage))
{
return FALSE;
}
if(!ReadBMPData(&bmpimage))
{
return FALSE;
}
TemplateMatch(bmpimage.imgbuf,bmptemplate.imgbuf); // 用模板进行跟踪
// 将模板的四周画上黑线
draw_rectangle(0);
pGrayData = bmpimage.imgbuf;
pRGBData = malloc(bmpimage.infohead.biWidth *bmpimage.infohead.biHeight *3);
for(index_data=0;index_data<(bmpimage.infohead.biWidth*bmpimage.infohead.biHeight);index_data++)
{
pRGBData[index_data*3] = pGrayData[index_data];
pRGBData[index_data*3+1] = pGrayData[index_data];
pRGBData[index_data*3+2] = pGrayData[index_data];
}
state=D_image_show_RGB24((unsigned int)pRGBData, bmpimage.infohead.biWidth, bmpimage.infohead.biHeight);
free(pRGBData);
/* 处理前图像输出到视频设备 */
//state = D_image_show_RGB24((unsigned int)bmpimage.imgbuf, bmpimage.infohead.biWidth, bmpimage.infohead.biHeight);
}
if(!OpenBmpFile(TEMPLATE_END_ADDRESS,&bmpimage))
{
return FALSE;
}
if(!GetBmpHeader(&bmpimage))
{
return FALSE;
}
if(!Allocbuf(&bmpimage))
{
return FALSE;
}
if(!ReadBMPData(&bmpimage))
{
return FALSE;
}
state=D_image_show_RGB24((unsigned int)pRGBData, bmpimage.infohead.biWidth, bmpimage.infohead.biHeight); while (1)
idle();
// return 0;
}
展开阅读全文