高空抛物监测Opencv+SORT

您所在的位置:网站首页 高空坠物急救方法有几种 高空抛物监测Opencv+SORT

高空抛物监测Opencv+SORT

2024-07-15 01:39:14| 来源: 网络整理| 查看: 265

高空抛物监测

本实践为AidLux智慧社区训练营学习总结,感谢授课讲师张大刀。

参考链接: https://blog.csdn.net/qq_32214321/article/details/107912440 https://zhuanlan.zhihu.com/p/398944211

直接从技术路线开始

高空抛物识别难点 高空抛物相机一般以仰视的角度,往住宅楼拍摄,抛出物体相对于整个楼栋,目标太小;干扰因素较多,如白天的飞鸟、飘落的树叶、夜晚的背景楼栋灯光等;环境影响如雨天、雾天、逆光等环境对结果影响较大。 数据采集

数据采集模块的难点在于相机的位置和角度的安装,对于不同的层高,建议的安装距离和分辨率选择对应的相机焦距等可以参考如下:image.png高空抛物的相机可以查看主流一线安防厂家海康,大华都有类似的产品,选型需要考虑:

夜间低照度,小区夜间光照不足,不建议通过补光的方式来提高环境照度,这样的环境下可以选型超星光摄像头,最低支持0.0002lux,可以有效保障夜间环境下的监控。白天高空抛物摄像头对着天空,白天有强烈的太阳光会造成逆光现象,可以选型摄像头支持120db的宽动态摄像头,同时也支持背光补偿,在光线复杂和强烈的环境下,仍然能显示好的图像效果。 算法设计

高空抛物识别

使用传统的动态目标检测,如光流检测和帧差法;使用目标检测+目标追踪算法,对抛出的物体先做目标检测,并对检测到的物体做追踪判断;使用物体追踪+过滤算法;使用视频分类的算法。

对于第一种方法

传统方法的动态目标检测,如光流检测和帧差法,稳定性稍差。优点在于对于数据要求低。

对于第二种方法,

使用目标检测检测被抛物体通过目标追踪对抛出物体的运动轨迹做追踪

受背景的影响很大,因为楼宇间的灯光等,同时使用目标检测+目标追踪的方法,其难点在于小目标的检测,很容易出现漏检。同时运动的物体很多,如晒得被子等,容易出现误检,同时需要大量的数据。

对于第三种方法,

针对第二种方法中的目标检测算法的效果不佳,采用高斯背景建模的方法,过滤背景信息;再使用目标追踪如kalman滤波,完成运动轨迹的记录,同时针对第二种方法中视频中会出现的树叶、飞鸟以及晒衣服等的摆动等不符合抛物运动的轨迹的误检,通过SOM网络进行聚类,SOM(自组织映射神经网络)会对不同运动的轨迹进行分析:

image.png

对运动轨迹进行分类,排除掉不符合抛物运动的轨迹:

image.png 另外可以对卡尔曼滤波追踪的前景图像块,做图像分类,做一次筛选,排除掉不是抛物的物体轨迹。 image.png 以上三种方法的识别逻辑是一样的,都是先做目标检测,再对目标检测的物体做追踪。 第二种方法相对于第一种方法,在目标检测环节采用的是深度学习方法。 第三种方法相对于第二种方法,在目标追踪后,针对运动的干扰项,通过SOM对运动轨迹过滤,通过图像分类对目标过滤;同时目标检测环节用的是传统动态目标检测,这里也可以换成第二种方法中的深度学习目标检测的方法(如果不考虑实时性)。 对于第四种方法

使用视频分类的方式,即对一段时间内的视频流做视频分类,这里可以通过第三步中先通过视频抽帧完成高斯背景建模,过滤掉背景后,再对前处理后的视频完成视频的分类。在后处理时,对分类阈值的判断逻辑,以及对输入模型的视频时长等比较讲究,这种方法目前看在满足实时性和精确性时较为折中的一种方法。 算法实现

