3D目标检测实用技巧(三)- 生成虚拟点

一、引言

本次参考的是VirConv生成虚拟点的方法:

VirConv/tools/PENet at master · hailanyi/VirConv · GitHubVirtual Sparse Convolution for Multimodal 3D Object Detection - VirConv/tools/PENet at master · hailanyi/VirConvicon-default.png?t=N7T8https://github.com/hailanyi/VirConv/tree/master/tools/PENet里面用到了一些小技巧,直接绕开评估,直接使用预训练的权重生成虚拟点。本文主要介绍如何使用各种各样的深度补全方法生成虚拟点,辅助3D目标检测:

 二、更改推理py文件

不同深度补全更改代码的方式是不同,有些甚至非常难改,可惜不能一点通。整体套路都是一样的,首先我们需要知道的一点就是,如果我们仅生成虚拟点,那么gt标签评估函数什么的都不重要了,想去掉就去掉。因此,我们最主要的就是如何读取我们自己的数据集以及如何准确的实现深度图到3D LiDAR坐标系的投影。

下面我们以当前SOTA LRRU为例,具体操作如下:

1、重写Dataloader

我们需要自己写一个读取KITTI 3D目标检测数据集的DataLoader,从而替换掉原来读取KITTI DC的DataLoader。主要更改的是读取方式,比如calib的读取,lidar的读取,以及图像的读取。(也不是说他的不好,主要是封装的太死了,我直接改用我写好的。)

调用:

        if self.arg.dataset == 'kitti': # 我们新加的my_loaderrgb, dep = self.my_loader[index]gt = NoneK = Nonepaths = Noneelse:  # 原来的读取方法dep, gt, K, rgb, paths = self.__getraw__(index)

下面是我参考VirConv的方法改好的完整代码:

class KittiDepthSemi(data.Dataset):"""A data loader for the Kitti dataset"""def __init__(self, split, args, arg):self.args = argsself.split = splitself.arg = argif arg.dataset == 'kitti-dc':self.paths = get_kittipaths(split, args)elif arg.dataset == 'kitti':self.my_loader = MyLoader(arg.detpath)self.transforms = kittitransformsself.ipfill = fill_in_fastdef __getraw__(self, index):dep = read_depth(self.paths['dep'][index]) if \(self.paths['dep'][index] is not None) else Nonegt = read_depth(self.paths['gt'][index]) if \self.paths['gt'][index] is not None else Nonergb = read_rgb(self.paths['rgb'][index]) if \(self.paths['rgb'][index] is not None) else Noneif self.paths['K'][index] is not None:if self.split == 'train' or (self.split == 'val' and self.args.val == 'full'):calib = read_calib_file(self.paths['K'][index])K_cam = Noneif 'image_02' in self.paths['rgb'][index]:K_cam = np.reshape(calib['P_rect_02'], (3, 4))elif 'image_03' in self.paths['rgb'][index]:K_cam = np.reshape(calib['P_rect_03'], (3, 4))K = [K_cam[0, 0], K_cam[1, 1], K_cam[0, 2], K_cam[1, 2]]else:f_calib = open(self.paths['K'][index], 'r')K_cam = f_calib.readline().split(' ')f_calib.close()K = [float(K_cam[0]), float(K_cam[4]), float(K_cam[2]),float(K_cam[5])]else:K = Nonereturn dep, gt, K, rgb, self.paths['dep'][index]def __getitem__(self, index):if self.arg.dataset == 'kitti':rgb, dep = self.my_loader[index]gt = NoneK = Nonepaths = Noneelse:dep, gt, K, rgb, paths = self.__getraw__(index)dep, gt, K, rgb = self.transforms(self.split, self.args, dep, gt, K, rgb)dep_np = dep.numpy().squeeze(0)dep_clear, _ = outlier_removal(dep_np)dep_clear = np.expand_dims(dep_clear, 0)dep_clear_torch = torch.from_numpy(dep_clear)# ip_basic filldep_np = dep.numpy().squeeze(0)dep_np_ip = np.copy(dep_np)dep_ip = self.ipfill(dep_np_ip, max_depth=100.0,extrapolate=True, blur_type='gaussian')dep_ip_torch = torch.from_numpy(dep_ip)dep_ip_torch = dep_ip_torch.to(dtype=torch.float32)# gt = dep_clear_torch if gt==None else gtcandidates = {'dep': dep, 'dep_clear': dep_clear_torch, 'gt': gt, 'rgb': rgb, 'ip': dep_ip_torch}items = {key: valfor key, val in candidates.items() if val is not None}if (self.args.debug_dp or self.args.test) and self.arg.dataset =='kitti-dc':items['d_path'] = pathsreturn itemsdef __len__(self):if self.args.toy_test:return self.args.toy_test_numberelse:try:return len(self.paths['gt'])except:return len(self.my_loader)

