美文网首页
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