关于PointHeadBox类的理解
forward函数
def forward(self, batch_dict):"""Args:batch_dict:batch_size:point_features: (N1 + N2 + N3 + ..., C) or (B, N, C)point_features_before_fusion: (N1 + N2 + N3 + ..., C)point_coords: (N1 + N2 + N3 + ..., 4) [bs_idx, x, y, z]point_labels (optional): (N1 + N2 + N3 + ...)gt_boxes (optional): (B, M, 8)Returns:batch_dict:point_cls_scores: (N1 + N2 + N3 + ..., 1)point_part_offset: (N1 + N2 + N3 + ..., 3)"""if self.model_cfg.get('USE_POINT_FEATURES_BEFORE_FUSION', False):point_features = batch_dict['point_features_before_fusion']else:point_features = batch_dict['point_features']#通过全连接层128-->256-->256-->3生成类别信息point_cls_preds = self.cls_layers(point_features) # (total_points, num_class)#通过全连接层128-->256-->256-->8生成回归框信息point_box_preds = self.box_layers(point_features) # (total_points, box_code_size)#在预测的3个类别中求出最大可能的类别作为标签信息,并经过sigmod函数point_cls_preds_max, _ = point_cls_preds.max(dim=-1)batch_dict['point_cls_scores'] = torch.sigmoid(point_cls_preds_max)ret_dict = {'point_cls_preds': point_cls_preds,'point_box_preds': point_box_preds}if self.training:#主要是生成每个点对应的真实的标签信息#以及真实框G相对于预测G_hat的框的参数偏移,每个点对应是1*8维向量targets_dict = self.assign_targets(batch_dict)ret_dict['point_cls_labels'] = targets_dict['point_cls_labels']ret_dict['point_box_labels'] = targets_dict['point_box_labels']if not self.training or self.predict_boxes_when_training:#求出每个点对应的预测的标签信息#以及P相对于预测的框G_hat的参数偏移,每个点对应是1*8维向量point_cls_preds, point_box_preds = self.generate_predicted_boxes(points=batch_dict['point_coords'][:, 1:4],point_cls_preds=point_cls_preds, point_box_preds=point_box_preds)batch_dict['batch_cls_preds'] = point_cls_predsbatch_dict['batch_box_preds'] = point_box_predsbatch_dict['batch_index'] = batch_dict['point_coords'][:, 0]batch_dict['cls_preds_normalized'] = Falseself.forward_ret_dict = ret_dictreturn batch_dict
注意
:对于每一个point,point_box_preds是1×8维向量,8维分别表示[xt, yt, zt, dxt, dyt, dzt, cost, sint],[xt, yt, zt]为中心点偏移量,[dxt, dyt, dzt]为长宽高偏移量,[cost, sint]为角度偏移量。
forward函数得到了每个前景点对应的真实标签值以及标注框信息;(self.assign_targets--------->self.assign_stack_targets-----> self.box_coder.encode_torch调用了PointResidualCoder类中的encode_torch函数)
得到了从G_hat到G的1*8维参数
每个前景点对应的预测标签值以及预测框信息;(self.generate_predicted_boxes--------->self.box_coder.decode_torch调用了PointResidualCoder类中的decode_torch函数)
得到了从P到G_hat的1*8维参数
得到这两组参数后用于后续计算损失时计算的box损失,采用的是L1回归损失
point_loss_box_src = F.smooth_l1_loss(point_box_preds[None, ...], point_box_labels[None, ...], weights=reg_weights[None, ...])
边框回归(Bounding Box Regression)详解
PointResidualCoder
class PointResidualCoder(object):def __init__(self, code_size=8, use_mean_size=True, **kwargs):super().__init__()self.code_size = code_sizeself.use_mean_size = use_mean_sizeif self.use_mean_size:self.mean_size = torch.from_numpy(np.array(kwargs['mean_size'])).cuda().float()assert self.mean_size.min() > 0def encode_torch(self, gt_boxes, points, gt_classes=None):"""Args:gt_boxes: (N, 7 + C) [x, y, z, dx, dy, dz, heading, ...]points: (N, 3) [x, y, z]gt_classes: (N) [1, num_classes]Returns:box_coding: (N, 8 + C)"""gt_boxes[:, 3:6] = torch.clamp_min(gt_boxes[:, 3:6], min=1e-5)xg, yg, zg, dxg, dyg, dzg, rg, *cgs = torch.split(gt_boxes, 1, dim=-1)xa, ya, za = torch.split(points, 1, dim=-1)if self.use_mean_size:assert gt_classes.max() <= self.mean_size.shape[0]point_anchor_size = self.mean_size[gt_classes - 1]dxa, dya, dza = torch.split(point_anchor_size, 1, dim=-1)diagonal = torch.sqrt(dxa ** 2 + dya ** 2)xt = (xg - xa) / diagonalyt = (yg - ya) / diagonalzt = (zg - za) / dzadxt = torch.log(dxg / dxa)dyt = torch.log(dyg / dya)dzt = torch.log(dzg / dza)else:xt = (xg - xa)yt = (yg - ya)zt = (zg - za)dxt = torch.log(dxg)dyt = torch.log(dyg)dzt = torch.log(dzg)cts = [g for g in cgs]return torch.cat([xt, yt, zt, dxt, dyt, dzt, torch.cos(rg), torch.sin(rg), *cts], dim=-1)def decode_torch(self, box_encodings, points, pred_classes=None):"""Args:box_encodings: (N, 8 + C) [x, y, z, dx, dy, dz, cos, sin, ...]points: [x, y, z]pred_classes: (N) [1, num_classes]Returns:"""xt, yt, zt, dxt, dyt, dzt, cost, sint, *cts = torch.split(box_encodings, 1, dim=-1)xa, ya, za = torch.split(points, 1, dim=-1)if self.use_mean_size:assert pred_classes.max() <= self.mean_size.shape[0]point_anchor_size = self.mean_size[pred_classes - 1]dxa, dya, dza = torch.split(point_anchor_size, 1, dim=-1)diagonal = torch.sqrt(dxa ** 2 + dya ** 2)xg = xt * diagonal + xayg = yt * diagonal + yazg = zt * dza + zadxg = torch.exp(dxt) * dxadyg = torch.exp(dyt) * dyadzg = torch.exp(dzt) * dzaelse:xg = xt + xayg = yt + yazg = zt + zadxg, dyg, dzg = torch.split(torch.exp(box_encodings[..., 3:6]), 1, dim=-1)rg = torch.atan2(sint, cost)cgs = [t for t in cts]return torch.cat([xg, yg, zg, dxg, dyg, dzg, rg, *cgs], dim=-1)
decode_torch
:如何通过point_box_preds的8维向量得到proposal的7维坐标?将每一个point原始xyz坐标加上坐标偏移量[xt, yt, zt]即可得到proposal中心点坐标,利用作者预设的point_anchor_size乘上长宽高偏移量[dxt, dyt, dzt]得到proposal长宽高,利用atan2函数计算角度heading。
论文出处
3D Object Detection for Autonomous Driving: A Review and New Outlooks
个人的理解是觉得这样可以同时优化生成的anchor大小并且可以调节中心坐标的偏移。
assign_targets
def assign_targets(self, input_dict):"""Args:input_dict:point_features: (N1 + N2 + N3 + ..., C)batch_size:point_coords: (N1 + N2 + N3 + ..., 4) [bs_idx, x, y, z]gt_boxes (optional): (B, M, 8)Returns:point_cls_labels: (N1 + N2 + N3 + ...), long type, 0:background, -1:ignoredpoint_part_labels: (N1 + N2 + N3 + ..., 3)"""point_coords = input_dict['point_coords']gt_boxes = input_dict['gt_boxes']assert gt_boxes.shape.__len__() == 3, 'gt_boxes.shape=%s' % str(gt_boxes.shape)assert point_coords.shape.__len__() in [2], 'points.shape=%s' % str(point_coords.shape)batch_size = gt_boxes.shape[0]extend_gt_boxes = box_utils.enlarge_box3d(gt_boxes.view(-1, gt_boxes.shape[-1]), extra_width=self.model_cfg.TARGET_CONFIG.GT_EXTRA_WIDTH).view(batch_size, -1, gt_boxes.shape[-1])targets_dict = self.assign_stack_targets(points=point_coords, gt_boxes=gt_boxes, extend_gt_boxes=extend_gt_boxes,set_ignore_flag=True, use_ball_constraint=False,ret_part_labels=False, ret_box_labels=True)return targets_dict
extend_gt_boxes 主要是将groud truth boxex在长、宽、高方向上扩展
assign_stack_targets
#此函数传入的都是对应点的真实预测值和真实标注框def assign_stack_targets(self, points, gt_boxes, extend_gt_boxes=None,ret_box_labels=False, ret_part_labels=False,set_ignore_flag=True, use_ball_constraint=False, central_radius=2.0):"""Args:points: (N1 + N2 + N3 + ..., 4) [bs_idx, x, y, z]gt_boxes: (B, M, 8)extend_gt_boxes: [B, M, 8]ret_box_labels:ret_part_labels:set_ignore_flag:use_ball_constraint:central_radius:Returns:point_cls_labels: (N1 + N2 + N3 + ...), long type, 0:background, -1:ignoredpoint_box_labels: (N1 + N2 + N3 + ..., code_size)"""assert len(points.shape) == 2 and points.shape[1] == 4, 'points.shape=%s' % str(points.shape)assert len(gt_boxes.shape) == 3 and gt_boxes.shape[2] == 8, 'gt_boxes.shape=%s' % str(gt_boxes.shape)assert extend_gt_boxes is None or len(extend_gt_boxes.shape) == 3 and extend_gt_boxes.shape[2] == 8, \'extend_gt_boxes.shape=%s' % str(extend_gt_boxes.shape)assert set_ignore_flag != use_ball_constraint, 'Choose one only!'#将数据分批次处理batch_size = gt_boxes.shape[0]bs_idx = points[:, 0]point_cls_labels = points.new_zeros(points.shape[0]).long()point_box_labels = gt_boxes.new_zeros((points.shape[0], 8)) if ret_box_labels else Nonepoint_part_labels = gt_boxes.new_zeros((points.shape[0], 3)) if ret_part_labels else None#将数据分批次处理for k in range(batch_size):bs_mask = (bs_idx == k)#这里以*_single应该是中间缓存变量,作为每一批次处理的变量存储数据#points_single取出对应批次的点云的坐标信息points_single = points[bs_mask][:, 1:4]point_cls_labels_single = point_cls_labels.new_zeros(bs_mask.sum())#将每一个点云数据分配到真实标注框上box_idxs_of_pts = roiaware_pool3d_utils.points_in_boxes_gpu( points_single.unsqueeze(dim=0), gt_boxes[k:k + 1, :, 0:7].contiguous()).long().squeeze(dim=0)#box_idxs_of_pts是每个点对应分配的标注框索引值,没有匹配的赋值为-1box_fg_flag = (box_idxs_of_pts >= 0) #根据之前扩展的3D框计算被忽略的点if set_ignore_flag:#将每一个点云数据分配到扩展后的标注框上extend_box_idxs_of_pts = roiaware_pool3d_utils.points_in_boxes_gpu(points_single.unsqueeze(dim=0), extend_gt_boxes[k:k+1, :, 0:7].contiguous()).long().squeeze(dim=0)fg_flag = box_fg_flag#异或运算,未扩展前没有包括,扩展后包含到的框,即被忽略的框ignore_flag = fg_flag ^ (extend_box_idxs_of_pts >= 0)point_cls_labels_single[ignore_flag] = -1elif use_ball_constraint:box_centers = gt_boxes[k][box_idxs_of_pts][:, 0:3].clone()box_centers[:, 2] += gt_boxes[k][box_idxs_of_pts][:, 5] / 2ball_flag = ((box_centers - points_single).norm(dim=1) < central_radius)fg_flag = box_fg_flag & ball_flagelse:raise NotImplementedError#记录前景点信息,可以理解为论文中所说的前景点分割gt_box_of_fg_points = gt_boxes[k][box_idxs_of_pts[fg_flag]]#最后一维代表的是标注框对应的类别信息,对应前景点的类别信息point_cls_labels_single[fg_flag] = 1 if self.num_class == 1 else gt_box_of_fg_points[:, -1].long()#记录一次批处理流程中所有点的类别信息point_cls_labels[bs_mask] = point_cls_labels_singleif ret_box_labels and gt_box_of_fg_points.shape[0] > 0:point_box_labels_single = point_box_labels.new_zeros((bs_mask.sum(), 8))#记录每一个前景点从G_hat到G的参数偏移,每个前景点最后输出是1*8维向量fg_point_box_labels = self.box_coder.encode_torch(gt_boxes=gt_box_of_fg_points[:, :-1], points=points_single[fg_flag],gt_classes=gt_box_of_fg_points[:, -1].long())point_box_labels_single[fg_flag] = fg_point_box_labelspoint_box_labels[bs_mask] = point_box_labels_singleif ret_part_labels:point_part_labels_single = point_part_labels.new_zeros((bs_mask.sum(), 3))transformed_points = points_single[fg_flag] - gt_box_of_fg_points[:, 0:3]transformed_points = common_utils.rotate_points_along_z(transformed_points.view(-1, 1, 3), -gt_box_of_fg_points[:, 6]).view(-1, 3)offset = torch.tensor([0.5, 0.5, 0.5]).view(1, 3).type_as(transformed_points)point_part_labels_single[fg_flag] = (transformed_points / gt_box_of_fg_points[:, 3:6]) + offsetpoint_part_labels[bs_mask] = point_part_labels_singletargets_dict = {'point_cls_labels': point_cls_labels,'point_box_labels': point_box_labels,'point_part_labels': point_part_labels}return targets_dict
经典框架解读 | 论文+代码 | 3D Detection | OpenPCDet | PointRCNN
相关文章:

