Короче говоря, Open3D ожидает, что ваше 3-канальное цветное изображение будет иметь uint8
тип .
В противном случае будет возвращено пустое облако точек, в результате чего вы получите пустое окно. см.
Обновление 2020-3-27, поздно ночью в моем часовом поясе:)
Теперь, когда вы предоставили свой код, давайте Погрузитесь в!
Из названий ваших функций, я полагаю, вы используете Open3D 0.7.0
или что-то в этом роде. Код, который я предоставил, находится в 0.9.0
. Изменены некоторые имена функций и добавлено новых функций .
Когда я запускаю ваш код в 0.9.0
(после некоторых незначительных изменений, конечно), появляется RuntimeError :
RuntimeError: [Open3D ERROR] [CreatePointCloudFromRGBDImage] Unsupported image format.
И мы можем видеть из источника Open3D 0.9.0
, что ваше цветное изображение должно иметь 3 канала и берут только 1 байт каждый (uint8) или из 1 канала и берут 4 байта (float, что означает интенсивность изображения):
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
.
Оба будут работать.
Теперь я надеюсь, что все ясно. Ура!
PS На самом деле я обычно находил исходный код 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])
И результат:
![enter image description here](https://i.stack.imgur.com/jmZBq.png)
Оригинал Ответ:
Вы неправильно поняли значение depth_scale
.
Используйте эту строку:
depth = o3d.geometry.Image(np.array(img_array[:, :, 3]*1000).astype('uint16'))
В документации Open3D указано значения глубины сначала масштабируются, а затем усекаются . На самом деле это означает, что значения пикселей в вашем изображении глубины будут сначала делить это число , а не умножаться, как вы можете видеть в Open3D source :
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 не указал это четко в своей документации), поскольку изображения с плавающей точкой встречаются реже.
Вы не может хранить 1.34
метров в .png изображениях, так как они теряют точность. В результате мы храним 1340
изображения глубины, и более поздние процессы сначала преобразуют его обратно в 1.34
.
Что касается встроенных функций камеры для вашего изображения глубины, я думаю, что будет конфигурация параметры в Blender при его создании. Я не знаком с Блендером, поэтому я не буду об этом говорить. Однако, если вы не понимаете общих черт камеры, вы можете взглянуть на this .