ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
image.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include <Image.h>
9 #include <RGBDImage.h>
10 
11 #include "pybind/docstring.h"
14 
15 namespace cloudViewer {
16 namespace geometry {
17 
18 // Image functions have similar arguments, thus the arg docstrings may be shared
19 static const std::unordered_map<std::string, std::string>
21  {"color", "The color image."},
22  {"convert_rgb_to_intensity",
23  "Whether to convert RGB image to intensity image."},
24  {"depth", "The depth image."},
25  {"depth_scale",
26  "The ratio to scale depth values. The depth values will first "
27  "be scaled and then truncated."},
28  {"depth_trunc",
29  "Depth values larger than ``depth_trunc`` gets truncated to "
30  "0. The depth values will first be scaled and then "
31  "truncated."},
32  {"filter_type", "The filter type to be applied."},
33  {"image", "The Image object."},
34  {"image_pyramid", "The ImagePyramid object"},
35  {"num_of_levels ", "Levels of the image pyramid"},
36  {"with_gaussian_filter",
37  "When ``True``, image in the pyramid will first be filtered "
38  "by a 3x3 Gaussian kernel before down sampling."}};
39 
40 void pybind_image(py::module &m) {
41  py::native_enum<Image::FilterType>(m, "ImageFilterType", "enum.Enum",
42  "Enum class for Image filter types.")
43  .value("Gaussian3", Image::FilterType::Gaussian3)
44  .value("Gaussian5", Image::FilterType::Gaussian5)
45  .value("Gaussian7", Image::FilterType::Gaussian7)
46  .value("Sobel3dx", Image::FilterType::Sobel3Dx)
47  .value("Sobel3dy", Image::FilterType::Sobel3Dy)
48  .export_values()
49  .finalize();
50 
51  py::class_<geometry::Image, PyGeometry<geometry::Image>,
52  std::shared_ptr<geometry::Image>, ccHObject>
53  image(m, "Image", py::buffer_protocol(),
54  "The image class stores image with customizable width, "
55  "height, num of channels and bytes per channel.");
56  py::detail::bind_default_constructor<geometry::Image>(image);
57  py::detail::bind_copy_functions<geometry::Image>(image);
58  image.def(py::init([](py::buffer b) {
59  py::buffer_info info = b.request();
60  int width, height, num_of_channels = 0, bytes_per_channel;
61  if (info.format == py::format_descriptor<uint8_t>::format() ||
62  info.format == py::format_descriptor<int8_t>::format()) {
63  bytes_per_channel = 1;
64  } else if (info.format ==
66  info.format ==
68  bytes_per_channel = 2;
69  } else if (info.format == py::format_descriptor<float>::format()) {
70  bytes_per_channel = 4;
71  } else {
72  throw std::runtime_error(
73  "Image can only be initialized from buffer of uint8, "
74  "uint16, or float!");
75  }
76  if (info.strides[info.ndim - 1] != bytes_per_channel) {
77  throw std::runtime_error(
78  "Image can only be initialized from c-style buffer.");
79  }
80  if (info.ndim == 2) {
81  num_of_channels = 1;
82  } else if (info.ndim == 3) {
83  num_of_channels = (int)info.shape[2];
84  }
85  height = (int)info.shape[0];
86  width = (int)info.shape[1];
87  auto img = new geometry::Image();
88  img->Prepare(width, height, num_of_channels, bytes_per_channel);
89  memcpy(img->data_.data(), info.ptr, img->data_.size());
90  return img;
91  }))
92  .def_buffer([](geometry::Image &img) -> py::buffer_info {
93  std::string format;
94  switch (img.bytes_per_channel_) {
95  case 1:
96  format = py::format_descriptor<uint8_t>::format();
97  break;
98  case 2:
99  format = py::format_descriptor<uint16_t>::format();
100  break;
101  case 4:
102  format = py::format_descriptor<float>::format();
103  break;
104  default:
105  throw std::runtime_error(
106  "Image has unrecognized bytes_per_channel.");
107  break;
108  }
109  if (img.num_of_channels_ == 1) {
110  return py::buffer_info(
111  img.data_.data(), img.bytes_per_channel_, format, 2,
112  {static_cast<unsigned long>(img.height_),
113  static_cast<unsigned long>(img.width_)},
114  {static_cast<unsigned long>(img.bytes_per_channel_ *
115  img.num_of_channels_ *
116  img.width_),
117  static_cast<unsigned long>(img.bytes_per_channel_ *
118  img.num_of_channels_)});
119  } else {
120  return py::buffer_info(
121  img.data_.data(), img.bytes_per_channel_, format, 3,
122  {static_cast<unsigned long>(img.height_),
123  static_cast<unsigned long>(img.width_),
124  static_cast<unsigned long>(img.num_of_channels_)},
125  {static_cast<unsigned long>(img.bytes_per_channel_ *
126  img.num_of_channels_ *
127  img.width_),
128  static_cast<unsigned long>(img.bytes_per_channel_ *
129  img.num_of_channels_),
130  static_cast<unsigned long>(
131  img.bytes_per_channel_)});
132  }
133  })
134  .def("__repr__",
135  [](const geometry::Image &img) {
136  return std::string("Image of size ") +
137  std::to_string(img.width_) + std::string("x") +
138  std::to_string(img.height_) + ", with " +
140  std::string(
141  " channels.\nUse numpy.asarray to access "
142  "buffer "
143  "data.");
144  })
145  .def(
146  "filter",
147  [](const geometry::Image &input,
148  geometry::Image::FilterType filter_type) {
149  if (input.num_of_channels_ != 1 ||
150  input.bytes_per_channel_ != 4) {
151  auto input_f = input.CreateFloatImage();
152  auto output = input_f->Filter(filter_type);
153  return *output;
154  } else {
155  auto output = input.Filter(filter_type);
156  return *output;
157  }
158  },
159  "Function to filter Image", "filter_type"_a)
160  .def("flip_vertical", &geometry::Image::FlipVertical,
161  "Function to flip image vertically (upside down)")
162  .def("flip_horizontal", &geometry::Image::FlipHorizontal,
163  "Function to flip image horizontally (from left to right)")
164  .def(
165  "create_pyramid",
166  [](const geometry::Image &input, size_t num_of_levels,
167  bool with_gaussian_filter) {
168  if (input.num_of_channels_ != 1 ||
169  input.bytes_per_channel_ != 4) {
170  auto input_f = input.CreateFloatImage();
171  auto output = input_f->CreatePyramid(
172  num_of_levels, with_gaussian_filter);
173  return output;
174  } else {
175  auto output = input.CreatePyramid(
176  num_of_levels, with_gaussian_filter);
177  return output;
178  }
179  },
180  "Function to create ImagePyramid", "num_of_levels"_a,
181  "with_gaussian_filter"_a)
182  .def_static(
183  "filter_pyramid",
184  [](const geometry::ImagePyramid &input,
185  geometry::Image::FilterType filter_type) {
186  auto output = geometry::Image::FilterPyramid(
187  input, filter_type);
188  return output;
189  },
190  "Function to filter ImagePyramid", "image_pyramid"_a,
191  "filter_type"_a);
192 
193  docstring::ClassMethodDocInject(m, "Image", "filter",
195  docstring::ClassMethodDocInject(m, "Image", "create_pyramid",
197  docstring::ClassMethodDocInject(m, "Image", "filter_pyramid",
199 
200  py::class_<geometry::RGBDImage, PyGeometry<geometry::RGBDImage>,
201  std::shared_ptr<geometry::RGBDImage>, ccHObject>
202  rgbd_image(m, "RGBDImage",
203  "RGBDImage is for a pair of registered color and depth "
204  "images, viewed from the same view, of the same "
205  "resolution. If you have other format, convert it "
206  "first.");
207  py::detail::bind_default_constructor<geometry::RGBDImage>(rgbd_image);
208  rgbd_image
209  .def_readwrite("color", &geometry::RGBDImage::color_,
210  "cloudViewer.geometry.Image: The color image.")
211  .def_readwrite("depth", &geometry::RGBDImage::depth_,
212  "cloudViewer.geometry.Image: The depth image.")
213  .def("__repr__",
214  [](const geometry::RGBDImage &rgbd_image) {
215  return std::string("RGBDImage of size \n") +
216  std::string("Color image : ") +
217  std::to_string(rgbd_image.color_.width_) +
218  std::string("x") +
219  std::to_string(rgbd_image.color_.height_) +
220  ", with " +
222  std::string(" channels.\n") +
223  std::string("Depth image : ") +
224  std::to_string(rgbd_image.depth_.width_) +
225  std::string("x") +
226  std::to_string(rgbd_image.depth_.height_) +
227  ", with " +
229  std::string(" channels.\n") +
230  std::string(
231  "Use numpy.asarray to access buffer data.");
232  })
233  .def_static("create_from_color_and_depth",
235  "Function to make RGBDImage from color and depth image",
236  "color"_a, "depth"_a, "depth_scale"_a = 1000.0,
237  "depth_trunc"_a = 3.0,
238  "convert_rgb_to_intensity"_a = true)
239  .def_static("create_from_redwood_format",
241  "Function to make RGBDImage (for Redwood format)",
242  "color"_a, "depth"_a,
243  "convert_rgb_to_intensity"_a = true)
244  .def_static("create_from_tum_format",
246  "Function to make RGBDImage (for TUM format)",
247  "color"_a, "depth"_a,
248  "convert_rgb_to_intensity"_a = true)
249  .def_static("create_from_sun_format",
251  "Function to make RGBDImage (for SUN format)",
252  "color"_a, "depth"_a,
253  "convert_rgb_to_intensity"_a = true)
254  .def_static("create_from_nyu_format",
256  "Function to make RGBDImage (for NYU format)",
257  "color"_a, "depth"_a,
258  "convert_rgb_to_intensity"_a = true);
259 
260  docstring::ClassMethodDocInject(m, "RGBDImage",
261  "create_from_color_and_depth",
263  docstring::ClassMethodDocInject(m, "RGBDImage",
264  "create_from_redwood_format",
266  docstring::ClassMethodDocInject(m, "RGBDImage", "create_from_tum_format",
268  docstring::ClassMethodDocInject(m, "RGBDImage", "create_from_sun_format",
270  docstring::ClassMethodDocInject(m, "RGBDImage", "create_from_nyu_format",
272 }
273 
274 void pybind_image_methods(py::module &m) {}
275 
276 } // namespace geometry
277 } // namespace cloudViewer
std::shared_ptr< core::Tensor > image
filament::Texture::InternalFormat format
int width
int height
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
The Image class stores image with customizable width, height, num of channels and bytes per channel.
Definition: Image.h:33
std::shared_ptr< Image > CreateFloatImage(Image::ColorToIntensityConversionType type=Image::ColorToIntensityConversionType::Weighted) const
Return a gray scaled float type image.
Image & Prepare(int width, int height, int num_of_channels, int bytes_per_channel)
Prepare Image properties and allocate Image buffer.
Definition: Image.h:109
int num_of_channels_
Number of chanels in the image.
Definition: Image.h:223
std::shared_ptr< Image > FlipVertical() const
Function to flip image vertically (upside down).
std::shared_ptr< Image > Filter(Image::FilterType type) const
Function to filter image with pre-defined filtering type.
int height_
Height of the image.
Definition: Image.h:221
int bytes_per_channel_
Number of bytes per channel.
Definition: Image.h:225
int width_
Width of the image.
Definition: Image.h:219
std::shared_ptr< Image > FlipHorizontal() const
Function to flip image horizontally (from left to right).
ImagePyramid CreatePyramid(size_t num_of_levels, bool with_gaussian_filter=true) const
Function to create image pyramid.
FilterType
Specifies the Image filter type.
Definition: Image.h:52
@ Gaussian3
Gaussian filter of size 3 x 3.
@ Gaussian5
Gaussian filter of size 5 x 5.
@ Sobel3Dx
Sobel filter along X-axis.
@ Sobel3Dy
Sobel filter along Y-axis.
@ Gaussian7
Gaussian filter of size 7 x 7.
static ImagePyramid FilterPyramid(const ImagePyramid &input, Image::FilterType type)
Function to filter image pyramid.
RGBDImage is for a pair of registered color and depth images,.
Definition: RGBDImage.h:27
static std::shared_ptr< RGBDImage > CreateFromTUMFormat(const Image &color, const Image &depth, bool convert_rgb_to_intensity=true)
Factory function to create an RGBD Image from TUM dataset.
static std::shared_ptr< RGBDImage > CreateFromNYUFormat(const Image &color, const Image &depth, bool convert_rgb_to_intensity=true)
Factory function to create an RGBD Image from NYU dataset.
static std::shared_ptr< RGBDImage > CreateFromSUNFormat(const Image &color, const Image &depth, bool convert_rgb_to_intensity=true)
Factory function to create an RGBD Image from SUN3D dataset.
Image color_
The color image.
Definition: RGBDImage.h:135
static std::shared_ptr< RGBDImage > CreateFromRedwoodFormat(const Image &color, const Image &depth, bool convert_rgb_to_intensity=true)
Factory function to create an RGBD Image from Redwood dataset.
Image depth_
The depth image.
Definition: RGBDImage.h:137
static std::shared_ptr< RGBDImage > CreateFromColorAndDepth(const Image &color, const Image &depth, double depth_scale=1000.0, double depth_trunc=3.0, bool convert_rgb_to_intensity=true)
Factory function to create an RGBD Image from color and depth Images.
void ClassMethodDocInject(py::module &pybind_module, const std::string &class_name, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
Definition: docstring.cpp:27
void pybind_image(py::module &m)
Definition: image.cpp:40
static const std::unordered_map< std::string, std::string > map_shared_argument_docstrings
Definition: image.cpp:20
std::vector< std::shared_ptr< Image > > ImagePyramid
Typedef and functions for ImagePyramid.
Definition: Image.h:24
void pybind_image_methods(py::module &m)
Definition: image.cpp:84
Generic file read and write utility for python interface.
std::string to_string(const T &n)
Definition: Common.h:20