(项目笔记)OpenCV目标检测程序
创始人
2024-04-07 20:44:47
0

本跟踪程序核心为OpenCV里BackgroundSubtractorMOG2()类。该类通过对当前帧和背景模板的每个像素做减法,来区分前景和背景物体。这一算法只适用于背景相对固定的情况,如固定摄像头。对于跟踪小车这种需要实时更新背景的情况不适用

1 Tacker类:标记并更新获取到的目标

import mathclass EuclideanDistTracker:def __init__(self):# Store the center positions of the objectsself.center_points = {}# Keep the count of the IDs# each time a new object id detected, the count will increase by oneself.id_count = 0# record IDs of objects tracked# @param: the rectangular frame that captures an object# @return: objects boxes and idsdef update(self, objects_rect):# Objects boxes and idsobjects_bbs_ids = []# Get center point of new object# time complexity O(N^2)for rect in objects_rect:# find the center of the objectx, y, w, h = rectcx = (x + x + w) // 2cy = (y + y + h) // 2# Find out if that object was detected alreadysame_object_detected = False# search the objects stored for the same objectfor id, pt in self.center_points.items():distance = math.hypot(cx - pt[0], cy - pt[1])# if the distance between two objects detected are very close, we consider# them to be one objectif distance < 25:self.center_points[id] = (cx, cy)print(self.center_points)objects_bbs_ids.append([x, y, w, h, id])same_object_detected = Truebreak# New object is detected we assign the ID to that objectif same_object_detected is False:self.center_points[self.id_count] = (cx, cy)    # update center coordinatesobjects_bbs_ids.append([x, y, w, h, self.id_count])self.id_count += 1# Clean the dictionary by center points to remove IDS not used anymorenew_center_points = {}for obj_bb_id in objects_bbs_ids:_, _, _, _, object_id = obj_bb_idcenter = self.center_points[object_id]new_center_points[object_id] = center# Update dictionary with IDs not used removedself.center_points = new_center_points.copy()return objects_bbs_ids

1

self.center_points = {}
self.id_count = 0

center_points字典用于保存记录的中心点坐标。其键为物体标记,值为该物体的中心点x和y坐标

2

for id, pt in self.center_points.items():distance = math.hypot(cx - pt[0], cy - pt[1])# if the distance between two objects detected are very close, we consider# them to be one objectif distance < 25:self.center_points[id] = (cx, cy)print(self.center_points)objects_bbs_ids.append([x, y, w, h, id])same_object_detected = Truebreak

在这一步我们通过新物体相当于之前标记过各个物体的位置,判断新检测到的一个物体是否为以前标记的物体。循环变量id为物体标记,pt为各个物体中心点坐标(pt[0] = x, pt[1] = y)

distance = math.hypot(cx - pt[0], cy - pt[1])

math.hypot(x, y)计算该点到原点的距离,相当于math.sqrt(x * x + y * y)。这一函数用于算出当前物体和已记录的第id个物体之间距离绝对值。如果此值小于25,我们认为这两个物体为同一个。接下来更新第id物体中心点坐标,并把更新后坐标和id添加到objects_bbs_ids,该二维列表保存每个物体的x,y坐标及长宽

3

            if same_object_detected is False:self.center_points[self.id_count] = (cx, cy)    # update center coordinatesobjects_bbs_ids.append([x, y, w, h, self.id_count])self.id_count += 1

在上一步中,如果没有任何一个已标记的物体和被检测物体坐标相近,及判断该物体为新物体。把新物体赋予新id(id_count += 1),并添加到center_points和objects_bbs_ids里

4

		new_center_points = {}for obj_bb_id in objects_bbs_ids:_, _, _, _, object_id = obj_bb_idcenter = self.center_points[object_id]new_center_points[object_id] = center# Update dictionary with IDs not used removedself.center_points = new_center_points.copy()return objects_bbs_ids

