为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Open3D 从图像生成点云时出现空白屏幕

使用 Open3D 从图像生成点云时出现空白屏幕

一只斗牛犬 2022-09-13 15:19:54
所以我尝试用Python中的Open3D库创建一个点云,最后,它基本上只是这里引用的2行,但是当我运行我的代码(见下文)时,我得到的只是一个弹出的白屏。我已经在Jupyter笔记本中运行了它,但是从控制台在python脚本中运行它没有改变任何东西,也没有抛出错误。我应该提到我在Blender中创建图像并将其另存为OpenExr,这意味着深度值范围在0到4之间(我已将其截断为4作为背景)。您可以在下面看到它们是正确的图像,我也可以将它们转换为Open3D图片并毫无问题地显示它们。
查看完整描述

2 回答

?
忽然笑

TA贡献1806条经验 获得超5个赞

简而言之,Open3D 希望您的 3 通道彩色图像为 uint8 类型。


否则,它将返回一个空的点云,从而导致您看到的空白窗口。


更新 2020-3-27,深夜在我的时区:)


现在您已经提供了代码,让我们开始吧!


从您的函数名称中,我猜您正在使用Open3D 0.7.0或类似的东西。我提供的代码在 0.9.0 中。某些函数名称已更改,并添加了新功能。


当我在 0.9.0 中运行您的代码时(当然经过一些小的修改后),会出现一个运行时错误:


RuntimeError: [Open3D ERROR] [CreatePointCloudFromRGBDImage] Unsupported image format.

我们可以从Open3D源中看到,您的彩色图像必须是3个通道,每个通道仅占用1个字节(uint8),或者是1个通道并占用4个字节(浮动,这意味着强度图像):0.9.0


std::shared_ptr<PointCloud> PointCloud::CreateFromRGBDImage(

        const RGBDImage &image,

        const camera::PinholeCameraIntrinsic &intrinsic,

        const Eigen::Matrix4d &extrinsic /* = Eigen::Matrix4d::Identity()*/,

        bool project_valid_depth_only) {

    if (image.depth_.num_of_channels_ == 1 &&

        image.depth_.bytes_per_channel_ == 4) {

        if (image.color_.bytes_per_channel_ == 1 &&

            image.color_.num_of_channels_ == 3) {

            return CreatePointCloudFromRGBDImageT<uint8_t, 3>(

                    image, intrinsic, extrinsic, project_valid_depth_only);

        } else if (image.color_.bytes_per_channel_ == 4 &&

                   image.color_.num_of_channels_ == 1) {

            return CreatePointCloudFromRGBDImageT<float, 1>(

                    image, intrinsic, extrinsic, project_valid_depth_only);

        }

    }

    utility::LogError(

            "[CreatePointCloudFromRGBDImage] Unsupported image format.");

    return std::make_shared<PointCloud>();

}

否则,会出现像我遇到的错误。

但是,在 的版本中,源代码是:0.7.0


std::shared_ptr<PointCloud> CreatePointCloudFromRGBDImage(

        const RGBDImage &image,

        const camera::PinholeCameraIntrinsic &intrinsic,

        const Eigen::Matrix4d &extrinsic /* = Eigen::Matrix4d::Identity()*/) {

    if (image.depth_.num_of_channels_ == 1 &&

        image.depth_.bytes_per_channel_ == 4) {

        if (image.color_.bytes_per_channel_ == 1 &&

            image.color_.num_of_channels_ == 3) {

            return CreatePointCloudFromRGBDImageT<uint8_t, 3>(image, intrinsic,

                                                              extrinsic);

        } else if (image.color_.bytes_per_channel_ == 4 &&

                   image.color_.num_of_channels_ == 1) {

            return CreatePointCloudFromRGBDImageT<float, 1>(image, intrinsic,

                                                            extrinsic);

        }

    }   

    utility::PrintDebug(

            "[CreatePointCloudFromRGBDImage] Unsupported image format.\n");

    return std::make_shared<PointCloud>();

}

这意味着Open3D仍然不支持它,但它只会警告你。并且仅在调试模式下!

