首页 > 编程问答 >使用 Open3D 点云到 RGB 图像转换中的颜色不匹配和深度不一致

使用 Open3D 点云到 RGB 图像转换中的颜色不匹配和深度不一致

时间:2024-07-22 14:23:08浏览次数:7  
标签:python computer-vision point-clouds open3d 3d-reconstruction

我正在使用 Open3D 将点云数据转换为 RGB 图像。但是,我遇到了输出图像中的颜色与输入点云中的颜色不匹配的问题。此外,本应位于背景的点却出现在前景中。这是我的代码的相关部分:

import numpy as np
import cv2

class Projector:
    def __init__(self, cloud) -> None:
        self.cloud = cloud
        self.points = np.asarray(cloud.points)
        self.colors = np.asarray(cloud.colors)
        self.n = len(self.points)

    def project_to_rgbd(self,
                        width,
                        height,
                        intrinsic,
                        extrinsic,
                        depth_scale,
                        depth_max):
        depth = np.zeros((height, width, 1), dtype=np.uint16)
        color = np.zeros((height, width, 3), dtype=np.uint8)

        for i in range(0, self.n):
            point4d = np.append(self.points[i], 1)
            new_point4d = np.matmul(extrinsic, point4d)
            point3d = new_point4d[:-1]
            zc = point3d[2]
            new_point3d = np.matmul(intrinsic, point3d)
            new_point3d = new_point3d / new_point3d[2]
            u = int(round(new_point3d[0]))
            v = int(round(new_point3d[1]))

            if u < 0 or u > width - 1 or v < 0 or v > height - 1 or zc <= 0 or zc > depth_max:
                continue

            d = zc * depth_scale
            if depth[v, u] == 0 or depth[v, u] > d:
                depth[v, u] = d
                color[v, u, :] = (self.colors[i] * 255).astype(np.uint8)

        im_color = o3d.geometry.Image(color)
        im_depth = o3d.geometry.Image(depth)
        rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(
            im_color, im_depth, depth_scale=1000.0, depth_trunc=depth_max, convert_rgb_to_intensity=False)
        return rgbd

pcd_path = "/home/shirono/Poe/data/1944301031BF721300_1721279605_z20.pcd"
pcd = o3d.io.read_point_cloud(pcd_path)

scene = o3d.visualization.Visualizer()
scene.create_window()
scene.add_geometry(pcd)
scene.update_renderer()
scene.poll_events()
scene.run()
view_control = scene.get_view_control()
cam = view_control.convert_to_pinhole_camera_parameters()
scene.destroy_window()

p = Projector(pcd)
rgbd = p.project_to_rgbd(cam.intrinsic.width,
                         cam.intrinsic.height,
                         cam.intrinsic.intrinsic_matrix,
                         cam.extrinsic,
                         1000,
                         10)

def save_rgb_from_rgbd(rgbd_image, save_path):
    rgb_image = np.asarray(rgbd_image.color)
    rgb_image = (rgb_image * 255).astype(np.uint8)
    rgb_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR)
    cv2.imwrite(save_path, rgb_image)

save_path = "output_rgb_image.png"
save_rgb_from_rgbd(rgbd, save_path)



We thought the conversion from RGB to BGR was wrong and tried but could not improve it.

代码中导致颜色不匹配和深度不一致的原因主要有以下几点:

  1. 颜色空间转换错误: 虽然代码中尝试使用 cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR) 进行颜色空间转换,但转换的时机不对。应该在将颜色数组 color 从 Open3D 图像转换为 OpenCV 图像之前就进行转换,而不是在保存图像之前才转换。
  2. 深度值缩放问题: 代码中使用了 depth_scale 参数,但在创建 RGBDImage 时又设置了 depth_scale=1000.0 ,这可能会导致深度值被缩放两次。应该统一使用一个深度值缩放比例。
  3. 深度缓冲区精度问题: 使用 uint16 存储深度值可能会导致精度不足,特别是在场景深度范围较大的情况下。可以考虑使用 float32 存储深度值以提高精度。
  4. 投影过程中缺少遮挡检测: 当前的代码只是简单地将所有点投影到图像平面,并没有考虑点之间的遮挡关系。这会导致本应位于背景的点出现在前景。

以下是如何修改代码以解决这些问题的建议:

import numpy as np
import cv2
import open3d as o3d

class Projector:
    def __init__(self, cloud) -> None:
        self.cloud = cloud
        self.points = np.asarray(cloud.points)
        self.colors = np.asarray(cloud.colors)
        self.n = len(self.points)

    def project_to_rgbd(self,
                        width,
                        height,
                        intrinsic,
                        extrinsic,
                        depth_scale,
                        depth_max):
        depth = np.zeros((height, width), dtype=np.float32)
        color = np.zeros((height, width, 3), dtype=np.uint8)

        for i in range(0, self.n):
            point4d = np.append(self.points[i], 1)
            new_point4d = np.matmul(extrinsic, point4d)
            point3d = new_point4d[:-1]
            zc = point3d[2]
            new_point3d = np.matmul(intrinsic, point3d)
            new_point3d = new_point3d / new_point3d[2]
            u = int(round(new_point3d[0]))
            v = int(round(new_point3d[1]))

            if u < 0 or u >= width or v < 0 or v >= height or zc <= 0 or zc > depth_max:
                continue

            d = zc * depth_scale
            if depth[v, u] == 0 or depth[v, u] > d:
                depth[v, u] = d
                # 在这里进行颜色空间转换
                color[v, u, :] = (self.colors[i] * 255).astype(np.uint8)[::-1]  # RGB to BGR

        im_color = o3d.geometry.Image(color)
        im_depth = o3d.geometry.Image(depth)
        # 统一使用 depth_scale
        rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(
            im_color, im_depth, depth_scale=depth_scale, depth_trunc=depth_max, convert_rgb_to_intensity=False)
        return rgbd

