OPENMV上的目标检测,目标定位模型

2023-05-16

目标板定位模型

代码地址

前言

在17届省赛结束后,因为担心国赛场地光照影响较大,写了这个目标检测算法。但因为时间以及实力不足,算法仅有了个雏形,没能成功部署,非常遗憾。
今年寒假终于有时间将其完善,也算对自己的锻炼。正好在18届的比赛中有无边框图片,发现该算法在无边框定位上也有较好效果,所以将这个算法开源,希望能对大家有所帮助与启发。
因为能力有限,算法还有许多优化空间。这里仅是抛砖引玉,期待大家的完善。

设计思路

在art上部署目标检测,最需要解决的问题是如何保证art那点可怜的算力能流畅运行目标检测模型。所以我们的重点是如何将模型简化。
本算法借鉴了SSD网络的一些思想,在经典的one-stage目标检测网络架构上进行了修改。
严格意义上来说,本算法不是目标检测网络,其仅完成了目标板定位的功能,并没有对目标板进行分类。也就是说,网络仅对背景与目标板两个类别进行分类。
这样做的原因如下:

  • 模型速度与输入尺寸是相矛盾的。因为art的算力有限,要想保证较高的帧率,除了使用轻量化结构降低权重大小外,还需降低输入尺寸。
  • 输入尺寸与分类正确率是矛盾的。我们训练目标板的分类模型会发现,模型输入尺寸至少要达到(64,64,3)才可以有较好的效果。想要提高精确度,在一定范围内,提高输入尺寸是必要手段之一。
  • 我们进行定位的摄像头一般需要视野较广,放在较高的位置,那么我们目标板在整张图片所占的面积可能只有二十分之一左右(以我们的摄像头高度为例,目标板的大小为32x32个像素,art的QQVGA模式图像大小为160x120)。而我们又希望帧率尽量高,那么分辨率就要进一步降低。那么,在无法保证目标清晰的情况下,分类的效果将会非常差。
  • 定位摄像头与识别摄像头通常是分开的。所以将目标检测网络部署在定位摄像头上,将分类网络部署在识别摄像头上,这样的效果可能会比较好。

所以,我们索性删掉进行分类的部分,专注于进行定位,让其起到与art的find_rect函数相同的作用。

为了使得模型更加轻量化,从以下方面简化网络。
首先给出两个前提:

  • 因为摄像头放得较高,所以可以将其与地面接近平行放置。那么由于目标板的尺寸是统一的,所以无论远近其大小都是一样的(在时间训练中会对数据进行增强,实际上允许一定程度的大小不一致)。
  • 目标与目标之间保持一定距离,不会出现目标重叠的情况。(这点可以从逐飞上位机生成的地图得以保证)

我们可以根据以上前提,对经典的目标检测网络作出如下改变:

  • 因为不需要进行分类任务,大幅减少backbone的深度。
  • 因为尺寸统一,我们就不需要多个预测特征层来适应不同大小的目标,仅需要一个就可以。
  • 因为目标板的外接矩形都是正方形,且尺寸基本一样,我们可以舍弃不同尺寸的锚框,用4x3个先验格子进行代替。每个格子负责预测该区域内的目标。
  • 目标检测一般预测(x,y,w,h)四个参数,因为尺寸基本一样我们不预测w和h,仅预测x和y。用一个经验参数r来确定目标外接矩形的边长(r由目标板在摄像头中倾斜45度的外接矩形边长确定)。

通过以上简化,我们的网络在量化后仅有38KB。经过朋友测试,在art连接电脑的情况下可以达到12帧,勉强可以满足定位的需求。

模型结构

backbone

  • 输入需要满足的要求:
    r 3 = 2 n \frac{r}{3}=2^n 3r=2n
    w 4 = 2 n \frac{w}{4}=2^n 4w=2n
    这样的设置是因为art的图像比例为4:3,然后一般进行下采样时是按步长为2进行。所以说可供选择的尺寸仅有(96,128),(48,64),更大或更小可能会出现模型运行速度较慢或精度较低等问题。
  • 考虑到兼容性问题,backbone暂时的保守使用mobilenent v2的bottleneck结构。有关bottleneck的介绍详见我的另一篇文章。你也可以尝试一些比较新的tricks,这样可能会更快。后续我也可能会参考yolo系列做一些优化。

预测特征层

预测特征层只有一个:4x3
在4x3的先验格子中,不会出现两个目标的中心落在一个格子的情况
正样本:4x3格子中有目标的格子
负样本:4x3格子中无目标的格子

