OpenPCDet系列 | 5.4.1 DenseHead中的AnchorGenerator锚框生成模块

news2024/11/23 9:03:02

文章目录

  • AnchorGenerator模块
  • AnchorGenerator.generate_anchors函数

AnchorGenerator模块

首先,根据点云场景将其划分为一个个grid,这个grid size是可以通过配置文件设定的点云场景方位和voxel大小计算出来的。

POINT_CLOUD_RANGE: [0, -39.68, -3, 69.12, 39.68, 1]
VOXEL_SIZE: [0.16, 0.16, 4]

在dense_head的初始化过程,就会在基类进行anchor的生成。

# 功能:dense head模块的基类
class AnchorHeadTemplate(nn.Module):
    def __init__(self, model_cfg, num_class, class_names, grid_size, point_cloud_range, predict_boxes_when_training):
        
        ......
        # anchor生成配置
        anchor_generator_cfg = self.model_cfg.ANCHOR_GENERATOR_CONFIG   # list:存储每个类别的anchor生成设置
        anchors, self.num_anchors_per_location = self.generate_anchors(
            anchor_generator_cfg, grid_size=grid_size, point_cloud_range=point_cloud_range,
            anchor_ndim=self.box_coder.code_size
        )
        
        ......

    @staticmethod
    def generate_anchors(anchor_generator_cfg, grid_size, point_cloud_range, anchor_ndim=7):
        """
        Args:
            anchor_generator_cfg:   每个类别的anchor配置
            grid_size:              网格大小 [432 496   1]
            point_cloud_range:      点云范围 [  0.   -39.68  -3.    69.12  39.68   1.  ]
            anchor_ndim:            anchor维度: 7 位置 + 大小 + 方向 [x,y,z,dx,dy,dz,rot]
        """
        anchor_generator = AnchorGenerator(
            anchor_range=point_cloud_range,
            anchor_generator_config=anchor_generator_cfg
        )

        # 对每个类别生成anchor的feature map [array([216, 248]), array([216, 248]), array([216, 248])]
        feature_map_size = [grid_size[:2] // config['feature_map_stride'] for config in anchor_generator_cfg]
        # 返回每个类别构建好的anchor[(1,248,216,1,2,7), ...] 和 每个位置anchor的数量[2, 2, 2]
        anchors_list, num_anchors_per_location_list = anchor_generator.generate_anchors(feature_map_size)

        if anchor_ndim != 7:    # 默认情况是为7, 如果anchor的维度不等于7,则补0
            for idx, anchors in enumerate(anchors_list):
                pad_zeros = anchors.new_zeros([*anchors.shape[0:-1], anchor_ndim - 7])
                new_anchors = torch.cat((anchors, pad_zeros), dim=-1)
                anchors_list[idx] = new_anchors

        return anchors_list, num_anchors_per_location_list

这里3d点云检测的anchor生成和yolov5等目标检测2d算法在图像网格点生成anchor类似。由于这里有3个类别,那么首先对每个列表都构建一个feature map,每个feature map尺度在这里和点特征矩阵的尺寸是一样的。随后,将这个feature map列表送入AnchorGenerator.generate_anchors函数来进行具体的anchor生成。

AnchorGenerator.generate_anchors函数解析如下。


AnchorGenerator.generate_anchors函数

以点云场景限制为:[ 0. -39.68 -3. 69.12 39.68 1. ] 为例。由于设定了grid size,那么就可以知道每个grid之间的步长,那么根据这个步长就有可以将整个点云场景均匀的划分为一个个等大的grid。

# 步长的确定:PointPillars不在z轴进行划分,所以z轴步长不需要考虑
x_stride = (self.anchor_range[3] - self.anchor_range[0]) / (grid_size[0] - 1)   # x方向步长
y_stride = (self.anchor_range[4] - self.anchor_range[1]) / (grid_size[1] - 1)   # y方向步长
x_offset, y_offset = 0, 0

# 根据步长构建xy方向的间隔点
x_shifts = torch.arange(    # (69.12 - 0) / (216 - 1) = 0.321488  间隔点有216个,所以步长为0.321488
    self.anchor_range[0] + x_offset, self.anchor_range[3] + 1e-5, step=x_stride, dtype=torch.float32,
).cuda()
y_shifts = torch.arange(    # (39.68 - (-39.68)) / (248 - 1) = 0.321295 间隔点有248个,所以步长为0.321295
    self.anchor_range[1] + y_offset, self.anchor_range[4] + 1e-5, step=y_stride, dtype=torch.float32,
).cuda()
z_shifts = x_shifts.new_tensor(anchor_height)   # [-1.78] PointPillar不对z轴进行区间划分

更具步长来构建一个三维的网格坐标是通过meshgrid函数来实现的。meshgrid可以理解为在原来的维度上进行扩展(此时3者的坐标维度是一样的)。随后将其进行拼接在一起,此时就获得了在点云场景中的一个三维坐标表示。拼接后的维度是[216,248,1,3],前三维信息是表示xyz轴,最后一维表示分别的坐标。

# 根据xyz步长构建三维网格坐标 [x_grid, y_grid, z_grid] --> [(216,248,1), (216,248,1),(216,248,1)]
x_shifts, y_shifts, z_shifts = torch.meshgrid([
    x_shifts, y_shifts, z_shifts
])  # [x_grid, y_grid, z_grid]
# meshgrid可以理解为在原来的维度上进行扩展, (np.meshgrid 和 torch.meshgrid 是返回结果不一样的)
# 例如:
# x原来为(216,)-->(216,1, 1)--> (216,248,1)
# y原来为(248,)--> (1,248,1)--> (216,248,1)
# z原来为 (1,) --> (1,1,1) --> (216,248,1)

# xyz位置信息堆叠,完成anchor位置信息的构建: (216,248,1,3)
anchors = torch.stack((x_shifts, y_shifts, z_shifts), dim=-1)  # [x,y,z,3]-->[216,248,1,3]

anchor坐标位置构建完后,随后与anchor的尺寸大小、旋转角信息进行组合

# 将anchor的位置信息与尺寸大小进行组合: (216,248,1,1,6)
anchors = anchors[:, :, :, None, :].repeat(1, 1, 1, anchor_size.shape[0], 1)        # (216,248,1,3) -> (216,248,1,1,3)
anchor_size = anchor_size.view(1, 1, 1, -1, 3).repeat([*anchors.shape[0:3], 1, 1])  # (1,1,1,1,3) -> (216,248,1,1,3)
anchors = torch.cat((anchors, anchor_size), dim=-1)     # anchors的位置+大小 --> (216,248,1,1,6)

# 将anchor的位置信息、尺寸大小、旋转角信息进行组合: (216,248,1,1,2,7)
anchors = anchors[:, :, :, :, None, :].repeat(1, 1, 1, 1, num_anchor_rotation, 1)   # (216,248,1,1,1,6) -> (216,248,1,1,2,6)
anchor_rotation = anchor_rotation.view(1, 1, 1, 1, -1, 1).repeat([*anchors.shape[0:3], num_anchor_size, 1, 1])  # (1,1,1,1,2,1) -> (216,248,1,1,2,1)
anchors = torch.cat((anchors, anchor_rotation), dim=-1)  # anchors的位置+大小+旋转方向 --> (216,248,1,1,2,7)

# 最后调整anchor的维度: (1,248,216,1,2,7)
# 最后一维的7表示的特征信息为: [x, y, z, dx, dy, dz, rot], [位置信息xyz, 尺寸信息, 旋转角度]
anchors = anchors.permute(2, 1, 0, 3, 4, 5).contiguous()    # (216,248,1,1,2,7) ->  (1,248,216,1,2,7)
#anchors = anchors.view(-1, anchors.shape[-1])

最后获取的anchor的维度: (1,248,216,1,2,7)。其中(1,248,216)表示点云场景每个grid的位置。2表示每个grid位置有两种方向的anhcor。然后7表示每种方向的anchor的具体位置信息、尺寸大小、旋转角度。如此,依次对每个类别进行anchor的生成,最后返回的是anchors_list。

ps:这里的anhcor的z轴位置信息还回加上anchor的高度,以汽车类别为例,由于每个anchor的z轴gird位置设置为'anchor_bottom_heights': [-1.78],然后再加上anchor高度的一半也就是1.56 // 2 = 0.78,z轴的位置信息就被更新为1,这个就是anchor的具体在z轴上的位置。下面就是某个grid位置的anchor配置信息,可以看见一个位置的一类anchor会有两个方向的尺寸位置一样的配置。

在这里插入图片描述

函数的最后返回的是anchor_list列表以及每个位置每个类别有多少种anchor的列表,如下所示:

在这里插入图片描述

至此,完成了每个grid每个类别的anchor生成配置。思路上是比较清晰的,具体的细节就是各种anchor信息在各位置的拼接处理。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/540654.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

研发工程师玩转Kubernetes——部署应用

Kubernetes是容器的管理编排工具,而容器则是程序的载体。我们先在Docker上部署应用,然后再在kubernetes上部署,并对它们进行对比学习。 Docker部署应用 查看运行中的容器 docker ps可以看到下面的表头,此时没有一个运行中的容器…

图片压缩指定大小,让您的图片高效而优美

在现代社会中,图片是我们不可或缺的一部分,在各行业中都有着非常重要的作用。但是,大尺寸的图片不仅会占用过多的存储空间,还会导致网页或应用程序的加载速度变慢。因此,将图片压缩到指定大小是一个必要的步骤。 图片…

文档管理-gitlab+markdown网页插件

特点 使用git进行版本管理,本地编辑使用Typora。使用gitlab进行权限管理可以在线阅读通过Markdown在线阅读插件实现,可显示目录显示与链接跳转,界面优于自带的wiki。 与其他方式对比 gitlab的wiki:显示界面效果不好&#xff0c…

书籍《脆弱的繁华》读后感

前几周看完了《脆弱的繁华》这本书,这本书当时是公司组织的一次活动,邀请书籍原作者,张程对书籍进行了讲解,同时这本书也是在此次活动中免费赠送的,作者对于书籍做了一些说明,并且对一些问题也进行了探讨&a…

Azkaban 集群模式部署

文章目录 Azkaban 集群模式部署一、配置Mysql Azkaban 集群模式部署 将这三个包,上传到hadoop102,第一个是azkaban需要的建表语句 这三个解压到 /opt 目录下 输入命令:tar -zxvf azkaban-db-3.84.4.tar.gz -C /opt/ 输入命令:ta…

spring注册beanDefinition

代码使用springboot测试 1.ConfigurationClassPostProcessor 构造context时会创建reader。 构造reader时会创建processor。 最关键是第一个,类型是ConfigurationClassPostProcessor。 AbstractApplicationContext类的refresh方法的invokeBeanFactoryPostProcesso…

Node输出日志的正确姿势

背景 每个程序员都喜欢在有问题的代码中插入一些日志的方法来帮助调试程序,比如System.out.println或console.log。解决后,就会将这些语句删除,周而复始。 但是通过系统日志输出的日志格式都是这种: // output console.log(&quo…

TensoRF-张量辐射场论文笔记

TensoRF-张量辐射场论文笔记_什度学习的博客-CSDN博客 注释代码: https://github.com/xunull/read-TensoRF 官方源码:https://github.com/apchenstu/TensoRF Install environment conda create -n TensoRF python3.8 conda activate TensoRF pip install torch t…

HTTPTomcatServlet学习

HTTP&Tomcat 今日目标: 了解JavaWeb开发的技术栈理解HTTP协议和HTTP请求与响应数据的格式掌握Tomcat的使用掌握在IDEA中使用Tomcat插件理解Servlet的执行流程和生命周期掌握Servlet的使用和相关配置 1. Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网&…

正点原子串口算法解析-定时器+数组长度判断

源码 片段1 片段2 片段3 解析 片段1的作用 开启一个10ms的定时器 片段2的作用 每10毫秒置位接收标志位且关闭定时器 片段3的作用和详解 代码第38行 用res变量接收数据 从代码第39行开始看 接收标志位不允许接收(不为0) 下面的所有代码都不会运行 如果接收标志为允许接收…

CRM管理系统如何选型?分别有什么作用?

CRM管理系统通常指CRM系统,中文名称是客户关系管理,起源于上世纪80年代的“接触管理”,它能确保客户在销售、营销、服务上的每一步交互都顺利高效,带动业绩的提升。今天就来说一说CRM管理系统是什么(从使用到选型&…

【HarmonyOS】元服务混淆打包以及反混淆mapping文件生成

大家所知的Android中的“混淆”可以分为两部分,一部分是 Java 代码的优化与混淆,依靠 proguard 混淆器来实现;另一部分是资源压缩,从而可以减少包体积。 一般应用release发布的时候都会选择开启混淆,防止应用被反编译…

OpenPCDet系列 | 5.4.3 DenseHead中的AxisAlignedTargetAssigner正负样本分配模块

文章目录 AxisAlignedTargetAssigner模块assign_targets处理流程1. 提取有效gt信息2. 提取需要处理的类别信息3. 帧信息整合4. 批信息整合 assign_targets_single处理流程1. 构建每个anchor的正负样本label分配2. 构建每个anchor的正负样本编码信息bbox_targets分配3. 构建每个…

NMEA 2000总线连接器组成类别及功能

NMEA 2000总线介绍 连接的所有设备都能彼此通信 NMEA 2000总线系统是一种数字网络,可连接船上各种系统和设备,例如雷达、GPS、深度传感器、气象环境和船体控制系统。 NMEA 2000总线的工作方式 NMEA 2000总线通过总线连接器连接各个设备和系统&#xf…

HANTS时间序列滤波算法的MATLAB实现

本文介绍在MATLAB中,实现基于HANTS算法(时间序列谐波分析法)的长时间序列数据去噪、重建、填补的详细方法。 HANTS(Harmonic Analysis of Time Series)是一种用于时间序列分析和插值的算法。它基于谐波分析原理&#x…

linux 常用命令awk

AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。 AWK用法 awk 用法:awk pattern {action} files 1.RS, ORS, F…

CFS三层内网靶机渗透

目录 一、靶场框架 靶场搭建: 二、渗透过程 三、总结 靶场介绍: 三层内网靶场,共有三个网段,分别为75网段(公网网段)、22网段(内网)、33网段(内网) 靶…

ChatGPT+ “剪映 or 百度AIGC” 快速生成短视频

🍏🍐🍊🍑🍒🍓🫐🥑🍋🍉🥝 ChatGPT快速生成短视频 文章目录 🍐1.ChatGPT 剪映🍏2.ChatGPT 百度AIGC平台&#x…

【ThinkPHP6系列学习-2】多应用模式配置

上一篇:【ThinkPHP6系列学习-1】下载并部署ThinkPHP6 这里写一写TP6下配置多应用。因为TP6和TP5有所差异,TP6默认是单应用模式(单模块),而我们实际项目中往往是多应用的(多个模块)&#xff0c…

1.Buffer_Overflow-2.Stack_Overflow / 写入字符串

这道题虽然简单 但是却给我了另一个解题的看法 我们先进行运行 我们看看保护 发现只有NX保护 反汇编看看 发现有shellcode 但是我们没有办法执行shellcode 因为v5 不会等于后面的 这里我原本没有想法 后面进行看看他的汇编 这里其实就很清楚了 .text:00000000004011BB …