在本次训练营课程中,因为涉及到高空抛物数据集的缺乏,所以在上面的四种方法中,主要选择第一种方法。 实际在做项目有数据集支撑的情况下,建议选择第三种或者第四种方法。 第二种方法目标检测+追踪的方式,对上游任务目标检测的要求较高,实际情况下的小目标容易漏检和误检,不建议使用。 而针对于第一种的传统算法中,一般会有帧差法或者光流检测。 但是这都是最初级的方法,因为有许多局限性,比如帧差法对噪声敏感,无法避免对树叶的误检,在摄像头有轻微摇晃的情况下也会有很多误检,也无法适应光线变化等; 光流法也是相同的问题,而且光流法还有另外一个最大的问题是其基于稀疏特征点匹配的算法,因此实际上没有很好的办法将整张图的特征点分为不同的目标——虽然有稠密光流检测算法,但是耗时较长。基于此,我们可以将第三种方法中的“背景建模”加入第一种方法中。image.png

去抖动

背景建模的前提是保证摄像机拍摄位置不变,保证背景是基本不发生变化的。 如路口的监控摄像机,只有车流人流等前景部分能发生移动,而马路树木等背景不能发生移动。所以这里我们防止相机镜头发生抖动,可以加上去抖动的算法,通过匹配算法实现 其主要的原理是通过每张图的特征,找到两个图片的关键点,并基于关键点获得变换矩阵后,将原图通过变换矩阵变换后,与第一张原始图片对齐。

#!/usr/bin/python # -*- coding:utf8 -*- # import the necessary packages import numpy as np import cv2 import time class Adjuster: def __init__(self, start_image, edge=(60, 20)): # determine if we are using OpenCV v3.X self.start_image = cv2.resize(start_image, (int(start_image.shape[1]/1), int(start_image.shape[0]/1))) self.edge = edge self.descriptor = cv2.ORB_create() self.matcher = cv2.DescriptorMatcher_create("BruteForce") (self.kps, self.features) = self.detectAndDescribe(self.start_image) def debouncing(self, image, ratio=0.7, reprojThresh=4.0, showMatches=False): image = cv2.resize(image, (int(image.shape[1]/1), int(image.shape[0]/1))) # start = time.time() (kps, features) = self.detectAndDescribe(image) # print(f"take {time.time() - start} s") M = self.matchKeypoints(kps, self.kps, features, self.features, ratio, reprojThresh) if M is None: return None (matches, H, status) = M result = cv2.warpPerspective(image, H, (image.shape[1] + image.shape[1], image.shape[0] + image.shape[0])) result = result[int(self.edge[1]):int(image.shape[0] - self.edge[1]), int(self.edge[0]):int(image.shape[1] - self.edge[0])] # cv2.namedWindow("result", cv2.WINDOW_NORMAL) # cv2.imshow("result", result) start_img = self.start_image[int(self.edge[1]):int(image.shape[0] - self.edge[1]), int(self.edge[0]):int(image.shape[1] - self.edge[0])] sub_img = cv2.absdiff(result, start_img) # cv2.namedWindow("start_img", cv2.WINDOW_NORMAL) # cv2.imshow("start_img", start_img) # cv2.namedWindow("sub_img", cv2.WINDOW_NORMAL) # cv2.imshow("sub_img", sub_img) return result def detectAndDescribe(self, image): # convert the image to grayscale if len(image.shape) > 2: gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) else: gray = image # detect and extract features from the image (kps, features) = self.descriptor.detectAndCompute(image, None) # convert the keypoints from KeyPoint objects to NumPy # arrays kps = np.float32([kp.pt for kp in kps]) # return a tuple of keypoints and features return (kps, features) def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh): # compute the raw matches and initialize the list of actual # matches rawMatches = self.matcher.knnMatch(featuresA, featuresB, 2) matches = [] # loop over the raw matches for m in rawMatches: # ensure the distance is within a certain ratio of each # other (i.e. Lowe's ratio test) if len(m) == 2 and m[0].distance 4: # construct the two sets of points ptsA = np.float32([kpsA[i] for (_, i) in matches]) ptsB = np.float32([kpsB[i] for (i, _) in matches]) # compute the homography between the two sets of points # ptsA = np.array([[0, 0], [100, 0], [100, 100], [0, 100]]) # ptsB = np.array([[50, 50], [200, 50], [200, 200], [50, 200]]) (H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh) # return the matches along with the homograpy matrix # and status of each matched point return (matches, H, status) # otherwise, no homograpy could be computed return None def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status): # initialize the output visualization image (hA, wA) = imageA.shape[:2] (hB, wB) = imageB.shape[:2] vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8") vis[0:hA, 0:wA] = imageA vis[0:hB, wA:] = imageB # loop over the matches for ((trainIdx, queryIdx), s) in zip(matches, status): # only process the match if the keypoint was successfully # matched if s == 1: # draw the match ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1])) ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1])) cv2.line(vis, ptA, ptB, (0, 255, 0), 2) # return the visualization return vis

