Visual Servoing Platform  version 3.6.1 under development (2024-04-27)
vpColorDepthConversion.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 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 
39 #include <visp3/core/vpColorDepthConversion.h>
40 
41 // System
42 #include <algorithm>
43 
44 // Core
45 #include <visp3/core/vpMath.h>
46 #include <visp3/core/vpMeterPixelConversion.h>
47 #include <visp3/core/vpPixelMeterConversion.h>
48 
49 namespace
50 {
51 
60 vpImagePoint adjust2DPointToBoundary(const vpImagePoint &ip, double width, double height)
61 {
62 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
63  return { vpMath::clamp(ip.get_i(), 0., height), vpMath::clamp(ip.get_j(), 0., width) };
64 #else
65  return vpImagePoint(vpMath::clamp(ip.get_i(), 0., height), vpMath::clamp(ip.get_j(), 0., width));
66 #endif
67 }
68 
76 vpColVector transform(const vpHomogeneousMatrix &extrinsics_params, vpColVector from_point)
77 {
78 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
79  from_point = { from_point, 0, 3 };
80  from_point.stack(1.);
81  return { extrinsics_params * from_point, 0, 3 };
82 #else
83  from_point = vpColVector(from_point, 0, 3);
84  from_point.stack(1.);
85  return vpColVector(extrinsics_params * from_point, 0, 3);
86 #endif
87 }
88 
96 vpImagePoint project(const vpCameraParameters &intrinsic_cam_params, const vpColVector &point)
97 {
98 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
99  vpImagePoint iP {};
100 #else
101  vpImagePoint iP;
102 #endif
103  vpMeterPixelConversion::convertPoint(intrinsic_cam_params, point[0] / point[2], point[1] / point[2], iP);
104 
105  return iP;
106 }
107 
116 vpColVector deproject(const vpCameraParameters &intrinsic_cam_params, const vpImagePoint &pixel, double depth)
117 {
118 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
119  double x { 0. }, y { 0. };
120  vpPixelMeterConversion::convertPoint(intrinsic_cam_params, pixel, x, y);
121  return { x * depth, y * depth, depth };
122 #else
123  double x = 0., y = 0.;
124  vpPixelMeterConversion::convertPoint(intrinsic_cam_params, pixel, x, y);
125 
126  vpColVector p(3);
127  p[0] = x * depth;
128  p[1] = y * depth;
129  p[2] = depth;
130  return p;
131 #endif
132 }
133 
134 } // namespace
135 
152  const vpImage<uint16_t> &I_depth, double depth_scale, double depth_min, double depth_max,
153  const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
154  const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
155 {
156  return projectColorToDepth(I_depth.bitmap, depth_scale, depth_min, depth_max, I_depth.getWidth(), I_depth.getHeight(),
157  depth_intrinsics, color_intrinsics, color_M_depth, depth_M_color, from_pixel);
158 }
159 
178  const uint16_t *data, double depth_scale, double depth_min, double depth_max, double depth_width,
179  double depth_height, const vpCameraParameters &depth_intrinsics, const vpCameraParameters &color_intrinsics,
180  const vpHomogeneousMatrix &color_M_depth, const vpHomogeneousMatrix &depth_M_color, const vpImagePoint &from_pixel)
181 {
182 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
183  vpImagePoint depth_pixel {};
184 
185  // Find line start pixel
186  const auto min_point = deproject(color_intrinsics, from_pixel, depth_min);
187  const auto min_transformed_point = transform(depth_M_color, min_point);
188  auto start_pixel = project(depth_intrinsics, min_transformed_point);
189  start_pixel = adjust2DPointToBoundary(start_pixel, depth_width, depth_height);
190 
191  // Find line end depth pixel
192  const auto max_point = deproject(color_intrinsics, from_pixel, depth_max);
193  const auto max_transformed_point = transform(depth_M_color, max_point);
194  auto end_pixel = project(depth_intrinsics, max_transformed_point);
195  end_pixel = adjust2DPointToBoundary(end_pixel, depth_width, depth_height);
196 
197  // search along line for the depth pixel that it's projected pixel is the closest to the input pixel
198  auto min_dist = -1.;
199  for (auto curr_pixel = start_pixel; curr_pixel.inSegment(start_pixel, end_pixel) && (curr_pixel != end_pixel);
200  curr_pixel = curr_pixel.nextInSegment(start_pixel, end_pixel)) {
201  const auto depth = depth_scale * data[static_cast<int>((curr_pixel.get_v() * depth_width) + curr_pixel.get_u())];
202  if (std::fabs(depth) <= std::numeric_limits<double>::epsilon()) {
203  continue;
204  }
205 
206  const auto point = deproject(depth_intrinsics, curr_pixel, depth);
207  const auto transformed_point = transform(color_M_depth, point);
208  const auto projected_pixel = project(color_intrinsics, transformed_point);
209 
210  const auto new_dist = vpMath::sqr(projected_pixel.get_v() - from_pixel.get_v()) +
211  vpMath::sqr(projected_pixel.get_u() - from_pixel.get_u());
212  if ((new_dist < min_dist) || (min_dist < 0)) {
213  min_dist = new_dist;
214  depth_pixel = curr_pixel;
215  }
216  }
217 
218 #else
219  vpImagePoint depth_pixel;
220 
221  // Find line start pixel
222  const vpColVector min_point = deproject(color_intrinsics, from_pixel, depth_min);
223  const vpColVector min_transformed_point = transform(depth_M_color, min_point);
224  vpImagePoint start_pixel = project(depth_intrinsics, min_transformed_point);
225  start_pixel = adjust2DPointToBoundary(start_pixel, depth_width, depth_height);
226 
227  // Find line end depth pixel
228  const vpColVector max_point = deproject(color_intrinsics, from_pixel, depth_max);
229  const vpColVector max_transformed_point = transform(depth_M_color, max_point);
230  vpImagePoint end_pixel = project(depth_intrinsics, max_transformed_point);
231  end_pixel = adjust2DPointToBoundary(end_pixel, depth_width, depth_height);
232 
233  // search along line for the depth pixel that it's projected pixel is the closest to the input pixel
234  double min_dist = -1.;
235  for (vpImagePoint curr_pixel = start_pixel; curr_pixel.inSegment(start_pixel, end_pixel) && curr_pixel != end_pixel;
236  curr_pixel = curr_pixel.nextInSegment(start_pixel, end_pixel)) {
237  const double depth = depth_scale * data[static_cast<int>(curr_pixel.get_v() * depth_width + curr_pixel.get_u())];
238  if (std::fabs(depth) <= std::numeric_limits<double>::epsilon())
239  continue;
240 
241  const vpColVector point = deproject(depth_intrinsics, curr_pixel, depth);
242  const vpColVector transformed_point = transform(color_M_depth, point);
243  const vpImagePoint projected_pixel = project(color_intrinsics, transformed_point);
244 
245  const double new_dist = vpMath::sqr(projected_pixel.get_v() - from_pixel.get_v()) +
246  vpMath::sqr(projected_pixel.get_u() - from_pixel.get_u());
247  if (new_dist < min_dist || min_dist < 0) {
248  min_dist = new_dist;
249  depth_pixel = curr_pixel;
250  }
251  }
252 #endif
253  return depth_pixel;
254 }
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
void stack(double d)
static vpImagePoint projectColorToDepth(const vpImage< uint16_t > &I_depth, double depth_scale, double depth_min, 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 ...
Definition: vpImagePoint.h:82
double get_j() const
Definition: vpImagePoint.h:125
vpImagePoint nextInSegment(const vpImagePoint &start, const vpImagePoint &end) const
Definition: vpImagePoint.h:215
double get_u() const
Definition: vpImagePoint.h:136
bool inSegment(const vpImagePoint &start, const vpImagePoint &end) const
Definition: vpImagePoint.h:162
double get_i() const
Definition: vpImagePoint.h:114
double get_v() const
Definition: vpImagePoint.h:147
Definition of the vpImage class member functions.
Definition: vpImage.h:69
unsigned int getWidth() const
Definition: vpImage.h:245
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:184
static double sqr(double x)
Definition: vpMath.h:201
static T clamp(const T &v, const T &lower, const T &upper)
Definition: vpMath.h:216
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)