3D目标检测实用技巧(二)- 实现点云(or 体素)向图像平面的投影并可视化

一、引言

受Focals Conv的启发,该论文中通过将点云投影到图片中清晰展现出点云学习后的情况:

本次实现的是体素向图像投影并显示,实现出来的效果如下:

二、 实现细节

1、体素投影到图像坐标系

这里我们参考的是VirConv的投影函数:

def index2uv(batch_dict, indices, batch_size, calib, stride, x_trans_train, trans_param):"""convert the 3D voxel indices to image pixel indices.将3D的voxel索引转换成图像像素"""# 变换维度的索引inv_idx = torch.Tensor([2, 1, 0]).long().cuda()batch_index = indices[:, 0]new_uv = indices.new(size=(indices.shape[0], 3))depth = indices.new(size=(indices.shape[0], 1)).float()for b_i in range(batch_size):# 找到对应的batchcur_in = indices[indices[:, 0] == b_i]# 转换成voxel3d特征cur_pts = index2points(cur_in, stride=stride)if trans_param is not None:# 反增强transed = x_trans_train.backward_with_param({'points': cur_pts[:, 1:4],'transform_param': trans_param[b_i]})cur_pts = transed['points']  # .cpu().numpy()else:cur_pts = cur_pts[:, 1:4]  # .cpu().numpy() 除了batch以外都取出来# 投影到相机坐标系pts_rect = calib[b_i].lidar_to_rect_cuda(cur_pts[:, 0:3])# 投影到图像坐标系pts_img, pts_rect_depth = calib[b_i].rect_to_img_cuda(pts_rect)# 转换成整型pts_img = pts_img.int()# pts_img = torch.from_numpy(pts_img).to(new_uv.device)# 找到对应的batch,把他的像素坐标取出来new_uv[indices[:, 0] == b_i, 1:3] = pts_img# pts_rect_depth = torch.from_numpy(pts_rect_depth).to(new_uv.device).float()# 深度信息depth[indices[:, 0] == b_i, 0] = pts_rect_depth[:]# batch对应new_uv[:, 0] = indices[:, 0]# 控制一下像素坐标# new_uv[:, 1] = torch.clamp(new_uv[:, 1], min=0, max=1400 - 1) // stride# new_uv[:, 2] = torch.clamp(new_uv[:, 2], min=0, max=600 - 1) // stridereturn new_uv, depth

以上代码具体可参考VirConv源码,这里不赘述。

调用:

# 读取体素坐标
pointxyz = sparse_t.indices
# 传入参数:从左向右依次是batch_dict总字典,pointxyz体素坐标,batchsize大小,calib标定矩阵,stride步长,TED独有的全局变换,trans_param增强参数
pc_xy, depth_pc = index2uv(batch_dict, pointxyz, batch_size, calib, 1, x_trans_train,trans_param)

以上是我目前能找的最有效,最简单的体素投影方法。

2、读取图像并根据深度来画体素

# 根据batch id 依次取出数据    
for batch_id in range(batch_size):# image的路径,这里我是放到batch_dict提前存好,所以这里可以直接改为路径img_path = str(batch_dict['image_path'][batch_id]).split('/')[-1]# 像素大小×255pcimg_batch = pcimg[batch_id] * 255# 根目录root_path = '/home/xd/xyy/VirConv-master/voxel_vision/vision_pcimg/' + img_path + '/'# 输出路径output_path = root_path + name + '_' + str(batch_id) + '.jpg'# 创建路径if not os.path.exists(root_path):os.makedirs(root_path)# 根据batch_id读取出当前batch下的体素坐标pc_xyz_indices = pc_xyz[pc_xyz[:, 0] == batch_id][:, 1:]for idx, pc in enumerate(pc_xyz_indices):# 根据深度确定颜色深度color = int((pc[2] / depth_max) * 255)# rectangle函数的主要作用是给指定的区域加上长宽分别为2的矩形边框if isinstance(pcimg_batch, torch.Tensor):pcimg_batch = pcimg_batch.cpu().numpy()if pc[0] < W and pc[1] < H:# 画体素cv2.rectangle(pcimg_batch, (int(pc[0] - 1), int(pc[1] - 1)), (int(pc[0] + 1), int(pc[1] + 1)),(0, 0, color), -1)cv2.imwrite(output_path, pcimg_batch)

3、完整代码

def vision_pc_img(sparse_t, pcimg, name, batch_dict, batch_size, calib, x_trans_train, trans_param, H=376, W=1241):pointxyz = sparse_t.indicespc_xy, depth_pc = index2uv(batch_dict, pointxyz, batch_size, calib, 1, x_trans_train,trans_param)# 保存pc_xy# for batch_id in range(batch_size):#     img_path = str(batch_dict['image_path'][batch_id]).split('/')[-1]#     name_2d = img_path + '/' + name#     save_2d(pc_xy[pc_xy[:,0]==batch_id], name_2d)# vision(sparse_t)pc_xyz = torch.cat((pc_xy, depth_pc), dim=1)depth_max, _ = torch.max(depth_pc.squeeze(1), dim=0)for batch_id in range(batch_size):img_path = str(batch_dict['image_path'][batch_id]).split('/')[-1]pcimg_batch = pcimg[batch_id] * 255root_path = '/home/xd/xyy/VirConv-master/voxel_vision/vision_pcimg/' + img_path + '/'output_path = root_path + name + '_' + str(batch_id) + '.jpg'if not os.path.exists(root_path):os.makedirs(root_path)pc_xyz_indices = pc_xyz[pc_xyz[:, 0] == batch_id][:, 1:]for idx, pc in enumerate(pc_xyz_indices):color = int((pc[2] / depth_max) * 255)# rectangle函数的主要作用是给指定的区域加上长宽分别为2的矩形边框if isinstance(pcimg_batch, torch.Tensor):pcimg_batch = pcimg_batch.cpu().numpy()if pc[0] < W and pc[1] < H:cv2.rectangle(pcimg_batch, (int(pc[0] - 1), int(pc[1] - 1)), (int(pc[0] + 1), int(pc[1] + 1)),(0, 0, color), -1)cv2.imwrite(output_path, pcimg_batch)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Java办公用品管理系统设计实现

