熟悉mmdetection3d数据在模型中的处理流程

2023-11-07 04:59

本文主要是介绍熟悉mmdetection3d数据在模型中的处理流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

    • 1、搭建模型
    • 2、读取数据
    • 3、运行流程
      • 3.1 图像特征获取
      • 3.2 点云特征获取
      • 3.3 head
      • 3.4 编码bbox
    • 4、可视化
    • 5、总结

  • 本图文数据集采取KITTI数据集
  • 配置文件的介绍可以参考博主上一篇图文
  • 本图文旨在利用一条数据,走完整个多模态数据处理分支,获得bbox,并可视化在图像上

1、搭建模型

  • 本次教程选用的模型为MVXNet,是一个多模态融合的3D目标检测模型

  • 配置文件: mmdetection3d/configs/mvxnet/dv_mvx-fpn_second_secfpn_adamw_2x8_80e_kitti-3d-3class.py

  • 本次使用预训练模型,可以在mmdetection3d的mozel zoo中下载 MVXNet模型

from mmdet3d.apis import init_model
config_file = '/home/wistful/work/mmdetection3d/configs/mvxnet/dv_mvx-fpn_second_secfpn_adamw_2x8_80e_kitti-3d-3class.py'
checkpoint_file = '/home/wistful/ResultDir/my_pth/mxvnet/dv_mvx-fpn_second_secfpn_adamw_2x8_80e_kitti-3d-3class_20210831_060805-83442923.pth'model = init_model(config_file, checkpoint_file, 'cuda:1')

在这里插入图片描述

2、读取数据

from mmdet3d.datasets import build_dataset
from mmcv import Configcfg = Config.fromfile(config_file)
# 读取数据集
datasets = [build_dataset(cfg.data.train)]
# 我们取其中的一条数据,作为演示用例
one_data = datasets[0][0]
  • 根据我们的配置文件,我们得到的datasets为一个长度为7424(KITTI训练集长度)的列表,每一项包括4个字段:[‘img_metas’, ‘points’, ‘img’, ‘gt_bboxes_3d’, ‘gt_labels_3d’]

  • 接下来所有数据均使用这一个one_data

3、运行流程

MVXNet结构图如下:

在这里插入图片描述

MVXNet简化版模型结构:

model = dict(type='DynamicMVXFasterRCNN',img_backbone=dict(), # 图像骨干img_neck=dict(), # 图像neckpts_voxel_layer=dict(), # 体素层pts_voxel_encoder=dict(), # 体素编码层pts_middle_encoder=dict(), # 中间编码层pts_backbone=dict(), # 点云骨干pts_neck=dict(), # 点云neckpts_bbox_head=dict() # bbox head)

结合结构图,以上配置文件的最简理解是,图像经过骨干、neck得到图像特征;点云经过体素、编码得到点云特征;查看原版配置文件就可以看到,会在一个层融合图像和点云特征;随后经过head,产出bbox。接下来,我们先来获取图像特征:

3.1 图像特征获取

extract_img_feat = model.extract_img_feat
# 获取图像特征,此处获取的是图像经过骨干和neck之后的数据,为5个通道数为256的特征
img_feats = extract_img_feat((one_data.get('img').data).unsqueeze(dim=0).cuda(), [one_data.get('img_metas').data])
for i in img_feats:print(i.shape)# extrac_img_feat代码:
def extract_img_feat(self, img, img_metas):"""Extract features of images."""if self.with_img_backbone and img is not None:input_shape = img.shape[-2:]  # 获取图片的尺寸# update real input shape of each single imgfor img_meta in img_metas:img_meta.update(input_shape=input_shape)  # 更新一下img_metasif img.dim() == 5 and img.size(0) == 1:  # 维度等于5的话去除一个维度(只取一个图片)img.squeeze_()elif img.dim() == 5 and img.size(0) > 1:  # 取出批量、图片个数、通道、高、宽B, N, C, H, W = img.size()img = img.view(B * N, C, H, W)  # 重构为 [批量*数量, 通道, 高, 宽]img_feats = self.img_backbone(img)  # 送入骨干else:return Noneif self.with_img_neck:img_feats = self.img_neck(img_feats)  # 将骨干再送入neckreturn img_feats

输出如下:

image-20230310194626048

3.2 点云特征获取

extract_pts_feat = model.extract_pts_feat
# 获取点云特征,此处同上面各个字段的类型需要去代码里看定义
img_feat_list = list(img_feats)
pts_feats = extract_pts_feat([one_data.get('points').data.cuda()], img_feat_list, [one_data.get('img_metas').data])# extract_pts_feat代码:
def extract_pts_feat(self, pts, img_feats, img_metas):"""Extract features of points."""if not self.with_pts_bbox:return Nonevoxels, num_points, coors = self.voxelize(pts)  # 体素化# 体素编码器voxel_features = self.pts_voxel_encoder(voxels, num_points, coors,img_feats, img_metas)batch_size = coors[-1, 0] + 1x = self.pts_middle_encoder(voxel_features, coors, batch_size)x = self.pts_backbone(x)if self.with_pts_neck:x = self.pts_neck(x)return x

此时,我们已经得到图像特征和点云特征了,下面将特征送入head

3.3 head

# 此处的head为Anchor3DHead,返回值有三个: cls_score, bbox_pred, dir_cls_preds
# 其中,clas_score 通道数为  num_classes * num_anchors, num_classes在配置文件中
# bbox_pred 通道数为 num_anchors * box_code_size
# dir_cls_preds 通道数为 num_anchors * 2
# 得到head的输出后,还需要运行一下解码模块,才能得到最终的bbox和分类情况
pts_bbox_head = model.pts_bbox_head
pts_out = pts_bbox_head(pts_feats)  # tuple[list[torch.Tensor]]
cls_score, bbox_pred, dir_cls_preds = pts_out
print("cls_score:", cls_score[0].shape)
print("bbox_pred:", bbox_pred[0].shape)
print("dir_cls_preds:", dir_cls_preds[0].shape)

在这里插入图片描述

3.4 编码bbox

# 将head得到的输出编码为bboxer
bboxes = model.pts_bbox_head.get_bboxes(cls_score, bbox_pred, dir_cls_preds, [one_data.get('img_metas').data])
print(type(bboxes[0][0]))  # 是在LiDAR坐标系下
bboxes_data = bboxes[0][0]  # 得到了n个预测框
bboxes_data

image-20230310195117153

以上是最简版的一条数据在模型里的流动过程,还有n多实现细节,需要去深扒代码

4、可视化

这一部分,我们可视化我们在3.4中得到的bbox,程序自己看吧

import cv2
from mmdet3d.core import show_multi_modality_resultimg_metas = one_data.get('img_metas').data
img_file_path = img_metas['filename'] # 获取one_data对应的图像文件名img = cv2.imread(img_file_path) # 读取图像
front_mat = one_data.get('img_metas').data.get('lidar2img') # 获取投影矩阵gt_boxes = one_data.get('gt_bboxes_3d').data # 从one_data中获取gt_bboxes
print(gt_boxes)
print(bboxes_data)
# gt_bboxes_cam
bboxes_data = bboxes_data.to('cpu')
# 保存可视化图像到out_dir
show_multi_modality_result(img=img,box_mode='lidar',gt_bboxes=gt_boxes,img_metas=img_metas,pred_bboxes=bboxes_data,proj_mat=front_mat,out_dir="/home/wistful/work/mmdetection3d/visual_img/",filename="test",show=False)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GcltvkGl-1678449986037)(null)]