# ... 其他代码 ...

p = Projector(pcd)
rgbd = p.project_to_rgbd(cam.intrinsic.width,
                         cam.intrinsic.height,
                         cam.intrinsic.intrinsic_matrix,
                         cam.extrinsic,
                         1000.0,  # 使用相同的 depth_scale
                         10)

def save_rgb_from_rgbd(rgbd_image, save_path):
    rgb_image = np.asarray(rgbd_image.color)
    # 不需要再进行颜色空间转换
    cv2.imwrite(save_path, rgb_image)

# ... 其他代码 ...

此外,为了解决遮挡问题,可以使用更复杂的投影方法,例如光线投射。Open3D 提供了一些功能可以帮助实现这一点,例如 o3d.geometry.RaycastingScene

希望这些修改可以解决颜色不匹配和深度不一致的问题。

标签:python,computer-vision,point-clouds,open3d,3d-reconstruction
From: 78777157

相关文章

  • 在 VSCode 中通过 Python 使用 YouTube API 时如何启用 Intellisense
    我想在使用GoogleYouTubeAPI和Python时在VSCode中获得IntelliSense。但我不知道详细步骤。fromgoogleapiclient.discoveryimportbuildapi_key="****"youtube=build("youtube","v3",developerKey=api_key)request=youtube.channels().list(part......
  • 当 python 脚本通过 jenkins + Github 在 Windows 本地计算机上运行时,chrome 浏览器不
    我的Python代码是(windowsMachine)fromseleniumimportwebdriverprint("newLine")print("2Line")print("3Line")holdChrome=webdriver.ChromeOptions()holdChrome.add_experimental_option("detach",True)#Restricta......
  • python_基础_数据类型
    基础数据类型不需要声明,只有被赋值后才会创建变量。变量本身没有类型,“类型”指的是所存值的类型。类型判断type(x)和isinstance(x,int)前者不会认为子类是一种他的父类类型后者会认为子类是父类类型>>>classA:...pass...>>>classB(A):...pass......
  • IPython 使用技巧
    IPython是一个强大的交互式Pythonshell,提供了许多方便的功能,使Python编程更加高效和愉快。本文将介绍一些IPython的实用技巧,帮助开发者充分利用其功能,提高编程效率。1.基本操作和快捷键1.1启动IPython可以通过在终端输入以下命令来启动IPython:ipython启动后,你......
  • 【python】类方法和静态方法的区别
    类方法和静态方法在Python中都可以用来定义与类相关的功能,但它们有不同的使用场景和优缺点。虽然类方法也可以用来实现验证逻辑,但静态方法在某些情况下更合适。让我们详细看看这两种方法的区别以及为什么在某些情况下静态方法可能更适合验证功能。类方法和静态方法的区别类......
  • Python自动化:一键提取千万个Excel指定数据
    一、传统方法的局限性打开每个Excel文件,逐个查找需要的数据。筛选出老板需要的数据列。复制并粘贴到新的工作表中。保存并关闭每个文件。这个过程不仅耗时,而且容易出错。每一次的筛选都可能遗漏数据,每一次的复制粘贴都可能引入错误。二、Python自动化的解决方案i......
  • Python:提交和跟踪许多子流程会导致“卡住”子流程
    我有一个第3方cli可执行文件,需要从python代码中调用。这些都是繁重的计算(CPU),我需要调用它大约50-100次。可执行文件本身在某种程度上是多线程的,但不是所有步骤,而且我有很多可用的核心。这意味着我希望同时运行多个子进程,但不是全部。因此,我需要提交其中一些,然后跟踪......
  • 无法在 Ubuntu 20.04 中安装 python3-venv,一些损坏的软件包
    这可能很长,但请耐心看完当我在关注这篇文章时尝试安装python3-venvsudoaptinstallbuild-essentiallibssl-devlibffi-devpython3-dev它抛出了以下错误:libffi-devpython3-devReadingpackagelists...DoneBuildingdependencytreeRead......
  • 正则表达式在python爬虫中常用的方法举例
    在爬虫中,正则表达式被广泛用于从网页中提取特定信息。以下是一些常用的正则表达式方法举例,以及它们在爬虫中的典型应用场景:1.提取URLimportreurl_pattern=r'https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+'urls=re.findall(url_pattern,html_content)用于从网页中......
  • 使用 Python XlsxWriter 将 DatePicker 添加到 Excel 单元格中?
    我正在尝试使用PythonXlsxWriter生成的Excel创建输入表单。我想知道是否可以在Excel单元格中添加一个迷你日历(作为DatePicker)供用户输入日期?我偶然发现了Microsoft支持团队提供的本指南插入日期选择器:|||https://support.microsoft.com/en-us/office/......