去抖动后,将当前图与初始图对比获得差分图,能显示前后图片之间的差异。

背景建模

背景建模主要是为了检测运动物体,输出前景图片。在获得图片的差分图后,将差分图放入背景建模中,获取前景运动图。 背景建模在opencv中主要包含knn建模和高斯建模(MOG2)两种方法,这里我们选择的是KNN的方法, 其中history表示影响背景模型的历史帧数,dist2Threshold 表示像素和样本之间平方距离的阈值,当大于阈值的话,则为前景:

import numpy as np import cv2 import time class knnDetector: def __init__(self, history, dist2Threshold, minArea): self.minArea = minArea self.detector = cv2.createBackgroundSubtractorKNN(history, dist2Threshold, False) self.kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) def detectOneFrame(self, frame): if frame is None: return None start = time.time() mask = self.detector.apply(frame) stop = time.time() print("detect cast {} ms".format(stop - start)) start = time.time() mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, self.kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, self.kernel) stop = time.time() print("open contours cast {} ms".format(stop - start)) start = time.time() contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) stop = time.time() print("find contours cast {} ms".format(stop - start)) i = 0 bboxs = [] start = time.time() for c in contours: i += 1 if cv2.contourArea(c) 2 * (self.org_box[2]-self.org_box[0]+bbox[2]-bbox[0]) and \ disdance > (self.org_box[3]-self.org_box[1]+bbox[3]-bbox[1]): self.is_throw = True ... return bbox, self.is_throw 可以看出当追踪到的目标移动的欧氏距离大于了当前检测框与初始检测框宽度和的两倍,并且大于当前检测框与初始检测框高度之和,就判断为高空抛物从逻辑来说,这样判断也容易出现误检测,比如将飞鸟,大风天晃动的树枝都有可能误检测为高空抛物:

Video_2023-03-01_150428.gif

可考虑修改判断逻辑为判断x,y轴的位移:左右移动0.5倍宽度和,向下移动2倍高度和,即为高空抛物(可根据实际情况调整判断逻辑)。 def get_state(self): ... x = (bbox[0]+bbox[2])/2 - (self.org_box[0]+self.org_box[2])/2 y = (bbox[1] + bbox[3]) / 2 - (self.org_box[1] + self.org_box[3]) / 2 if math.fabs(x) > 0.5 * (self.org_box[2]-self.org_box[0]+bbox[2]-bbox[0]) and \ y > 2*(self.org_box[3]-self.org_box[1]+bbox[3]-bbox[1]): self.is_throw = True return bbox, self.is_throw 测试如下:左边类飞鸟往斜上方移动的就不再识别为抛物了,而右边旋转视频后模拟的向下运动则能识别为抛物。

Video_2023-03-01_162434.gif Video_2023-03-01_163015.gif

当然,若不缺数据的话建议考虑第三种方法,对检测到的轨迹进行分类识别 效果演示

每组测试展示了实际检测抛物效果和基于背景建模的目标检测情况,这里展示的两组测试从上到下分别是:

KNN背景建模 + sort(3,5,0.1) + 欧式距离判断抛物MOG2背景建模 + sort(6,1,0.1) + x,y轴移动距离判断抛物

实际多轮测试中发现:

sort的参数变化对该测试视频影响不大,背景建模的影响较大,两种对抛物的逻辑判断不影响该测试视频的最终检测结果,但是若有更多干扰(如飞鸟)则结果未可知。从mask的情况可以看出,虽然有对视频做去抖动处理,但测试视频的抖动还是对检测框产生了较大影响,最终影响sort的效果

opencv+sort算法高空抛物监测

下面是用aidlux部署在手机上的演示视频:缩小了视频尺寸,在手机上检测速度有所提升,但同时检测效果也稍差 https://www.bilibili.com/video/BV1JY4y117qh?p=2 项目代码

百度云盘链接:https://pan.baidu.com/s/147gi2MLqC6KiBGHyzSsbkw 提取码:aid3 本人调试的代码:https://download.csdn.net/download/kalahali/87620832



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