分类头和回归头结构

  • 分类头:因为只有目标和背景两类,使用sigmoid激活所以分类头的输出为 (batch size,3,4,1)。
  • 回归头:因为只预测 c x , c y c_x,c_y cx,cy两个值,所以回归头输出为 (batch size,3,4,2)。

目标编码与解码

目标编码

d x = c x − x 0 w d_x = \frac{c_x-x_0}{w} dx=wcxx0
d y = c y − y 0 h d_y = \frac{c_y-y_0}{h} dy=hcyy0
d x , d y 为目标中心相对于先验格子中心偏移量的归一化值。 c x , c y 为目标的中心坐标。 d_x,d_y为目标中心相对于先验格子中心偏移量的归一化值。c_x,c_y为目标的中心坐标。 dx,dy为目标中心相对于先验格子中心偏移量的归一化值。cx,cy为目标的中心坐标。
x 0 , y 0 为先验格子的中心坐标。 w , h 为先验格子的宽和高。 x_0,y_0为先验格子的中心坐标。w,h为先验格子的宽和高。 x0,y0为先验格子的中心坐标。wh为先验格子的宽和高。

编码后的label长度为36,其中前24项为12个先验格子中的回归坐标偏移量,剩下的12项为12个格子中是否有目标的置信度。

目标与先验格子的匹配策略

相邻的两个格子中心的距离为32,一个格子的大小为40。也就是说,相邻两个格子会有相交的区域。
对于目标与先验格子的匹配,遵循以下两条原则:

  • 第一原则:目标中心与某个格子中心距离小于16,那么这个格子与目标匹配。
  • 第二原则:若格子尚为被匹配,则选取处于格子范围内且离格子中心最近的目标进行匹配。

第一原则保证了每个目标都能与先验格子进行匹配,第二原则增加了正样本数,且避免了边界效应。
注意:上述所有具体数值可以根据模型输入大小已经模型结构等因素进行调整,比如输入为(48,64,3)的模型只要将上述的参数全部除以2就行。

解码与后处理

解码就是对模型输出做编码的逆运算,这样会得出一个坐标序列。然后对坐标做非极大值抑制。

损失函数

将总体的目标损失函数定义为 定位损失(loc)和置信度损失(conf)的加权和:
L ( x , c , l , g ) = 1 N ( L c o n f ( x , c ) + α L l o c ( x , l , g ) ) \begin{equation} L(x,c,l,g) = \frac{1}{N}(L_{conf}(x,c)+\alpha L_{loc} (x,l,g)) \end{equation} L(x,c,l,g)=N1(Lconf(x,c)+αLloc(x,l,g))
其中 N 为真实值中有目标的格子数,如果 N = 0 ,则将损失设为 0 ; 其中N为真实值中有目标的格子数,如果N=0,则将损失设为0; 其中N为真实值中有目标的格子数,如果N=0,则将损失设为0
而 α 参数用于调整置信度损失和定位损失之间的比例,默认 α = 1 。 而 α 参数用于调整置信度损失和定位损失之间的比例,默认 α=1。 α参数用于调整置信度损失和定位损失之间的比例,默认α=1

置信度损失

因为为sigmoid激活后的二分类任务,使用交叉熵损失函数
L c o n f ( x , c ) = − ∑ (   y l o g ( c i ^ ) + ( 1 − y ) l o g ( c i ^ )   ) \begin{equation} % L_{conf}(x,c) = -\sum_{i \in Pos}^N log(\hat{c}_{i}) - \sum_{i \in Neg}^M log(\hat{c}_{i}) L_{conf}(x,c) = -\sum (\ ylog(\hat{c_i}) +(1-y)log(\hat{c_i}) \ ) \end{equation} Lconf(x,c)=( ylog(ci^)+(1y)log(ci^) )
c i ^ = S i g m o i d ( c i ) \hat{c_i} = Sigmoid(c_i) ci^=Sigmoid(ci)

y = { 1 , 0 } , 当标签上有目标时为 1 ,无目标时为零。其实就是 B i n a r y   C r o s s e n t r o p y 损失。 y=\left\{1,0\right\},当标签上有目标时为1,无目标时为零。其实就是Binary \ Crossentropy 损失。 y={10},当标签上有目标时为1,无目标时为零。其实就是Binary Crossentropy损失。

位置损失

