Visual Servoing Platform  version 3.6.1 under development (2024-05-03)
testRealSense2_D435_align.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Test Intel RealSense D435 acquisition with librealsense2.
33  *
34 *****************************************************************************/
40 #include <iostream>
41 #include <visp3/core/vpConfig.h>
42 
43 #if defined(VISP_HAVE_REALSENSE2) && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) \
44  && defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON) && (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI))
45 
46 #include <visp3/core/vpImage.h>
47 #include <visp3/core/vpImageConvert.h>
48 #include <visp3/core/vpMeterPixelConversion.h>
49 #include <visp3/gui/vpDisplayGDI.h>
50 #include <visp3/gui/vpDisplayX.h>
51 #include <visp3/sensor/vpRealSense2.h>
52 
53 namespace
54 {
55 void createDepthHist(std::vector<uint32_t> &histogram2, const pcl::PointCloud<pcl::PointXYZ>::Ptr &pointcloud,
56  double depth_scale)
57 {
58  std::fill(histogram2.begin(), histogram2.end(), 0);
59 
60  for (uint32_t i = 0; i < pointcloud->height; i++) {
61  for (uint32_t j = 0; j < pointcloud->width; j++) {
62  const pcl::PointXYZ &pcl_pt = pointcloud->at(j, i);
63  ++histogram2[static_cast<uint32_t>(pcl_pt.z * depth_scale)];
64  }
65  }
66 
67  for (int i = 2; i < 0x10000; i++)
68  histogram2[i] += histogram2[i - 1]; // Build a cumulative histogram for
69  // the indices in [1,0xFFFF]
70 }
71 
72 void createDepthHist(std::vector<uint32_t> &histogram2, const std::vector<vpColVector> &pointcloud, double depth_scale)
73 {
74  std::fill(histogram2.begin(), histogram2.end(), 0);
75 
76  for (size_t i = 0; i < pointcloud.size(); i++) {
77  const vpColVector &pt = pointcloud[i];
78  ++histogram2[static_cast<uint32_t>(pt[2] * depth_scale)];
79  }
80 
81  for (int i = 2; i < 0x10000; i++)
82  histogram2[i] += histogram2[i - 1]; // Build a cumulative histogram for
83  // the indices in [1,0xFFFF]
84 }
85 
86 unsigned char getDepthColor(const std::vector<uint32_t> &histogram2, double z, double depth_scale)
87 {
88  // 0-255 based on histogram location
89  return static_cast<unsigned char>(histogram2[static_cast<uint32_t>(z * depth_scale)] * 255 / histogram2[0xFFFF]);
90 }
91 } // namespace
92 
93 int main(int argc, char *argv[])
94 {
95  bool align_to_depth = false;
96  bool color_pointcloud = false;
97  bool col_vector = false;
98  bool no_align = false;
99  for (int i = 1; i < argc; i++) {
100  if (std::string(argv[i]) == "--align_to_depth") {
101  align_to_depth = true;
102  }
103  else if (std::string(argv[i]) == "--color") {
104  color_pointcloud = true;
105  }
106  else if (std::string(argv[i]) == "--col_vector") {
107  col_vector = true;
108  }
109  else if (std::string(argv[i]) == "--no_align") {
110  no_align = true;
111  }
112  }
113 
114  std::cout << "align_to_depth: " << align_to_depth << std::endl;
115  std::cout << "color_pointcloud: " << color_pointcloud << std::endl;
116  std::cout << "col_vector: " << col_vector << std::endl;
117  std::cout << "no_align: " << no_align << std::endl;
118 
119  vpRealSense2 rs;
120  rs2::config config;
121  const int width = 640, height = 480, fps = 30;
122  config.enable_stream(RS2_STREAM_COLOR, width, height, RS2_FORMAT_RGBA8, fps);
123  config.enable_stream(RS2_STREAM_DEPTH, width, height, RS2_FORMAT_Z16, fps);
124  config.enable_stream(RS2_STREAM_INFRARED, width, height, RS2_FORMAT_Y8, fps);
125  rs.open(config);
126  const double depth_scale = 1.0 / rs.getDepthScale();
127 
128  vpImage<vpRGBa> I_color(height, width), I_depth(height, width), I_pcl(height, width), I_pcl2(height, width);
129  vpImage<vpRGBa> I_display(height * 2, width), I_display2(height * 2, width), I_display3(height * 2, width);
130  vpImage<uint16_t> I_depth_raw(height, width);
131 
132 #ifdef VISP_HAVE_X11
133  vpDisplayX d1, d2, d3;
134 #else
135  vpDisplayGDI d1, d2, d3;
136 #endif
137  d1.init(I_display, 0, 0, "Color + depth");
138  d2.init(I_display2, width, 0, "Color + ROS pointcloud");
139  d3.init(I_display3, 2 * width, 0, "Color + pointcloud");
140 
141  pcl::PointCloud<pcl::PointXYZ>::Ptr pointcloud(new pcl::PointCloud<pcl::PointXYZ>());
142  pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointcloud_color(new pcl::PointCloud<pcl::PointXYZRGB>());
143  std::vector<vpColVector> vp_pointcloud;
144  std::vector<uint32_t> histogram(0x10000), histogram2(0x10000);
145 
146  rs2::align align_to(align_to_depth ? RS2_STREAM_DEPTH : RS2_STREAM_COLOR);
147  vpCameraParameters cam_projection =
148  align_to_depth ? rs.getCameraParameters(RS2_STREAM_DEPTH) : rs.getCameraParameters(RS2_STREAM_COLOR);
149 
150  while (true) {
151  if (color_pointcloud) {
152  rs.acquire(reinterpret_cast<unsigned char *>(I_color.bitmap),
153  reinterpret_cast<unsigned char *>(I_depth_raw.bitmap), &vp_pointcloud, pointcloud_color, nullptr,
154  no_align ? nullptr : &align_to);
155  }
156  else {
157  rs.acquire(reinterpret_cast<unsigned char *>(I_color.bitmap),
158  reinterpret_cast<unsigned char *>(I_depth_raw.bitmap), &vp_pointcloud, pointcloud, nullptr,
159  no_align ? nullptr : &align_to);
160  }
161 
162  vpImageConvert::createDepthHistogram(I_depth_raw, I_depth);
163 
164  I_pcl = vpRGBa(0, 0, 0);
165  if (color_pointcloud) {
166  for (uint32_t i = 0; i < pointcloud_color->height; i++) {
167  for (uint32_t j = 0; j < pointcloud_color->width; j++) {
168  const pcl::PointXYZRGB &pcl_pt = pointcloud_color->at(j, i);
169  double Z = pcl_pt.z;
170  if (Z > 1e-2) {
171  double x = pcl_pt.x / Z;
172  double y = pcl_pt.y / Z;
173 
174  vpImagePoint imPt;
175  vpMeterPixelConversion::convertPoint(cam_projection, x, y, imPt);
176  unsigned int u =
177  std::min<unsigned int>(static_cast<unsigned int>(width - 1), static_cast<unsigned int>(std::max<double>(0.0, imPt.get_u())));
178  unsigned int v =
179  std::min<unsigned int>(static_cast<unsigned int>(height - 1), static_cast<unsigned int>(std::max<double>(0.0, imPt.get_v())));
180  I_pcl[v][u] = vpRGBa(pcl_pt.r, pcl_pt.g, pcl_pt.b);
181  }
182  }
183  }
184  }
185  else {
186  createDepthHist(histogram, pointcloud, depth_scale);
187 
188  for (uint32_t i = 0; i < pointcloud->height; i++) {
189  for (uint32_t j = 0; j < pointcloud->width; j++) {
190  const pcl::PointXYZ &pcl_pt = pointcloud->at(j, i);
191  double Z = pcl_pt.z;
192  if (Z > 1e-2) {
193  double x = pcl_pt.x / Z;
194  double y = pcl_pt.y / Z;
195 
196  vpImagePoint imPt;
197  vpMeterPixelConversion::convertPoint(cam_projection, x, y, imPt);
198  unsigned int u =
199  std::min<unsigned int>(static_cast<unsigned int>(width - 1), static_cast<unsigned int>(std::max<double>(0.0, imPt.get_u())));
200  unsigned int v =
201  std::min<unsigned int>(static_cast<unsigned int>(height - 1), static_cast<unsigned int>(std::max<double>(0.0, imPt.get_v())));
202  unsigned char depth_viz = getDepthColor(histogram, pcl_pt.z, depth_scale);
203  I_pcl[v][u] = vpRGBa(depth_viz, depth_viz, depth_viz);
204  }
205  }
206  }
207  }
208 
209  I_pcl2 = vpRGBa(0, 0, 0);
210  createDepthHist(histogram2, vp_pointcloud, depth_scale);
211  for (size_t i = 0; i < vp_pointcloud.size(); i++) {
212  const vpColVector &pt = vp_pointcloud[i];
213  double Z = pt[2];
214  if (Z > 1e-2) {
215  double x = pt[0] / Z;
216  double y = pt[1] / Z;
217 
218  vpImagePoint imPt;
219  vpMeterPixelConversion::convertPoint(cam_projection, x, y, imPt);
220  unsigned int u =
221  std::min<unsigned int>(static_cast<unsigned int>(width - 1), static_cast<unsigned int>(std::max<double>(0.0, imPt.get_u())));
222  unsigned int v =
223  std::min<unsigned int>(static_cast<unsigned int>(height - 1), static_cast<unsigned int>(std::max<double>(0.0, imPt.get_v())));
224  unsigned char depth_viz = getDepthColor(histogram2, Z, depth_scale);
225  I_pcl2[v][u] = vpRGBa(depth_viz, depth_viz, depth_viz);
226  }
227  }
228 
229  I_display.insert(I_color, vpImagePoint(0, 0));
230  I_display.insert(I_depth, vpImagePoint(I_color.getHeight(), 0));
231 
232  I_display2.insert(I_color, vpImagePoint(0, 0));
233  I_display2.insert(I_pcl, vpImagePoint(I_color.getHeight(), 0));
234 
235  I_display3.insert(I_color, vpImagePoint(0, 0));
236  I_display3.insert(I_pcl2, vpImagePoint(I_color.getHeight(), 0));
237 
238  vpDisplay::display(I_display);
239  vpDisplay::display(I_display2);
240  vpDisplay::display(I_display3);
241 
242  const int nb_lines = 5;
243  for (int i = 1; i < nb_lines; i++) {
244  const int col_idx = i * (width / nb_lines);
245  vpDisplay::displayLine(I_display, 0, col_idx, I_display.getRows() - 1, col_idx, vpColor::green, 2);
246  vpDisplay::displayLine(I_display2, 0, col_idx, I_display.getRows() - 1, col_idx, vpColor::green, 2);
247  vpDisplay::displayLine(I_display3, 0, col_idx, I_display.getRows() - 1, col_idx, vpColor::green, 2);
248  }
249 
250  vpDisplay::flush(I_display);
251  vpDisplay::flush(I_display2);
252  vpDisplay::flush(I_display3);
253 
254  if (vpDisplay::getClick(I_display, false) || vpDisplay::getClick(I_display2, false) ||
255  vpDisplay::getClick(I_display3, false)) {
256  break;
257  }
258  }
259 
260  return EXIT_SUCCESS;
261 }
262 
263 #else
264 int main() { return EXIT_SUCCESS; }
265 #endif
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
static const vpColor green
Definition: vpColor.h:214
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:128
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="") vp_override
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void flush(const vpImage< unsigned char > &I)
static void createDepthHistogram(const vpImage< uint16_t > &src_depth, vpImage< vpRGBa > &dest_rgba)
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_u() const
Definition: vpImagePoint.h:136
double get_v() const
Definition: vpImagePoint.h:147
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Definition: vpRGBa.h:61
vpCameraParameters getCameraParameters(const rs2_stream &stream, vpCameraParameters::vpCameraParametersProjType type=vpCameraParameters::perspectiveProjWithDistortion, int index=-1) const
void acquire(vpImage< unsigned char > &grey, double *ts=nullptr)
bool open(const rs2::config &cfg=rs2::config())
float getDepthScale()