Open3D (C++ API)  0.15.1
ImageImpl.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// The MIT License (MIT)
5//
6// Copyright (c) 2018-2021 www.open3d.org
7//
8// Permission is hereby granted, free of charge, to any person obtaining a copy
9// of this software and associated documentation files (the "Software"), to deal
10// in the Software without restriction, including without limitation the rights
11// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12// copies of the Software, and to permit persons to whom the Software is
13// furnished to do so, subject to the following conditions:
14//
15// The above copyright notice and this permission notice shall be included in
16// all copies or substantial portions of the Software.
17//
18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24// IN THE SOFTWARE.
25// ----------------------------------------------------------------------------
26
27#include <limits>
28
31#include "open3d/core/Indexer.h"
32#include "open3d/core/Tensor.h"
35
36namespace open3d {
37namespace t {
38namespace geometry {
39namespace kernel {
40namespace image {
41
42#ifndef __CUDACC__
43using std::isinf;
44using std::isnan;
45#endif
46
47#ifdef __CUDACC__
48void ToCUDA
49#else
51#endif
52 (const core::Tensor& src,
53 core::Tensor& dst,
54 double scale,
55 double offset) {
56 core::Indexer indexer({src}, dst, core::DtypePolicy::NONE);
57 // elem_t: corresponds to dst_dtype.
58 // scalar_t: corresponds to src_dtype.
59 // calc_t: calculation type for intermediate results.
60#define LINEAR_SATURATE(elem_t, calc_t) \
61 elem_t limits[2] = {std::numeric_limits<elem_t>::min(), \
62 std::numeric_limits<elem_t>::max()}; \
63 calc_t c_scale = static_cast<calc_t>(scale); \
64 calc_t c_offset = static_cast<calc_t>(offset); \
65 DISPATCH_DTYPE_TO_TEMPLATE(src.GetDtype(), [&]() { \
66 core::ParallelFor( \
67 src.GetDevice(), indexer.NumWorkloads(), \
68 [=] OPEN3D_DEVICE(int64_t workload_idx) { \
69 auto src_ptr = \
70 indexer.GetInputPtr<scalar_t>(0, workload_idx); \
71 auto dst_ptr = indexer.GetOutputPtr<elem_t>(workload_idx); \
72 calc_t out = static_cast<calc_t>(*src_ptr) * c_scale + \
73 c_offset; \
74 out = out < limits[0] ? limits[0] : out; \
75 out = out > limits[1] ? limits[1] : out; \
76 *dst_ptr = static_cast<elem_t>(out); \
77 }); \
78 });
79 core::Dtype dst_dtype = dst.GetDtype();
80 if (dst_dtype == core::Float32) {
81 LINEAR_SATURATE(float, float)
82 } else if (dst_dtype == core::Float64) {
83 LINEAR_SATURATE(double, double)
84 } else if (dst_dtype == core::Int8) {
85 LINEAR_SATURATE(int8_t, float)
86 } else if (dst_dtype == core::UInt8) {
87 LINEAR_SATURATE(uint8_t, float)
88 } else if (dst_dtype == core::Int16) {
89 LINEAR_SATURATE(int16_t, float)
90 } else if (dst_dtype == core::UInt16) {
91 LINEAR_SATURATE(uint16_t, float)
92 } else if (dst_dtype == core::Int32) {
94 } else if (dst_dtype == core::UInt32) {
96 } else if (dst_dtype == core::Int64) {
97 LINEAR_SATURATE(int64_t, double)
98 } else if (dst_dtype == core::UInt64) {
100 }
101#undef LINEAR_SATURATE
102}
103
104#ifdef __CUDACC__
105void ClipTransformCUDA
106#else
108#endif
109 (const core::Tensor& src,
110 core::Tensor& dst,
111 float scale,
112 float min_value,
113 float max_value,
114 float clip_fill) {
115 NDArrayIndexer src_indexer(src, 2);
116 NDArrayIndexer dst_indexer(dst, 2);
117
118 int64_t rows = src.GetShape(0);
119 int64_t cols = dst.GetShape(1);
120 int64_t n = rows * cols;
121
122 DISPATCH_DTYPE_TO_TEMPLATE(src.GetDtype(), [&]() {
123 core::ParallelFor(src.GetDevice(), n,
124 [=] OPEN3D_DEVICE(int64_t workload_idx) {
125 int64_t y = workload_idx / cols;
126 int64_t x = workload_idx % cols;
127
128 float in = static_cast<float>(
129 *src_indexer.GetDataPtr<scalar_t>(x, y));
130 float out = in / scale;
131 out = out <= min_value ? clip_fill : out;
132 out = out >= max_value ? clip_fill : out;
133 *dst_indexer.GetDataPtr<float>(x, y) = out;
134 });
135 });
136}
137
138// Reimplementation of the reference:
139// https://github.com/mp3guy/ICPCUDA/blob/master/Cuda/pyrdown.cu#L41
140#ifdef __CUDACC__
141void PyrDownDepthCUDA
142#else
144#endif
145 (const core::Tensor& src,
146 core::Tensor& dst,
147 float depth_diff,
148 float invalid_fill) {
149 NDArrayIndexer src_indexer(src, 2);
150 NDArrayIndexer dst_indexer(dst, 2);
151
152 int rows = src_indexer.GetShape(0);
153 int cols = src_indexer.GetShape(1);
154
155 int rows_down = dst_indexer.GetShape(0);
156 int cols_down = dst_indexer.GetShape(1);
157 int n = rows_down * cols_down;
158
159 // Gaussian filter window size
160 // Gaussian filter weights
161 const int gkernel_size = 5;
162 const int gkernel_size_2 = gkernel_size / 2;
163 const float gweights[3] = {0.375f, 0.25f, 0.0625f};
164
165#ifndef __CUDACC__
166 using std::abs;
167 using std::max;
168 using std::min;
169#endif
170
172 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
173 int y = workload_idx / cols_down;
174 int x = workload_idx % cols_down;
175
176 int y_src = 2 * y;
177 int x_src = 2 * x;
178
179 float v_center = *src_indexer.GetDataPtr<float>(x_src, y_src);
180 if (v_center == invalid_fill) {
181 *dst_indexer.GetDataPtr<float>(x, y) = invalid_fill;
182 return;
183 }
184
185 int x_min = max(0, x_src - gkernel_size_2);
186 int y_min = max(0, y_src - gkernel_size_2);
187
188 int x_max = min(cols - 1, x_src + gkernel_size_2);
189 int y_max = min(rows - 1, y_src + gkernel_size_2);
190
191 float v_sum = 0;
192 float w_sum = 0;
193 for (int yk = y_min; yk <= y_max; ++yk) {
194 for (int xk = x_min; xk <= x_max; ++xk) {
195 float v = *src_indexer.GetDataPtr<float>(xk, yk);
196 int dy = abs(yk - y_src);
197 int dx = abs(xk - x_src);
198
199 if (v != invalid_fill &&
200 abs(v - v_center) < depth_diff) {
201 float w = gweights[dx] * gweights[dy];
202 v_sum += w * v;
203 w_sum += w;
204 }
205 }
206 }
207
208 *dst_indexer.GetDataPtr<float>(x, y) =
209 w_sum == 0 ? invalid_fill : v_sum / w_sum;
210 });
211}
212
213#ifdef __CUDACC__
214void CreateVertexMapCUDA
215#else
217#endif
218 (const core::Tensor& src,
219 core::Tensor& dst,
220 const core::Tensor& intrinsics,
221 float invalid_fill) {
222 NDArrayIndexer src_indexer(src, 2);
223 NDArrayIndexer dst_indexer(dst, 2);
225 core::Device("CPU:0")));
226
227 int64_t rows = src.GetShape(0);
228 int64_t cols = src.GetShape(1);
229 int64_t n = rows * cols;
230
231#ifndef __CUDACC__
232 using std::isinf;
233 using std::isnan;
234#endif
235
237 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
238 auto is_invalid = [invalid_fill] OPEN3D_DEVICE(float v) {
239 if (isinf(invalid_fill)) return isinf(v);
240 if (isnan(invalid_fill)) return isnan(v);
241 return v == invalid_fill;
242 };
243
244 int64_t y = workload_idx / cols;
245 int64_t x = workload_idx % cols;
246
247 float d = *src_indexer.GetDataPtr<float>(x, y);
248
249 float* vertex = dst_indexer.GetDataPtr<float>(x, y);
250 if (!is_invalid(d)) {
251 ti.Unproject(static_cast<float>(x), static_cast<float>(y),
252 d, vertex + 0, vertex + 1, vertex + 2);
253 } else {
254 vertex[0] = invalid_fill;
255 vertex[1] = invalid_fill;
256 vertex[2] = invalid_fill;
257 }
258 });
259}
260#ifdef __CUDACC__
261void CreateNormalMapCUDA
262#else
264#endif
265 (const core::Tensor& src, core::Tensor& dst, float invalid_fill) {
266 NDArrayIndexer src_indexer(src, 2);
267 NDArrayIndexer dst_indexer(dst, 2);
268
269 int64_t rows = src_indexer.GetShape(0);
270 int64_t cols = src_indexer.GetShape(1);
271 int64_t n = rows * cols;
272
274 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
275 int64_t y = workload_idx / cols;
276 int64_t x = workload_idx % cols;
277
278 float* normal = dst_indexer.GetDataPtr<float>(x, y);
279
280 if (y < rows - 1 && x < cols - 1) {
281 float* v00 = src_indexer.GetDataPtr<float>(x, y);
282 float* v10 = src_indexer.GetDataPtr<float>(x + 1, y);
283 float* v01 = src_indexer.GetDataPtr<float>(x, y + 1);
284
285 if ((v00[0] == invalid_fill && v00[1] == invalid_fill &&
286 v00[2] == invalid_fill) ||
287 (v01[0] == invalid_fill && v01[1] == invalid_fill &&
288 v01[2] == invalid_fill) ||
289 (v10[0] == invalid_fill && v10[1] == invalid_fill &&
290 v10[2] == invalid_fill)) {
291 normal[0] = invalid_fill;
292 normal[1] = invalid_fill;
293 normal[2] = invalid_fill;
294 return;
295 }
296
297 float dx0 = v01[0] - v00[0];
298 float dy0 = v01[1] - v00[1];
299 float dz0 = v01[2] - v00[2];
300
301 float dx1 = v10[0] - v00[0];
302 float dy1 = v10[1] - v00[1];
303 float dz1 = v10[2] - v00[2];
304
305 normal[0] = dy0 * dz1 - dz0 * dy1;
306 normal[1] = dz0 * dx1 - dx0 * dz1;
307 normal[2] = dx0 * dy1 - dy0 * dx1;
308
309 constexpr float EPSILON = 1e-5f;
310 float normal_norm =
311 sqrt(normal[0] * normal[0] + normal[1] * normal[1] +
312 normal[2] * normal[2]);
313 normal_norm = std::max(normal_norm, EPSILON);
314 normal[0] /= normal_norm;
315 normal[1] /= normal_norm;
316 normal[2] /= normal_norm;
317 } else {
318 normal[0] = invalid_fill;
319 normal[1] = invalid_fill;
320 normal[2] = invalid_fill;
321 }
322 });
323}
324
325#ifdef __CUDACC__
326void ColorizeDepthCUDA
327#else
329#endif
330 (const core::Tensor& src,
331 core::Tensor& dst,
332 float scale,
333 float min_value,
334 float max_value) {
335 NDArrayIndexer src_indexer(src, 2);
336 NDArrayIndexer dst_indexer(dst, 2);
337
338 int64_t rows = src.GetShape(0);
339 int64_t cols = dst.GetShape(1);
340 int64_t n = rows * cols;
341
342 float inv_interval = 255.0f / (max_value - min_value);
343 DISPATCH_DTYPE_TO_TEMPLATE(src.GetDtype(), [&]() {
344 core::ParallelFor(
345 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
346 int64_t y = workload_idx / cols;
347 int64_t x = workload_idx % cols;
348
349 float in = static_cast<float>(
350 *src_indexer.GetDataPtr<scalar_t>(x, y));
351 float out = in / scale;
352 out = out <= min_value ? min_value : out;
353 out = out >= max_value ? max_value : out;
354
355 int idx =
356 static_cast<int>(inv_interval * (out - min_value));
357 uint8_t* out_ptr = dst_indexer.GetDataPtr<uint8_t>(x, y);
358 out_ptr[0] = turbo_srgb_bytes[idx][0];
359 out_ptr[1] = turbo_srgb_bytes[idx][1];
360 out_ptr[2] = turbo_srgb_bytes[idx][2];
361 });
362 });
363}
364
365} // namespace image
366} // namespace kernel
367} // namespace geometry
368} // namespace t
369} // namespace open3d
Common CUDA utilities.
#define OPEN3D_DEVICE
Definition: CUDAUtils.h:64
#define DISPATCH_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:49
std::shared_ptr< core::Tensor > image
Definition: FilamentRenderer.cpp:228
#define LINEAR_SATURATE(elem_t, calc_t)
Definition: Device.h:39
Definition: Dtype.h:39
Definition: Indexer.h:280
Definition: Tensor.h:51
static Tensor Eye(int64_t n, Dtype dtype, const Device &device)
Create an identity matrix of size n x n.
Definition: Tensor.cpp:392
Definition: GeometryIndexer.h:180
OPEN3D_HOST_DEVICE void * GetDataPtr() const
Definition: GeometryIndexer.h:335
OPEN3D_HOST_DEVICE index_t GetShape(int i) const
Definition: GeometryIndexer.h:331
Helper class for converting coordinates/indices between 3D/3D, 3D/2D, 2D/3D.
Definition: GeometryIndexer.h:44
OPEN3D_HOST_DEVICE void Unproject(float u_in, float v_in, float d_in, float *x_out, float *y_out, float *z_out) const
Unproject a 2D uv coordinate with depth to 3D in camera coordinate.
Definition: GeometryIndexer.h:130
int offset
Definition: FilePCD.cpp:64
const Dtype UInt32
Definition: Dtype.cpp:69
const Dtype Int64
Definition: Dtype.cpp:66
const Dtype UInt16
Definition: Dtype.cpp:68
const Dtype Int32
Definition: Dtype.cpp:65
const Dtype Int16
Definition: Dtype.cpp:64
const Dtype UInt8
Definition: Dtype.cpp:67
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Definition: ParallelFor.h:122
const Dtype Float64
Definition: Dtype.cpp:62
const Dtype UInt64
Definition: Dtype.cpp:70
const Dtype Int8
Definition: Dtype.cpp:63
const Dtype Float32
Definition: Dtype.cpp:61
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t timeout_in_ms capture_handle capture_handle capture_handle image_handle temperature_c k4a_image_t image_handle uint8_t image_handle image_handle image_handle image_handle uint32_t
Definition: K4aPlugin.cpp:567
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t timeout_in_ms capture_handle capture_handle capture_handle image_handle temperature_c k4a_image_t image_handle uint8_t image_handle image_handle image_handle image_handle image_handle timestamp_usec white_balance image_handle k4a_device_configuration_t config device_handle char size_t serial_number_size bool int32_t int32_t max_value
Definition: K4aPlugin.cpp:668
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample uint64_t
Definition: K4aPlugin.cpp:362
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t timeout_in_ms capture_handle capture_handle capture_handle image_handle temperature_c k4a_image_t image_handle uint8_t image_handle image_handle image_handle image_handle image_handle timestamp_usec white_balance image_handle k4a_device_configuration_t config device_handle char size_t serial_number_size bool int32_t min_value
Definition: K4aPlugin.cpp:666
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t int32_t
Definition: K4aPlugin.cpp:414
void ClipTransformCPU(const core::Tensor &src, core::Tensor &dst, float scale, float min_value, float max_value, float clip_fill=0.0f)
Definition: ImageImpl.h:109
void CreateNormalMapCPU(const core::Tensor &src, core::Tensor &dst, float invalid_fill)
Definition: ImageImpl.h:265
void ColorizeDepthCPU(const core::Tensor &src, core::Tensor &dst, float scale, float min_value, float max_value)
Definition: ImageImpl.h:330
void CreateVertexMapCPU(const core::Tensor &src, core::Tensor &dst, const core::Tensor &intrinsics, float invalid_fill)
Definition: ImageImpl.h:218
void PyrDownDepthCPU(const core::Tensor &src, core::Tensor &dst, float diff_threshold, float invalid_fill)
Definition: ImageImpl.h:145
void ToCPU(const core::Tensor &src, core::Tensor &dst, double scale, double offset)
Definition: ImageImpl.h:52
Definition: PinholeCameraIntrinsic.cpp:35