MyLoader:

class MyLoader():def __init__(self, root_path=''):self.root_path = root_pathself.file_list = self.include_all_files()def include_all_files(self):velo_path = os.path.join(self.root_path, 'velodyne')all_files = os.listdir(velo_path)all_files.sort()all_files = [x[0:6] for x in all_files]return all_filesdef __len__(self):return len(self.file_list)def __getitem__(self, item):file_idx = self.file_list[item]# 读取kitti的基本信息file_image_path = os.path.join(self.root_path, 'image_2', file_idx + '.png')file_velo_path = os.path.join(self.root_path, 'velodyne', file_idx + '.bin')file_calib = os.path.join(self.root_path, 'calib', file_idx + '.txt')# 返回的是个Calibration的对象:初始化了P2,P3,Tr_velo2cam,R0calib = calibration_kitti.Calibration(file_calib)# 读取点云和imgpoints = np.fromfile(str(file_velo_path), dtype=np.float32).reshape(-1, 4)# points = layer_point_discard(points, 0.9)image = np.array(io.imread(file_image_path), dtype=np.int32)image = image[:352, :1216]# 这里将点云rgb, depth = load_depth_input(calib, image, points)

2、投影并保存为虚拟点

这一块其实挺简单的,我们只需要找到预测出来深度图的位置,一般都挺明显的,例如:

outputf = net(samplef)

里面保存着预测好的深度图,然后我们需要根据刚刚读取好的calib将深度图投影到3D空间中:

def save_depth_as_points(depth, idx, root_path, args):file_idx = str(idx).zfill(6)# 保存成png,同时也保存成bin文件file_image_path = os.path.join(root_path, 'image_2', file_idx + '.png')file_velo_path = os.path.join(root_path, 'velodyne', file_idx + '.bin')file_calib = os.path.join(root_path, 'calib', file_idx + '.txt')calib = calibration_kitti.Calibration(file_calib)# ############################改动1:最最最重要!!!!!!calib修正##################################### 这里calib不修正的话,会导致最后投影直接出问题。calib.cv -= args.top_crop# 读取lidar文件lidar = np.fromfile(str(file_velo_path), dtype=np.float32).reshape(-1, 4)# 读取图像信息image = np.array(io.imread(file_image_path), dtype=np.int32)# ###############################2、改动2:rgb这里要改成252################################## 这里千万千万不要改,如果把这个改成100:352,或者是:252就会出现img投影和depth投影不能完全重合的情况,具体看qq发的效果图image = image[:352, :1216]# #######################保存rgb##################### paths_rgb = os.path.join(root_path, 'velodyne_depth')# out_path_img = os.path.join(paths_rgb, file_idx + '_rgb.png')# cv2.imwrite(out_path_img, image)# 将lidar数据转换到相机pts_rect = calib.lidar_to_rect(lidar[:, 0:3])# 截取FOV视角的lidar点云fov_flag = get_fov_flag(pts_rect, image.shape, calib)lidar = lidar[fov_flag]# lidar = layer_point_discard(lidar, 0.7)# liar深度保存位置paths = os.path.join(root_path, 'velodyne_depth_lrru')if not os.path.exists(paths):os.makedirs(paths)# 文件格式out_path = os.path.join(paths, file_idx + '.npy')# ##############################2、改动2:这里也要改成252#################################333depth = depth.squeeze(0).permute(1,2,0).cpu().detach().numpy()# # ###############depth_img保存初始深度图##################### root_path = '/media/xd/7fffee8d-7279-4e6a-80bf-7880ff37da7a/xyy/LRRU/vision/corrupted_image/'# if not os.path.exists(root_path):#     os.makedirs(root_path)# total_path = root_path + 'pre_init' + str(idx) + '.jpg'# cv2.imwrite(total_path, depth)## out_path_img = os.path.join(paths, file_idx + '.png')# img = np.squeeze(depth)# img = (img * 256).astype('uint16')# cv2.imwrite(out_path_img, img)# ######################保存最终合并gt信息的深度补全数据point###################### calib.cv -= args.top_crop# calib.cu -= args.top_crop# calib.fv -= args.top_crop# 将深度图转换成voxelfinal_points, new_lidar, new_p = depth2pointsrgbp(depth, image, calib, lidar)# 保存成float16类型final_points = final_points.astype(np.float16)new_lidar = new_lidar.astype(np.float16)# vision(final_points)# vision(new_lidar)# 保存成npynp.save(out_path, final_points)return len(final_points)