当且仅当预测与真实图片在某个格子内有目标时才进行计算(回归结果不在格子内也算,这就体现出Smooth L1 的价值了)。
偏差为与格子中心进行归一化后的偏差(除以格子的边长)。
使用Smooth L1 loss
生成的标签为目标中心相对于格子中心的偏差。
L l o c ( x , l , g ) = ∑ i ∈ P o s N ∑ m ∈ { c x , c y } x i s m o o t h L 1 ( l i m − g ^ i m ) \begin{equation} L_{loc}(x,l,g) = \sum_{i \in Pos }^N \sum_{m \in \left\{c_x,c_y\right\}} x_i smooth_{L1}(l_i^{m}- \hat{g}_i^{m}) \end{equation} Lloc(x,l,g)=iPosNm{cx,cy}xismoothL1(limg^im)
其中 l 为预测值的回归偏移量归一化值, g ^ 为真实值的回归偏移量归一化值。 其中l为预测值的回归偏移量归一化值,\hat{g}为真实值的回归偏移量归一化值。 其中l为预测值的回归偏移量归一化值,g^为真实值的回归偏移量归一化值。
x i = { 1 , 0 } ,当且仅当标签与预测都有目标时为 1 。 x_i=\left\{1,0\right\},当且仅当标签与预测都有目标时为1。 xi={10},当且仅当标签与预测都有目标时为1

正负样本比例

ssd中利用Hard negative mining方法得到1:3的正负样本比例。这里为了方便,直接利用数据生成器生产1:3正负样本比例的数据集,暂时不在损失函数部分实现Hard negative mining。

部署

