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

感兴趣区域、特定区域、框出移动物体的轮廓、越界检测、入侵物体检测、使用 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 做出来了)

参考资料:

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

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

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

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值