博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Opencv实现运动检测
阅读量:5150 次
发布时间:2019-06-13

本文共 2893 字,大约阅读时间需要 9 分钟。

 

运动检测多种多样,这里的需求只是检测到有运动物体就行了,而且

要尽量减少误报的情况。另外尽量降低CPU的消耗,因为最终需要在树莓派上面运行。

看了一些中文的文章,发现无法很好地理解别人说的内容,反而是外国人写的文章比较实在

这里的思路和代码来自一篇外文博客,原文来自:http://blog.cedric.ws/opencv-simple-motion-detection

 

 

这里博主使用了差值的办法来检测运动。也就是准备三幅图像,分布叫做prev, current 和next

这三幅图像是一个视频的前后三帧。

 

可以这样表示检测的过程:

diff1 = prev - nextdiff2 = current - nextresult = diff1 & diff2

 

 

用opencv的语言来说,就是:

absdiff(prev_frame, next_frame, d1);absdiff(current_frame, next_frame, d2);bitwise_and(d1, d2, result);

 

另外,最后还要加一个阈值,因为很细小的运动,比如窗帘被气流吹动的行为会造成一个误报的

现象,这里主要是需要检测大动作,比如一只小狗走来走去的现象。

threshold(result, result, 35, 255, CV_THRESH_BINARY);

检测的结果如下: 

可以说有初步成效了。

 

下面,可以在上图的白色区域放置一个矩形框(用opencv可以很轻松地做到)

这里博主贴出了代码:

// loop over image and detect changesfor(int j = y_start; j < y_stop; j+=2){ // height    for(int i = x_start; i < x_stop; i+=2){ // width        // check if at pixel (j,i) intensity is equal to 255        // this means that the pixel is different in the sequence        // of images (prev_frame, current_frame, next_frame)        if(static_cast(motion.at
(j,i)) == 255) { number_of_changes++; if(min_x>i) min_x = i; if(max_x
j) min_y = j; if(max_y

从代码里面看,这里遍历了整一幅差值图像(也就是上面的result图),并且将所有为255亮度的

点统计起来,并且生成两个结果:

1.number of changes,也就是变化为100%的点的数量

2.max值和min值,用于在变化周围画矩形

 

这是画矩形的代码:

if(number_of_changes){    //check if not out of bounds    if(min_x-10 > 0) min_x -= 10;    if(min_y-10 > 0) min_y -= 10;    if(max_x+10 < result.cols-1) max_x += 10;    if(max_y+10 < result.rows-1) max_y += 10;    // draw rectangle round the changed pixel    Point x(min_x,min_y);    Point y(max_x,max_y);    Rect rect(x,y);    Mat cropped = result(rect);    cropped.copyTo(result_cropped);    rectangle(result,rect,color,1);}

这里的处理number of changes应该是判断大于某个值的时候再画,因为

可能出现误报。

 

优化

到这里为止,可以得到两个结论:

1.这个算法是比较简单的,也就是CPU消耗比较少。

2.这个算法存在着不足,也就是误报的问题。

 

因为这个算法要应用到树莓派中,所以特别复杂但是精准的办法就不可取。

上面的办法可以做两点优化,第一个是判断number of changes大于某个值的时候再画,

第二个是判断图像中出现移动物体时延迟一段时间后再判断,这样会减少误报。

// If a lot of changes happened, we assume something changed.if(number_of_changes>=there_is_motion){    if(number_of_sequence>0){        saveImg(result,DIR,EXT,DIR_FORMAT.c_str(),FILE_FORMAT.c_str());        saveImg(result_cropped,DIR,EXT,DIR_FORMAT.c_str(),CROPPED_FILE_FORMAT.c_str());    }    number_of_sequence++;}else{    number_of_sequence = 0;    // Delay, wait a 1/2 second.    cvWaitKey (DELAY);}

注意到,这里是检测到了物体再delay,而不是每次都delay。这样会保证整个检测系统的运行

质量。

 

另一个办法是通过标准差来检测先后的变化,当然这个办法会消耗额外的CPU,不过可以试试看

// calculate the standard deviationScalar mean, stddev;meanStdDev(motion, mean, stddev);// if not to much changes then the motion is real (neglect agressive snow, temporary sunlight)if(stddev[0] < max_deviation)

 

 

最后博主给出了代码(github上也有):

https://github.com/cedricve/motion-detection/blob/master/motion_src/src/motion_detection.cpp

 

因为目前没有可用的摄像头,买到之后试试博主的代码并且更新博客。

 

转载于:https://www.cnblogs.com/tanhangbo/p/4293800.html

你可能感兴趣的文章
nginx配置socket服务
查看>>
C语言初学 俩数相除问题
查看>>
B/S和C/S架构的区别
查看>>
[Java] Java record
查看>>
jQuery - 控制元素显示、隐藏、切换、滑动的方法
查看>>
postgresql学习文档
查看>>
Struts2返回JSON数据的具体应用范例
查看>>
js深度克隆对象、数组
查看>>
c++ 贪吃蛇
查看>>
socket阻塞与非阻塞,同步与异步
查看>>
图论求割点模板
查看>>
poj3903 Stock Exchange 二分+dp
查看>>
leetcode 141. Linked List Cycle 、 142. Linked List Cycle II
查看>>
团队工作第二天
查看>>
python escape sequences
查看>>
【转】Odoo:基本字段类型
查看>>
将中文数字转换层阿拉伯数字
查看>>
用C#调用蓝牙编程
查看>>
图片组件——axure线框图部件库介绍
查看>>
恩尼格码的发明和破解
查看>>