【目标跟踪】奇葩需求如何处理(一)

2024-03-14 23:52

本文主要是介绍【目标跟踪】奇葩需求如何处理(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、前言
  • 二、奇葩需求
    • 2.1、减速带
    • 2.2、红绿灯
  • 三、后记

一、前言

  1. 工作中往往出现些奇葩需求。那个***需要跟踪,减速带、红绿灯、井盖,甚至是鸟、烟头、手指等。
  2. 今天就给大家分享下博主遇到那些奇葩需求,遇到了这些奇葩需求首先问候产品经理(斜眼笑.jpg)。
  3. 玩笑归玩笑,冷静下来还是要好好分析实际需求,想想如何解决这些实际问题。作为个优秀的工程师,解决问题才是关键。

二、奇葩需求

在低级别无人驾驶中,一般就是辅助倒车,辅助驾驶,辅助避让。或者说多数情况无人驾驶都是在特定的场景,如常说的高速场景。

而在高级别无人驾驶中如L4级别,要考虑的需求会大很多。当然,在 2024 年的今天,想在乘用车上实现无人驾驶还是有段距离,但在市场与政策双重刺激下,相信在不久的将来会实现。

今天给大家分享下一些在高级别无人驾驶过程中遇到的一些奇葩需求,遇到这些需求有哪些处理方法。

2.1、减速带

需求:当车体前方有减带时,我们要告知车子减速通行。

减速带在城市交通道路上是非常常见的。

图片名称

这个跟正常识别人、车等障碍物不太一样。类似减速带这类障碍物是可通行的,只是需要做减速通行。那么我们处理的逻辑就要改变。这里不仅仅是简单的检测。减速带的检测模型可以使用 segformer 模型或 TwinsNet 模型,也可以使用 yolo 系列做检测。

因为检测不可避免的存在错误检测。如果没有减速带检测出减速带,此时车子会出现明显卡顿,加速减速、加速减速,想想也知道场面多么滑稽。这里可以结合历史信息做一个平滑处理,主要是为了处理没有减速带而错误检测出减速带的情况。

    int num = (objectMessage->contours.size() != 0) ? 1: 0;resVec.push_back(num);sum += num;int length = resVec.size();if (length > maxLength) {sum -= resVec[0];resVec.erase(resVec.begin());length -= 1;}ans = (sum >= length * weight)? 1:0;  // 判断是否输出

2.2、红绿灯

图片名称

城市道路红绿灯特别场景,许多做智能驾驶厂家都吹嘘自己可以做的很好,实测上很难评([捂脸])。

红绿灯场景处理比较复杂主要几个方面

  1. 红绿灯目标小,难以稳定检测(不像人、车);且数据集少,标注成本大。
  2. 场景大多数存在多个红绿灯,难以把控这个红绿灯干嘛的,那个红绿灯干嘛的。
  3. 红绿灯灯的种类多,有人字的、有自信车形状的、有圆形的;红绿灯种类多,有放马路中央的,有几米高的,也有放地上的。
  4. 红绿灯识别完需要对红绿灯分类,黄灯、红灯、绿灯、没有灯等等。
  5. 红绿灯交通规则较为复杂,对路径规划提出较大要求。

综上所述,可以得知红绿灯场景处理起来的确费时费力,且效果不一定好。对于标注、规划等问题,这里不详细讲述。这里主要讲解跟踪逻辑。

检测红绿灯这个直接用我们 yolo 系列就足够了。颜色识别我们用颜色分类做。还需要结合历史信息综合判断,如在 1s 的连续帧不会红——>绿——>红来回跳动。可以根据国家红绿灯标准制定相应的策略,可以容忍unkonw。

目标跟踪选用 Bytetrack 或 BotSort。个人更加推荐 BotSort。原因是:(1)红绿灯目标小对匹配要求高(2)车子轻微抖动会影响跟踪

这里放一段开源 BotSort python 代码。如果想了解论文详细思想可以参考博主之前博客 https://blog.csdn.net/qq_49560248/article/details/136026766。

import cv2
import numpy as np
import copydef applyFeaures(self, raw_frame, detections=None):# Initializeheight, width, _ = raw_frame.shapeframe = cv2.cvtColor(raw_frame, cv2.COLOR_BGR2GRAY)H = np.eye(2, 3)# Downscale image (TODO: consider using pyramids)if self.downscale > 1.0:# frame = cv2.GaussianBlur(frame, (3, 3), 1.5)frame = cv2.resize(frame, (width // self.downscale, height // self.downscale))width = width // self.downscaleheight = height // self.downscale# find the keypointsmask = np.zeros_like(frame)# mask[int(0.05 * height): int(0.95 * height), int(0.05 * width): int(0.95 * width)] = 255mask[int(0.02 * height): int(0.98 * height), int(0.02 * width): int(0.98 * width)] = 255if detections is not None:for det in detections:tlbr = (det[:4] / self.downscale).astype(np.int_)mask[tlbr[1]:tlbr[3], tlbr[0]:tlbr[2]] = 0keypoints = self.detector.detect(frame, mask)# compute the descriptorskeypoints, descriptors = self.extractor.compute(frame, keypoints)# Handle first frameif not self.initializedFirstFrame:# Initialize dataself.prevFrame = frame.copy()self.prevKeyPoints = copy.copy(keypoints)self.prevDescriptors = copy.copy(descriptors)# Initialization doneself.initializedFirstFrame = Truereturn H# Match descriptors.knnMatches = self.matcher.knnMatch(self.prevDescriptors, descriptors, 2)# Filtered matches based on smallest spatial distancematches = []spatialDistances = []maxSpatialDistance = 0.25 * np.array([width, height])# Handle empty matches caseif len(knnMatches) == 0:# Store to next iterationself.prevFrame = frame.copy()self.prevKeyPoints = copy.copy(keypoints)self.prevDescriptors = copy.copy(descriptors)return Hfor m, n in knnMatches:if m.distance < 0.9 * n.distance:prevKeyPointLocation = self.prevKeyPoints[m.queryIdx].ptcurrKeyPointLocation = keypoints[m.trainIdx].ptspatialDistance = (prevKeyPointLocation[0] - currKeyPointLocation[0],prevKeyPointLocation[1] - currKeyPointLocation[1])if (np.abs(spatialDistance[0]) < maxSpatialDistance[0]) and \(np.abs(spatialDistance[1]) < maxSpatialDistance[1]):spatialDistances.append(spatialDistance)matches.append(m)meanSpatialDistances = np.mean(spatialDistances, 0)stdSpatialDistances = np.std(spatialDistances, 0)inliesrs = (spatialDistances - meanSpatialDistances) < 2.5 * stdSpatialDistancesgoodMatches = []prevPoints = []currPoints = []for i in range(len(matches)):if inliesrs[i, 0] and inliesrs[i, 1]:goodMatches.append(matches[i])prevPoints.append(self.prevKeyPoints[matches[i].queryIdx].pt)currPoints.append(keypoints[matches[i].trainIdx].pt)prevPoints = np.array(prevPoints)currPoints = np.array(currPoints)# Find rigid matrixif (np.size(prevPoints, 0) > 4) and (np.size(prevPoints, 0) == np.size(prevPoints, 0)):H, inliesrs = cv2.estimateAffinePartial2D(prevPoints, currPoints, cv2.RANSAC)# Handle downscaleif self.downscale > 1.0:H[0, 2] *= self.downscaleH[1, 2] *= self.downscaleelse:print('Warning: not enough matching points')# Store to next iterationself.prevFrame = frame.copy()self.prevKeyPoints = copy.copy(keypoints)self.prevDescriptors = copy.copy(descriptors)return H

关于红绿灯定位。这个光靠相机很难实现精准定位。一般需要地图信息辅助,视觉方面可以辅助区分相机大致位置如:左红绿灯是人行道 前红绿灯是机动车道。这里放一段博主初略估计的效果图

图片名称

三、后记

除了上面这些需求,博主还遇到更加奇葩的,今天就到这,下次分享更奇葩的。欢迎大家交流

这篇关于【目标跟踪】奇葩需求如何处理(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/810124

相关文章

解决docker目录内存不足扩容处理方案

《解决docker目录内存不足扩容处理方案》文章介绍了Docker存储目录迁移方法:因系统盘空间不足,需将Docker数据迁移到更大磁盘(如/home/docker),通过修改daemon.json配... 目录1、查看服务器所有磁盘的使用情况2、查看docker镜像和容器存储目录的空间大小3、停止dock

5 种使用Python自动化处理PDF的实用方法介绍

《5种使用Python自动化处理PDF的实用方法介绍》自动化处理PDF文件已成为减少重复工作、提升工作效率的重要手段,本文将介绍五种实用方法,从内置工具到专业库,帮助你在Python中实现PDF任务... 目录使用内置库(os、subprocess)调用外部工具使用 PyPDF2 进行基本 PDF 操作使用

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

Python异常处理之避免try-except滥用的3个核心原则

《Python异常处理之避免try-except滥用的3个核心原则》在Python开发中,异常处理是保证程序健壮性的关键机制,本文结合真实案例与Python核心机制,提炼出避免异常滥用的三大原则,有需... 目录一、精准打击:只捕获可预见的异常类型1.1 通用异常捕获的陷阱1.2 精准捕获的实践方案1.3

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Python动态处理文件编码的完整指南

《Python动态处理文件编码的完整指南》在Python文件处理的高级应用中,我们经常会遇到需要动态处理文件编码的场景,本文将深入探讨Python中动态处理文件编码的技术,有需要的小伙伴可以了解下... 目录引言一、理解python的文件编码体系1.1 Python的IO层次结构1.2 编码问题的常见场景二

Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧

《Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧》本文将通过实际代码示例,深入讲解Python函数的基本用法、返回值特性、全局变量修改以及异常处理技巧,感兴趣的朋友跟随小编一起看看... 目录一、python函数定义与调用1.1 基本函数定义1.2 函数调用二、函数返回值详解2.1 有返

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性