【目标测距】雷达投影测距

文章目录

  • 前言
  • 一、读取点云
  • 二、点云投影图片
  • 三、读取检测信息
  • 四、点云投影测距
  • 五、学习交流

前言

  1. 雷达点云投影相机。图片目标检测,通过检测框约束等等对目标赋予距离。
  2. 计算消耗较大,适合离线验证操作。在线操作可以只投影雷达检测框。

一、读取点云

  • python 读取点云,我这里用的是 open3d 这个库。
import open3d as o3d

pcd_path = "1.pcd"
pcd = o3d.io.read_point_cloud(pcd_path)  # 点云

二、点云投影图片

  • 明白标定原理,这部分就很简单,就是一个矩阵运算。投影像素误差多少与传感器标定强相关。
  • 下面代码中 mtx:相机内参 r_camera_to_lidar_inv:相机到雷达的旋转矩阵的逆矩阵 t_camera_to_lidar:相机到雷达的平移向量
    在这里插入图片描述
import open3d as o3d
import numpy as np
import cv2

color_label = [(255, 0, 0), (121, 68, 222), (0, 0, 255), (0, 255, 0), (199, 199, 53)]  # 红黄蓝绿青


# 不同距显示不同颜色
def get_color(distance):
    for i in range(2, 50):
        if i < distance < i + 1:
            return color_label[i % len(color_label)]
    return color_label[0]


pcd_path = "1.pcd"
pcd = o3d.io.read_point_cloud(pcd_path)  # 点云
image = cv2.imread("1.jpg")

cloud = np.asarray(pcd.points)
for point in cloud:
    camera_coordinate = np.dot(mtx, np.dot(r_camera_to_lidar_inv, point.reshape(3, 1) - t_camera_to_lidar))
    pixe_coordinate = camera_coordinate / camera_coordinate[2]
    x_pixe, y_pixe, _ = pixe_coordinate
    cv2.circle(image, (int(x_pixe), int(y_pixe)), 1, get_color(camera_coordinate[2]), 2)

三、读取检测信息

  • 图像目标检测信息保存在txt文件。格式: frame , x_center , y_cente , width , height , score。
import numpy as np


def GetDetFrameRes(seq_dets, frame):
    detects = seq_dets[(seq_dets[:, 0] == frame) & (seq_dets[:, 5] <= 6), 1:6]
    detects[:, 0:2] -= detects[:, 2:4] / 2  # convert to [x中心,y中心,w,h] to [x左上,y左上,w,h]
    detects[:, 2:4] += detects[:, 0:2]  # convert to [x左上,y左上,w,h] to [x左上,y左上,x右下,y右下]
    return detects


det_dir = "result.txt"
det_data = np.loadtxt(det_dir, delimiter=',')
# 假如有100帧图片
for i in range(100):
    dets_frame = GetDetFrameRes(det_data, i)  # 获取第i帧检测结果

四、点云投影测距

  • 判断点云是否在图像目标检测框内。
  • 对于图片目标检测框有重复的情况,需要对目标检测框进行排列,距离靠前的检测框优先计算。
  • 选取点云中 x 最小的为目标的距离,y 距离取目标框内平均值
    在这里插入图片描述
import os
import cv2
import yaml
import numpy as np
import open3d as o3d
from datetime import datetime


def read_yaml(path):
    with open(path, 'r', encoding='utf-8') as f:
        result = yaml.load(f.read(), Loader=yaml.FullLoader)
    camera_mtx = result["camera"]["front_center"]["K"]
    r_camera = result["camera"]["front_center"]["rotation"]
    t_camera = result["camera"]["front_center"]["translation"]
    lidar_to_car = result["lidar"]["top_front"]["coordinate_transfer"]
    c_m = np.array([camera_mtx]).reshape(3, 3)
    r_c = np.array([r_camera]).reshape(3, 3)
    t_c = np.array([t_camera]).reshape(3, 1)
    l_c = np.array([lidar_to_car]).reshape(4, 4)
    return c_m, r_c, t_c, l_c


def get_box_color(index):
    color_list = [(96, 48, 176), (105, 165, 218), (18, 153, 255)]
    return color_list[index % len(color_list)]


# 不同距显示不同颜色
def get_color(distance):
    for i in range(2, 50):
        if i < distance < i + 1:
            return color_label[i % len(color_label)]
    return color_label[0]


