Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpColorDepthConversion.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Color to depth conversion.
32 */
33
38
39#include <visp3/core/vpColorDepthConversion.h>
40
41// System
42#include <algorithm>
43#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
44#include <optional>
45#endif
46
47// Core
48#include <visp3/core/vpMath.h>
49#include <visp3/core/vpMeterPixelConversion.h>
50#include <visp3/core/vpPixelMeterConversion.h>
51
53
54#ifndef DOXYGEN_SHOULD_SKIP_THIS
55namespace
56{
57
66vpImagePoint adjust2DPointToBoundary(const vpImagePoint &ip, double width, double height)
67{
68#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
69 return { vpMath::clamp(ip.get_i(), 0., height), vpMath::clamp(ip.get_j(), 0., width) };
70#else
71 return vpImagePoint(vpMath::clamp(ip.get_i(), 0., height), vpMath::clamp(ip.get_j(), 0., width));
72#endif
73}
74
82vpColVector transform(const vpHomogeneousMatrix &extrinsics_params, vpColVector from_point)
83{
84#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
85 from_point = { from_point, 0, 3 };
86 from_point.stack(1.);
87 return { extrinsics_params * from_point, 0, 3 };
88#else
89 from_point = vpColVector(from_point, 0, 3);
90 from_point.stack(1.);
91 return vpColVector(extrinsics_params * from_point, 0, 3);
92#endif
93}
94
102vpImagePoint project(const vpCameraParameters &intrinsic_cam_params, const vpColVector &point)
103{
104#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
105 vpImagePoint iP {};
106#else
107 vpImagePoint iP;
108#endif
109 vpMeterPixelConversion::convertPoint(intrinsic_cam_params, point[0] / point[2], point[1] / point[2], iP);
110
111 return iP;
112}
113
122vpColVector deproject(const vpCameraParameters &intrinsic_cam_params, const vpImagePoint &pixel, double depth)
123{
124#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
125 double x { 0. }, y { 0. };
126 vpPixelMeterConversion::convertPoint(intrinsic_cam_params, pixel, x, y);
127 return { x * depth, y * depth, depth };
128#else
129 double x = 0., y = 0.;
130 vpPixelMeterConversion::convertPoint(intrinsic_cam_params, pixel, x, y);
131
132 vpColVector p(3);
133 p[0] = x * depth;
134 p[1] = y * depth;
135 p[2] = depth;
136 return p;
137#endif
138}
139
140#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
141double getDepth(const float *data, const std::optional<double> depth_scale, const double &offset)
142{
143 (void)depth_scale;
144 return static_cast<double>(data[static_cast<int>(offset)]);
145}
146
147double getDepth(const uint16_t *data, const std::optional<double> depth_scale, const double &offset)
148{
149 return *depth_scale * static_cast<double>(data[static_cast<int>(offset)]);
150}
151
169template<typename Type>
170vpImagePoint project_color_to_depth(
171 const Type *data, std::optional<double> depth_scale, const double &depth_min, const double &depth_max, const double &depth_width,
172 const double &depth_height, const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
173 const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
174{
175 vpImagePoint depth_pixel {};
176
177 // Find line start pixel
178 const auto min_point = deproject(color_intrinsics, from_pixel, depth_min);
179 const auto min_transformed_point = transform(depth_M_color, min_point);
180 auto start_pixel = project(depth_intrinsics, min_transformed_point);
181 start_pixel = adjust2DPointToBoundary(start_pixel, depth_width, depth_height);
182
183 // Find line end depth pixel
184 const auto max_point = deproject(color_intrinsics, from_pixel, depth_max);
185 const auto max_transformed_point = transform(depth_M_color, max_point);
186 auto end_pixel = project(depth_intrinsics, max_transformed_point);
187 end_pixel = adjust2DPointToBoundary(end_pixel, depth_width, depth_height);
188
189 // search along line for the depth pixel that it's projected pixel is the closest to the input pixel
190 auto min_dist = -1.;
191 for (auto curr_pixel = start_pixel; curr_pixel.inSegment(start_pixel, end_pixel) && (curr_pixel != end_pixel);
192 curr_pixel = curr_pixel.nextInSegment(start_pixel, end_pixel)) {
193 const auto depth = getDepth(data, depth_scale, (curr_pixel.get_v() * depth_width) + curr_pixel.get_u());
194 bool stop_for_loop = false;
195 if (std::fabs(depth) <= std::numeric_limits<double>::epsilon()) {
196 stop_for_loop = true;
197 }
198 if (!stop_for_loop) {
199 const auto point = deproject(depth_intrinsics, curr_pixel, depth);
200 const auto transformed_point = transform(color_M_depth, point);
201 const auto projected_pixel = project(color_intrinsics, transformed_point);
202
203 const auto new_dist = vpMath::sqr(projected_pixel.get_v() - from_pixel.get_v()) +
204 vpMath::sqr(projected_pixel.get_u() - from_pixel.get_u());
205 if ((new_dist < min_dist) || (min_dist < 0)) {
206 min_dist = new_dist;
207 depth_pixel = curr_pixel;
208 }
209 }
210 }
211 return depth_pixel;
212}
213#else
214double getDepth(const float *data, const double *depth_scale, const double &offset)
215{
216 (void)depth_scale;
217 return static_cast<double>(data[static_cast<int>(offset)]);
218}
219
220double getDepth(const uint16_t *data, const double *depth_scale, const double &offset)
221{
222 return *depth_scale * static_cast<double>(data[static_cast<int>(offset)]);
223}
224
225template<typename Type>
226vpImagePoint project_color_to_depth(
227 const Type *data, const double *depth_scale, const double &depth_min, const double &depth_max, const double &depth_width,
228 const double &depth_height, const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
229 const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
230{
231 vpImagePoint depth_pixel;
232
233 // Find line start pixel
234 const vpColVector min_point = deproject(color_intrinsics, from_pixel, depth_min);
235 const vpColVector min_transformed_point = transform(depth_M_color, min_point);
236 vpImagePoint start_pixel = project(depth_intrinsics, min_transformed_point);
237 start_pixel = adjust2DPointToBoundary(start_pixel, depth_width, depth_height);
238
239 // Find line end depth pixel
240 const vpColVector max_point = deproject(color_intrinsics, from_pixel, depth_max);
241 const vpColVector max_transformed_point = transform(depth_M_color, max_point);
242 vpImagePoint end_pixel = project(depth_intrinsics, max_transformed_point);
243 end_pixel = adjust2DPointToBoundary(end_pixel, depth_width, depth_height);
244
245 // search along line for the depth pixel that it's projected pixel is the closest to the input pixel
246 double min_dist = -1.;
247 for (vpImagePoint curr_pixel = start_pixel; curr_pixel.inSegment(start_pixel, end_pixel) && curr_pixel != end_pixel;
248 curr_pixel = curr_pixel.nextInSegment(start_pixel, end_pixel)) {
249 const double depth = getDepth(data, depth_scale, (curr_pixel.get_v() * depth_width) + curr_pixel.get_u());
250
251 bool stop_for_loop = false;
252 if (std::fabs(depth) <= std::numeric_limits<double>::epsilon()) {
253 stop_for_loop = true;
254 }
255 if (!stop_for_loop) {
256 const vpColVector point = deproject(depth_intrinsics, curr_pixel, depth);
257 const vpColVector transformed_point = transform(color_M_depth, point);
258 const vpImagePoint projected_pixel = project(color_intrinsics, transformed_point);
259
260 const double new_dist = vpMath::sqr(projected_pixel.get_v() - from_pixel.get_v()) +
261 vpMath::sqr(projected_pixel.get_u() - from_pixel.get_u());
262 if (new_dist < min_dist || min_dist < 0) {
263 min_dist = new_dist;
264 depth_pixel = curr_pixel;
265 }
266 }
267 }
268 return depth_pixel;
269}
270#endif
271} // namespace
272
273#endif // DOXYGEN_SHOULD_SKIP_THIS
274
291 const vpImage<uint16_t> &I_depth, const double &depth_scale, const double &depth_min, const double &depth_max,
292 const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
293 const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
294{
295 return projectColorToDepth(I_depth.bitmap, depth_scale, depth_min, depth_max, I_depth.getWidth(), I_depth.getHeight(),
296 depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
297}
298
317 const uint16_t *data, const double &depth_scale, const double &depth_min, const double &depth_max, const double &depth_width,
318 const double &depth_height, const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
319 const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
320{
321#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
322 return project_color_to_depth(data, std::optional<double>(depth_scale), depth_min, depth_max, depth_width, depth_height,
323 depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
324
325#else
326 return project_color_to_depth(data, &depth_scale, depth_min, depth_max, depth_width, depth_height,
327 depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
328#endif
329}
330
345 const vpImage<float> &I_depth, const double &depth_min, const double &depth_max,
346 const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
347 const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
348{
349 return projectColorToDepth(I_depth.bitmap, depth_min, depth_max, I_depth.getWidth(), I_depth.getHeight(),
350 depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
351}
352
369 const float *data, const double &depth_min, const double &depth_max, const double &depth_width,
370 const double &depth_height, const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
371 const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
372{
373#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17)
374 return project_color_to_depth(data, std::nullopt, depth_min, depth_max, depth_width, depth_height,
375 depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
376
377#else
378 return project_color_to_depth(data, nullptr, depth_min, depth_max, depth_width, depth_height,
379 depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
380#endif
381}
382END_VISP_NAMESPACE
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
void stack(double d)
static vpImagePoint projectColorToDepth(const vpImage< uint16_t > &I_depth, const double &depth_scale, const double &depth_min, const double &depth_max, const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics, const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
Implementation of an homogeneous matrix and operations on such kind of matrices.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_j() const
double get_u() const
bool inSegment(const vpImagePoint &start, const vpImagePoint &end) const
double get_i() const
double get_v() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
static double sqr(double x)
Definition vpMath.h:203
static T clamp(const T &v, const T &lower, const T &upper)
Definition vpMath.h:219
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)