最后可视化的结果如下:

 3、完整代码

完整的LRRU,TWISE,DySPN,PENet,CompletionFormer等各种补全生成虚拟点的方法会在我论文录用后开源。

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

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

相关文章

腾讯文档推出智能白板创新品类,自研开物引擎支持全端应用

4月18日,“腾讯文档,打开想象”2024产品发布会在线上举办。腾讯社交协作产品部总经理、腾讯文档负责人鄢贤卿在会上,正式发布智能白板创新品类、双核编辑“开物引擎”、云加端解决方案等产品矩阵。他表示,在自研文档品类和自研双核…

ctfshow web入门 SQl注入web171--web179

从这里开始SQl建议大家去看这篇文章学习一下先 MySQl web171 法一联合查询 题目 $sql "select username,password from user where username !flag and id ".$_GET[id]." limit 1;";爆数据库名 -1 union select 1,database(),3 -- 爆表名 -1 union s…

数据结构 - 栈

概述 计算机科学中,stack是一种线性的数据结构,只能在其一段添加和移除数据. 习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,就如同生活中的一摞书 先提供一个接口: public interface Stack <E>{/*** 向栈顶压入元素* param value -- 待压入值* returns…

✌粤嵌—2024/4/18—旋转链表✌

代码实现&#xff1a; 方法一&#xff1a;在原链表中找到旋转之后的首尾&#xff0c;改变指向 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* rotateRight(struct ListNode *head, int k) {i…

线程安全问题的原因和解决方案

目录 原因分析 解决线程安全问题——加锁 synchroized&#xff08;&#xff09; 死锁 死锁的四个必要条件 线程安全是指多个线程同时访问共享资源时&#xff0c;不会产生不正确的结果。线程安全问题的主要原因是多个线程对共享数据进行读写操作时的并发性。这可能导致竞态…

制作直通网线和交叉网线

制作直通网线和交叉网线 1. 网络直通线2. 网络交叉线References 双绞线的连接方法有两种&#xff1a;直通连接和交叉连接 。 直通连接是将双绞线的两端分别都依次按白橙、橙、白绿、蓝、白蓝、绿、白棕、棕色的顺序 (国际 EIA/TIA 568B 标准) 压入 RJ45 水晶头内。这种方法制作…

壁纸、软件、电子书、音乐资源、数据库资源,囤一囤

资源网站我真的有很多&#xff01;&#xff01;下面这十几个都是壁纸资源、软件资源、电子书资源、音乐资源、数据库资源等等&#xff0c;感兴趣的囤一囤&#xff01; 一、壁纸资源 1、PEXELS 网址&#xff1a; https://www.pexels.com/zh-cn/ 一个专门分享无版权图片的网站…

Windows突然蓝屏解决办法

Windows突然蓝屏&#xff0c;然后重复开机没有用&#xff0c;但是能进入bios系统&#xff0c;证明内存和磁盘没事&#xff0c;用大白菜制作了PE系统盘制作过程&#xff08;之前一直都是用官方镜像制作&#xff0c;但是发现用大白菜制作可以对系统之前的磁盘里面重要的信息拷贝到…

Python用于比较数据结构并生成差异报告的工具库之data-diff使用详解

概要 Python的data-diff库是一个用于比较数据结构并生成差异报告的工具。它可以处理各种数据类型,如字典、列表、集合等,使得开发者能够快速识别数据之间的差异。 安装 通过pip可以轻松安装data-diff: pip install data-diff特性 支持多种数据类型:能够比较字典、列表、…

tokio 学习

Rust Async 异步编程 简易教程 理解tokio核心(1): runtime Rust 中的异步编程 Rust 中的 async 和线程 OS 线程&#xff1a; 适用于少量任务&#xff0c;有内存和 CPU 开销&#xff0c;且线程生成和线程间切换非常昂贵线程池可以降低一些成本允许重用同步代码&#xff0c;…

新手做抖音小店,最易爆单的几大类目分享,抓紧收藏!

大家好&#xff0c;我是电商糖果 新手做抖店没有经验&#xff0c;不了解市场&#xff0c;很多人都担心类目选错了&#xff0c;很难起店。 毕竟电商行业有一句话&#xff0c;类目大于一切&#xff0c;选择大于努力。 类目没有选对&#xff0c;再折腾也没用。 糖果做抖音小店…

eclipse配置SVN和Maven插件

3、 安装SVN插件 使用如下方法安装 Help–Install New Software 注意&#xff1a;目前只能安装1.8.x这个版本的SVN&#xff0c;如果使用高版本的SVN&#xff0c;在安装SVN和maven整合插件的时候就会报错&#xff0c;这应该是插件的bug。 点击Add name: subclipse location…

五款3dmax常用插件推荐(含云渲染工具)

在三维建模和动画设计领域&#xff0c;3ds Max软件因其强大功能和灵活性而广受欢迎。为了进一步提升工作效率和创作质量&#xff0c;有许多插件可供选择。本文推荐五款常用3ds Max插件&#xff0c;帮助你更好实现复杂的模型和动效创作。 五款3dmax常用插件推荐 1、Kitchen Cab…

Linux gcc 6

本章开始学习工具 什么是工具&#xff1f; 本质也是指令 yum 命令 小火车 sudo yum install sl&#xff08;安装sl&#xff09; sudo yum install -y sl //直接yes就不提示了 yum list //将yum源上的软件都穷举出来 yum search sl //结果不友好&#xff0c;不推荐 yum lis…

活动报名 | 如何进行全增量一体的异构数据库实时同步

伴随着新技术的不断涌现&#xff0c;市场竞争也在不断开辟新的角斗场——新的业务需求&#xff0c;新的应用设想都在这里迸发。 面对如此日新月异的竞争环境&#xff0c;企业的当务之急&#xff0c;是为新应用扎根准备好随时可取、准确一致的高质量数据土壤。在这样的背景下&a…

(二十八)Flask之wtforms库【上手使用篇】

目录&#xff1a; 每篇前言&#xff1a;用户登录验证&#xff1a;用户注册验证&#xff1a;使用示例&#xff1a; 抽象解读使用wtforms编写的类&#xff1a;简单谈一嘴&#xff1a;开始抽象&#xff1a; 每篇前言&#xff1a; &#x1f3c6;&#x1f3c6;作者介绍&#xff1a;【…

Docker 磁盘占用过多问题处理过程记录

一、问题描述 突然发现服务器磁盘使用超过95%了&#xff08;截图时2.1 和 2.2 已经执行过了&#xff09; 二、问题分析与解决 2.1&#xff0c;docker 无用镜像占用磁盘 # 使用 docker images 查看服务的镜像 docker images# 可以手动删除一些很大不用的 docker rmi ***## 也…

一秒内传输50万对纠缠光子?!纽约市量子网络刷新纪录

量子网络技术行业的领军企业Qunnect宣布&#xff0c;在纽约市的GothamQ网络上&#xff0c;其偏振量子比特的传输性能刷新了纪录。Qunnect利用现有的商用光缆实现了每秒传输50万对高保真度纠缠光子的速率&#xff0c;且该网络的正常运行时间超过了99%。 纽约34公里长的GothamQ量…

服务器数据恢复—RAID5故障导致SAP+oracle数据丢失的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌服务器存储中有一组由6块SAS硬盘组建的RAID5阵列&#xff0c;其中有1块硬盘作为热备盘使用。上层划分若干lun&#xff0c;存放Oracle数据库数据。 服务器存储故障&分析&#xff1a; 该RAID5阵列中一块硬盘出现故障离线&#xff0…

开启Three.js之旅(会持续完善)

文章目录 Three.js必备构建项目场景Scene相机CameraPerspectiveCamera 渲染器WebGLRendererCSS3DRenderer 灯光LightAmbientLightDirectionalLight 平行光PointLight 加载器CacheFileLoaderLoaderGLTFLoaderRGBELoaderTextureLoader 材质MetarialMeshBasicMaterialMeshLambertM…