基于JavaWeb开发的办公用品管理系统设计实现 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &#x1…

【每日一题】928. 尽量减少恶意软件的传播 II-2024.4.17

题目&#xff1a; 928. 尽量减少恶意软件的传播 II 给定一个由 n 个节点组成的网络&#xff0c;用 n x n 个邻接矩阵 graph 表示。在节点网络中&#xff0c;只有当 graph[i][j] 1 时&#xff0c;节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。…

react 项目路由配置(react-router-dom 版本 v6.3、v6.4)

根据 react-router-dom 的版本&#xff0c;有不同的方式 一、react-router-dom v6.3 用到的主要 api: BrowserRouteruseRoutesOutlet 下面是详细步骤&#xff1a; 1、index.js BrowserRouter 用来实现 单页的客户端路由使用 BrowserRouter 包裹 App放在 顶级 位置&#x…

【Redis 神秘大陆】001 背景基础理论

一、背景&基础理论 1.1 什么是缓存 缓存&#xff1a;存储在计算机上的一个原始数据复制集&#xff0c;以便于访问——维基百科 1.2 为什么用缓存 提升用户体验&#xff1a; 【即效率、效益和基本主观满意度】CAST 使用者的状态、系统性能及环境&#xff0c;不同的人对于…

2.2 @SpringBootApplication

2.2 SpringBootApplication 在前文的介绍中&#xff0c;读者已经了解到SpringBootApplication注解是加在项目的启动类上的。 SpringBootApplication实际上是一个组合注解&#xff0c;定义如下&#xff1a; SpringBootConfiguration EnableAutoConfiguration ComponentScan(exc…

开抖音小店需要多少资金的投入?全网最全介绍!

大家好&#xff0c;我是电商糖果 随着想在抖音开店卖货的人越来越多&#xff0c;大家对开抖音小店的资金投入越来越好奇。 糖果做抖音小店也有四年时间了&#xff0c;关于小店的资金投入&#xff0c;还是比较清楚的。 这里就来给大家列举&#xff0c;我愿称之为全网最全的开…

【java】static类的加载顺序

首先我们看一个案例 public class Test extends Base {static {System.out.println("test static");}public Test() {System.out.println("test control");}public static void main(String[] args) {new Test();} } class Base{static {System.out.print…

32.5k star!发现一个新的 API 调试工具!postman 要被替换了【文末有项目源码】

在软件开发过程中&#xff0c;API&#xff08;应用程序接口&#xff09;扮演着至关重要的角色。为了确保 API 的可靠性和性能&#xff0c;开发人员需要一种高效的方式来测试和调试它们。这方面的工具&#xff0c;大家经常用到的应该就是 postman 了。不过&#xff0c;今天想要给…

当你拥有Xbox-GamePass就能更快体验NewGame

如果你有游戏通行证终极通行证&#xff0c;那么你就可以看到很多预售的游戏&#xff0c;以及更多游戏内容。 Shadow of the Tomb Raider: Definitive Edition《古墓丽影:暗影&#xff08;终极版&#xff09;》 征服残酷无情的丛林&#xff0c;并活着走出来。探索充满裂隙和幽深…

Android 性能优化(七):APK安装包体积优化

包体积优化重要性 移动 App 特别关注投放转化率指标&#xff0c;而 App 包体积是影响用户新增的重要因素&#xff0c;而 App 的包体积又是影响投放转化率的重要因素。 Google 2016 年公布的研究报告显示&#xff0c;包体积每上升 6MB 就会带来下载转化率降低 1%&#xff0c; …

C++进阶——继承

前言&#xff1a;从这篇文章开始&#xff0c;我们进入C进阶知识的分享&#xff0c;在此之前&#xff0c;我们需要先来回顾一个知识&#xff1a; C语言有三大特性&#xff0c;分别是封装、继承和多态&#xff0c;而我们前边所分享的各种容器类&#xff0c;迭代器等&#xff0c;…

新型大数据架构之湖仓一体(Lakehouse)架构特性说明——Lakehouse 架构(一)

文章目录 为什么需要新的数据架构&#xff1f;湖仓一体&#xff08;Lakehouse&#xff09;——新的大数据架构模式同时具备数仓与数据湖的优点湖仓一体架构存储层计算层 湖仓一体特性单一存储拥有数据仓库的查询性能存算分离开放式架构支持各种数据源类型支持各种使用方式架构简…