智能系统专业实验(五):目标跟踪实验
- 实验目的
通过该实验,初步了解运动目标跟踪算法基本原理,体会并学习如何用该算法实现视频跟踪,并完成模板匹配跟踪部分的程序。
- 实验基本原理及步骤(或方案设计及理论计算)
1、基本原理
模板匹配就是在一幅大图像中搜寻目标,已知在该图中有要寻找的目标,且该目标与模板有相同的尺寸、方向和图像,通过一定的算法可以在图中找到目标,确定其坐标位置。
如图 4-1 所示,设模板T 叠放在搜索图S 上平移,模板覆盖下的那块搜索图叫做子图,这块子图的左上角像素点为S 的坐标,即参考点,从图中可知 i 和 j 的取值范围为:,其中,为被搜索图的大小,为模板T的大小。
现在可以比较T与 的内容,如两者一致,则T 和 之差为零,所以我们可以用下式来衡量T 和的相似程度:
展开上式有:
上式等号右边第三项表示模板的总能量,是一个常数与坐标位置(i, j)无关,第一项是模板覆盖下那块子图的能量,它随(i, j)坐标位置的改变而缓慢改变,这两项都与模板匹配无关。第二项是子图像和模板的互相关,随(i, j)而改变,T和 匹配时该项有最大值。
上式第二项的计算是通过将图像元素和模板图像元素联系起来获得的,将相关元素相乘后累加。现在我们完全可以将模板图像T 视为一个按行或者按列存储的向量,将被T 覆盖的图像区域 视为另一个按照同样的方式存储的向量。这样,相似程度的计算就转换成了向量之间的点积运算。
显然,当和方向相同时,(为向量和的夹角),此时上式取得最大值||和||,即当模板和子图匹配时,相关运算产生最大的响应。但是,上式最终的取值还与向量和自身的模值有关,比如说由于||自身较大而同样能产生一个很高的响应,因此我们需要用向量模值的归一化进行处理。
改进的用于匹配的相关系数计算公式如下:
当模板和子图完全一样时,相关系数R(i, j)=1。在被搜索图中逐个像素点地移动模板图像T ,同时计算每处子图与模板的相关系数,当移过整幅图像S之后,找出R 的最大值,最大响应点坐标 即为最佳匹配的左上角点。以该坐标为起始点,范围大小以模板的大小为准就可以锁定目标。
2、算法步骤
(1)首先取得待跟踪的目标图像,该目标图像通常较小,称该图像为模板,以T 表示;
(2)定义匹配公式以备在移动模板时得到匹配度;
(3)把模板T 在待检测的图像(往往是视频中的一帧帧图像)中移动,在模板覆盖下那块搜索图叫做子图 ,每移动到一个位置就按定义的匹配公式计算匹配度,直至移动完整幅图像为止;
(4)按照匹配度的大小,选择匹配度最大(即最匹配)的位置,此位置即为最佳匹配位置,以此点为起始点,范围的大小就以模板的大小为准,即可锁定目标;
(5)针对视频中的每一帧图像执行步骤(3)~(4),实现目标跟踪的目的。
- 实验结果分析及回答问题(或测试环境及测试结果)
实验图像
实验结果
如上图所示,白框内即为检测目标。
- 实验代码
#include<stdio.h>
#include<cstring>
#include<math.h>
#include<windows.h>
#include <time.h>
#define imageW 120
#define imageH 80
#define TW 52
#define TH 36
int ImagePtr[11][9600];
int image[11][9600];
int Height[11];int Width[11];
int bmpHeight, bmpWidth, biBitCount;
unsigned char *pBmpBuf;
RGBQUAD *pColorTable;
void read_temp(){
const char src1[] = "1.bmp";
const char src2[] = "2.bmp";
const char src3[] = "3.bmp";
const char src4[] = "4.bmp";
const char src5[] = "5.bmp";
const char src6[] = "6.bmp";
const char src7[] = "7.bmp";
const char src8[] = "8.bmp";
const char src9[] = "9.bmp";
const char src10[] = "10.bmp";
const char src11[] = "template.bmp";
for (int photonum = 0;photonum < 11;photonum++){
FILE *fp = fopen(src11, "rb");
if (photonum == 0) fp = fopen(src1, "rb");
else if (photonum == 1) fp = fopen(src2, "rb");
else if (photonum == 2) fp = fopen(src3, "rb");
else if (photonum == 3) fp = fopen(src4, "rb");
else if (photonum == 4) fp = fopen(src5, "rb");
else if (photonum == 5) fp = fopen(src6, "rb");
else if (photonum == 6) fp = fopen(src7, "rb");
else if (photonum == 7) fp = fopen(src8, "rb");
else if (photonum == 8) fp = fopen(src9, "rb");
else if (photonum == 9) fp = fopen(src10, "rb");
if (fp == 0){printf("false\n");}
fseek(fp, sizeof(BITMAPFILEHEADER), 0);
BITMAPINFOHEADER head;
fread(&head, 40, 1, fp);
bmpHeight = head.biHeight;
bmpWidth = head.biWidth;
biBitCount = head.biBitCount;
fseek(fp, sizeof(RGBQUAD), 1);
int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;
pBmpBuf = new unsigned char[LineByte*bmpHeight];
fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
fclose(fp);
int rgbMap[bmpHeight * bmpWidth][3];
for (int i = 0; i < bmpHeight;i++){ //取位图 rgb 三通道数据
for (int j = 0; j < bmpWidth;j++){
unsigned char *tmp;
tmp = pBmpBuf + i * LineByte + j * 3;
rgbMap[i * bmpWidth + j][0] = int(*(tmp));
rgbMap[i * bmpWidth + j][1] = int(*(tmp+1));
rgbMap[i * bmpWidth + j][2] = int(*(tmp+2));
}
}
for (int i = 0; i < bmpHeight * bmpWidth;i++){
ImagePtr[photonum][i] = rgbMap[i][0]*0.299 + rgbMap[i][1]*0.587 + rgbMap[i][2]*0.114;
image[photonum][i] = ImagePtr[photonum][i];
}
Height[photonum] = bmpHeight;
Width[photonum] = bmpWidth;
}
}
void write_temp(){
const char src1[] = "segResultTest1.bmp";
const char src2[] = "segResultTest2.bmp";
const char src3[] = "segResultTest3.bmp";
const char src4[] = "segResultTest4.bmp";
const char src5[] = "segResultTest5.bmp";
const char src6[] = "segResultTest6.bmp";
const char src7[] = "segResultTest7.bmp";
const char src8[] = "segResultTest8.bmp";
const char src9[] = "segResultTest9.bmp";
const char src10[] = "segResultTest10.bmp";
for (int photonum = 0;photonum < 10;photonum++){
FILE *fp1 = fopen(src10, "wb");
if (photonum == 0) fp1 = fopen(src1, "wb");
else if (photonum == 1) fp1 = fopen(src2, "wb");
else if (photonum == 2) fp1 = fopen(src3, "wb");
else if (photonum == 3) fp1 = fopen(src4, "wb");
else if (photonum == 4) fp1 = fopen(src5, "wb");
else if (photonum == 5) fp1 = fopen(src6, "wb");
else if (photonum == 6) fp1 = fopen(src7, "wb");
else if (photonum == 7) fp1 = fopen(src8, "wb");
else if (photonum == 8) fp1 = fopen(src9, "wb");
if (fp1 == 0){
printf("false\n");
}
int LineByte1 = (imageW * 8 / 8 + 3) / 4 * 4;
//修改文件头,其中有两项需要修改,分别为 bfSize 和 bfOffBits
BITMAPFILEHEADER bfhead;
bfhead.bfType = 0x4D42;
bfhead.bfSize = 14 + 40 + 256 * sizeof(RGBQUAD)+LineByte1*imageH;
bfhead.bfReserved1 = 0;
bfhead.bfReserved2 = 0;
bfhead.bfOffBits = 14 + 40 + 256 * sizeof(RGBQUAD);//修改偏移字节数
fwrite(&bfhead, 14, 1, fp1); //将修改后的文件头存入 fp1;
BITMAPINFOHEADER head1;
head1.biBitCount = 8; //将每像素的位数改为 8
head1.biClrImportant = 0;
head1.biCompression = 0;
head1.biClrUsed = 0;
head1.biHeight = imageH;
head1.biWidth = imageW;
head1.biPlanes = 1;
head1.biSize = 40;
head1.biSizeImage = LineByte1*imageH;//修改位图数据的大小
head1.biXPelsPerMeter = 0;
head1.biYPelsPerMeter = 0;
fwrite(&head1, 40, 1, fp1); //将修改后的信息头存入 fp1;
pColorTable = new RGBQUAD[256];
for (int i = 0; i < 256; i++){
pColorTable[i].rgbRed = i;
pColorTable[i].rgbGreen = i;
pColorTable[i].rgbBlue = i; //是颜色表里的 B、G、R 分量都相等,且等于索引值
}
fwrite(pColorTable, sizeof(RGBQUAD), 256, fp1); //将颜色表写入 fp1
//写位图数据
unsigned char *newBmp;
newBmp = new unsigned char[LineByte1*imageH];
for (int i = 0; i < imageH; i++){
for (int j = 0; j < imageW; j++){
unsigned char *pb;
pb = newBmp + i * LineByte1 + j;
*pb = image[photonum][i * imageW + j];
}
}
fwrite(newBmp, LineByte1*imageH, 1, fp1);
fclose(fp1);
}
}
void fun2(){
unsigned int i, j, p, q;
//灰度均衡化
float u_0 = 0;
float U[11];
float Sigma[11];
float sigma_0 = 0;
for(i = 0; i < 11; i++){
float u = 0;
float sigma = 0;
for(j = 0; j < Height[i]; j++){
for(p = 0; p < Width[i]; p++){
u += ImagePtr[i][j * Width[i] + p];
}
}
u = u / (Height[i] * Width[i]);
U[i] = u;
u_0 += u;
for(j = 0; j < Height[i]; j++){
for(p = 0; p < Width[i]; p++){
sigma += pow(ImagePtr[i][j * Width[i] + p] - u, 2);
}
}
sigma = sigma / (Height[i] * Width[i]);
sigma_0 += sigma;
Sigma[i] = sigma;
}
u_0 = u_0 / 11;
sigma_0 = sigma_0 / 11;
for(i = 0; i < 11; i++){
for(j = 0; j < Height[i]; j++){
for(p = 0; p < Width[i]; p++){
ImagePtr[i][j * Width[i] + p] = (sigma_0 / Sigma[i]) * (ImagePtr[i][j * Width[i] + p] - U[i]) + u_0;
}
}
}
float t = 0;
for(i = 0; i < TW * TH; i++){
t += pow(image[10][i], 2);
}
t = sqrt(t);
for(i = 0; i < 10; i++){
int x = 0;
int y = 0;
int ox = 0;
int oy = 0;
float maxR = 0;
while(y < imageH - TH){
x = 0;
while(x < imageW - TW){
float R = 0;
float s = 0;
float st = 0;
for(j = x; j < x + TW; j++){
for(p = y; p < y + TH; p++){
int m = j - x;
int n = p - y;
st += image[i][p * imageW + j] * image[10][n *TW + m];
s += pow(image[i][p * imageW + j], 2);
}
}
s = sqrt(s);
R = st / (s * t);
if(maxR < R){
maxR = R;
ox = x;
oy = y;
}
x += 1;
}
y += 1;
}
// printf("%d %d %d\n",i,ox,oy);
for(j = ox-4; j < ox + TW+4; j++){
for(p = oy - 4; p < oy; p++){
image[i][p * imageW + j] = 255;
}
}
for(j = ox-4; j < ox + TW+4; j++){
for(p = oy + TH; p < oy + TH + 4; p++){
image[i][p * imageW + j] = 255;
}
}
for(j = ox - 4; j < ox; j++){
for(p = oy; p < oy + TH; p++){
image[i][p * imageW + j] = 255;
}
}
for(j = ox + TW; j < ox + TW + 4; j++){
for(p = oy; p < oy + TH; p++){
image[i][p * imageW + j] = 255;
}
}
}
}
int main(){
read_temp();
fun2();
write_temp();
system("pause");
return 0;
}
上一篇: nodejs+angular2实现图片上传功能的示例代码分享
下一篇: 遗传算法求解 函数优化问题