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

对移动目标的轮廓的框选,将使用下面这篇文章提及的方法:曾伊言:边缘检测,框出物体的轮廓(使用opencv-python的函数cv2.findContours() )​zhuanlan.zhihu.com

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

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

...

# 差值提取的核心代码

dif = np.abs(dif - img_back)

gray = cv2.cvtColor(dif, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, self.min_thresh, 255, 0) # 对差值取阈值,和激活函数Relu有点像

thresh = cv2.blur(thresh, (self.thresh_blur, self.thresh_blur)) # 模糊的这个操作是很重要的

...

...

# 计算得出轮廓的核心代码

thresh, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

...

approxs = [cv2.approxPolyDP(cnt, self.min_side_len, True) for cnt in contours]

approxs = [approx for approx in approxs

if len(approx) > self.min_side_num and cv2.arcLength(approx, True) > self.min_poly_len]

contours = approxs

...2018-06-30 初版 Yonv1943

2018-07-02 对RrawROI的注释方案,即对region_of_interest_pts 的赋值

传言青蛙蹲在地上不动的时候,将死掉不动的小昆虫摆放在它的眼前,青蛙也无动于衷。而当某些小昆虫在青蛙眼前飞来飞去的时候,青蛙会注意到它们,然后将它们吃了。我这个程序也可“注意到”镜头拍摄到的移动物体,因此我也将它称为 FrogEyes。

这是传统的图像处理(不涉及深度学习),所以算法的本质是:对固定摄像头前后两帧图片做差值,得到并框出不同的区域(使用opencv-python 的 cv2.findContours()函数)

因此,该方法只适用于固定镜头的移动物体识别,如果拍摄实时图像的时候镜头是移动的,那么此时移动物体的识别就只能交由深度学习去解决了。

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

如果目标是纯色的,那么对图片做差值得到的结果,将不能得到目标的完整轮廓左边是背景图片,右边是实时图片

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

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

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

简单地设置背景图片会来两个新的问题:若相机视角被移动(比如路过的人不小心碰了一下),那么实时图片和背景图片做差值,将会得到整个画面,目标检测失效

若背景发生变化,比如镜头中的桌子被移动了,或者环境光突然发生变化,或者有目标进入镜头后,赖着不走,etc. 那么镜头如实将会一直把这变化为框出来,这不智能

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

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

相关代码

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

def get_polygon_contours(self, img, img_back):

img = np.copy(img)

dif = np.array(img, dtype=np.int16)

dif = np.abs(dif - img_back)

dif = np.array(dif, dtype=np.uint8) # get different

gray = cv2.cvtColor(dif, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, self.min_thresh, 255, 0)

thresh = cv2.blur(thresh, (self.thresh_blur, self.thresh_blur))

if np.max(thresh) == 0: # have not different

contours = [] # 空列表在Python的逻辑判断中,是False

else:

thresh, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# hulls = [cv2.convexHull(cnt) for cnt, hie in zip(contours, hierarchy[0]) if hie[2] == -1]

# hulls = [hull for hull in hulls if cv2.arcLength(hull, True) > self.min_hull_len]

# contours = hulls

approxs = [cv2.approxPolyDP(cnt, self.min_side_len, True) for cnt in contours]

approxs = [approx for approx in approxs

if len(approx) > self.min_side_num and cv2.arcLength(approx, True) > self.min_poly_len]

contours = approxs

return contours

位于类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

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

...

# 在 类的初始化中 def __init__(self, img, roi_pts):

self.min_side_len = int(self.img_len0 / 24) # min side len of polygon

self.min_poly_len = int(self.img_len0 / 12)

self.thresh_blur = int(self.img_len0 / 8)

...

# 在 类的函数 get_polygon_contours() 中

approxs = [cv2.approxPolyDP(cnt, self.min_side_len, True) for cnt in contours]

approxs = [approx for approx in approxs

if len(approx) > self.min_side_num and cv2.arcLength(approx, True) > self.min_poly_len]

contours = approxs

...

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

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

感兴趣区域的设定

感兴趣区域的设定视频 ↓https://www.zhihu.com/video/997462804596600832

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

应用讨论

移动物体识别的这个特性,在固定摄像头实时视频侦测的时候比较有用,比如:监控摄像头,检测到镜头画面有变化(移动物体出现)的时候,才开启记录功能,录下视频,避免记录重复视频,节省磁盘空间。(即电子蛙眼)

保留前景,过滤掉无关的背景。

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

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

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

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

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

用传统图像识别将目标准确框出,并过滤掉背景,传给目标检测模型,甚至可以取代目标检测提取候选框的那一步,将目标检测的工作,从:生成候选框 → 分类器处理多个候选框,得到类别匹配度信息 →

计算匹配度,筛选出得分高的目标 → 调整对应候选框的位置 →

输出目标及对应的候选框

简化为:传统图形识别框出待分类的目标移动目标 →