def GetDetFrameRes(seq_dets, frame):
    detects = seq_dets[(seq_dets[:, 0] == frame) & (seq_dets[:, 5] <= 6), 1:6]
    detects[:, 0:2] -= detects[:, 2:4] / 2  # convert to [x中心,y中心,w,h] to [x左上,y左上,w,h]
    detects[:, 2:4] += detects[:, 0:2]  # convert to [x左上,y左上,w,h] to [x左上,y左上,x右下,y右下]
    return detects


# 点云投影到图片
def point_to_image(image_path, pcd_point, det_data, show=False):
    cloud = np.asarray(pcd_point.points)
    image = cv2.imread(image_path)
    det_data = det_data[np.argsort(det_data[:, 3])[::-1]]
    n = len(det_data)
    point_dict = {i: [] for i in range(n)}
    for point in cloud:
        if 2 < point[0] < 100 and -30 < point[1] < 30:
            camera_coordinate = np.dot(mtx, np.dot(r_camera_to_lidar_inv, point.reshape(3, 1) - t_camera_to_lidar))
            pixe_coordinate = camera_coordinate / camera_coordinate[2]
            x_pixe, y_pixe, _ = pixe_coordinate

            # 判断一个点是否在检测框里面
            idx = np.argwhere((x_pixe >= det_data[:, 0]) & (x_pixe <= det_data[:, 2]) &
                              (y_pixe >= det_data[:, 1]) & (y_pixe <= det_data[:, 3])).reshape(-1)
            if list(idx):
                index = int(idx[0])
                cv2.circle(image, (int(x_pixe), int(y_pixe)), 1, get_box_color(index), 2)
                point_dict[index].append([point[0], point[1]])

    for i in range(n):
        cv2.rectangle(image, (int(det_data[i][0]), int(det_data[i][1])), (int(det_data[i][2]), int(det_data[i][3])),
                      get_box_color(int(det_data[i][4])), 2)  # 不同类别画不同颜色框
        np_data = np.array(point_dict[i])
        if len(np_data) < 3:
            continue
        x = np.min(np_data[:, 0])
        min_index = np.argmin(np_data, axis=0)
        y = np.average(np_data[min_index, 1])
        cv2.putText(image, '{},{}'.format(round(x, 1), round(y, 1)), (int(det_data[i][0]), int(det_data[i][1]) - 10),
                    cv2.FONT_HERSHEY_COMPLEX, 1, get_box_color(int(det_data[i][4])), 2)
    video.write(image)
    if show:
        cv2.namedWindow("show", 0)
        cv2.imshow("show", image)
        cv2.waitKey(0)


def main():
    pcd_file_paths = os.listdir(pcd_dir)
    img_file_paths = os.listdir(img_dir)
    len_diff = max(0, len(pcd_file_paths) - len(img_file_paths))
    img_file_paths.sort(key=lambda x: float(x[:-4]))
    pcd_file_paths.sort(key=lambda x: float(x[:-4]))
    pcd_file_paths = [pcd_dir + x for x in pcd_file_paths]
    img_file_paths = [img_dir + x for x in img_file_paths]
    det_data = np.loadtxt(det_dir, delimiter=',')
    for i in range(min(len(img_file_paths), len(pcd_file_paths))):
        pcd = o3d.io.read_point_cloud(pcd_file_paths[i + len_diff])  # 点云
        now = datetime.now()
        dets_frame = GetDetFrameRes(det_data, i)
        point_to_image(img_file_paths[i], pcd, dets_frame, show=show)
        print(i, datetime.now() - now)
    video.release()


