粒子滤波跟踪算法

    xiaoxiao2022-07-06  220

    #include <opencv2/core/core.hpp> #include "opencv2/imgproc/imgproc.hpp" #include <opencv2/highgui/highgui.hpp> #include <stdio.h> #include <iostream>

    using namespace cv; using namespace std;

    Rect select; bool select_flag = false; bool tracking = false;//跟踪标志位 bool select_show = false; Point origin; Mat frame, hsv; int after_select_frames = 0;//选择矩形区域完后的帧计数

    /****rgb空间用到的变量****/ //int hist_size[]={16,16,16};//rgb空间各维度的bin个数 //float rrange[]={0,255.0}; //float grange[]={0,255.0}; //float brange[]={0,255.0}; //const float *ranges[] ={rrange,grange,brange};//range相当于一个二维数组指针

    /****hsv空间用到的变量****/ int hist_size[] = { 16, 16, 16 }; float hrange[] = { 0, 180.0 }; float srange[] = { 0, 256.0 }; float vrange[] = { 0, 256.0 };

    //int hist_size[]={32,32,32}; //float hrange[]={0,359.0.0}; //float srange[]={0,1.0}; //float vrange[]={0,1.0}; const float *ranges[] = { hrange, srange, vrange };

    int channels[] = { 0, 1, 2 };

    /****有关粒子窗口变化用到的相关变量****/ int A1 = 2; int A2 = -1; int B0 = 1; double sigmax = 1.0; double sigmay = 0.5; double sigmas = 0.001;

    /****定义使用粒子数目宏****/ #define PARTICLE_NUMBER 100 //如果这个数设定太大,经测试这个数字超过25就会报错,则在运行时将会出现错误

    /****定义粒子结构体****/ typedef struct particle {     int orix, oriy;//原始粒子坐标     int x, y;//当前粒子的坐标     double scale;//当前粒子窗口的尺寸     int prex, prey;//上一帧粒子的坐标     double prescale;//上一帧粒子窗口的尺寸     Rect rect;//当前粒子矩形窗口     Mat hist;//当前粒子窗口直方图特征     double weight;//当前粒子权值 }PARTICLE;

    PARTICLE particles[PARTICLE_NUMBER];

    /************************************************************************************************************************/ /****                            如果采用这个onMouse()函数的话,则可以画出鼠标拖动矩形框的4种情形                        ****/ /************************************************************************************************************************/ void onMouse(int event, int x, int y, int, void*) {     //Point origin;//不能在这个地方进行定义,因为这是基于消息响应的函数,执行完后origin就释放了,所以达不到效果。     if (select_flag)     {         select.x = MIN(origin.x, x);//不一定要等鼠标弹起才计算矩形框,而应该在鼠标按下开始到弹起这段时间实时计算所选矩形框         select.y = MIN(origin.y, y);         select.width = abs(x - origin.x);//算矩形宽度和高度         select.height = abs(y - origin.y);         select &= Rect(0, 0, frame.cols, frame.rows);//保证所选矩形框在视频显示区域之内

            //        rectangle(frame,select,Scalar(0,0,255),3,8,0);//显示手动选择的矩形框     }     if (event == CV_EVENT_LBUTTONDOWN)     {         select_flag = true;//鼠标按下的标志赋真值         tracking = false;         select_show = true;         after_select_frames = 0;//还没开始选择,或者重新开始选择,计数为0         origin = Point(x, y);//保存下来单击是捕捉到的点         select = Rect(x, y, 0, 0);//这里一定要初始化,因为在opencv中Rect矩形框类内的点是包含左上角那个点的,但是不含右下角那个点。     }     else if (event == CV_EVENT_LBUTTONUP)     {         select_flag = false;         tracking = true;         select_show = false;         after_select_frames = 1;//选择完后的那一帧当做第1帧     } }

    /****粒子权值降序排列函数****/ int particle_decrease(const void *p1, const void *p2) {     PARTICLE* _p1 = (PARTICLE*)p1;     PARTICLE* _p2 = (PARTICLE*)p2;     if (_p1->weight<_p2->weight)         return 1;     else if (_p1->weight>_p2->weight)         return -1;     return 0;//相等的情况下返回0 }

    int main(int argc, unsigned char* argv[]) {     char c;     Mat target_img, track_img;     Mat target_hist, track_hist;     PARTICLE *pParticle;

        /***打开摄像头****/     VideoCapture cam(0);     if (!cam.isOpened())         return -1;

        /****读取一帧图像****/     cam >> frame;     if (frame.empty())         return -1;

        VideoWriter output_dst("demo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 10, frame.size(), 1);

        /****建立窗口****/     namedWindow("camera", 1);//显示视频原图像的窗口

        /****捕捉鼠标****/     setMouseCallback("camera", onMouse, 0);

        while (1)     {         /****读取一帧图像****/         cam >> frame;         if (frame.empty())             return -1;

            /****将rgb空间转换为hsv空间****/         cvtColor(frame, hsv, CV_BGR2HSV);

            if (tracking)         {

                if (1 == after_select_frames)//选择完目标区域后             {                 /****计算目标模板的直方图特征****/                 target_img = Mat(hsv, select);//在此之前先定义好target_img,然后这样赋值也行,要学会Mat的这个操作                 calcHist(&target_img, 1, channels, Mat(), target_hist, 3, hist_size, ranges);                 normalize(target_hist, target_hist);

                    /****初始化目标粒子****/                 pParticle = particles;//指针初始化指向particles数组                 for (int x = 0; x<PARTICLE_NUMBER; x++)                 {                     pParticle->x = cvRound(select.x + 0.5*select.width);//选定目标矩形框中心为初始粒子窗口中心                     pParticle->y = cvRound(select.y + 0.5*select.height);                     pParticle->orix = pParticle->x;//粒子的原始坐标为选定矩形框(即目标)的中心                     pParticle->oriy = pParticle->y;                     pParticle->prex = pParticle->x;//更新上一次的粒子位置                     pParticle->prey = pParticle->y;                     pParticle->rect = select;                     pParticle->prescale = 1;                     pParticle->scale = 1;                     pParticle->hist = target_hist;                     pParticle->weight = 0;                     pParticle++;                 }             }             else if (2 == after_select_frames)//从第二帧开始就可以开始跟踪了             {                 double sum = 0.0;                 pParticle = particles;                 RNG rng;//随机数产生器

                    /****更新粒子结构体的大部分参数****/                 for (int i = 0; i<PARTICLE_NUMBER; i++)                 {                     int x, y;                     int xpre, ypre;                     double s, pres;

                        xpre = pParticle->x;                     ypre = pParticle->y;                     pres = pParticle->scale;

                        /****更新粒子的矩形区域即粒子中心****/                     x = cvRound(A1*(pParticle->x - pParticle->orix) + A2*(pParticle->prex - pParticle->orix) +                         B0*rng.gaussian(sigmax) + pParticle->orix);                     pParticle->x = max(0, min(x, frame.cols - 1));

                        y = cvRound(A1*(pParticle->y - pParticle->oriy) + A2*(pParticle->prey - pParticle->oriy) +                         B0*rng.gaussian(sigmay) + pParticle->oriy);                     pParticle->y = max(0, min(y, frame.rows - 1));

                        s = A1*(pParticle->scale - 1) + A2*(pParticle->prescale - 1) + B0*(rng.gaussian(sigmas)) + 1.0;                     pParticle->scale = max(1.0, min(s, 3.0));

                        pParticle->prex = xpre;                     pParticle->prey = ypre;                     pParticle->prescale = pres;                     //        pParticle->orix=pParticle->orix;                     //        pParticle->oriy=pParticle->oriy;

                        //注意在c语言中,x-1.0,如果x是int型,则这句语法有错误,但如果前面加了cvRound(x-0.5)则是正确的                     pParticle->rect.x = max(0, min(cvRound(pParticle->x - 0.5*pParticle->scale*pParticle->rect.width), frame.cols));                     pParticle->rect.y = max(0, min(cvRound(pParticle->y - 0.5*pParticle->scale*pParticle->rect.height), frame.rows));                     pParticle->rect.width = min(cvRound(pParticle->rect.width), frame.cols - pParticle->rect.x);                     pParticle->rect.height = min(cvRound(pParticle->rect.height), frame.rows - pParticle->rect.y);                     //        pParticle->rect.width=min(cvRound(pParticle->scale*pParticle->rect.width),frame.cols-pParticle->rect.x);                     //        pParticle->rect.height=min(cvRound(pParticle->scale*pParticle->rect.height),frame.rows-pParticle->rect.y);

                        /****计算粒子区域的新的直方图特征****/                     track_img = Mat(hsv, pParticle->rect);                     calcHist(&track_img, 1, channels, Mat(), track_hist, 3, hist_size, ranges);                     normalize(track_hist, track_hist);

                        /****更新粒子的权值****/                     //            pParticle->weight=compareHist(target_hist,track_hist,CV_COMP_INTERSECT);                     //采用巴氏系数计算相似度,永远与最开始的那一目标帧相比较                     pParticle->weight = 1.0 - compareHist(target_hist, track_hist, CV_COMP_BHATTACHARYYA);                     /****累加粒子权值****/                     sum += pParticle->weight;                     pParticle++;                 }

                    /****归一化粒子权重****/                 pParticle = particles;                 for (int i = 0; i<PARTICLE_NUMBER; i++)                 {                     pParticle->weight /= sum;                     pParticle++;                 }

                    /****根据粒子的权值降序排列****/                 pParticle = particles;                 qsort(pParticle, PARTICLE_NUMBER, sizeof(PARTICLE), &particle_decrease);

                    /****根据粒子权重重采样粒子****/                 PARTICLE newParticle[PARTICLE_NUMBER];                 int np = 0, k = 0;                 for (int i = 0; i<PARTICLE_NUMBER; i++)                 {                     np = cvRound(pParticle->weight*PARTICLE_NUMBER);                     for (int j = 0; j<np; j++)                     {                         newParticle[k++] = particles[i];                         if (k == PARTICLE_NUMBER)                             goto EXITOUT;                     }                 }                 while (k<PARTICLE_NUMBER)                     newParticle[k++] = particles[0];             EXITOUT:                 for (int i = 0; i<PARTICLE_NUMBER; i++)                     particles[i] = newParticle[i];             }//end else

                //????????这个排序很慢,粒子数一多就卡             //    qsort(pParticle,PARTICLE_NUMBER,sizeof(PARTICLE),&particle_decrease);

                /****计算粒子期望,采用所有粒子位置的期望值做为跟踪结果****/             /*Rect_<double> rectTrackingTemp(0.0,0.0,0.0,0.0);             pParticle=particles;             for(int i=0;i<PARTICLE_NUMBER;i++)             {             rectTrackingTemp.x+=pParticle->rect.x*pParticle->weight;             rectTrackingTemp.y+=pParticle->rect.y*pParticle->weight;             rectTrackingTemp.width+=pParticle->rect.width*pParticle->weight;             rectTrackingTemp.height+=pParticle->rect.height*pParticle->weight;             pParticle++;             }*/

                /****计算最大权重目标的期望位置,作为跟踪结果****/             Rect rectTrackingTemp(0, 0, 0, 0);             pParticle = particles;             rectTrackingTemp.x = pParticle->x - 0.5*pParticle->rect.width;             rectTrackingTemp.y = pParticle->y - 0.5*pParticle->rect.height;             rectTrackingTemp.width = pParticle->rect.width;             rectTrackingTemp.height = pParticle->rect.height;

                /****计算最大权重目标的期望位置,采用权值最大的1/4个粒子数作为跟踪结果****/             /*Rect rectTrackingTemp(0,0,0,0);             double weight_temp=0.0;             pParticle=particles;             for(int i=0;i<PARTICLE_NUMBER/4;i++)             {             weight_temp+=pParticle->weight;             pParticle++;             }             pParticle=particles;             for(int i=0;i<PARTICLE_NUMBER/4;i++)             {             pParticle->weight/=weight_temp;             pParticle++;             }             pParticle=particles;             for(int i=0;i<PARTICLE_NUMBER/4;i++)             {             rectTrackingTemp.x+=pParticle->rect.x*pParticle->weight;             rectTrackingTemp.y+=pParticle->rect.y*pParticle->weight;             rectTrackingTemp.width+=pParticle->rect.width*pParticle->weight;             rectTrackingTemp.height+=pParticle->rect.height*pParticle->weight;             pParticle++;             }*/

                /****计算最大权重目标的期望位置,采用所有粒子数作为跟踪结果****/             /*Rect rectTrackingTemp(0,0,0,0);             pParticle=particles;             for(int i=0;i<PARTICLE_NUMBER;i++)             {             rectTrackingTemp.x+=cvRound(pParticle->rect.x*pParticle->weight);             rectTrackingTemp.y+=cvRound(pParticle->rect.y*pParticle->weight);             pParticle++;             }             pParticle=particles;             rectTrackingTemp.width = pParticle->rect.width;             rectTrackingTemp.height = pParticle->rect.height;*/

                //创建目标矩形区域             Rect tracking_rect(rectTrackingTemp);

                pParticle = particles;

                /****显示各粒子运动结果****/             for (int m = 0; m<PARTICLE_NUMBER; m++)             {                 rectangle(frame, pParticle->rect, Scalar(255, 0, 0), 1, 8, 0);                 pParticle++;             }

                /****显示跟踪结果****/             rectangle(frame, tracking_rect, Scalar(0, 0, 255), 3, 8, 0);

                after_select_frames++;//总循环每循环一次,计数加1             if (after_select_frames>2)//防止跟踪太长,after_select_frames计数溢出                 after_select_frames = 2;         }

            if (select_show)             rectangle(frame, select, Scalar(0, 0, 255), 3, 8, 0);//显示手动选择的矩形框         output_dst << frame;         //显示视频图片到窗口         imshow("camera", frame);

            //    select.zeros();         //键盘响应         c = (char)waitKey(20);         if (27 == c)//ESC键             return -1;     }

        return 0; }

    最新回复(0)