DepthImageUtility.cc
Go to the documentation of this file.
1 
38 #include <MultiSense/MultiSenseChannel.hh>
39 
40 #ifdef WIN32
41 #ifndef WIN32_LEAN_AND_MEAN
42 #define WIN32_LEAN_AND_MEAN 1
43 #endif
44 
45 #include <windows.h>
46 #include <winsock2.h>
47 #else
48 #include <unistd.h>
49 #include <arpa/inet.h> // htons
50 #endif
51 
52 #include <fstream>
53 #include <iomanip>
54 #include <iostream>
55 #include <limits>
56 #include <memory>
57 #include <sstream>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <string>
63 
64 #include <getopt/getopt.h>
65 #include <ChannelUtilities.hh>
66 #include <Io.hh>
67 
68 using namespace crl::multisense;
69 
70 namespace { // anonymous
71 
72 volatile bool doneG = false;
73 
74 void usage(const char *programNameP)
75 {
76  std::cerr << "USAGE: " << programNameP << " [<options>]" << std::endl;
77  std::cerr << "Where <options> are:" << std::endl;
78  std::cerr << "\t-a <current_address> : CURRENT IPV4 address (default=10.66.171.21)" << std::endl;
79  std::cerr << "\t-m <mtu> : CURRENT MTU (default=1500)" << std::endl;
80  std::cerr << "\t-c : Save color images and depth in the color image frame" << std::endl;
81 
82  exit(1);
83 }
84 
85 #ifdef WIN32
86 BOOL WINAPI signalHandler(DWORD dwCtrlType)
87 {
88  CRL_UNUSED (dwCtrlType);
89  doneG = true;
90  return TRUE;
91 }
92 #else
93 void signalHandler(int sig)
94 {
95  (void) sig;
96  doneG = true;
97 }
98 #endif
99 
100 struct UserData
101 {
102  Channel *driver = nullptr;
103  std::shared_ptr<const ImageBufferWrapper> auxLumaRectified = nullptr;
104  std::shared_ptr<const ImageBufferWrapper> auxChromaRectified = nullptr;
107  bool hasAux = false;
108 };
109 
110 std::vector<uint16_t> createDepthImage(const image::Header &disparity,
111  const image::Calibration &calibration,
112  const system::DeviceInfo &deviceInfo,
113  bool auxFrame)
114 {
115  const size_t width = disparity.width;
116  const size_t height = disparity.height;
117 
118  //
119  // Scale our calibration based on the current sensor resolution. Calibrations stored on the camera
120  // are for full resolution images
121 
122  const double xScale = 1.0 / ((static_cast<double>(deviceInfo.imagerWidth) /
123  static_cast<double>(width)));
124 
125  const double yScale = 1.0 / ((static_cast<double>(deviceInfo.imagerHeight) /
126  static_cast<double>(height)));
127 
128  //
129  // Decompose rectified projection matrices sorted in the form
130  //
131  // Left: Right:
132  // Fx 0 Cx 0 Fx 0 Cx FxTx
133  // 0 Fy Cy 0 0 Fy Cy 0
134  // 0 0 0 1 0 0 0 1
135 
136  const double fx = calibration.left.P[0][0] * xScale;
137  const double fy = calibration.left.P[1][1] * yScale;
138  const double cx = calibration.left.P[0][2] * xScale;
139  const double cy = calibration.left.P[1][2] * yScale;
140  const double tx = calibration.right.P[0][3] / calibration.right.P[0][0];
141  const double cxRight = calibration.right.P[0][2] * xScale;
142 
143  const double auxFx = calibration.aux.P[0][0] * xScale;
144  const double auxFy = calibration.aux.P[1][1] * yScale;
145  const double auxCx = calibration.aux.P[0][2] * xScale;
146  const double auxCy = calibration.aux.P[1][2] * yScale;
147  const double auxFxTx = calibration.aux.P[0][3] * xScale;
148  const double auxFyTy = calibration.aux.P[1][3] * yScale;
149  const double auxTz = calibration.aux.P[2][3];
150 
151 
152  const uint16_t *disparityP = reinterpret_cast<const uint16_t*>(disparity.imageDataP);
153 
154  std::vector<uint16_t> pixels(height * width, 0);
155 
156  const double max_ni_depth = std::numeric_limits<uint16_t>::max();
157 
158  for (size_t h = 0 ; h < height ; ++h) {
159  for (size_t w = 0 ; w < width ; ++w) {
160 
161  const size_t index = h * width + w;
162 
163  //
164  // MultiSense 16 bit disparity images are stored in 1/16 of a pixel. This allows us to send subpixel
165  // resolutions with integer values
166 
167  const double d = static_cast<double>(disparityP[index]) / 16.0;
168 
169  if (d == 0) {
170  continue;
171  }
172 
173  //
174  // Q matrix used for reprojection. Manually preform the multiplication with the vector:
175  // [w, h, d, 1]^T
176  //
177  // FyTx 0 0 -FyCxTx
178  // 0 FxTx 0 -FxCyTx
179  // 0 0 0 FxFyTx
180  // 0 0 -Fy Fy(Cx - Cx')
181 
182  const double xB = ((fy * tx) * w) + (-fy * cx * tx);
183  const double yB = ((fx * tx) * h) + (-fx * cy * tx);
184  const double zB = (fx * fy * tx);
185  const double invB = 1. / (-fy * d) + (fy * (cx - cxRight));
186 
187  uint16_t depth = 0;
188  size_t depthIndex = 0;
189  if (auxFrame) {
190 
191  //
192  // Take our disparity, convert it into 3D point, and project the 3D point into the rectified aux
193  // image using the aux P matrix which has the form:
194  //
195  // Fx 0 Cx FxTx
196  // 0 Fy Cy FyTy
197  // 0 0 1 Tz
198 
199  const double x = xB * invB;
200  const double y = yB * invB;
201  const double z = zB * invB;
202 
203  depth = static_cast<uint16_t>(std::min(max_ni_depth, std::max(0.0, (z + auxTz) * 1000)));
204 
205  const double u = ((auxFx * x) + (auxCx * z) + auxFxTx) / (z + auxTz);
206  const double v = ((auxFy * y) + (auxCy * z) + auxFyTy) / (z + auxTz);
207 
208  depthIndex = static_cast<int>(v) * width + static_cast<int>(u);
209 
210  if (u < 0 || v < 0 || u >= width || v >= height || depthIndex >= (width * height)) {
211  continue;
212  }
213 
214  }
215  else {
216 
217  depth = static_cast<uint16_t>(std::min(max_ni_depth, std::max(0.0, (zB * invB) * 1000)));
218 
219  depthIndex = index;
220  }
221 
222  pixels[depthIndex] = depth;
223  }
224  }
225 
226  return pixels;
227 }
228 
229 bool saveColor(const std::string& fileName,
230  std::shared_ptr<const ImageBufferWrapper> leftRect,
231  std::shared_ptr<const ImageBufferWrapper> leftChromaRect)
232 {
233  std::vector<uint8_t> output(leftRect->data().width * leftRect->data().height * 3);
234  ycbcrToBgr(leftRect->data(), leftChromaRect->data(), output.data());
235 
236  io::savePpm(fileName, leftRect->data().width, leftRect->data().height, output.data());
237  return true;
238 }
239 
240 void imageCallback(const image::Header& header,
241  void *userDataP)
242 {
243  UserData *userData = reinterpret_cast<UserData*>(userDataP);
244 
245  if (!userData->driver) {
246  std::cerr << "Invalid MultiSense channel" << std::endl;
247  return;
248  }
249 
250  switch (header.source) {
252  {
253  io::savePgm(std::to_string(header.frameId) + "_left_rectified.pgm",
254  header.width,
255  header.height,
256  header.bitsPerPixel,
257  "",
258  header.imageDataP);
259  return;
260  }
262  {
263  if (header.bitsPerPixel != 16) {
264  std::cerr << "Unsupported disparity pixel depth" << std::endl;
265  return;
266  }
267 
268  //
269  // Create a depth image using a OpenNI Depth format (i.e. quantizing depth in mm to 16 bits)
270 
271  io::savePgm(std::to_string(header.frameId) + "depth.pgm",
272  header.width,
273  header.height,
274  16,
275  "",
276  createDepthImage(header, userData->calibration, userData->deviceInfo, userData->hasAux).data());
277 
278  return;
279  }
281  {
282  userData->auxChromaRectified = std::make_shared<ImageBufferWrapper>(userData->driver, header);
283 
284  if (userData->auxLumaRectified && userData->auxLumaRectified->data().frameId == header.frameId) {
285  saveColor(std::to_string(header.frameId) + "_rectified_color.ppm",
286  userData->auxLumaRectified,
287  userData->auxChromaRectified);
288  }
289  return;
290  }
292  {
293  userData->auxLumaRectified = std::make_shared<ImageBufferWrapper>(userData->driver, header);
294 
295  if (userData->auxChromaRectified && userData->auxChromaRectified->data().frameId == header.frameId) {
296  saveColor(std::to_string(header.frameId) + "_rectified_color.ppm",
297  userData->auxLumaRectified,
298  userData->auxChromaRectified);
299  }
300  return;
301  }
302  default:
303  {
304  std::cerr << "Unknown image source: " << header.source << std::endl;
305  return;
306  }
307  }
308 }
309 
310 } // anonymous
311 
312 int main(int argc,
313  char **argvPP)
314 {
315  std::string currentAddress = "10.66.171.21";
316  int32_t mtu = 0;
317  bool useColor = false;
318 
319 #if WIN32
320  SetConsoleCtrlHandler (signalHandler, TRUE);
321 #else
322  signal(SIGINT, signalHandler);
323 #endif
324 
325  //
326  // Parse args
327 
328  int c;
329 
330  while(-1 != (c = getopt(argc, argvPP, "a:m:c")))
331  switch(c) {
332  case 'a': currentAddress = std::string(optarg); break;
333  case 'm': mtu = atoi(optarg); break;
334  case 'c': useColor = true; break;
335  default: usage(*argvPP); break;
336  }
337 
338  Status status;
339 
340  //
341  // Initialize communications.
342 
343  auto channelP = std::make_unique<ChannelWrapper>(currentAddress);
344  if (nullptr == channelP || nullptr == channelP->ptr()) {
345  std::cerr << "Failed to establish communications with \"" << currentAddress << "\"" << std::endl;
346  return EXIT_FAILURE;
347  }
348 
349  //
350  // Change MTU
351 
352  if (mtu >= 1500)
353  status = channelP->ptr()->setMtu(mtu);
354  else
355  status = channelP->ptr()->setBestMtu();
356  if (Status_Ok != status) {
357  std::cerr << "Failed to set MTU: " << Channel::statusString(status) << std::endl;
358  }
359 
360  //
361  // Query calibration
362 
363  image::Calibration calibration;
364  status = channelP->ptr()->getImageCalibration(calibration);
365  if (Status_Ok != status) {
366  std::cerr << "Failed to query calibration: " << Channel::statusString(status) << std::endl;
367  return EXIT_FAILURE;
368  }
369 
370  //
371  // Query device info
372 
374  status = channelP->ptr()->getDeviceInfo(deviceInfo);
375  if (Status_Ok != status) {
376  std::cerr << "Failed to query device info: " << Channel::statusString(status) << std::endl;
377  return EXIT_FAILURE;
378  }
379 
380  //
381  // Change framerate and resolution to 1/4 resolution
382 
383  image::Config cfg;
384 
385  status = channelP->ptr()->getImageConfig(cfg);
386  if (Status_Ok != status) {
387  std::cerr << "Failed to get image config: " << Channel::statusString(status) << std::endl;
388  return EXIT_FAILURE;
389  } else {
390  cfg.setFps(10.0);
391  cfg.setResolution(deviceInfo.imagerWidth / 2, deviceInfo.imagerHeight / 2);
392 
393  status = channelP->ptr()->setImageConfig(cfg);
394  if (Status_Ok != status) {
395  std::cerr << "Failed to configure sensor: " << Channel::statusString(status) << std::endl;
396  return EXIT_FAILURE;
397  }
398  }
399 
400  //
401  // If we have a aux camera, stream aux color data instead of left rectified images
402 
403  bool hasAux = false;
405 
406  if (useColor &&
410 
412  hasAux = true;
413  }
414 
415 
416  //
417  // Setup user data to store camera state for pointcloud reprojection
418 
419  UserData userData{channelP->ptr(), nullptr, nullptr, calibration, deviceInfo, hasAux};
420 
421  //
422  // Add callbacks
423 
424  channelP->ptr()->addIsolatedCallback(imageCallback,
429  &userData);
430 
431 
432  //
433  // Start streaming
434 
435  status = channelP->ptr()->startStreams(streams);
436  if (Status_Ok != status) {
437  std::cerr << "Failed to start streams: " << Channel::statusString(status) << std::endl;
438  return EXIT_FAILURE;
439  }
440 
441  while(!doneG) {
442  usleep(1000000);
443  }
444 
445  status = channelP->ptr()->stopStreams(Source_All);
446  if (Status_Ok != status) {
447  std::cerr << "Failed to stop streams: " << Channel::statusString(status) << std::endl;
448  return EXIT_FAILURE;
449  }
450 
451  return EXIT_SUCCESS;
452 }
usage
static void usage()
Definition: FirmwareUpdateUtility.cc:51
crl::multisense::Status_Ok
static CRL_CONSTEXPR Status Status_Ok
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:99
crl::multisense::image::Header::height
uint32_t height
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:470
getopt.h
getopt
int getopt(int argc, char **argv, char *opts)
Definition: getopt.c:31
ChannelUtilities.hh
CRL_UNUSED
#define CRL_UNUSED(var)
Definition: Legacy/include/MultiSense/details/utility/Portability.hh:44
crl::multisense::image::Calibration::Data::P
float P[3][4]
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:1927
crl::multisense::image::Header::width
uint32_t width
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:468
crl::multisense::image::Calibration::aux
Data aux
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:1935
crl::multisense::image::Calibration::left
Data left
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:1931
Portability.hh
crl::multisense::system::DeviceInfo::imagerWidth
uint32_t imagerWidth
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3307
crl::multisense::image::Config
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:797
io::savePgm
bool savePgm(const std::string &fileName, uint32_t width, uint32_t height, uint32_t bitsPerPixel, const std::string &comment, const void *dataP)
Definition: Io.hh:67
io::savePpm
bool savePpm(const std::string &fileName, uint32_t width, uint32_t height, const void *dataP)
Definition: Io.hh:43
crl::multisense::DataSource
uint64_t DataSource
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:115
crl::multisense::Channel::statusString
static const char * statusString(Status status)
Definition: Legacy/details/channel.cc:876
crl::multisense::system::DeviceInfo
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3245
crl::multisense::Source_All
static CRL_CONSTEXPR DataSource Source_All
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:118
crl::multisense::system::DeviceInfo::hardwareRevision
uint32_t hardwareRevision
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3297
crl::multisense::image::Calibration
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:1910
d
d
ycbcrToBgr
constexpr std::array< uint8_t, 3 > ycbcrToBgr(const crl::multisense::image::Header &luma, const crl::multisense::image::Header &chroma, const size_t u, const size_t v)
Definition: ChannelUtilities.hh:115
crl::multisense::Source_Disparity_Left
static CRL_CONSTEXPR DataSource Source_Disparity_Left
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:129
crl::multisense::system::DeviceInfo::HARDWARE_REV_MULTISENSE_C6S2_S27
static CRL_CONSTEXPR uint32_t HARDWARE_REV_MULTISENSE_C6S2_S27
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3258
crl::multisense::Status
int32_t Status
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:94
crl::multisense::system::DeviceInfo::HARDWARE_REV_MULTISENSE_KS21i
static CRL_CONSTEXPR uint32_t HARDWARE_REV_MULTISENSE_KS21i
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3268
header
std_msgs::Header const * header(const M &m)
crl::multisense::Channel
Definition: Legacy/include/MultiSense/MultiSenseChannel.hh:69
crl::multisense
Definition: Legacy/details/channel.cc:62
crl::multisense::system::DeviceInfo::HARDWARE_REV_MULTISENSE_S30
static CRL_CONSTEXPR uint32_t HARDWARE_REV_MULTISENSE_S30
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3259
crl::multisense::image::Header::imageDataP
const void * imageDataP
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:487
optarg
char * optarg
Definition: getopt.c:29
crl::multisense::image::Calibration::right
Data right
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:1933
crl::multisense::Source_Chroma_Rectified_Aux
static CRL_CONSTEXPR DataSource Source_Chroma_Rectified_Aux
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:127
Io.hh
crl::multisense::image::Config::setResolution
void setResolution(uint32_t w, uint32_t h)
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:811
crl::multisense::image::Config::setFps
void setFps(float f)
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:852
crl::multisense::system::DeviceInfo::imagerHeight
uint32_t imagerHeight
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:3309
multisense::to_string
std::string to_string(const Status &status)
Convert a status object to a user readable string.
Definition: utilities.cc:137
main
int main(int argc, char **argvPP)
Definition: DepthImageUtility.cc:312
crl::multisense::image::Header
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:460
crl::multisense::Source_Luma_Rectified_Left
static CRL_CONSTEXPR DataSource Source_Luma_Rectified_Left
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:123
crl::multisense::Source_Luma_Rectified_Aux
static CRL_CONSTEXPR DataSource Source_Luma_Rectified_Aux
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:142


multisense_lib
Author(s):
autogenerated on Thu Apr 17 2025 02:49:08