if __name__ == '__main__':
    color_label = [(255, 0, 0), (121, 68, 222), (0, 0, 255), (0, 255, 0), (199, 199, 53)]  # 红黄蓝绿青
    path = "F:\\data\\"
    pcd_dir = path + "lidar_points\\"  # 点云文件夹绝对路径
    img_dir = path + "image_raw\\"  # 图片文件夹绝对路径
    det_dir = path + "result.txt"  # 目标检测信息
    video_dir = path + "point_img4.mp4"
    video = cv2.VideoWriter(video_dir, cv2.VideoWriter_fourcc('m', 'p', '4', 'v'), 10, (1920, 1080))  # 保存视频
    cali_dir = "sensor.yaml"
    mtx, r_camera, t_camera, lidar_to_car = read_yaml(cali_dir)
    r_lidar, t_lidar = lidar_to_car[:3, :3], lidar_to_car[:3, -1].reshape(3, 1)
    r_camera_to_lidar = np.linalg.inv(r_lidar) @ r_camera
    r_camera_to_lidar_inv = np.linalg.inv(r_camera_to_lidar)
    t_camera_to_lidar = np.linalg.inv(r_lidar) @ (t_camera - t_lidar)  # 前相机,主雷达标定结果
    show = True
    main()

五、学习交流

有任何疑问可以私信我,欢迎交流学习。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

纯CSS实现炫酷文本阴影效果

如图所示&#xff0c;这是一个文本阴影效果&#xff0c;阴影有多个颜色&#xff0c;鼠标悬停时文本阴影效果消失&#xff0c;文本回到正常的效果。让我们逐步分解代码&#xff0c;看看如何使用纯CSS实现这个效果的。 基于以上动图可以分析出以下是本次实现的主要几个功能点&am…

大健康产业的先行者「完美公司」携手企企通,推进企业采购供应链数字化进程

随着中国经济持续向好&#xff0c;消费升级和美妆步骤增加&#xff0c;美妆和个人护理产品已逐渐成为中国消费者的日用消费品&#xff0c;推动了护肤品和化妆品的销售额增速均超过10%&#xff0c;成为中国整个快速消费品市场中的一颗亮眼明珠。 据国家统计局数据显示&#xff0…

跨境出海人必备的营销指南:海外各大社交媒体的对比

随着全球数字化的加速&#xff0c;社交媒体已经成为人们交流、分享、获取信息的主要渠道。根据最新的全球数字报告 “DIGITAL 2022: GLOBAL OVERVIEW REPORT”显示&#xff0c;截至2022年&#xff0c;全球有46.2亿社交媒体用户&#xff0c;这个数字相当于世界总人口的58.4%。这…

【Echarts】Echarts在不同屏幕分辨率下不同配置

目录 1、图表横坐标&#xff1a;分辨率低的情况下&#xff0c;刻度标签旋转的角度&#xff0c;在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠。2、图表图例&#xff1a;在 legend 文字超过6个字的时候对文字做裁剪并且开启 tooltip 参考文章&#xff1a;1、使…

mybatis使用foreach标签实现union集合操作

最近遇到一个场景就是Java开发中&#xff0c;需要循环多个表名&#xff0c;然后用同样的查询操作分别查表&#xff0c;最终得到N个表中查询的结果集合。在查询内容不一致时Java中跨表查询常用的是遍历表名集合循环查库&#xff0c;比较耗费资源&#xff0c;效率较低。在查询内容…

作为测试你连K8S都不懂,你还有脸说自己是测试?

kubernetes&#xff0c;简称 K8s&#xff0c;是用 8 代替中间 8 个字符 “ubernete” 而成的缩写&#xff0c;是一个开源的&#xff0c;用于管理云平台中多个主机上的容器化的应用&#xff0c;Kubernetes 的目标是让部署容器化的应用简单并且高效(powerful)&#xff0c;Kuberne…

高版本Vivado和Linux 4.x内核移植Digilent Driver

移植环境 Vivado 2022.2Ubuntu 22.04petalinux 2022.2Linux内核4.14&#xff08;xilinx-linux-2018.3&#xff09;linux-digilent 主要问题 https://github.com/Digilent/linux-digilent 这些驱动支持Linux kernel release 4.x&#xff0c;然而和Vitis 2022.2 套件对应的内核…

【自我管理】To-do list已过时?学写Done List培养事业成功感

自我管理&#xff1a;已完成清单&#xff08;doneList&#xff09;培养事业成功感 待办事项清单常常让人感到压力山大&#xff0c;让人不想面对工作。但是&#xff0c;你知道吗&#xff1f;除了待办清单之外&#xff0c;还有一个叫做「已完成清单」的东西&#xff0c;它可能更符…

元宇宙外科手术vrar仿真实验室平台提高了培训效率和安全性