这里我得到了四个输出,是因为我改动了一下show_multi_modality_result方法,加了一个将地面真相bbox和预测bbox绘制到一张图像上的方法。如下图所示,橙色为地面真相bbox,蓝色为预测框

在这里插入图片描述

5、总结

简单画了一个流程图,橙色代表我们获取的数据内容,蓝色代表网络,绿色代表我们得到的东西

在这里插入图片描述

这篇关于熟悉mmdetection3d数据在模型中的处理流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

MySQL游标和触发器的操作流程

《MySQL游标和触发器的操作流程》本文介绍了MySQL中的游标和触发器的使用方法,游标可以对查询结果集进行逐行处理,而触发器则可以在数据表发生更改时自动执行预定义的操作,感兴趣的朋友跟随小编一起看看... 目录游标游标的操作流程1. 定义游标2.打开游标3.利用游标检索数据4.关闭游标例题触发器触发器的基

MySQL数据目录迁移的完整过程

《MySQL数据目录迁移的完整过程》文章详细介绍了将MySQL数据目录迁移到新硬盘的整个过程,包括新硬盘挂载、创建新的数据目录、迁移数据(推荐使用两遍rsync方案)、修改MySQL配置文件和重启验证... 目录1,新硬盘挂载(如果有的话)2,创建新的 mysql 数据目录3,迁移 MySQL 数据(推荐两

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

MySQL快速复制一张表的四种核心方法(包括表结构和数据)

《MySQL快速复制一张表的四种核心方法(包括表结构和数据)》本文详细介绍了四种复制MySQL表(结构+数据)的方法,并对每种方法进行了对比分析,适用于不同场景和数据量的复制需求,特别是针对超大表(1... 目录一、mysql 复制表(结构+数据)的 4 种核心方法(面试结构化回答)方法 1:CREATE

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

SpringSecurity中的跨域问题处理方案

《SpringSecurity中的跨域问题处理方案》本文介绍了跨域资源共享(CORS)技术在JavaEE开发中的应用,详细讲解了CORS的工作原理,包括简单请求和非简单请求的处理方式,本文结合实例代码... 目录1.什么是CORS2.简单请求3.非简单请求4.Spring跨域解决方案4.1.@CrossOr

MySQL中的DELETE删除数据及注意事项

《MySQL中的DELETE删除数据及注意事项》MySQL的DELETE语句是数据库操作中不可或缺的一部分,通过合理使用索引、批量删除、避免全表删除、使用TRUNCATE、使用ORDERBY和LIMI... 目录1. 基本语法单表删除2. 高级用法使用子查询删除删除多表3. 性能优化策略使用索引批量删除避免

requests处理token鉴权接口和jsonpath使用方式

《requests处理token鉴权接口和jsonpath使用方式》文章介绍了如何使用requests库进行token鉴权接口的处理,包括登录提取token并保存,还详述了如何使用jsonpath表达... 目录requests处理token鉴权接口和jsonpath使用json数据提取工具总结reques