模型的部署不需要标签文件,但需要后处理函数。后处理包括解码以及非极大值抑制。因为现在手上没有art,所以这里暂时不提供脚本。可以参考utils.target_utils下的target_decoder类进行改写。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OPENMV上的目标检测,目标定位模型 的相关文章

  • 结构体+联合体 详解

    文章目录 一 结构体1 结构体变量2 特殊声明3 结构体的引用1 嵌套调用2 自引用 三 结构体的初始化四 结构体的内存对齐1 用法2 练习题3 修改对齐数 五 位段1 用法2 练习题 六 联合体1 用法2 练习题1 正常算法题2 用联合体
  • Ubuntu20.04——一篇文章让你从零配置VINS_Mono环境以及运行(2023年最新)

    注 xff1a 文末包含该文章涉及的所有安装包的网盘链接 零 换源 xff08 也可以先不换 xff0c 后面觉得下载慢再换也行 xff09 1 备份原来的源 sudo cp etc apt sources list etc apt sou
  • 学C语言推荐的书和软件—C Primer Plus和Dev C++

    写这个的目的是复习巩固C Primer Plus的知识 xff0c 我会一直更新这个系列 对于这本书 xff0c 入门C语言是完全够了 xff0c 后面的链表 队列和二叉树比较综合 xff0c 难度大一些 用这本书学C语言非常好 xff0c
  • mavlink python

    from pymavlink import mavutil Create the connection m 61 mavutil mavlink connection 39 udpin 0 0 0 0 14550 39 dir m mav
  • C++Vector浅析,Vector用法大全

    vector基本概念 功能 xff1a vector数据结构和数组非常相似 xff0c 也成为单端数组 vector与普通数组的区别 xff1a 不同之处在与数组是静态空间 xff0c 而vector可以动态扩展 动态扩展 xff1a 并不
  • 网络通信--Linux

    文章目录 网络通信的基础通信模型IP地址和端口port 网络套接字网络字节序初识UDP与TCP两种协议sockaddr结构体家族认识一些网络常用基础函数 UDP实现简单通信TCP实现简单通信总结 网络通信的基础 网络通信是建立在多层协议之下
  • Git分支和版本(标签)

    目录 一 Git分支 1 1 四大环境 xff08 分支 xff09 1 1 1 分支和标签的关系 1 2 分支的作用 1 3 演示分支 1 3 1 在Gitee中创建项目 1 3 2 克隆到本地 1 3 3 建立分支 1 3 4 切换分支
  • 前端必会算法——栈和队列

    上一篇 前端必会算法 标准快速排序 栈和队列 栈 xff08 Stack xff09 可以理解为是一个箱子 xff0c 存放东西的容器 栈结构的特点 xff1a 先入后出 xff0c 栈相当于一个箱子 xff0c 先放进去的东西被压在了下面
  • OpenMV的单颜色识别讲解

    OpenMV的官方教程 xff1a 寻找色块 xff1b single color rgb565 blob tracking示例讲解 xff1b 视频讲解 需要提前看的文章 xff1a 程序烧录 xff1b 颜色阈值设置 目录 thresh
  • STM32CubeMX串口通讯

    串口的简单介绍 RS 232与TTL 根据通讯使用的电平标准不同 xff0c 串口通讯可分为 TTL 标准及 RS 232 标准 而STM32的串口是TTL电平标准的 如果需要使用到RS 232则需要一个电平转换芯片 单工通信 半双工通信和
  • 自制超简易通讯协议(中断接收)

    前言 在做蓝牙语音小车时 xff0c 总遇到各式各样的问题 本文主题是笔者在解决串口不够并且数据量小的问题时突发奇想自定义一个简易的通讯协议 由于是用89c51做的主控 xff0c 外设的资源比较紧张 串口只有一个 xff0c 但两个系统需
  • 【Java杂谈】Iterator(迭代器)的使用

    x1f3b8 Iterator是什么 xff1f 迭代器是Java提供的一种访问集合的方法 xff0c Iterator 是 Java 迭代器最简单的实现 xff0c 常用来访问ArrayList HashMap等类的对象 Iterator
  • orb 纯背景物体识别

    include lt chrono gt include lt iostream gt include lt opencv2 core core hpp gt include lt opencv2 features2d features2d
  • Windows逆向安全(一)之基础知识(九)

    汇编比较三种循环 众所周知 xff0c 在C语言可以使用可以使用三种循环 xff0c 分别是 xff1a while do while和for 本文从汇编的角度出发 xff0c 观察这三种循环的差异 范例代码 先贴出三种循环的代码 xff0
  • c++读取yolov5模型进行目标检测(读取摄像头实时监测)

    文章介绍 本文是篇基于yolov5模型的一个工程 xff0c 主要是利用c 43 43 将yolov5模型进行调用并测试 xff0c 从而实现目标检测任务 任务过程中主要重点有两个 xff0c 第一 版本问题 xff0c 第二配置问题 一
  • ROS初学(二):ROS的三种基本通信机制(来自赵虚左老师)

    一 综述 ROS引入通信机制 xff0c 是为了实现ROS节点 xff08 进程 xff09 之间的通信 利用ROS进程的分布式框架 xff0c 可以使得每个进程独立的工作 xff0c 甚至分布于不同的主机工作 机器人上的各种传感器 xff
  • webpack 5.5.1 compiled with 1 error in 63 ms

    新建项目空白目录 xff0c 并运行 npm init y 命令 xff0c 初始化包管理配置文件 package json 新建 src 源代码目录 新建 src gt index html 首页和 src gt index js 脚本文
  • TypeError: Class constructor ServeCommand cannot be invoked without ‘new‘

    安装webpack插件 webpack dev server配置时将package json里面webpack改为webpack serve后 xff0c 运行npm run 脚本名 时出现 TypeError Class construc
  • Field ‘browser‘ doesn‘t contain a valid alias configuration

    意思是字段 39 browser 39 不包含有效的别名配置 意思就是说你打包的css路径不对 这个是我的代码 这里js里面导入的css路径不对 xff0c css文件夹不是和index js平级 xff0c 应该是上级所以正确的代码应该是
  • Failed to load resource: the server responded with a status of 404 (Not Found)

    问题场景 xff1a 编写路由模块 解决方法 xff1a 1 先检测路径是否有写错 2 将vscode中开的插件vetur关闭 3 上面方法不管用时 xff0c 将浏览器插件关闭 xff0c 例如油猴 有什么错误望大佬指出 xff01 xf