分类器计算目标匹配度,判断目标类别 →

输出目标轮廓,以及目标的类别

简化的内容如下:简化目标检测的任务:从“判断目标位置,确定目标类型”简化为“判断目标类型”

处理的图片变小了:从原来的全图检测 缩减为对移动目标对应图片的检测

减小背景的影响:框出移动目标轮廓,并删去背景,减少了影响分类判断的干扰因素

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

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

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

参考资料:

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

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

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

基于python的移动物体检测_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)...相关推荐

  1. OpenCV中感兴趣区域的选取与检测(一)

    1.感兴趣区域的选取 感兴趣区域(Region of Interest, ROI)的选取,一般有两种情形:1)已知ROI在图像中的位置:2)ROI在图像中的位置未知. 1)第一种情形 很简单,根据RO ...

  2. 提取图像感兴趣区域_从图像中提取感兴趣区域

    提取图像感兴趣区域 Welcome to the second post in this series where we talk about extracting regions of intere ...

  3. opencv 手选roi区域_如何用opencv实现感兴趣区域ROI的选取

    OpenCV中感兴趣区域的选取与检测 感兴趣区域(Region of Interest, ROI)的选取,一般有两种情形:1)已知ROI在图像中的位置:2)ROI在图像中的位置未知. 1)第一种情形 ...

  4. 微帧ROI视频智能编码:基于人眼感兴趣区域,实现极致观感体验

    "The world is too much with us". 为了更好地认识这个纷繁复杂的世界,人类进化出了一套独特的视觉系统--中央凹成像系统,即当我们看东西时,眼睛聚焦的地 ...

  5. 钢板表面缺陷感兴趣区域检测算法

    钢板表面缺陷感兴趣区域检测算法 图像预处理作为缺陷图像检测的关键环节,对缺陷分割和识别的精度产生重要影响.图像预处理包括:原始钢板图像感兴趣区域(Region of Interest,ROI)检测 ...

  6. vs矩形框边框线显示被选中的区域;_如何使用OpenCV可视化的截取感兴趣区域

    OpenCV是一个著名的计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效--由一系列 C 函数和少量 C++ 类构成,同时提供了Python ...

  7. python二值化 感兴趣区域_Python+OpenCV感兴趣区域ROI提取方法

    方法一:使用轮廓 步骤1 """src为原图""" ROI = np.zeros(src.shape, np.uint8) #感兴趣区域RO ...

  8. OpenCV python(二)图像预处理:改变图像大小 提取感兴趣区域

    OpenCV python(二)图像预处理:改变图像大小 && 提取感兴趣区域 一.改变图像大小 1.获取图像宽.高.通道数 2.resize函数 3.案例 二.ROI感兴趣区域 1. ...

  9. python提取图片感兴趣区域_Python+OpenCV感兴趣区域ROI提取方法

    方法一:使用轮廓 步骤1 """src为原图""" ROI = np.zeros(src.shape, np.uint8) #感兴趣区域RO ...

最新文章

  1. 利用Directsound编程实现实时混音
  2. 编程之美-饮料供货方法整理
  3. 中国科学院深圳先进技术研究院为Banana Pi团队提供活动场地
  4. boost::uuid模块实现宽流存档测试序列化 uuid的测试程序
  5. xubuntu沒有登錄輸入框,左上角出現白色方框,解決方案
  6. python3.7安装keras教程_Python3.7安装keras和TensorFlow的教程图解
  7. CTex + Texmaker
  8. Python_pandas 两种主要的数据类型(Series、DataFrame)
  9. react-redux一点就透,我这么笨都懂了!
  10. 微软集成 Edge 开发者工具到 Visual Studio ,工具迎来“大换血”?
  11. 深入浅出linux驱动,Linux Kernel 字符驱动的深入浅出讲解
  12. 如何格式化电脑_电脑硬盘不小心格式化如何恢复【恢复方法】
  13. Latex slide中添加算法流程图
  14. freemaker使用三目表达式
  15. size-constrained-clustering
  16. 股票自动买卖 java_股票如何实现程序化交易和自动交易?
  17. python-while-函数
  18. 【数据分析】SQL面试题整理
  19. 图片报道:2008年12月4日夜,暴风雪突袭烟台(上)
  20. Excel拆分合并数据,使用vb编程,效率提高50倍

热门文章

  1. 深度学习核心技术精讲100篇(三十八)-滴滴司机调度系统实践
  2. Word2Vec ——gensim实战教程
  3. 在该系统上全局禁用了虚拟打印功能,不会为该虚拟机启用此功能--解决办法
  4. 自动驾驶技术-环境感知篇:多传感器融合技术
  5. Full Gc经历分析
  6. 【采用】【风控体系】携程基于大数据分析的实时风控体系
  7. computed vs methods
  8. ubuntu18 安装 chrome
  9. @Autowired自动装配对象和new对象的区别
  10. 设置Network id:      5777 in MetaMask