opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)...

感兴趣区域、特定区域、框出移动物体的轮廓、越界检测、入侵物体检测、使用 opencv-python库的函数cv2.findContours、cv2.approxPolyDP、cv2.arcLength,利用固定摄像头拍摄的实时视频,框出移动物体的轮廓(即FrogEyes蛙眼移动物体侦测)

对移动目标的轮廓的框选,将使用下面这篇文章提及的方法:

曾伊言:边缘检测,框出物体的轮廓(使用opencv-python的函数cv2.findContours() )​zhuanlan.zhihu.com
opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第1张图片

移动物体框选结果预览(即便镜头被移动了,它也能够自己调整回来,方法后面会讲):

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第2张图片
https://www.zhihu.com/video/997056905654755328

核心代码预览(可以先看看我用到了哪些函数,完整版代码(点击查看)已上传到github):

...
2018-06-30 初版 Yonv1943
2018-07-02 对RrawROI的注释方案,即对region_of_interest_pts 的赋值
传言青蛙蹲在地上不动的时候,将死掉不动的小昆虫摆放在它的眼前,青蛙也无动于衷。而当某些小昆虫在青蛙眼前飞来飞去的时候,青蛙会注意到它们,然后将它们吃了。我这个程序也可“注意到”镜头拍摄到的移动物体,因此我也将它称为 FrogEyes。
这是传统的图像处理(不涉及深度学习),所以 算法的本质是:对固定摄像头前后两帧图片做差值,得到并框出不同的区域(使用opencv-python 的 cv2.findContours()函数) 因此,该方法只适用于固定镜头的移动物体识别,如果拍摄实时图像的时候镜头是移动的,那么此时移动物体的识别就只能交由深度学习去解决了。

不能简单地对比前后两帧的图片

  • 如果简单地对比前后两帧图片,那么对图片做差值,将会得到前后帧图片中不同的区域,这个区域并不是目标的轮廓
  • 如果目标是纯色的,那么对图片做差值得到的结果,将不能得到目标的完整轮廓

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第3张图片
左边是背景图片,右边是实时图片

若将实时图片与背景图片做差值,那么将会得到红色区域

若将实时图片与先前图片做差值,那么将会得到黄色区域

实际情况中,当图片帧率比较高,目标移动速度慢(甚至不移动),由前后两帧图片做对比的算法的黄色区域会非常小。当然可以通过对比更久前的图片(两帧差别更大)来得到更大的不同区域,不过,这样一来,黄色的区域就不是目标的轮廓了,而是目标在两个时段区域的并集。所以,如果事先保存好背景图片,那么就可以将实时图片与背景图片对比,并得到准确的目标轮廓。

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第4张图片
代码的流程图

简单地设置背景图片会来两个新的问题:

  • 相机视角被移动(比如路过的人不小心碰了一下),那么实时图片和背景图片做差值,将会得到整个画面,目标检测失效
  • 背景发生变化,比如镜头中的桌子被移动了,或者环境光突然发生变化,或者有目标进入镜头后,赖着不走,etc. 那么镜头如实将会一直把这变化为框出来,这不智能

这些都是不更新背景图片导致的,所以要设置更新背景图片的策略

下面讲流程图中【对比并有策略地更新背景图片】的策略:

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第5张图片
背景图片更新策略

相关代码

由边缘检测改写而来的函数,它根据输入的两张图片,返回被检测出的目标轮廓,如果两张图片相似,那么就返回一个空列表 [] ,空列表在Python的逻辑判断中,是False,方便背景图片更改的逻辑判断:

def 

位于类EdgeDetection 中的 函数main_get_img_show(),执行更换背景的逻辑判断

...
contours = self.get_polygon_contours(img, self.img_back)  # 这个函数框出并返回目标轮廓

self.img_list.append(img)  # 将实时图片加入历史图片队列
img_prev = self.img_list.pop(0)  # 取出最在的历史图片

# 两个逻辑判断,决定是否更换背景图片
# 一个是背景图片微调,即背景与实时相似的时候,更新背景图片
# 另一个是背景图片更换,当历史图片与实时图片相似的时候,证明背景已经更改一段时间了,因此更新背景
self.img_back = img 
    if not contours or not self.get_polygon_contours(img, img_prev) 
    else self.img_back
...

需要明白的Python小技巧——空列表在Python的逻辑判断中,是False

print("[] is %s" % bool([]))
if []:
    print("[] is True")
else:
    print("[] is False")

如下,被视为背景的卡片移动了,出现两个框,一段时间后红框消失,证明背景图片被更换,伸入手进行测试,其他功能正常:

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第6张图片
https://www.zhihu.com/video/997434329294729216

