对移动目标的轮廓的框选,将使用下面这篇文章提及的方法:
曾伊言:边缘检测,框出物体的轮廓(使用opencv-python的函数cv2.findContours() )zhuanlan.zhihu.com移动物体框选结果预览(即便镜头被移动了,它也能够自己调整回来,方法后面会讲):
https://www.zhihu.com/video/997056905654755328核心代码预览(可以先看看我用到了哪些函数,完整版代码(点击查看)已上传到github):
...
2018-06-30 初版 Yonv1943
2018-07-02 对RrawROI的注释方案,即对region_of_interest_pts 的赋值
传言青蛙蹲在地上不动的时候,将死掉不动的小昆虫摆放在它的眼前,青蛙也无动于衷。而当某些小昆虫在青蛙眼前飞来飞去的时候,青蛙会注意到它们,然后将它们吃了。我这个程序也可“注意到”镜头拍摄到的移动物体,因此我也将它称为 FrogEyes。
这是传统的图像处理(不涉及深度学习),所以 算法的本质是:对固定摄像头前后两帧图片做差值,得到并框出不同的区域(使用opencv-python 的 cv2.findContours()函数) 因此,该方法只适用于固定镜头的移动物体识别,如果拍摄实时图像的时候镜头是移动的,那么此时移动物体的识别就只能交由深度学习去解决了。
若将实时图片与背景图片做差值,那么将会得到红色区域
若将实时图片与先前图片做差值,那么将会得到黄色区域
实际情况中,当图片帧率比较高,目标移动速度慢(甚至不移动),由前后两帧图片做对比的算法的黄色区域会非常小。当然可以通过对比更久前的图片(两帧差别更大)来得到更大的不同区域,不过,这样一来,黄色的区域就不是目标的轮廓了,而是目标在两个时段区域的并集。所以,如果事先保存好背景图片,那么就可以将实时图片与背景图片对比,并得到准确的目标轮廓。
代码的流程图简单地设置背景图片会来两个新的问题:
这些都是不更新背景图片导致的,所以要设置更新背景图片的策略
由边缘检测改写而来的函数,它根据输入的两张图片,返回被检测出的目标轮廓,如果两张图片相似,那么就返回一个空列表 [] ,空列表在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")
如下,被视为背景的卡片移动了,出现两个框,一段时间后红框消失,证明背景图片被更换,伸入手进行测试,其他功能正常:
https://www.zhihu.com/video/997434329294729216还有一个对目标轮廓的筛选过程——根据轮廓多边形的边数、周长进行筛选:
...
视频的前面几秒,手指在灰色部分,即ROI(Regin of Interest)以外,没有触发轮廓框选,进入区域后,出现了一个四边形将目标框出,而且周长足够:
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 的类里面。
感兴趣区域的设定视频 ↓
https://www.zhihu.com/video/997462804596600832↑ 视频中的操作:按退格键重新划定ROI ,鼠标点击定义多边形,按enter 确认ROI
应用讨论
移动物体识别的这个特性,在固定摄像头实时视频侦测的时候比较有用,比如:
比较前后帧像素差异算法的缺点 @朱琦
这种方法受光线变化影响非常大。如果我们只想要检测闯入感兴趣区域的物体,那么这种方法会不可避免地把影子认为是闯入物体。
而深度学习目标检测可以排除这种影响。因此这种算法最好是和深度学习相结合:使用这种像素差异算法进行低准确率的检测,然后使用深度学习进行最终的判断。如:对于画面长时间持续不动的多个摄像头,我们使用像素差异算法进行检测,当检测到有物体闯入时,程序将异常报给给深度学习卷积网络,由它进行把关。(这样子可以减少计算,同时维持判断精度。例如:车库车辆检测,异常闯入检测)。
用在自动生成训练集上:(自从2018年数据集逐渐完善、以及半监督算法的发展,以下方法已经过时)
将要识别的物体放在镜头前,不断地移动物体(最好是换不同高度环绕拍摄),识别出物体轮廓,处理成边缘羽化的png图片,然后和其他背景合成大量训练集(此时可以通过轮廓输出框选完毕的box,再批量创建label,自动导出成为xml格式,就可以为所欲为了)(可以看我的另外一篇:利用初步训练的深度学习模型自动生成训练图片,包括csv文件、Python字典、TensorFlow目标检测训练图片xml注释 相互转换(还没写完))
用传统图像识别将目标准确框出,并过滤掉背景,传给目标检测模型,甚至可以取代目标检测提取候选框的那一步,将目标检测的工作,从:
生成候选框 → 分类器处理多个候选框,得到类别匹配度信息 →
计算匹配度,筛选出得分高的目标 → 调整对应候选框的位置 →
输出目标及对应的候选框
简化为:
传统图形识别框出待分类的目标移动目标 →
分类器计算目标匹配度,判断目标类别 →
输出目标轮廓,以及目标的类别
简化的内容如下:
在缩小了目标检测应用范围的情况下(只能用来检测固定镜头的移动物体/入侵物体,用在安防摄像头上面最好了),预计这样子处理可以减少计算量,提高检测准确率。
用在固定摄像头实时目标检测上:(自2018年Mask-RCNN发展成熟后,以下方法已过时)
移动物体框选结果预览(深度学习结合目标检测结合(这里用的是Yolo目标检测),假装把segmentation 做出来了)
参考资料:
边缘检测,框出物体的轮廓(使用opencv-python的函数cv2.findContours() )
Drawing filled polygon using mouse events in open cv using python
在评论区指出的问题,我会修改到正文中,并注明贡献者的名字。
在评论区提出的问题,我可能会尝试解答,并添加到正文中。
交流可以促进社区与自身成长,欢迎评论,谢谢大家。