Open3D (C++ API)  0.19.0
Loading...
Searching...
No Matches
ImageImpl.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2024 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7
8#include <limits>
9
12#include "open3d/core/Indexer.h"
13#include "open3d/core/Tensor.h"
16
17namespace open3d {
18namespace t {
19namespace geometry {
20namespace kernel {
21namespace image {
22
23#ifndef __CUDACC__
24using std::isinf;
25using std::isnan;
26#endif
27
28#if defined(__CUDACC__)
29void ToCUDA
30#elif defined(SYCL_LANGUAGE_VERSION)
31void ToSYCL
32#else
34#endif
35 (const core::Tensor& src,
36 core::Tensor& dst,
37 double scale,
38 double offset) {
40 // elem_t: corresponds to dst_dtype.
41 // scalar_t: corresponds to src_dtype.
42 // calc_t: calculation type for intermediate results.
43#define LINEAR_SATURATE(elem_t, calc_t) \
44 elem_t limits[2] = {std::numeric_limits<elem_t>::min(), \
45 std::numeric_limits<elem_t>::max()}; \
46 calc_t c_scale = static_cast<calc_t>(scale); \
47 calc_t c_offset = static_cast<calc_t>(offset); \
48 DISPATCH_DTYPE_TO_TEMPLATE(src.GetDtype(), [&]() { \
49 core::ParallelFor( \
50 src.GetDevice(), indexer.NumWorkloads(), \
51 [=] OPEN3D_DEVICE(int64_t workload_idx) { \
52 auto src_ptr = \
53 indexer.GetInputPtr<scalar_t>(0, workload_idx); \
54 auto dst_ptr = indexer.GetOutputPtr<elem_t>(workload_idx); \
55 calc_t out = static_cast<calc_t>(*src_ptr) * c_scale + \
56 c_offset; \
57 out = out < limits[0] ? limits[0] : out; \
58 out = out > limits[1] ? limits[1] : out; \
59 *dst_ptr = static_cast<elem_t>(out); \
60 }); \
61 });
62 core::Dtype dst_dtype = dst.GetDtype();
63 if (dst_dtype == core::Float32) {
64 LINEAR_SATURATE(float, float)
65 } else if (dst_dtype == core::Float64) {
66 LINEAR_SATURATE(double, double)
67 } else if (dst_dtype == core::Int8) {
68 LINEAR_SATURATE(int8_t, float)
69 } else if (dst_dtype == core::UInt8) {
70 LINEAR_SATURATE(uint8_t, float)
71 } else if (dst_dtype == core::Int16) {
72 LINEAR_SATURATE(int16_t, float)
73 } else if (dst_dtype == core::UInt16) {
74 LINEAR_SATURATE(uint16_t, float)
75 } else if (dst_dtype == core::Int32) {
76 LINEAR_SATURATE(int32_t, double)
77 } else if (dst_dtype == core::UInt32) {
78 LINEAR_SATURATE(uint32_t, double)
79 } else if (dst_dtype == core::Int64) {
80 LINEAR_SATURATE(int64_t, double)
81 } else if (dst_dtype == core::UInt64) {
82 LINEAR_SATURATE(uint64_t, double)
83 }
84#undef LINEAR_SATURATE
85}
86
87#if defined(__CUDACC__)
88void ClipTransformCUDA
89#elif defined(SYCL_LANGUAGE_VERSION)
90void ClipTransformSYCL
91#else
93#endif
94 (const core::Tensor& src,
95 core::Tensor& dst,
96 float scale,
97 float min_value,
98 float max_value,
99 float clip_fill) {
100 NDArrayIndexer src_indexer(src, 2);
101 NDArrayIndexer dst_indexer(dst, 2);
102
103 int64_t rows = src.GetShape(0);
104 int64_t cols = dst.GetShape(1);
105 int64_t n = rows * cols;
106
107 DISPATCH_DTYPE_TO_TEMPLATE(src.GetDtype(), [&]() {
108 core::ParallelFor(src.GetDevice(), n,
109 [=] OPEN3D_DEVICE(int64_t workload_idx) {
110 int64_t y = workload_idx / cols;
111 int64_t x = workload_idx % cols;
112
113 float in = static_cast<float>(
114 *src_indexer.GetDataPtr<scalar_t>(x, y));
115 float out = in / scale;
116 out = out <= min_value ? clip_fill : out;
117 out = out >= max_value ? clip_fill : out;
118 *dst_indexer.GetDataPtr<float>(x, y) = out;
119 });
120 });
121}
122
123// Reimplementation of the reference:
124// https://github.com/mp3guy/ICPCUDA/blob/master/Cuda/pyrdown.cu#L41
125#if defined(__CUDACC__)
126void PyrDownDepthCUDA
127#elif defined(SYCL_LANGUAGE_VERSION)
128void PyrDownDepthSYCL
129#else
131#endif
132 (const core::Tensor& src,
133 core::Tensor& dst,
134 float depth_diff,
135 float invalid_fill) {
136 NDArrayIndexer src_indexer(src, 2);
137 NDArrayIndexer dst_indexer(dst, 2);
138
139 int rows = src_indexer.GetShape(0);
140 int cols = src_indexer.GetShape(1);
141
142 int rows_down = dst_indexer.GetShape(0);
143 int cols_down = dst_indexer.GetShape(1);
144 int n = rows_down * cols_down;
145
146 // Gaussian filter window size
147 // Gaussian filter weights
148 const int gkernel_size = 5;
149 const int gkernel_size_2 = gkernel_size / 2;
150 const float gweights[3] = {0.375f, 0.25f, 0.0625f};
151
152#ifndef __CUDACC__
153 using std::abs;
154 using std::max;
155 using std::min;
156#endif
157
159 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
160 int y = workload_idx / cols_down;
161 int x = workload_idx % cols_down;
162
163 int y_src = 2 * y;
164 int x_src = 2 * x;
165
166 float v_center = *src_indexer.GetDataPtr<float>(x_src, y_src);
167 if (v_center == invalid_fill) {
168 *dst_indexer.GetDataPtr<float>(x, y) = invalid_fill;
169 return;
170 }
171
172 int x_min = max(0, x_src - gkernel_size_2);
173 int y_min = max(0, y_src - gkernel_size_2);
174
175 int x_max = min(cols - 1, x_src + gkernel_size_2);
176 int y_max = min(rows - 1, y_src + gkernel_size_2);
177
178 float v_sum = 0;
179 float w_sum = 0;
180 for (int yk = y_min; yk <= y_max; ++yk) {
181 for (int xk = x_min; xk <= x_max; ++xk) {
182 float v = *src_indexer.GetDataPtr<float>(xk, yk);
183 int dy = abs(yk - y_src);
184 int dx = abs(xk - x_src);
185
186 if (v != invalid_fill &&
187 abs(v - v_center) < depth_diff) {
188 float w = gweights[dx] * gweights[dy];
189 v_sum += w * v;
190 w_sum += w;
191 }
192 }
193 }
194
195 *dst_indexer.GetDataPtr<float>(x, y) =
196 w_sum == 0 ? invalid_fill : v_sum / w_sum;
197 });
198}
199
200#if defined(__CUDACC__)
201void CreateVertexMapCUDA
202#elif defined(SYCL_LANGUAGE_VERSION)
203void CreateVertexMapSYCL
204#else
206#endif
207 (const core::Tensor& src,
208 core::Tensor& dst,
209 const core::Tensor& intrinsics,
210 float invalid_fill) {
211 NDArrayIndexer src_indexer(src, 2);
212 NDArrayIndexer dst_indexer(dst, 2);
214 core::Device("CPU:0")));
215
216 int64_t rows = src.GetShape(0);
217 int64_t cols = src.GetShape(1);
218 int64_t n = rows * cols;
219
220#ifndef __CUDACC__
221 using std::isinf;
222 using std::isnan;
223#endif
224
226 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
227 auto is_invalid = [invalid_fill] OPEN3D_DEVICE(float v) {
228 if (isinf(invalid_fill)) return isinf(v);
229 if (isnan(invalid_fill)) return isnan(v);
230 return v == invalid_fill;
231 };
232
233 int64_t y = workload_idx / cols;
234 int64_t x = workload_idx % cols;
235
236 float d = *src_indexer.GetDataPtr<float>(x, y);
237
238 float* vertex = dst_indexer.GetDataPtr<float>(x, y);
239 if (!is_invalid(d)) {
240 ti.Unproject(static_cast<float>(x), static_cast<float>(y),
241 d, vertex + 0, vertex + 1, vertex + 2);
242 } else {
243 vertex[0] = invalid_fill;
244 vertex[1] = invalid_fill;
245 vertex[2] = invalid_fill;
246 }
247 });
248}
249#if defined(__CUDACC__)
250void CreateNormalMapCUDA
251#elif defined(SYCL_LANGUAGE_VERSION)
252void CreateNormalMapSYCL
253#else
255#endif
256 (const core::Tensor& src, core::Tensor& dst, float invalid_fill) {
257 NDArrayIndexer src_indexer(src, 2);
258 NDArrayIndexer dst_indexer(dst, 2);
259
260 int64_t rows = src_indexer.GetShape(0);
261 int64_t cols = src_indexer.GetShape(1);
262 int64_t n = rows * cols;
263
265 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
266 int64_t y = workload_idx / cols;
267 int64_t x = workload_idx % cols;
268
269 float* normal = dst_indexer.GetDataPtr<float>(x, y);
270
271 if (y < rows - 1 && x < cols - 1) {
272 float* v00 = src_indexer.GetDataPtr<float>(x, y);
273 float* v10 = src_indexer.GetDataPtr<float>(x + 1, y);
274 float* v01 = src_indexer.GetDataPtr<float>(x, y + 1);
275
276 if ((v00[0] == invalid_fill && v00[1] == invalid_fill &&
277 v00[2] == invalid_fill) ||
278 (v01[0] == invalid_fill && v01[1] == invalid_fill &&
279 v01[2] == invalid_fill) ||
280 (v10[0] == invalid_fill && v10[1] == invalid_fill &&
281 v10[2] == invalid_fill)) {
282 normal[0] = invalid_fill;
283 normal[1] = invalid_fill;
284 normal[2] = invalid_fill;
285 return;
286 }
287
288 float dx0 = v01[0] - v00[0];
289 float dy0 = v01[1] - v00[1];
290 float dz0 = v01[2] - v00[2];
291
292 float dx1 = v10[0] - v00[0];
293 float dy1 = v10[1] - v00[1];
294 float dz1 = v10[2] - v00[2];
295
296 normal[0] = dy0 * dz1 - dz0 * dy1;
297 normal[1] = dz0 * dx1 - dx0 * dz1;
298 normal[2] = dx0 * dy1 - dy0 * dx1;
299
300 constexpr float EPSILON = 1e-5f;
301 float normal_norm =
302 sqrt(normal[0] * normal[0] + normal[1] * normal[1] +
303 normal[2] * normal[2]);
304 normal_norm = std::max(normal_norm, EPSILON);
305 normal[0] /= normal_norm;
306 normal[1] /= normal_norm;
307 normal[2] /= normal_norm;
308 } else {
309 normal[0] = invalid_fill;
310 normal[1] = invalid_fill;
311 normal[2] = invalid_fill;
312 }
313 });
314}
315
316#if defined(__CUDACC__)
317void ColorizeDepthCUDA
318#elif defined(SYCL_LANGUAGE_VERSION)
319void ColorizeDepthSYCL
320#else
322#endif
323 (const core::Tensor& src,
324 core::Tensor& dst,
325 float scale,
326 float min_value,
327 float max_value) {
328 NDArrayIndexer src_indexer(src, 2);
329 NDArrayIndexer dst_indexer(dst, 2);
330
331 int64_t rows = src.GetShape(0);
332 int64_t cols = dst.GetShape(1);
333 int64_t n = rows * cols;
334
335 float inv_interval = 255.0f / (max_value - min_value);
336 DISPATCH_DTYPE_TO_TEMPLATE(src.GetDtype(), [&]() {
337 core::ParallelFor(
338 src.GetDevice(), n, [=] OPEN3D_DEVICE(int64_t workload_idx) {
339 int64_t y = workload_idx / cols;
340 int64_t x = workload_idx % cols;
341
342 float in = static_cast<float>(
343 *src_indexer.GetDataPtr<scalar_t>(x, y));
344 float out = in / scale;
345 out = out <= min_value ? min_value : out;
346 out = out >= max_value ? max_value : out;
347
348 int idx =
349 static_cast<int>(inv_interval * (out - min_value));
350 uint8_t* out_ptr = dst_indexer.GetDataPtr<uint8_t>(x, y);
351 out_ptr[0] = turbo_srgb_bytes[idx][0];
352 out_ptr[1] = turbo_srgb_bytes[idx][1];
353 out_ptr[2] = turbo_srgb_bytes[idx][2];
354 });
355 });
356}
357
358} // namespace image
359} // namespace kernel
360} // namespace geometry
361} // namespace t
362} // namespace open3d
Common CUDA utilities.
#define OPEN3D_DEVICE
Definition CUDAUtils.h:44
#define DISPATCH_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition Dispatch.h:30
std::shared_ptr< core::Tensor > image
Definition FilamentRenderer.cpp:328
#define LINEAR_SATURATE(elem_t, calc_t)
double t
Definition SurfaceReconstructionPoisson.cpp:172
Indexer indexer
Definition UnaryEWSYCL.cpp:34
Definition Device.h:18
Definition Dtype.h:20
Definition Indexer.h:280
Definition Tensor.h:32
static Tensor Eye(int64_t n, Dtype dtype, const Device &device)
Create an identity matrix of size n x n.
Definition Tensor.cpp:417
Definition GeometryIndexer.h:161
OPEN3D_HOST_DEVICE void * GetDataPtr() const
Definition GeometryIndexer.h:315
OPEN3D_HOST_DEVICE index_t GetShape(int i) const
Definition GeometryIndexer.h:311
Helper class for converting coordinates/indices between 3D/3D, 3D/2D, 2D/3D.
Definition GeometryIndexer.h:25
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:111
int offset
Definition FilePCD.cpp:46
const Dtype UInt32
Definition Dtype.cpp:50
const Dtype Int64
Definition Dtype.cpp:47
const Dtype UInt16
Definition Dtype.cpp:49
const Dtype Int32
Definition Dtype.cpp:46
const Dtype Int16
Definition Dtype.cpp:45
const Dtype UInt8
Definition Dtype.cpp:48
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Definition ParallelFor.h:135
const Dtype Float64
Definition Dtype.cpp:43
const Dtype UInt64
Definition Dtype.cpp:51
const Dtype Int8
Definition Dtype.cpp:44
const Dtype Float32
Definition Dtype.cpp:42
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:94
void CreateNormalMapCPU(const core::Tensor &src, core::Tensor &dst, float invalid_fill)
Definition ImageImpl.h:256
void ColorizeDepthCPU(const core::Tensor &src, core::Tensor &dst, float scale, float min_value, float max_value)
Definition ImageImpl.h:323
void CreateVertexMapCPU(const core::Tensor &src, core::Tensor &dst, const core::Tensor &intrinsics, float invalid_fill)
Definition ImageImpl.h:207
void PyrDownDepthCPU(const core::Tensor &src, core::Tensor &dst, float diff_threshold, float invalid_fill)
Definition ImageImpl.h:132
void ToCPU(const core::Tensor &src, core::Tensor &dst, double scale, double offset)
Definition ImageImpl.h:35
Definition PinholeCameraIntrinsic.cpp:16