还有一个对目标轮廓的筛选过程——根据轮廓多边形的边数、周长进行筛选:

...

视频的前面几秒,手指在灰色部分,即ROI(Regin of Interest)以外,没有触发轮廓框选,进入区域后,出现了一个四边形将目标框出,而且周长足够:

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第7张图片
https://www.zhihu.com/video/997459527129841664

(从这个视频中还可以看出,我的移动目标轮廓框选算法还是有疏漏的,比如影子也框进去了、手指退出后,还留有错误的红框)

感兴趣区域的设定

上面也提及了感兴趣区域,这里就顺便贴出用OpenCV-Python的GUI实现的 ROI区域设置代码,这部分代码就是从Drawing filled polygon using mouse events in open cv using python 网页上 Dan Mašek 的答案改写而来。就放在 完整版 DEMO_edge_detction.py 中命名为 DrawROI 的类里面。

感兴趣区域的设定视频 ↓

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第8张图片
https://www.zhihu.com/video/997462804596600832

↑ 视频中的操作:按退格键重新划定ROI ,鼠标点击定义多边形,按enter 确认ROI


应用讨论

移动物体识别的这个特性,在固定摄像头实时视频侦测的时候比较有用,比如:

  1. 监控摄像头,检测到镜头画面有变化(移动物体出现)的时候,才开启记录功能,录下视频,避免记录重复视频,节省磁盘空间。(即电子蛙眼)
  2. 保留前景,过滤掉无关的背景。

比较前后帧像素差异算法的缺点 @朱琦

这种方法受光线变化影响非常大。如果我们只想要检测闯入感兴趣区域的物体,那么这种方法会不可避免地把影子认为是闯入物体。

而深度学习目标检测可以排除这种影响。因此这种算法最好是和深度学习相结合:使用这种像素差异算法进行低准确率的检测,然后使用深度学习进行最终的判断。如:对于画面长时间持续不动的多个摄像头,我们使用像素差异算法进行检测,当检测到有物体闯入时,程序将异常报给给深度学习卷积网络,由它进行把关。(这样子可以减少计算,同时维持判断精度。例如:车库车辆检测,异常闯入检测)。

用在自动生成训练集上:(自从2018年数据集逐渐完善、以及半监督算法的发展,以下方法已经过时)

将要识别的物体放在镜头前,不断地移动物体(最好是换不同高度环绕拍摄),识别出物体轮廓,处理成边缘羽化的png图片,然后和其他背景合成大量训练集(此时可以通过轮廓输出框选完毕的box,再批量创建label,自动导出成为xml格式,就可以为所欲为了)(可以看我的另外一篇:利用初步训练的深度学习模型自动生成训练图片,包括csv文件、Python字典、TensorFlow目标检测训练图片xml注释 相互转换(还没写完))

用传统图像识别将目标准确框出,并过滤掉背景,传给目标检测模型,甚至可以取代目标检测提取候选框的那一步,将目标检测的工作,从:

生成候选框 → 分类器处理多个候选框,得到类别匹配度信息 →
计算匹配度,筛选出得分高的目标 → 调整对应候选框的位置 →
输出目标及对应的候选框

简化为:

传统图形识别框出待分类的目标移动目标 →
分类器计算目标匹配度,判断目标类别 →
输出目标轮廓,以及目标的类别

简化的内容如下:

  • 简化目标检测的任务:从“判断目标位置,确定目标类型”简化为“判断目标类型”
  • 处理的图片变小了:从原来的全图检测 缩减为对移动目标对应图片的检测
  • 减小背景的影响:框出移动目标轮廓,并删去背景,减少了影响分类判断的干扰因素

在缩小了目标检测应用范围的情况下(只能用来检测固定镜头的移动物体/入侵物体,用在安防摄像头上面最好了),预计这样子处理可以减少计算量,提高检测准确率。

用在固定摄像头实时目标检测上:(自2018年Mask-RCNN发展成熟后,以下方法已过时)

移动物体框选结果预览(深度学习结合目标检测结合(这里用的是Yolo目标检测),假装把segmentation 做出来了)

opencv函数findcontours_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)..._第9张图片

参考资料:

边缘检测,框出物体的轮廓(使用opencv-python的函数cv2.findContours() )

Drawing filled polygon using mouse events in open cv using python


在评论区指出的问题,我会修改到正文中,并注明贡献者的名字。

在评论区提出的问题,我可能会尝试解答,并添加到正文中。

交流可以促进社区与自身成长,欢迎评论,谢谢大家。

你可能感兴趣的:(python,opencv,findcontours,python,opencv,规定区域手势识别,准确检测图像的轮廓,opencv)