关于PointHeadBox类的理解
forward函数 def forward(self, batch_dict):"""Args:batch_dict:batch_size:point_features: (N1 N2 N3 ..., C) or (B, N, C)point_features_before_fusion: (N1 N2 N3 ..., C)point_coords: (N1 N2 N3 ..., 4) [bs_idx, x, y, z]point_labels (opti…...
javascript二维数组(10)ajax的使用
在JQuery中,使用AJAX的方法主要有以下几种: $.ajax():这是JQuery中最通用的AJAX请求方法。它需要一个包含各种参数的对象,其中包括请求的URL、请求方式、数据类型、请求参数等。请求成功后执行的回调函数也是通过参数来定义的。 …...

CMMI5认证哪些企业可以申请
CMMI5认证哪些企业可以申请 什么是CMMI5认证 CMMI(Capability Maturity Model Integration)是一种用于评估组织的软件工程能力的国际标准。CMMI模型包括5个等级,其中CMMI5是最高等级,代表组织具有达到持续优化和创新的能力。获得…...

【iptables 实战】9 docker网络原理分析
在开始本章阅读之前,需要提前了解以下的知识 阅读本节需要一些docker的基础知识,最好是在linux上安装好docker环境。提前掌握iptables的基础知识,前文参考【iptables 实战】 一、docker网络模型 docker网络模型如下图所示 说明࿱…...

【多级缓存】
文章目录 1. JVM进程缓存2. Lua语法3. 实现多级缓存3.1 反向代理流程3.2 OpenResty快速入门 4. 查询Tomcat4.1 发送http请求的API4.2 封装http工具4.3 基于ID负载均衡4.4 流程小结 5. Redis缓存查询5.1 实现Redis查询 6. Nginx本地缓存6.1 本地缓存API6.2 实现本地缓存查询 7. …...

第五课 树与图
文章目录 第五课 树与图lc94.二叉树的中序遍历--简单题目描述代码展示 lc589.N叉树的层序遍历--中等题目描述代码展示 lc297.二叉树的序列化和反序列化--困难题目描述代码展示 lc105.从前序与中序遍历序列构造二叉树--中等题目描述代码展示 lc106.从中序与后序遍历序列构造二叉…...
2023-10-07 事业-代号z-副业-CQ私服-调研与分析
摘要: CQ作为一款运营了20年的游戏, 流传出的私服可以说是层出不穷, 到了现在我其实对这款游戏的长线运营的前景很悲观. 但是作为商业的一部分, 对其做谨慎的分析还是很有必要的. 传奇调研的来源: 一. 各种售卖私服的网站 传奇服务端版本库-传奇手游源码「免费下载」传奇GM论…...

合并不同门店数据-上下合并
项目背景:线下超市分店,统计产品的销售数量和销售额,并用透视表计算求和 merge()函数可以根据链接键横向连接两张不同表,concat()函数可以上下合并和左右合并2种不同的合并方式。merge()函数只能横向连接两张表,而con…...

学习记忆——数学篇——案例——算术——整除特点
理解记忆法 对于数的整除特征大家都比较熟悉:比如4看后两位(因为100是4的倍数),8看后三位(因为1000是8的倍数),5末尾是0或5,3与9看各位数字和等等,今天重点研究一下3,9,…...

PHP8中的魔术方法-PHP8知识详解
在PHP 8中,魔术方法是一种特殊的方法,它们以两个下划线(__)开头。魔术方法允许您定义类的行为,例如创建对象、调用其他方法或访问和修改类的属性。以下是一些常见的魔术方法: __construct(): 类的构造函数…...

[图论]哈尔滨工业大学(哈工大 HIT)学习笔记23-31
视频来源:4.1.1 背景_哔哩哔哩_bilibili 目录 1. 哈密顿图 1.1. 背景 1.2. 哈氏图 2. 邻接矩阵/邻接表 3. 关联矩阵 3.1. 定义 4. 带权图 1. 哈密顿图 1.1. 背景 (1)以地球为建模,从一个大城市开始遍历其他大城市并且返回…...

Nginx+Keepalived实现服务高可用
Nginx 和 Keepalived 是常用于构建高可用性(High Availability)架构的工具。Nginx 是一款高性能的Web服务器和反向代理服务器,而Keepalived则提供了对Nginx服务的健康状态监测和故障切换功能。 下载Nginx 在服务器1和服务器2分别下载nginx …...

picodet onnx转其它芯片支持格式时遇到
文章目录 报错信息解决方法两模型精度对比 报错信息 报错信息为: Upsample(resize) Resize_0 not support attribute coordinate_transformation_mode:half_pixel. 解决方法 整个模型转换过程是:paddle 动态模型转成静态,再用paddle2onnx…...
【学习笔记】CF704B Ant Man
智商不够啊,咋想到贪心的😅 非常经典的贪心模型🤔 首先,从小到大将每个 i i i插入到排列中,用 D P DP DP记录还有多少个位置可以插入,可以通过钦定新插入的位置左右两边是否继续插入数来提前计算贡献。注…...
SQLines数据迁移工具
Data and Analytics Platform Migration - SQLines Tools SQLines提供的工具可以帮助您在不同的数据库平台之间传输数据、转换数据库模式(DDL)、视图、存储过程、包、用户定义函数(udf)、触发器、SQL查询和SQL脚本。 SQLines SQL Converter OverviewCommand LineConfigurati…...
pkl文件与打开(使用numpy和pickle)
文章目录 1. 什么是pkl文件2. 如何打开?Reference 1. 什么是pkl文件 1)python中有一种存储方式,可以存储为.pkl文件。 2)该存储方式,可以将python项目过程中用到的一些暂时变量、或者需要提取、暂存的字符串、列表、…...

3d渲染农场全面升级,好用的渲染平台值得了解
什么是渲染农场? 渲染农场是专门从事 3D 渲染的大型机器集合,称为渲染节点,这些机器组合在一起执行一项任务(渲染 3D 帧和动画)。通过将渲染工作分配给数百台机器,可以显着减少渲染时间,从而使…...

1.5 JAVA程序运行的机制
**1.5 Java程序的运行机制** --- **简介:** Java程序的运行涉及两个主要步骤:编译和运行。这种机制确保了Java的跨平台特性。 **主要内容:** 1. **Java程序的执行过程**: - **编译**:首先,扩展名为.jav…...
基于FPGA的拔河游戏设计
基于FPGA的拔河游戏机 设计内容: (1)拔河游戏机需要11个发光二极管排成一行,开机 后只有中间一个亮点,作为拔河的中间线。 游戏双方 各持一个按键,迅速且不断地按动产生脉冲,哪方按 得快,亮点就向哪方移动, 每按一次,亮点移动一次。 移到任一方二极管的终端,该方就…...

关联规则挖掘(下):数据分析 | 数据挖掘 | 十大算法之一
⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...

英国云服务器上安装宝塔面板(BT Panel)
在英国云服务器上安装宝塔面板(BT Panel) 是完全可行的,尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎,虽然官方主要面向中国大陆…...

Pandas 可视化集成:数据科学家的高效绘图指南
为什么选择 Pandas 进行数据可视化? 在数据科学和分析领域,可视化是理解数据、发现模式和传达见解的关键步骤。Python 生态系统提供了多种可视化工具,如 Matplotlib、Seaborn、Plotly 等,但 Pandas 内置的可视化功能因其与数据结…...