随机推荐

  • Vue3.js【未完成】

    Vue3 js 如何关闭烦人的vscode的提示框 https blog csdn net liuyuemozhu article details 101056556 ES6模块化与异步编程高级用法 ES6模块化 1 回顾 xff1a no
  • npm ERR! code ERESOLVEnpm ERR! ERESOLVE unable to resolve dependency tree

    npm下载报错 xff0c 这个是因为npm版本问题 xff0c 例如我下载element ui运行npm i element ui S 因为版本问题我就无法下载 xff0c 解决办法就是在末尾加上 legacy peer deps 即np
  • 前端面试题

    浏览器 输入一个URL到页面过程中发生了什么 xff08 高频 xff09 首先在浏览器中输入URL 查找缓存 xff1a 浏览器先查看浏览器缓存 系统缓存 路由缓存中是否有该地址页面 xff0c 如果有则显示页面内容 如果没有则进行下一步
  • MATALAB动态爱心代码

    第一步 xff1a 先下载MATLAB软件 xff08 该代码只适用于此软件 xff0c 要下载软件才可运行 xff09 第二步 xff1a 点击主页 新建脚本 xff08 可自己给脚本命名 xff0c 我命名的是aixin xff09 第
  • Linux相关博文中使用的头文件

    收录博文中看到的已经封装好的文件时 xff0c 方便各位查看 Log hpp 日志信息 pragma once include lt iostream gt include lt cstdio gt include lt cstdarg g
  • 构造函数和析构函数执行顺序

    析构函数运行顺序 xff1a 1 主函数结束 xff1b 2 函数调用结束 xff1b 3 用delete删除 xff08 new创建的 xff09 对象时 注释代码运行结果 输入坐标6 xff0c 3 xff0c 6 xff0c 2 xf
  • 27.【C/C++ 最全vector数组的用法 (详解)】

    vector动态数组 xff08 一 xff09 什么是vector xff1f xff08 二 xff09 vector的作用是什么 xff08 三 xff09 经典用法 1 vector函数的定义 代码展示 效果展示 2 vector的
  • 析构函数运行顺序

    全局变量 xff0c 静态局部变量 xff0c 局部变量空间的堆分配和栈分配 其中全局变量和静态局部变量时从 静态存储区中划分的空间 xff0c 二者的区别在于作用域的不同 xff0c 全局变量作用域大于静态局部变量 xff08 只用于声明
  • 03_临界段的保护

    一 临界段的概念 所谓的临界段就是在执行时不能被中断的代码段 在FreeRTOS中 xff0c 临界段最常出现的地方就是对全局变量的操作 那么什么情况下临界段会被打断 xff1f 一个是系统调度 xff0c 还有一个是外部中断 在FreeR
  • Qt自定义窗口继承基类

    设计一个窗口基类模板 xff0c 方便子类的统一风格使用 xff0c 省略重写事件函数 xff0c 代码思路
  • ROS学习笔记4:创建工作空间和功能包

    一 linux命令行使用基础 xff1a 1 cd命令 xff08 change directory xff09 xff1a xff08 1 xff09 语法 xff1a cd dirName xff08 dirName xff1a 要切换
  • 一段代码给你讲清楚【链式存储结构】

    1 基础定义 链式存储结构 xff08 linked storage structure xff09 xff0c 是逻辑存储结构的一种 xff0c 链式存储结构中每一个逻辑元素用一个内存结点存储 xff0c 每一个结点都是单独分配的 xff
  • Flask之before_request与after_request

    Flask之before request与after request 更多的用法或说明请查看文档 xff1a https dormousehole readthedocs io en latest api html flask Flask
  • C++教程之迭代器Iterator

    前言 之前的两篇文章我们主要了解了vector和string的相关知识 xff0c 从中我们知道可以通过下标来访问vector的元素或者string的字符 xff0c 但是除了这种方式还有一种更为通用的方式获取元素 xff0c 那就是迭代器
  • Qt 绘制图表 - Qt Charts版

    一 前言 自从 Qt 发布以来 xff0c 给广大跨平台界面研发人员带来了无数的福利 但是Qt自己却一直没有提供自带的图表库 xff0c 这就使得 QWT QCustomPlot 等第三方图表库有了巨大的生存空间 xff0c 为了降低开发成
  • Qt 多线程使用moveToThread

    Qt有两种多线程的方法 xff0c 其中一种是继承QThread的run函数 xff0c 另外一种是把一个继承于QObject的类用moveToThread函数转移到一个Thread里 Qt4 8之前都是使用继承QThread的run这种方
  • Qt 之http学习

    在Qt网络编程中 xff0c 需要用到协议 xff0c 即HTTP 它是超文本传输协议 xff0c 它是一种文件传输协议 新建工程名为 http xff0c 然后选中QtNetwork模块 xff0c 最后Base class选择QWidg
  • QT之QString

    字符串类 QString xff1a 在Qt官方文档中是这样描述QString的 xff1a The QString class provides a Unicode character string 我们可以将做C 43 43 中的str
  • 什么是栈?什么是任务栈?

    在裸机系统中 xff0c 它们统统放在一个叫栈的地方 栈式单片机RAM里一段连续的内存空间 栈的大小一般在启动文件或者链接脚本里里面指定 最后由C库函数 main进行初始化 每个任务都是独立的 xff0c 互不干扰的 所以要为每个任务都分配
  • OPENMV上的目标检测,目标定位模型

    目标板定位模型 代码地址 前言 在17届省赛结束后 xff0c 因为担心国赛场地光照影响较大 xff0c 写了这个目标检测算法 但因为时间以及实力不足 xff0c 算法仅有了个雏形 xff0c 没能成功部署 xff0c 非常遗憾 今年寒假终