这一步用于删除已消失的目标,防止center_points里保存太多无用坐标。我们将id存在在objects_bbs_ids里面的物体在center_points里予以保留,对剩余的物体随着更新删除。objects_bbs_ids里面为存在在本次函数调用时这一帧的所有已有和新添加的物体。

本程序只能区分物体和背景,无法对物体特征进行记录,因此如果一个物体离开画面后再次进入,会被赋予新的id

2 主方法

import cv2
from tracker import *# Create tracker object
tracker = EuclideanDistTracker()cap = cv2.VideoCapture("highway.mp4")# Object detection from Stable camera
object_detector = cv2.createBackgroundSubtractorMOG2(history = 100, varThreshold = 50, detectShadows = True)while True:# get video height and widthret, frame = cap.read()height, width = frame.shape[0:2]# Extract Region of interestroi = frame[340: 720,500: 800]# 1. Object Detectionmask = object_detector.apply(roi)_, mask = cv2.threshold(mask, 254, 255, cv2.THRESH_BINARY)contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)detections = []for cnt in contours:# Calculate area and remove small objectsarea = cv2.contourArea(cnt)if area > 100:# cv2.drawContours(roi, [cnt], -1, (0, 255, 0), 2)x, y, w, h = cv2.boundingRect(cnt)detections.append([x, y, w, h])# 2. Object Trackingboxes_ids = tracker.update(detections)for box_id in boxes_ids:x, y, w, h, id = box_idcv2.putText(roi, str(id), (x, y - 15), cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)cv2.rectangle(roi, (x, y), (x + w, y + h), (0, 255, 0), 3)cv2.imshow("roi", roi)cv2.imshow("Frame", frame)cv2.imshow("Mask", mask)key = cv2.waitKey(30)if key == 27:breakcap.release()
cv2.destroyAllWindows()

1

object_detector = cv2.createBackgroundSubtractorMOG2(history = 100, varThreshold = 50, detectShadows = True)

创建OpenCV里面的BackgroundSubtractorMOG2对象,参数解释如下:
1 int history:用于训练背景的帧数。这一参数会影响训练背景的学习率(如果不手动设置学习率),帧数越大,学习率越小,训练越慢
2 int varThreshould: 方差阈值,用于判断当前像素前景和背景,如当前像素和背景图片差大于阈值及认定为前景。一般阈值设为16,在光照变化明显的情况下要提高,阈值越大检测越不灵敏
3 boolean detectShadows: 是否检测影子。如检测会提高程序时间复杂度

2

 mask = object_detector.apply(roi)_, mask = cv2.threshold(mask, 254, 255, cv2.THRESH_BINARY)contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)detections = []for cnt in contours:# Calculate area and remove small objectsarea = cv2.contourArea(cnt)if area > 100:# cv2.drawContours(roi, [cnt], -1, (0, 255, 0), 2)x, y, w, h = cv2.boundingRect(cnt)

图像二值化:
cv2.threshold(src, thresh, maxval, type[, dist])
src:传入灰度图像
thresh: 起始阈值
maxval:最大值
type:图像处理类型
使用THRESH_BINARY使得像素值大于thresh是像素值设为maxval,否则像素值设为0

使用findContours找出所有轮廓,删掉过小的噪点(大小小于100),然后将剩余物体轮廓用最小矩形标出

3

    boxes_ids = tracker.update(detections)for box_id in boxes_ids:x, y, w, h, id = box_idcv2.putText(roi, str(id), (x, y - 15), cv2.FONT_HERSHEY_PLAIN, 2, (255, 0, 0), 2)cv2.rectangle(roi, (x, y), (x + w, y + h), (0, 255, 0), 3)

调用tracker的update方法更新物体标记,在图像上画出物体标记及矩形框标注物体

示例如下:
在这里插入图片描述
成功检测案例

2 在这里插入图片描述
一旦摄像头出现移动导致背景改变,会出现大量错误检测。因此该算法只适用于背景固定的情况

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...