美文网首页
opencv运动模板实现

opencv运动模板实现

作者: 碧影江白 | 来源:发表于2017-10-04 21:47 被阅读65次
    #include<opencv2/opencv.hpp>
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <ctype.h>
    //不同的跟踪参数  
    const double MHI_DURATION = 0.5;
    const double MAX_TIME_DELTA = 0.5;
    const double MIN_TIME_DELTA = 0.05;
    // 用于运动检测的循环帧数,与机器速度及FPS设置有关  
    const int N = 2;
    IplImage **buf = 0;//图像数组
    int last = 0;
    // 临时图像  
    IplImage *mhi = 0; // MHI: 运动历史图像  
    IplImage *orient = 0; // 方向  
    IplImage *mask = 0; // 有效的运动掩码  
    IplImage *segmask = 0; // 运动分割映射  
    CvMemStorage* storage = 0; // 临时存储区  // parameters: 
    using namespace std;
    //  img - input video frame  
    //  dst - resultant motion picture  
    //  args - optional parameters  
    void  update_mhi(IplImage* img, IplImage* dst, int diff_threshold){
        double timestamp = (double)clock() / CLOCKS_PER_SEC; // 获取当前时间,以秒为单位  
        CvSize size = cvSize(img->width, img->height); // 获取当前帧尺寸  
        int i, idx1 = last, idx2;
        IplImage* silh;
        CvSeq* seq;
        CvRect comp_rect;
        double count;
        double angle;
        CvPoint center;
        double magnitude;
        CvScalar color;
    
        // 开始时为图像分配内存 or 帧尺寸改变时重新分配内存  
        if (!mhi || mhi->width != size.width || mhi->height != size.height){
            if (buf == 0){
                //为图像数组分配内存
                buf = (IplImage**)malloc(N*sizeof(buf[0]));
                memset(buf, 0, N*sizeof(buf[0]));//均设为0
            }
    
            for (i = 0; i < N; i++){
                //图像数组内的每一个图像都是单通道0数组
                cvReleaseImage(&buf[i]);
                buf[i] = cvCreateImage(size, IPL_DEPTH_8U, 1);
                cvZero(buf[i]);
            }
            //释放各个已用过的图像内容,以便重新写入
            cvReleaseImage(&mhi);
            cvReleaseImage(&orient);
            cvReleaseImage(&segmask);
            cvReleaseImage(&mask);
    
            //将mhi设置为0矩阵
            mhi = cvCreateImage(size, IPL_DEPTH_32F, 1);
            cvZero(mhi);// clear MHI at the beginning  
            orient = cvCreateImage(size, IPL_DEPTH_32F, 1);
            segmask = cvCreateImage(size, IPL_DEPTH_32F, 1);
            mask = cvCreateImage(size, IPL_DEPTH_8U, 1);
        }
    
        //将最后一张图片更新成当前图片
        cvCvtColor(img, buf[last], CV_BGR2GRAY); //RGB帧图像格式转换为gray  
    
        idx2 = (last + 1) % N; // index of (last - (N-1))th frame  
        last = idx2;//往后面移动一个单位,为前一帧图像的所在位置下标
    
        silh = buf[idx2];
        // 相邻两帧的差  
        cvAbsDiff(buf[idx1], buf[idx2], silh);
    
        cvThreshold(silh, silh, diff_threshold, 1, CV_THRESH_BINARY); // 对差图像做二值化  
    
        //去掉影像以更新历史图像,mhi更新,mhi内为一定时间内的差值图像和,二值化黑白图像
        cvUpdateMotionHistory(silh, mhi, timestamp, MHI_DURATION); // 更新运动历史图像
        cvShowImage("mhi",mhi);
        // convert MHI to blue 8u image  
        // cvCvtScale的第四个参数 shift = (MHI_DURATION - timestamp)*255./MHI_DURATION  
        //相当于cvConvertScale(src,dst,scale,shift)
        //计算结果:dst=src*scale+shift
        // 控制帧差的消失速率  ,数组与数组相乘函数,由于不同的时间特性给帧的显示提供渐变作用
        cvCvtScale(mhi, mask, 255. / MHI_DURATION,
            (MHI_DURATION - timestamp)*255. / MHI_DURATION);
    
        cvShowImage("mask", mask);
        cvZero(dst);
        cvMerge(mask, 0, 0, 0, dst);//将几个单通道图像合并为一个多通道图像,只有蓝色
    
        // B,G,R,0 convert to BLUE image  
    
        // 计算运动的梯度方向以及正确的方向掩码  
        // Filter size = 3  
        //参数:在未渐变的图像中去除大梯度
        //历史图像,梯度正确的点,点的梯度方向,梯度值的范围规定
        cvCalcMotionGradient(mhi, mask, orient,
            MAX_TIME_DELTA, MIN_TIME_DELTA, 3);
        cvShowImage("orient", orient);
    
        if (!storage)
            storage = cvCreateMemStorage(0);
        else
            cvClearMemStorage(storage);
    
        // 运动分割: 获得运动部件的连续序列  
        //输入图像,输出图像,内存空间,当前时间,联系时间限制
        seq = cvSegmentMotion(mhi, segmask, storage, timestamp, MAX_TIME_DELTA);
        for (i = -1; i < seq->total; i++){
    
            if (i < 0) {        // 对整幅图像操作  
                //i=-1在序列中无具体操作,故在循环中加入为了得出全局运动的整体运动方向
                //绘制结果应为白色大圆,为整体的运动方向
                comp_rect = cvRect(0, 0, size.width, size.height);
                color = CV_RGB(255, 255, 255);
                magnitude = 100;  // 画线长度以及圆半径的大小控制  
            }
            else {          // 第i个运动组件  
                //分割后的小运动方向标记
                //为红色小圆
                comp_rect = ((CvConnectedComp*)cvGetSeqElem(seq, i))->rect;
                // 去掉小的部分  
                if (comp_rect.width + comp_rect.height < 100)
                    continue;
                color = CV_RGB(255, 0, 0);
                magnitude = 30;
                //if(seq->total > 0) MessageBox(NULL,"Motion Detected",NULL,0);  
            }
            //选择组件ROI 
            //感兴趣区域的设置,当i=-1时为整个图片的大小
            //当i!=-1时,为每一个分割区域的大小
            cvSetImageROI(silh, comp_rect);
            cvSetImageROI(mhi, comp_rect);
            cvSetImageROI(orient, comp_rect);
            cvSetImageROI(mask, comp_rect);
    
            // 在选择的区域内,计算运动方向  --计算全局运动的方向
            angle = cvCalcGlobalOrientation(orient, mask, mhi, timestamp, MHI_DURATION);
            angle = 360.0 - angle;  //adjust for images with top-left origin
            // 在轮廓内计算点数
            // Norm(L1) = 所有像素值的和
            count = cvNorm(silh, 0, CV_L1, 0);
    
            //重置感兴趣区域
            cvResetImageROI(mhi);
            cvResetImageROI(orient);
            cvResetImageROI(mask);
            cvResetImageROI(silh);
    
            // 检查小运动的情形  
            if (count < comp_rect.width*comp_rect.height * 0.05)  //  像素的5%  
                continue;
    
            // 画一个带箭头的记录以表示方向  
            center = cvPoint((comp_rect.x + comp_rect.width / 2), (comp_rect.y + comp_rect.height / 2));
    
            cvCircle(dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0);
            cvLine(dst, center, cvPoint(cvRound(center.x + magnitude*cos(angle*CV_PI / 180)),
                cvRound(center.y - magnitude*sin(angle*CV_PI / 180))),//cvRound四舍五入得到一个整型数字
                color, 3, CV_AA, 0);
        }
    }
    
    int main(){
    
        IplImage* motion = 0;
        CvCapture* capture = 0;
        capture = cvCreateCameraCapture(0);
    
        if (capture){
            IplImage* image = cvQueryFrame(capture);
            cvNamedWindow("Motion", 1);
            for (;;){
                image = cvQueryFrame(capture);
                cvShowImage("Motion",image);
                if (!motion)
                {
                    motion = cvCreateImage(cvSize(image->width, image->height), 8, 3);
                    cvZero(motion);
                    //motion->origin = image->origin;
                }
    
                update_mhi(image, motion, 30);
                cvShowImage("Motion", motion);
    
                char c = cvWaitKey(10);
                if (c == 27)
                {
                    break;
                }
    
            }
            cvReleaseCapture(&capture);
            cvDestroyWindow("Motion");
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:opencv运动模板实现

          本文链接:https://www.haomeiwen.com/subject/ouacyxtx.html