新博客地址:http://gorthon.sinaapp.com/ 要装opencv库 //main.cpp #include"mvfast.h" void main() { IplImage *prev = NULL, *curr = NULL; IplImage *grayA = NULL,*grayB = NULL;//只分配图像头 prev = cvLoadImage("bgr1.jpg", CV_LOAD_IMAGE_UNCHANGED); curr = cvLoadImage("bgr2.jpg", CV_LOAD_IMAGE_UNCHANGED); CvSize size = cvGetSize(prev); grayA = cvCreateImage(size, IPL_DEPTH_8U, 1); grayB = cvCreateImage(size, IPL_DEPTH_8U, 1); cvConvertImage(prev, grayA, 0); cvConvertImage(curr, grayB, 0); /*或者用下面两句也可以得到灰度图 cvCvtColor(prev, grayA, CV_BGR2GRAY);//分配数据,转换成灰度图处理 cvCvtColor(curr, grayB, CV_BGR2GRAY); */ //cvSaveImage("gray1.jpg",grayA); //cvSaveImage("gray2.jpg",grayB); IplImage *result = NULL; result = cvCreateImage(size, IPL_DEPTH_8U, 1); MVFAST(grayA, grayB, result); cvNamedWindow("mvfast", CV_WINDOW_AUTOSIZE); cvShowImage("mvfast", grayB); cvWaitKey(0);//没有这句话程序就会运行完出错。 } 下面是头文件: #include <cv.h> #include <highgui.h> #include <iostream.h> #include <stdlib.h> #define D 15 #define Ts 512//SAD<512时终止搜索 #define LL 1//L<=LL进行SDS,LL<L<LH先LDS再SDS,L>LH进行有条件的SDS #define LH 2 double current_min_sad = -1; //#define BIG 100 //#define SMALL 1 double SAD(uchar* prev_block, uchar* curr_block, int step) { double sum=0; for(int i=0; i<D; i++) for(int j=0; j<D; j++) sum += fabs(*(curr_block + i*step + j) - *(prev_block + i*step + j)); return sum; }//两块的平均绝对帧差和SAD int getLDSMin(double temp1[9]) { int min1 = 0; double temp2[9];//求MAD最小值,最小值存放在末尾即temp2[8]中 for(int i = 0; i<9; i++) temp2[i] = temp1[i]; double s = 0; for(i=0; i<8; i++) if(temp2[i] < temp2[i+1]) { s = temp2[i]; temp2[i] = temp2[i+1]; temp2[i+1] = s; } current_min_sad = temp2[8]; for(i=0; i<9; i++) if(temp2[8] == temp1[i]) return i;//返回最小值在temp1中index return 0; } int getSDSMin(double temp1[5]) { int min1 = 0; double temp2[5];//求MAD最小值,最小值存放在末尾即temp2[4]中 for(int i = 0; i<5; i++) temp2[i] = temp1[i]; double s = 0; for(i=0; i<4; i++) if(temp2[i] < temp2[i+1]) { s = temp2[i]; temp2[i] = temp2[i+1]; temp2[i+1] = s; } current_min_sad = temp2[4]; for(i=0; i<5; i++) if(temp2[4] == temp1[i]) return i;//返回最小值在temp1中index return 0; } int LDS(uchar* prev_block, uchar* cur_block, int step) { /************************************************************************/ /* 大菱形搜索 : Large Diamond Search */ /************************************************************************/ double temp1[9];//temp1数组存放搜索的九个SAD值 uchar*cb[] = {cur_block, cur_block - 2*step, cur_block - step + 1, cur_block + 2, / cur_block + step + 1, cur_block + 2*step, cur_block + step - 1, cur_block - 2, cur_block - step - 1}; //分别代表当前块: //【中心点】,中心点【上边】第二点,中心点【右上】点,中心点【右边】第二点 //中心点【右下】点,中心点【下边】第二点,中心点【左下】点,中心点【左边】第二点,中心点【左上】点 for (int i=0; i<9; i++) { temp1[i] = SAD(prev_block, cb[i], step); if(temp1[i]<Ts) { current_min_sad = temp1[i]; return i; } } return getLDSMin(temp1);//返回temp1中最小值的index } int SDS(uchar* prev_block, uchar* cur_block, int step) { /************************************************************************/ /* 小菱形搜索 : Small Diamond Search */ /************************************************************************/ double temp1[5];//temp1数组存放搜索的5个块的SAD值 uchar*cb[5] = {cur_block, cur_block - step, cur_block + 1, cur_block + step, cur_block - 1}; //分别代表当前块: //【中心点】,中心点【上边】点,中心点【右边】点,中心点【下边】点,中心点【左边】点 for (int i=0; i<5; i++) { temp1[i] = SAD(prev_block, cb[i], step); if(temp1[i]<Ts) { current_min_sad = temp1[i]; return i; } } return getSDSMin(temp1);//返回temp1中最小值的index } struct Block { int min_sad_index;//记录每一块最小的sad的index double min_sad;//最小的sad值 int search_type;//记录每块搜索结束类型(小菱形还是大菱形) CvPoint mv;//运动矢量 }; void MVFAST(IplImage* pre, IplImage* cur, IplImage *result)//运动矢量场自适应搜索技术 { uchar *cur_data = (uchar*)(cur->imageData);//当前帧的【像素集】 uchar *pre_data = (uchar*)(pre->imageData);//上一帧的【像素集】 uchar* cur_block = NULL; //当前帧的【当前块】 uchar* pre_block = NULL; //上一帧的【当前块】 uchar *left_block = NULL; //上一帧当前块的【左边块】 uchar *up_block = NULL; //上一帧当前块的 【上边块】 uchar *rightup_block = NULL; //上一帧当前块的 【右上块】 CvSize size = cvGetSize(pre); int height = size.height; int width = size.width; int step = pre->widthStep; int i = 0, j = 0;//循环变量 int x = D / 2 , y = D / 2;//【当前帧】中心坐标 int min_index_temp = 0;//临时SAD最小值的index int Lleft = 0, Lup = 0, Lrightup = 0; uchar *result_data = (uchar*)(result->imageData); for (i=0; i<height; i++) for (j=0; j<width; j++) *(result_data + i*width + j) = 255;//白色背景填充 int BI = height / D;//将图像分为【 BI(纵向)* BJ(横向)】块,每块(搜索窗)大小D*D int BJ = width / D; Block *block = new Block[BI*BJ]; for (i=0; i<BI; i++) for (j=0; j<BJ; j++) { block[i * D + j].mv.x = 0; block[i * D + j].mv.y = 0; } for (i=0; i<BI; i++) { for (j=0; j<BJ; j++)//第[i][j]块 { int cx = x = j * D + D / 2; int cy = y = i * D + D / 2; pre_block = (pre_data + i * D * step + j * D) + (step * (D / 2) + D / 2);//【前一帧】第[BI][BJ]块的【起始位置】+【D/2偏置】得到【中心点】 cur_block = (cur_data + i * D * step + j * D) + (step * (D / 2) + D / 2);//【当前帧】第[BI][BJ]块的【起始位置】+【D/2偏置】得到【中心点】 block[i * D + j].min_sad = SAD(pre_block, cur_block, step); if(block[i * D + j].min_sad < Ts)//中心点SAD小于阈值Ts,则停止搜索 { block[i * D + j].mv.x = 0;//dx = 0 block[i * D + j].mv.y = 0;//dy = 0 block[i * D + j].min_sad_index = 0; //block[i * D + j].search_type = BIG; cvLine(result, cvPoint(x, y), cvPoint(x,y),CV_RGB(0,0,0), 1, 8, 0); continue; } else { //计算前一帧的3块的L值: if (i>0 && j>0 && i<BI-1 && j<BJ-1)//3块存在时,计算相应的L。不存在时相应L为0(已初始化)。 { Lleft = abs(block[i * D + j - 1].mv.x) + abs(block[i * D + j - 1].mv.y); Lup = abs(block[(i - 1) * D + j - 1].mv.x) + abs(block[(i - 1) * D + j - 1].mv.y); Lrightup = abs(block[(i - 1) * D + j + 1].mv.x) + abs(block[(i - 1) * D + j + 1].mv.y); } int L = Lleft > Lup ? Lleft : Lup; L = L > Lrightup ? L : Lrightup; if (L < LL)//情况1:SDS { int counter = 0; min_index_temp = 1; while(counter < 6 && min_index_temp != 0)//6次小菱形搜索 { counter ++; min_index_temp = SDS(pre_block, cur_block, step); //block[i * D + j].search_type = SMALL; block[i * D + j].min_sad = current_min_sad; switch(min_index_temp) { case 0:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 0;y = y;x = x;break; case 1:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = -1;block[i * D + j].min_sad_index = 1;y = y - 1;x = x;break; case 2:block[i * D + j].mv.x = 1;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 2;y = y;x = x + 1;break; case 3:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 1;block[i * D + j].min_sad_index = 3;y = y + 1;x = x;break; case 4:block[i * D + j].mv.x = -1;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index =4;y = y;x = x - 1;break; } }//end while }//end if,情况1结束 else if (L>LL && L<LH)//情况2:LDS+SDS { int counter = 0; min_index_temp = LDS(pre_block, cur_block, step); block[i * D + j].min_sad = current_min_sad; if(min_index_temp != 0)//不在大菱形中心,则最多再进行3次搜索 while(counter<3) { min_index_temp = LDS(pre_block, cur_block, step); counter++; //block[i * D + j].search_type = BIG; switch(min_index_temp) { case 1:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = -2;block[i * D + j].min_sad_index = 1;y = y - 2;x = x;break; case 2:block[i * D + j].mv.x = 1;block[i * D + j].mv.y = -1;block[i * D + j].min_sad_index = 2;y = y - 1;x = x + 1;break; case 3:block[i * D + j].mv.x = 2;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 3;y = y;x = x + 2;break; case 4:block[i * D + j].mv.x = 1;block[i * D + j].mv.y = 1;block[i * D + j].min_sad_index = 4;y = y + 1;x = x + 1;break; case 5:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 2;block[i * D + j].min_sad_index = 5;y = y + 2;x = x;break; case 6:block[i * D + j].mv.x = -1;block[i * D + j].mv.y = 1;block[i * D + j].min_sad_index = 6;y = y + 1;x = x - 1;break; case 7:block[i * D + j].mv.x = -2;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 7;y = y;x = x - 2;break; case 8:block[i * D + j].mv.x = -1;block[i * D + j].mv.y = -1;block[i * D + j].min_sad_index = 8;y = y - 1;x = x - 1;break; } }//end while else //在大菱形中心,再进行小菱形搜索 { switch(min_index_temp)//将中心点转移到sad最小值那个像素点上去 { case 1:cur_block = cur_data - 2*step;break; case 2:cur_block = cur_data - step + 1;break; case 3:cur_block = cur_data + 2;break; case 4:cur_block = cur_data + step + 1;break; case 5:cur_block = cur_data + 2*step;break; case 6:cur_block = cur_data + step -1;break; case 7:cur_block = cur_data - 2;break; case 8:cur_block = cur_data - step - 1;break; } counter = 0; min_index_temp = SDS(pre_block, cur_block, step); while(min_index_temp != 0 && counter<6)//最多6次小菱形 { counter++; min_index_temp = SDS(pre_block, cur_block, step); //block[i * D + j].search_type = SMALL; block[i * D + j].min_sad = current_min_sad; switch(min_index_temp) { case 0:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 0;y = y;x = x;break; case 1:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = -1;block[i * D + j].min_sad_index = 1;y = y - 1;x = x;break; case 2:block[i * D + j].mv.x = 1;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 2;y = y;x = x + 1;break; case 3:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 1;block[i * D + j].min_sad_index = 3;y = y + 1;x = x;break; case 4:block[i * D + j].mv.x = -1;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 4;y = y;x = x - 1;break; } }//end while } }//end elif,情况2结束 else//情况3:SDS { double up_sad_min = block[i * (D - 1) + j].min_sad;//上块最小的sad double rightup_sad_min = block[i * (D - 1) + j +1].min_sad;//右上 double left_sad_min = block[i * D + j - 1].min_sad;//左 double sad_min3 = up_sad_min < rightup_sad_min ? up_sad_min : rightup_sad_min; sad_min3 = sad_min3 < left_sad_min ? sad_min3 : left_sad_min;//3个当中的最小值 //计算新的中心点: CvPoint mv;//运动矢量 if (sad_min3 == up_sad_min) { mv.x = block[i * (D - 1) + j].mv.x; mv.y = block[i * (D - 1) + j].mv.y; } else if (sad_min3 == rightup_sad_min) { mv.x = block[i * (D - 1) + j +1].mv.x; mv.y = block[i * (D - 1) + j +1].mv.y; } else { mv.x = block[i * D + j - 1].mv.x; mv.y = block[i * D + j - 1].mv.y; } cur_block = (cur_data + i * (D - 1) * step + j * (D - 1)) + (step * (D / 2) + D / 2) + mv.x * D * step + mv.y * D;//3块中sad最小的那个坐标为中心 int couter = 0; min_index_temp = 1; while(couter<6 && min_index_temp != 0)//最多再6次小菱形 { couter++; min_index_temp = SDS(pre_block, cur_block, step); //block[i * D + j].search_type = SMALL; block[i * D + j].min_sad = current_min_sad; switch(min_index_temp) { case 0:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 0;y = y;x = x;break; case 1:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = -1;block[i * D + j].min_sad_index = 1;y = y - 1;x = x;break; case 2:block[i * D + j].mv.x = 1;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 2;y = y;x = x + 1;break; case 3:block[i * D + j].mv.x = 0;block[i * D + j].mv.y = 1;block[i * D + j].min_sad_index = 3;y = y + 1;x = x;break; case 4:block[i * D + j].mv.x = -1;block[i * D + j].mv.y = 0;block[i * D + j].min_sad_index = 4;y = y;x = x - 1;break; } }//end while }//情况3结束 } cvLine(result, cvPoint(cx, cy), cvPoint(cx, cy), CV_RGB(0,0,0), 3, 8, 0); cvLine(result, cvPoint(cx, cy), cvPoint(x, y), CV_RGB(0,0,0), 1, 8, 0); }//end for j }//end for i /************************************************************************/ /* 完成自适应 */ /************************************************************************/ delete []block; }