之后,它将返回一个空的点云。(实际上两个版本都这样做。这解释了空白窗口。


现在你应该知道,你可以成功。虽然您仍然应该首先规范化您的彩色图像。

或者,您可以将彩色图像转换为范围和类型 。

两者都行得通。convert_rgb_to_intensity=True[0, 255]uint8


现在我希望一切都清楚了。万岁!


附言:实际上我通常发现Open3D源代码易于阅读。如果你知道C++,每当这样的事情发生时,你都可以阅读它。


2020-3-27更新:


我无法重现您的结果,我不知道为什么会发生这种情况(您应该提供一个最小的可重现示例)。


使用您在注释中提供的图像,我编写了以下代码,并且运行良好。如果它仍然无法在您的计算机上工作,则可能是您的Open3D已损坏。


(我不熟悉 .exr 图像,因此数据提取可能很丑陋:)


import Imath

import array

import OpenEXR


import numpy as np

import open3d as o3d



# extract data from exr files

f = OpenEXR.InputFile('frame.exr')

FLOAT = Imath.PixelType(Imath.PixelType.FLOAT)

cs = list(f.header()['channels'].keys())  # channels

data = [np.array(array.array('f', f.channel(c, FLOAT))) for c in cs] 

data = [d.reshape(720, 1280) for d in data]

rgb = np.concatenate([data[i][:, :, np.newaxis] for i in [3, 2, 1]], axis=-1)

# rgb /= np.max(rgb)  # this will result in a much darker image

np.clip(rgb, 0, 1.0)  # to better visualize as HDR is not supported?


# get rgbd image

img = o3d.geometry.Image((rgb * 255).astype(np.uint8))

depth = o3d.geometry.Image((data[-1] * 1000).astype(np.uint16))

rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(img, depth, convert_rgb_to_intensity=False)


# some guessed intrinsics

intr = o3d.open3d.camera.PinholeCameraIntrinsic(1280, 720, fx=570, fy=570, cx=640, cy=360)


# get point cloud and visualize

pcd = o3d.geometry.PointCloud.create_from_rgbd_image(rgbd, intr)

o3d.visualization.draw_geometries([pcd])

结果是:

//img1.sycdn.imooc.com//63202f39000113d906470362.jpg

原始答案:


您误解了 的含义。depth_scale


使用以下行:

depth = o3d.geometry.Image(np.array(img_array[:, :, 3]*1000).astype('uint16'))


Open3D文档说,深度值将首先被缩放,然后被截断。实际上,这意味着深度图像中的像素值将首先除以此数字而不是乘法,正如您在Open3D源代码中看到的那样:


std::shared_ptr<Image> Image::ConvertDepthToFloatImage(

        double depth_scale /* = 1000.0*/, double depth_trunc /* = 3.0*/) const {

    // don't need warning message about image type

    // as we call CreateFloatImage

    auto output = CreateFloatImage();

    for (int y = 0; y < output->height_; y++) {

        for (int x = 0; x < output->width_; x++) {

            float *p = output->PointerAt<float>(x, y);

            *p /= (float)depth_scale;

            if (*p >= depth_trunc) *p = 0.0f;

        }

    }

    return output;

}

实际上,我们通常想当然地认为深度图像的值应该是整数(我想这就是为什么Open3D没有在他们的文档中明确指出这一点),因为浮点图像不太常见。

您无法将米存储在.png图像中,因为它们会失去精度。因此,我们存储了深度图像,稍后的进程将首先将其转换回 。1.3413401.34


至于深度图像的相机固有函数,我猜在创建Blender时会有配置参数。我不熟悉搅拌机,所以我不会谈论它。但是,如果您不了解一般的相机固有特性,则可能需要看一下。


查看完整回答
反对 回复 2022-09-13
?
慕娘9325324

TA贡献1783条经验 获得超4个赞

但是,我假设他的Open3D版本与我的版本不同,我不得不像这样更改2个函数调用(并稍微更改了命名):


exr_img = OpenEXR.InputFile('frame0100.exr')

cs = list(exr_img.header()['channels'].keys())  # channels

FLOAT = Imath.PixelType(Imath.PixelType.FLOAT)


img_data = [np.array(array.array('f', exr_img.channel(c, FLOAT))) for c in cs]

img_data = [d.reshape(720,1280) for d in img_data]


rgb = np.concatenate([img_data[i][:, :, np.newaxis] for i in [3, 2, 1]], axis=-1)

np.clip(rgb, 0, 1.0)  # to better visualize as HDR is not supported?



img = o3d.geometry.Image((rgb * 255).astype(np.uint8))

depth = o3d.geometry.Image((img_data[-1] * 1000).astype(np.uint16))

#####rgbd = o3d.geometry.RGBDImage.create_from_color_and_depth(img, depth, convert_rgb_to_intensity=False)


rgbd = o3d.create_rgbd_image_from_color_and_depth(img, depth, convert_rgb_to_intensity=False)



# some guessed intrinsics

intr = o3d.open3d.camera.PinholeCameraIntrinsic(1280, 720, fx=570, fy=570, cx=640, cy=360)


# get point cloud and visualize

#####pcd = o3d.geometry.PointCloud.create_from_rgbd_image(rgbd, intr)

pcd = o3d.create_point_cloud_from_rgbd_image(rgbd, intr)



o3d.visualization.draw_geometries([pcd])

否则我得到以下错误:


AttributeError: type object 'open3d.open3d.geometry.RGBDImage' has no attribute 'create_from_color_and_depth'

希望这也能帮助其他人使用我的Python / Open3D版本。不太确定我的代码中的错误究竟在哪里,但我对拥有可用的代码感到满意。再次感谢赵晶!


查看完整回答
反对 回复 2022-09-13
  • 2 回答
  • 0 关注
  • 936 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信