在科研与教育的领域中&#xff0c;实验室的作用举足轻重。然而&#xff0c;传统实验室受限于时间、空间、资源等因素&#xff0c;难以满足日益增长的科研与教育需求。在这一背景下&#xff0c;3D元宇宙仿真实验室应运而生&#xff0c;以其独特的优势&#xff0c;成为科研与教育…

【windows 清理redis 缓存】

redis-cli.exe flushall flushdb

大数据时代,怎样通过日志分析保护我们的数据!

在今天的大数据时代&#xff0c;大量的数据被生成和存储。对于IT行业来说&#xff0c;日志文件是宝贵的信息财富。 通过合理的日志分析和解读&#xff0c;可以帮助企业提高运维效率、加强安全防护、改进产品质量和优化用户体验&#xff0c;本文将深入探讨日志分析在IT中的重要性…

成都优优聚美团代运营:塑造卓越优势,引领电商新时代

在当今这个数字化时代&#xff0c;美团作为中国最大的本地生活服务平台之一&#xff0c;正在为消费者和商家搭建一个无缝链接的桥梁。而在成都&#xff0c;有一家名为优优聚美团代运营的公司&#xff0c;他们凭借着专业的技能和高效的服务&#xff0c;成为了美团平台上的佼佼者…

linux上交叉编译qt库

linux上交叉编译qt库 Qt程序从X86平台Linux移植到ARM平台Linux需要做什么 1.在ubuntu上使用qt的源码交叉编译出Qt库 2.将编译好的库拷贝到开发板上并设置相应的环境变量&#xff08;库路径啥的&#xff09; 前两步一劳永逸&#xff0c;做一次就行 3.X86上写好程序代码&…

企业微信将应用安装到工作台

在上篇中介绍了配置小程序应用及指令、数据回调获取第三方凭证&#xff1b; 本篇将介绍如何将应用安装到企业工作台。 添加测试企业 通过【应用管理】->【测试企业配置】添加测试企业。 通过企业微信扫描二维码添加测试企业。 注意&#xff1a;需要扫描的账号为管理员权限…

C#中.NET 7.0 Windows窗体应用通过EF访问已有数据库并实现追加、删除、修改、插入记录

目录 一、前言 1.Database.ExecuteSqlCommand 方法不被EF7.0支持 2.SET IDENTITY_INSERT Blog {ON,OFF}不起作用 3.主键和标识列分离&#xff0c;成功实现插入与修改 二、新建本文涉及的项目 三、程序设计 1.Form1.cs源码 2.Form1.cs[设计] 四、生成和测试 1.原始表 …

【EI会议征稿】2024年电气技术与自动化工程国际学术会议 (ETAE 2024)

2024年电气技术与自动化工程国际学术会议 (ETAE 2024) 2024 International Conference on Electrical Technology and Automation Engineering 2024年电气技术与自动化工程国际学术会议 (ETAE 2024) 将于2024年3月8-10日在中国杭州召开。电气工程及其自动化和人们的日常生活…

Vue3的7种和Vue2的12种组件通信

Vue3 组件通信方式 props$emitexpose / ref$attrsv-modelprovide / injectVuex Vue3 通信使用写法 props 用 props 传数据给子组件有两种方法&#xff0c;如下 方法一&#xff0c;混合写法 // Parent.vue 传送 <child :msg1"msg1" :msg2"msg2">…

CLIP浅谈

CLIP论文地址&#xff1a;Learning Transferable Visual Models From Natural Language Supervision CLIP代码地址&#xff1a;https://github.com/openai/CLIP 简介 CLIP是OpenAI在2021年2月发表的一篇文章&#xff0c;它的主要贡献有以下2点&#xff1a; 1&#xff09;将图…

MCU内存基础知识

文章目录 一、存储器分类二、C语言内存分区内存区三、STM32启动文件分析四、应用分析 一、存储器分类 RAM&#xff08;Random Access Memory) &#xff1a;掉电之后就丢失数据&#xff0c;读写速度块 ROM (Read Only Memory) &#xff1a;掉电之后仍然可以保持数据 单片机的RA…

【Java SE】 详解java访问限定符

访问限定符 Java中主要通过类和访问权限来实现封装&#xff1a;类可以将数据以及封装数据的方法结合在一起&#xff0c;更符合人类对事物的认知&#xff0c;而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符&#xff1a; 实际只有三种访问限定…