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 
9 
10 #include <Logging.h>
11 
12 #include <string>
13 #include <unordered_map>
14 #include <utility>
15 #include <vector>
16 
18 #include "cloudViewer/core/Dtype.h"
24 
25 namespace cloudViewer {
26 namespace t {
27 namespace geometry {
28 
29 using dtype_channels_pairs = std::vector<std::pair<core::Dtype, int64_t>>;
30 
31 Image::Image(int64_t rows,
32  int64_t cols,
33  int64_t channels,
34  core::Dtype dtype,
35  const core::Device &device)
37  Reset(rows, cols, channels, dtype, device);
38 }
39 
40 Image::Image(const core::Tensor &tensor)
42  if (!tensor.IsContiguous()) {
43  utility::LogError("Input tensor must be contiguous.");
44  }
45  if (tensor.NumDims() == 2) {
46  data_ = tensor.Reshape(
47  core::shape_util::Concat(tensor.GetShape(), {1}));
48  } else if (tensor.NumDims() == 3) {
49  data_ = tensor;
50  } else {
51  utility::LogError("Input tensor must be 2-D or 3-D, but got shape {}.",
52  tensor.GetShape().ToString());
53  }
54 }
55 
56 Image &Image::Reset(int64_t rows,
57  int64_t cols,
58  int64_t channels,
59  core::Dtype dtype,
60  const core::Device &device) {
61  if (rows < 0) {
62  utility::LogError("rows must be >= 0, but got {}.", rows);
63  }
64  if (cols < 0) {
65  utility::LogError("cols must be >= 0, but got {}.", cols);
66  }
67  if (channels <= 0) {
68  utility::LogError("channels must be > 0, but got {}.", channels);
69  }
70 
71  data_ = core::Tensor({rows, cols, channels}, dtype, device);
72  return *this;
73 }
74 
76  bool copy /*= false*/,
77  utility::optional<double> scale_ /* = utility::nullopt */,
78  double offset /* = 0.0 */) const {
79  if (dtype == GetDtype() && !scale_.has_value() && offset == 0.0) {
80  return copy ? Image(data_.Clone()) : *this;
81  }
82  // Check IPP datatype support for each function in IPP documentation:
83  // https://software.intel.com/content/www/us/en/develop/documentation/ipp-dev-reference/top/volume-2-image-processing.html
84  // IPP supports all pairs of conversions for these data types
85  static const std::vector<core::Dtype> ipp_supported{
88 
89  double scale = 1.0;
90  if (!scale_.has_value() &&
91  (dtype == core::Float32 || dtype == core::Float64)) {
92  if (GetDtype() == core::UInt8) {
93  scale = 1. / 255;
94  } else if (GetDtype() == core::UInt16) {
95  scale = 1. / 65535;
96  }
97  } else {
98  scale = scale_.value_or(1.0);
99  }
100 
101  Image dst_im;
102  if (!copy && dtype == GetDtype()) {
103  dst_im.data_ = data_;
104  } else {
105  dst_im.data_ = core::Tensor::Empty(
106  {GetRows(), GetCols(), GetChannels()}, dtype, GetDevice());
107  }
108  if (HAVE_IPP && // Check for IPP fast implementation.
109  data_.IsCPU() &&
110  std::count(ipp_supported.begin(), ipp_supported.end(), GetDtype()) >
111  0 &&
112  std::count(ipp_supported.begin(), ipp_supported.end(), dtype) > 0) {
113  IPP_CALL(ipp::To, data_, dst_im.data_, scale, offset);
114  } else { // NPP does not provide a useful API, so use native kernels
115  kernel::image::To(data_, dst_im.data_, scale, offset);
116  }
117  return dst_im;
118 }
119 
121  if (GetChannels() != 3) {
123  "Input image channels must be 3 for RGBToGray, but got {}.",
124  GetChannels());
125  }
126  static const dtype_channels_pairs ipp_supported{
127  {core::UInt8, 3},
128  {core::UInt16, 3},
129  {core::Float32, 3},
130  };
131  static const dtype_channels_pairs npp_supported{
132  {core::UInt8, 3},
133  {core::UInt16, 3},
134  {core::Float32, 3},
135  };
136 
137  Image dst_im;
138  dst_im.data_ = core::Tensor::Empty({GetRows(), GetCols(), 1}, GetDtype(),
139  GetDevice());
140  if (data_.IsCUDA() &&
141  std::count(npp_supported.begin(), npp_supported.end(),
142  std::make_pair(GetDtype(), GetChannels())) > 0) {
144  } else if (HAVE_IPP && data_.IsCPU() &&
145  std::count(ipp_supported.begin(), ipp_supported.end(),
146  std::make_pair(GetDtype(), GetChannels())) > 0) {
148  } else {
150  "RGBToGray with data type {} on device {} is not implemented!",
152  }
153  return dst_im;
154 }
155 
156 Image Image::Resize(float sampling_rate, InterpType interp_type) const {
157  if (sampling_rate == 1.0f) {
158  return *this;
159  }
160  if (GetDtype() == core::Bool) { // Resize via UInt8
162  .Resize(sampling_rate, interp_type)
163  .AsTensor()
164  .ReinterpretCast(core::Bool));
165  }
166 
167  static const dtype_channels_pairs npp_supported{
168  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
169  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
170  {core::UInt8, 4}, {core::UInt16, 4}, {core::Float32, 4},
171 
172  };
173 
174  static const dtype_channels_pairs ipp_supported{
175  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
176  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
177  {core::UInt8, 4}, {core::UInt16, 4}, {core::Float32, 4},
178  };
179 
180  Image dst_im;
181  dst_im.data_ = core::Tensor::Empty(
182  {static_cast<int64_t>(GetRows() * sampling_rate),
183  static_cast<int64_t>(GetCols() * sampling_rate), GetChannels()},
184  GetDtype(), GetDevice());
185 
186  if (data_.IsCUDA() &&
187  std::count(npp_supported.begin(), npp_supported.end(),
188  std::make_pair(GetDtype(), GetChannels())) > 0) {
189  CUDA_CALL(npp::Resize, data_, dst_im.data_, interp_type);
190  } else if (HAVE_IPP && data_.IsCPU() &&
191  std::count(ipp_supported.begin(), ipp_supported.end(),
192  std::make_pair(GetDtype(), GetChannels())) > 0) {
193  IPP_CALL(ipp::Resize, data_, dst_im.data_, interp_type);
194  } else {
196  "Resize with data type {} on device {} is not "
197  "implemented!",
199  }
200  return dst_im;
201 }
202 
203 Image Image::Dilate(int kernel_size) const {
204  // Check NPP datatype support for each function in documentation:
205  // https://docs.nvidia.com/cuda/npp/group__nppi.html
206  static const dtype_channels_pairs npp_supported{
207  {core::Bool, 1}, {core::UInt8, 1}, {core::UInt16, 1},
208  {core::Int32, 1}, {core::Float32, 1}, {core::Bool, 3},
209  {core::UInt8, 3}, {core::UInt16, 3}, {core::Int32, 3},
210  {core::Float32, 3}, {core::Bool, 4}, {core::UInt8, 4},
211  {core::UInt16, 4}, {core::Int32, 4}, {core::Float32, 4},
212  };
213  // Check IPP datatype support for each function in IPP documentation:
214  // https://software.intel.com/content/www/us/en/develop/documentation/ipp-dev-reference/top/volume-2-image-processing.html
215  static const dtype_channels_pairs ipp_supported{
216  {core::Bool, 1}, {core::UInt8, 1}, {core::UInt16, 1},
217  {core::Float32, 1}, {core::Bool, 3}, {core::UInt8, 3},
218  {core::Float32, 3}, {core::Bool, 4}, {core::UInt8, 4},
219  {core::Float32, 4}};
220 
221  Image dst_im;
223  if (data_.IsCUDA() &&
224  std::count(npp_supported.begin(), npp_supported.end(),
225  std::make_pair(GetDtype(), GetChannels())) > 0) {
226  CUDA_CALL(npp::Dilate, data_, dst_im.data_, kernel_size);
227  } else if (HAVE_IPP && data_.IsCPU() &&
228  std::count(ipp_supported.begin(), ipp_supported.end(),
229  std::make_pair(GetDtype(), GetChannels())) > 0) {
230  IPP_CALL(ipp::Dilate, data_, dst_im.data_, kernel_size);
231  } else {
233  "Dilate with data type {} on device {} is not implemented!",
235  }
236  return dst_im;
237 }
238 
240  float value_sigma,
241  float dist_sigma) const {
242  if (kernel_size < 3) {
243  utility::LogError("Kernel size must be >= 3, but got {}.", kernel_size);
244  }
245 
246  static const dtype_channels_pairs npp_supported{
247  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
248  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
249  };
250  static const dtype_channels_pairs ipp_supported{
251  {core::UInt8, 1},
252  {core::Float32, 1},
253  {core::UInt8, 3},
254  {core::Float32, 3},
255  };
256 
257  Image dst_im;
259  if (data_.IsCUDA() &&
260  std::count(npp_supported.begin(), npp_supported.end(),
261  std::make_pair(GetDtype(), GetChannels())) > 0) {
262  CUDA_CALL(npp::FilterBilateral, data_, dst_im.data_, kernel_size,
263  value_sigma, dist_sigma);
264  } else if (HAVE_IPP && data_.IsCPU() &&
265  std::count(ipp_supported.begin(), ipp_supported.end(),
266  std::make_pair(GetDtype(), GetChannels())) > 0) {
267  IPP_CALL(ipp::FilterBilateral, data_, dst_im.data_, kernel_size,
268  value_sigma, dist_sigma);
269  } else {
271  "FilterBilateral with data type {} on device {} is not "
272  "implemented!",
274  }
275  return dst_im;
276 }
277 
278 Image Image::Filter(const core::Tensor &kernel) const {
279  static const dtype_channels_pairs npp_supported{
280  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
281  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
282  {core::UInt8, 4}, {core::UInt16, 4}, {core::Float32, 4},
283  };
284  static const dtype_channels_pairs ipp_supported{
285  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
286  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
287  {core::UInt8, 4}, {core::UInt16, 4}, {core::Float32, 4},
288  };
289 
290  Image dst_im;
292  if (data_.IsCUDA() &&
293  std::count(npp_supported.begin(), npp_supported.end(),
294  std::make_pair(GetDtype(), GetChannels())) > 0) {
295  CUDA_CALL(npp::Filter, data_, dst_im.data_, kernel);
296  } else if (HAVE_IPP && data_.IsCPU() &&
297  std::count(ipp_supported.begin(), ipp_supported.end(),
298  std::make_pair(GetDtype(), GetChannels())) > 0) {
299  IPP_CALL(ipp::Filter, data_, dst_im.data_, kernel);
300  } else {
302  "Filter with data type {} on device {} is not "
303  "implemented!",
305  }
306  return dst_im;
307 }
308 
309 Image Image::FilterGaussian(int kernel_size, float sigma) const {
310  if (kernel_size < 3 || kernel_size % 2 == 0) {
311  utility::LogError("Kernel size must be an odd number >= 3, but got {}.",
312  kernel_size);
313  }
314 
315  static const dtype_channels_pairs npp_supported{
316  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
317  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
318  {core::UInt8, 4}, {core::UInt16, 4}, {core::Float32, 4},
319  };
320  static const dtype_channels_pairs ipp_supported{
321  {core::UInt8, 1}, {core::UInt16, 1}, {core::Float32, 1},
322  {core::UInt8, 3}, {core::UInt16, 3}, {core::Float32, 3},
323  {core::UInt8, 4}, {core::UInt16, 4}, {core::Float32, 4},
324  };
325 
326  Image dst_im;
328  if (data_.IsCUDA() &&
329  std::count(npp_supported.begin(), npp_supported.end(),
330  std::make_pair(GetDtype(), GetChannels())) > 0) {
331  CUDA_CALL(npp::FilterGaussian, data_, dst_im.data_, kernel_size, sigma);
332  } else if (HAVE_IPP && data_.IsCPU() &&
333  std::count(ipp_supported.begin(), ipp_supported.end(),
334  std::make_pair(GetDtype(), GetChannels())) > 0) {
335  IPP_CALL(ipp::FilterGaussian, data_, dst_im.data_, kernel_size, sigma);
336  } else {
338  "FilterGaussian with data type {} on device {} is not "
339  "implemented!",
341  }
342  return dst_im;
343 }
344 
345 std::pair<Image, Image> Image::FilterSobel(int kernel_size) const {
346  if (!(kernel_size == 3 || kernel_size == 5)) {
347  utility::LogError("Kernel size must be 3 or 5, but got {}.",
348  kernel_size);
349  }
350 
351  // 16 signed is also supported by the engines, but is non-standard thus
352  // not supported by cloudViewer. To filter 16 bit unsigned depth images, we
353  // recommend first converting to Float32.
354  static const dtype_channels_pairs npp_supported{
355  {core::UInt8, 1},
356  {core::Float32, 1},
357  };
358  static const dtype_channels_pairs ipp_supported{
359  {core::UInt8, 1},
360  {core::Float32, 1},
361  };
362 
363  // Routines: 8u16s, 32f
364  Image dst_im_dx, dst_im_dy;
365  core::Dtype dtype = GetDtype();
366  if (dtype == core::Float32) {
367  dst_im_dx = core::Tensor::EmptyLike(data_);
368  dst_im_dy = core::Tensor::EmptyLike(data_);
369  } else if (dtype == core::UInt8) {
371  data_.GetDevice());
373  data_.GetDevice());
374  }
375 
376  if (data_.IsCUDA() &&
377  std::count(npp_supported.begin(), npp_supported.end(),
378  std::make_pair(GetDtype(), GetChannels())) > 0) {
379  CUDA_CALL(npp::FilterSobel, data_, dst_im_dx.data_, dst_im_dy.data_,
380  kernel_size);
381  } else if (HAVE_IPP && data_.IsCPU() &&
382  std::count(ipp_supported.begin(), ipp_supported.end(),
383  std::make_pair(GetDtype(), GetChannels())) > 0) {
384  IPP_CALL(ipp::FilterSobel, data_, dst_im_dx.data_, dst_im_dy.data_,
385  kernel_size);
386  } else {
388  "FilterSobel with data type {} on device {} is not "
389  "implemented!",
391  }
392  return std::make_pair(dst_im_dx, dst_im_dy);
393 }
394 
396  Image blur = FilterGaussian(5, 1.0f);
397  return blur.Resize(0.5, InterpType::Nearest);
398 }
399 
400 Image Image::PyrDownDepth(float diff_threshold, float invalid_fill) const {
401  if (GetRows() <= 0 || GetCols() <= 0 || GetChannels() != 1) {
403  "Invalid shape, expected a 1 channel image, but got ({}, {}, "
404  "{})",
405  GetRows(), GetCols(), GetChannels());
406  }
407 
409 
410  core::Tensor dst_tensor = core::Tensor::Empty(
411  {GetRows() / 2, GetCols() / 2, 1}, GetDtype(), GetDevice());
413  diff_threshold, invalid_fill);
414  return t::geometry::Image(dst_tensor);
415 }
416 
418  float min_value,
419  float max_value,
420  float clip_fill) const {
421  if (GetRows() <= 0 || GetCols() <= 0 || GetChannels() != 1) {
423  "Invalid shape, expected a 1 channel image, but got ({}, {}, "
424  "{})",
425  GetRows(), GetCols(), GetChannels());
426  }
427 
429 
430  if (scale < 0 || min_value < 0 || max_value < 0) {
432  "Expected positive scale, min_value, and max_value, but got "
433  "{}, {}, and {}",
434  scale, min_value, max_value);
435  }
436  if (!(std::isnan(clip_fill) || std::isinf(clip_fill) || clip_fill == 0)) {
438  "The clip_fill value {} is not recommended. Please use Inf, "
439  "NaN or, 0",
440  clip_fill);
441  }
442 
443  Image dst_im(GetRows(), GetCols(), 1, core::Float32, data_.GetDevice());
444  kernel::image::ClipTransform(data_, dst_im.data_, scale, min_value,
445  max_value, clip_fill);
446  return dst_im;
447 }
448 
450  float invalid_fill) {
451  if (GetRows() <= 0 || GetCols() <= 0 || GetChannels() != 1) {
453  "Invalid shape, expected a 1 channel image, but got ({}, {}, "
454  "{})",
455  GetRows(), GetCols(), GetChannels());
456  }
457 
459  core::AssertTensorShape(intrinsics, {3, 3});
460 
461  Image dst_im(GetRows(), GetCols(), 3, GetDtype(), GetDevice());
462  kernel::image::CreateVertexMap(data_, dst_im.data_, intrinsics,
463  invalid_fill);
464  return dst_im;
465 }
466 
467 Image Image::CreateNormalMap(float invalid_fill) {
468  if (GetRows() <= 0 || GetCols() <= 0 || GetChannels() != 3) {
470  "Invalid shape, expected a 3 channel image, but got ({}, {}, "
471  "{})",
472  GetRows(), GetCols(), GetChannels());
473  }
474 
476 
477  Image dst_im(GetRows(), GetCols(), 3, GetDtype(), GetDevice());
478  kernel::image::CreateNormalMap(data_, dst_im.data_, invalid_fill);
479  return dst_im;
480 }
481 
482 Image Image::ColorizeDepth(float scale, float min_value, float max_value) {
483  if (GetRows() <= 0 || GetCols() <= 0 || GetChannels() != 1) {
485  "Invalid shape, expected a 1 channel image, but got ({}, {}, "
486  "{})",
487  GetRows(), GetCols(), GetChannels());
488  }
489 
491 
492  if (scale < 0 || min_value < 0 || max_value < 0 || min_value >= max_value) {
494  "Expected positive scale, min_value, and max_value, but got "
495  "{}, {}, and {}",
496  scale, min_value, max_value);
497  }
498 
499  Image dst_im(GetRows(), GetCols(), 3, core::UInt8, GetDevice());
500  kernel::image::ColorizeDepth(data_, dst_im.data_, scale, min_value,
501  max_value);
502  return dst_im;
503 }
504 
506  const core::Device &device) {
507  static const std::unordered_map<int, core::Dtype> kBytesToDtypeMap = {
508  {1, core::UInt8},
509  {2, core::UInt16},
510  {4, core::Float32},
511  };
512 
513  if (image_legacy.IsEmpty()) {
514  return Image(0, 0, 1, core::Float32, device);
515  }
516 
517  auto iter = kBytesToDtypeMap.find(image_legacy.bytes_per_channel_);
518  if (iter == kBytesToDtypeMap.end()) {
519  utility::LogError("Unsupported image bytes_per_channel ({})",
520  image_legacy.bytes_per_channel_);
521  }
522 
523  core::Dtype dtype = iter->second;
524 
525  Image image(image_legacy.height_, image_legacy.width_,
526  image_legacy.num_of_channels_, dtype, device);
527 
528  size_t num_bytes = image_legacy.height_ * image_legacy.BytesPerLine();
529  core::MemoryManager::MemcpyFromHost(image.data_.GetDataPtr(), device,
530  image_legacy.data_.data(), num_bytes);
531  return image;
532 }
533 
535  auto dtype = GetDtype();
536  if (!(dtype == core::UInt8 || dtype == core::UInt16 ||
537  dtype == core::Float32))
538  utility::LogError("Legacy image does not support data type {}.",
539  dtype.ToString());
540  if (!data_.IsContiguous()) {
541  utility::LogError("Image tensor must be contiguous.");
542  }
543  cloudViewer::geometry::Image image_legacy;
544  image_legacy.Prepare(static_cast<int>(GetCols()),
545  static_cast<int>(GetRows()),
546  static_cast<int>(GetChannels()),
547  static_cast<int>(dtype.ByteSize()));
548  size_t num_bytes = image_legacy.height_ * image_legacy.BytesPerLine();
549  core::MemoryManager::MemcpyToHost(image_legacy.data_.data(),
551  num_bytes);
552  return image_legacy;
553 }
554 
555 std::string Image::ToString() const {
556  return fmt::format("Image[size={{{},{}}}, channels={}, {}, {}]", GetRows(),
558  GetDevice().ToString());
559 }
560 
561 } // namespace geometry
562 } // namespace t
563 } // namespace cloudViewer
Common CUDA utilities.
#define CUDA_CALL(cuda_function,...)
Definition: CUDAUtils.h:49
std::shared_ptr< core::Tensor > image
filament::Texture::InternalFormat format
int count
int offset
#define IPP_CALL(ipp_function,...)
Definition: IPPImage.h:96
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
#define AssertTensorDtypes(tensor,...)
Definition: TensorCheck.h:33
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
bool copy
Definition: VtkUtils.cpp:74
bool IsCUDA() const
Definition: Device.h:99
bool IsCPU() const
Definition: Device.h:95
static void MemcpyFromHost(void *dst_ptr, const Device &dst_device, const void *host_ptr, size_t num_bytes)
Same as Memcpy, but with host (CPU:0) as default src_device.
static void MemcpyToHost(void *host_ptr, const void *src_ptr, const Device &src_device, size_t num_bytes)
Same as Memcpy, but with host (CPU:0) as default dst_device.
std::string ToString() const
Definition: SizeVector.cpp:132
int64_t NumDims() const
Definition: Tensor.h:1172
bool IsContiguous() const
Definition: Tensor.h:1036
static Tensor EmptyLike(const Tensor &other)
Definition: Tensor.h:247
Device GetDevice() const override
Definition: Tensor.cpp:1435
Tensor ReinterpretCast(const core::Dtype &dtype) const
Definition: Tensor.cpp:388
Tensor Reshape(const SizeVector &dst_shape) const
Definition: Tensor.cpp:671
Tensor Clone() const
Copy Tensor to the same device.
Definition: Tensor.h:502
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
SizeVector GetShape() const
Definition: Tensor.h:1127
The Image class stores image with customizable width, height, num of channels and bytes per channel.
Definition: Image.h:33
virtual bool IsEmpty() const override
Definition: Image.h:87
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
int height_
Height of the image.
Definition: Image.h:221
int BytesPerLine() const
Returns data size per line (row, or the width) in bytes.
Definition: Image.h:122
int bytes_per_channel_
Number of bytes per channel.
Definition: Image.h:225
int width_
Width of the image.
Definition: Image.h:219
std::vector< uint8_t > data_
Image storage buffer.
Definition: Image.h:227
The base geometry class.
Definition: Geometry.h:23
GeometryType
Specifies possible geometry types.
Definition: Geometry.h:28
The Image class stores image with customizable rows, cols, channels, dtype and device.
Definition: Image.h:29
Image Dilate(int kernel_size=3) const
Return a new image after performing morphological dilation.
Definition: Image.cpp:203
Image ClipTransform(float scale, float min_value, float max_value, float clip_fill=0.0f) const
Return new image after scaling and clipping image values.
Definition: Image.cpp:417
InterpType
Image interpolation algorithms.
Definition: Image.h:178
@ Nearest
Nearest neighbors interpolation.
static constexpr bool HAVE_IPP
Do we use IPP for accelerating image processing operations?
Definition: Image.h:339
Image PyrDown() const
Return a new downsampled image with pyramid downsampling.
Definition: Image.cpp:395
std::string ToString() const
Text description.
Definition: Image.cpp:555
Image PyrDownDepth(float diff_threshold, float invalid_fill=0.f) const
Edge and invalid value preserving downsampling by 2 specifically for depth images.
Definition: Image.cpp:400
static Image FromLegacy(const cloudViewer::geometry::Image &image_legacy, const core::Device &Device=core::Device("CPU:0"))
Create from a legacy CloudViewer Image.
Definition: Image.cpp:505
Image Resize(float sampling_rate=0.5f, InterpType interp_type=InterpType::Nearest) const
Return a new image after resizing with specified interpolation type.
Definition: Image.cpp:156
Image & Reset(int64_t rows=0, int64_t cols=0, int64_t channels=1, core::Dtype dtype=core::Float32, const core::Device &device=core::Device("CPU:0"))
Reinitialize image with new parameters.
Definition: Image.cpp:56
cloudViewer::geometry::Image ToLegacy() const
Convert to legacy Image type.
Definition: Image.cpp:534
Image ColorizeDepth(float scale, float min_value, float max_value)
Colorize an input depth image (with Dtype UInt16 or Float32).
Definition: Image.cpp:482
Image CreateVertexMap(const core::Tensor &intrinsics, float invalid_fill=0.0f)
Create a vertex map from a depth image using unprojection.
Definition: Image.cpp:449
Image(int64_t rows=0, int64_t cols=0, int64_t channels=1, core::Dtype dtype=core::Float32, const core::Device &device=core::Device("CPU:0"))
Constructor for image.
Definition: Image.cpp:31
core::Device GetDevice() const override
Get device of the image.
Definition: Image.h:96
Image FilterGaussian(int kernel_size=3, float sigma=1.0f) const
Return a new image after Gaussian filtering.
Definition: Image.cpp:309
Image RGBToGray() const
Converts a 3-channel RGB image to a new 1-channel Grayscale image.
Definition: Image.cpp:120
Image To(const core::Device &device, bool copy=false) const
Transfer the image to a specified device.
Definition: Image.h:132
Image CreateNormalMap(float invalid_fill=0.0f)
Create a normal map from a vertex map.
Definition: Image.cpp:467
core::Dtype GetDtype() const
Get dtype of the image.
Definition: Image.h:93
std::pair< Image, Image > FilterSobel(int kernel_size=3) const
Return a pair of new gradient images (dx, dy) after Sobel filtering.
Definition: Image.cpp:345
core::Tensor AsTensor() const
Returns the underlying Tensor of the Image.
Definition: Image.h:124
int64_t GetChannels() const
Get the number of channels of the image.
Definition: Image.h:90
Image FilterBilateral(int kernel_size=3, float value_sigma=20.0f, float distance_sigma=10.0f) const
Return a new image after bilateral filtering.
Definition: Image.cpp:239
int64_t GetCols() const
Get the number of columns of the image.
Definition: Image.h:87
Image Filter(const core::Tensor &kernel) const
Return a new image after filtering with the given kernel.
Definition: Image.cpp:278
int64_t GetRows() const
Get the number of rows of the image.
Definition: Image.h:84
constexpr T value_or(V &&v) const &
Definition: Optional.h:485
constexpr bool has_value() const noexcept
Definition: Optional.h:440
#define LogWarning(...)
Definition: Logging.h:72
#define LogError(...)
Definition: Logging.h:60
SizeVector Concat(const SizeVector &l_shape, const SizeVector &r_shape)
Concatenate two shapes.
Definition: ShapeUtil.cpp:199
const Dtype Bool
Definition: Dtype.cpp:52
const Dtype UInt8
Definition: Dtype.cpp:48
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
Definition: SlabTraits.h:49
const Dtype Int16
Definition: Dtype.cpp:45
const Dtype Float64
Definition: Dtype.cpp:43
const Dtype UInt16
Definition: Dtype.cpp:49
const Dtype Int32
Definition: Dtype.cpp:46
const Dtype Float32
Definition: Dtype.cpp:42
void To(const core::Tensor &src_im, core::Tensor &dst_im, double scale, double offset)
Definition: IPPImage.cpp:42
void Dilate(const core::Tensor &src_im, core::Tensor &dst_im, int kernel_size)
Definition: IPPImage.cpp:133
void FilterBilateral(const core::Tensor &src_im, core::Tensor &dst_im, int kernel_size, float value_sigma, float distance_sigma)
Definition: IPPImage.cpp:202
void Filter(const core::Tensor &src_im, core::Tensor &dst_im, const core::Tensor &kernel)
Definition: IPPImage.cpp:170
void Resize(const core::Tensor &src_im, core::Tensor &dst_im, Image::InterpType interp_type)
Definition: IPPImage.cpp:94
void RGBToGray(const core::Tensor &src_im, core::Tensor &dst_im)
Definition: IPPImage.cpp:71
void FilterGaussian(const core::Tensor &src_im, core::Tensor &dst_im, int kernel_size, float sigma)
Definition: IPPImage.cpp:233
void FilterSobel(const core::Tensor &src_im, core::Tensor &dst_im_dx, core::Tensor &dst_im_dy, int kernel_size)
Definition: IPPImage.cpp:261
void CreateVertexMap(const core::Tensor &src, core::Tensor &dst, const core::Tensor &intrinsics, float invalid_fill)
Definition: Image.cpp:62
void ClipTransform(const core::Tensor &src, core::Tensor &dst, float scale, float min_value, float max_value, float clip_fill)
Definition: Image.cpp:31
void ColorizeDepth(const core::Tensor &src, core::Tensor &dst, float scale, float min_value, float max_value)
Definition: Image.cpp:92
void PyrDownDepth(const core::Tensor &src, core::Tensor &dst, float diff_threshold, float invalid_fill)
Definition: Image.cpp:48
void CreateNormalMap(const core::Tensor &src, core::Tensor &dst, float invalid_fill)
Definition: Image.cpp:79
void To(const core::Tensor &src, core::Tensor &dst, double scale, double offset)
Definition: Image.cpp:17
void FilterSobel(const core::Tensor &src_im, core::Tensor &dst_im_dx, core::Tensor &dst_im_dy, int kernel_size)
Definition: NPPImage.cpp:406
void Resize(const cloudViewer::core::Tensor &src_im, cloudViewer::core::Tensor &dst_im, t::geometry::Image::InterpType interp_type)
Definition: NPPImage.cpp:97
void Dilate(const core::Tensor &src_im, core::Tensor &dst_im, int kernel_size)
Definition: NPPImage.cpp:178
void FilterGaussian(const core::Tensor &src_im, core::Tensor &dst_im, int kernel_size, float sigma)
Definition: NPPImage.cpp:378
void RGBToGray(const core::Tensor &src_im, core::Tensor &dst_im)
Definition: NPPImage.cpp:63
void Filter(const cloudViewer::core::Tensor &src_im, cloudViewer::core::Tensor &dst_im, const cloudViewer::core::Tensor &kernel)
Definition: NPPImage.cpp:246
void FilterBilateral(const core::Tensor &src_im, core::Tensor &dst_im, int kernel_size, float value_sigma, float distance_sigma)
Definition: NPPImage.cpp:319
std::vector< std::pair< core::Dtype, int64_t > > dtype_channels_pairs
Definition: Image.cpp:29
Generic file read and write utility for python interface.