40#include <visp3/core/vpConfig.h>
41#if defined(VISP_HAVE_REALSENSE2) && defined(VISP_HAVE_THREADS) \
42 && defined(VISP_HAVE_DISPLAY) && defined(VISP_HAVE_PUGIXML) \
43 && ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
45#include <condition_variable>
51#if defined(VISP_HAVE_PCL)
52#include <pcl/pcl_config.h>
53#if defined(VISP_HAVE_PCL_COMMON)
54#include <pcl/point_types.h>
55#include <pcl/point_cloud.h>
57#if defined(VISP_HAVE_PCL_IO)
58#include <pcl/io/pcd_io.h>
62#include <visp3/core/vpImageConvert.h>
63#include <visp3/core/vpIoException.h>
64#include <visp3/core/vpIoTools.h>
65#include <visp3/core/vpXmlParserCamera.h>
66#include <visp3/gui/vpDisplayFactory.h>
67#include <visp3/io/vpImageIo.h>
68#include <visp3/sensor/vpRealSense2.h>
70#ifdef ENABLE_VISP_NAMESPACE
76void usage(
const char *argv[],
int error,
int stream_width,
int stream_height,
int stream_fps)
78 std::cout <<
"\nNAME " << std::endl
80 <<
" - Record data (color, depth, infrared, point cloud) with a Realsense device." << std::endl;
82 std::cout <<
"\nDESCRIPTION " << std::endl
83 <<
" This app allows to record a dataset (color, depth, infrared, point cloud) acquired" << std::endl
84 <<
" with a Realsense device. Once acquired, the dataset can be visualized using visp-read-rs-dataset.cpp app."
87 std::cout <<
"\nSYNOPSIS " << std::endl
90 <<
" [--output-folder,-o <output folder>]"
91 <<
" [--pattern,-e <filename numbering pattern (e.g. %06d)>]"
92 <<
" [--step-by-step,-C]"
94 <<
" [--save-color,-c]"
95 <<
" [--save-depth,-d]"
96 <<
" [--save-infrared,-i]"
98 <<
" [--img-in-jpeg-fmt,-j]"
99 <<
" [--depth-in-bin-fmt,-depth-bin]"
100 <<
" [--pcl-in-bin-fmt,-pcl-bin]"
101#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
102 <<
" [--pcl-in-npz-fmt,-pcl-npz]"
104 <<
" [--stream-width,-sw <stream width>]"
105 <<
" [--stream-height,-sh <stream height>]"
106 <<
" [--stream-fps,-f <framerate>]"
107 <<
" [--display-colored-depth,-colored-depth]"
111 std::cout <<
"\nOPTIONS " << std::endl
112 <<
" --save, -s" << std::endl
113 <<
" Flag to enable data saving in output folder." << std::endl
114 <<
" When this flag is not used, we only display data." << std::endl
116 <<
" --output-folder,-o <custom output folder>" << std::endl
117 <<
" Custom output folder that will host saved data." << std::endl
118 <<
" By default, for each data acquisition, a new output folder is" << std::endl
119 <<
" created with the current date in the following format" << std::endl
120 <<
" YYYY_MM_DD_HH:MM:SS, for example 2025_11_07_15:44:34." << std::endl
122 <<
" --step-by-step,-C" << std::endl
123 <<
" Trigger one shot data saver after each user click." << std::endl
125 <<
" --pattern,-e <filename numbering pattern (e.g. %06d)>" << std::endl
126 <<
" Filename numbering pattern to use when saving data." << std::endl
128 <<
" --aligned,-a" << std::endl
129 <<
" Color and depth are aligned." << std::endl
131 <<
" --save-color,-c" << std::endl
132 <<
" Add color stream to saved data when --save option is used." << std::endl
133 <<
" By default, images are saved in png format. To save in jpeg format" << std::endl
134 <<
" use --img-in-jpeg-fmt flag." << std::endl
136 <<
" --save-depth,-d" << std::endl
137 <<
" Add depth stream to saved data when --save option is enabled." << std::endl
138 <<
" By default, depth images are saved in NumPy (.npz) format." << std::endl
139 <<
" To save in little-endian binary format use --depth-in-bin-fmt flag." << std::endl
141 <<
" --save-infrared" << std::endl
142 <<
" Add infrared stream to saved data when --save option is enabled." << std::endl
143 <<
" By default, images are saved in png format. To save in jpeg format" << std::endl
144 <<
" use --img-in-jpeg-fmt flag." << std::endl
146 <<
" --save-pcl,-p" << std::endl
147 <<
" Add point cloud stream to saved data when --save option is enabled." << std::endl
148#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_IO) && defined(VISP_HAVE_PCL_COMMON)
149 <<
" Since PCL library is available, by default the point cloud is saved in" << std::endl
150 <<
" Point Cloud Data file format (.pcd extension file)." << std::endl
152#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
153 <<
" There is also the possibility to save the point cloud in NumPy" << std::endl
154 <<
" format (.npy extension file) enabling --pcl-in-npz-fmt option" << std::endl
155 <<
" or in little-endian binary format enabling --pcl-in-bin-fmt option." << std::endl
157 <<
" Point clould could be saved in little-endian binary format enabling" << std::endl
158 <<
" --pcl-in-bin-fmt option." << std::endl
161 <<
" --img-in-jpeg-fmt,-j" << std::endl
162 <<
" Save image data using jpeg format (otherwise PNG is used)." << std::endl
164 <<
" --depth-in-bin-fmt,-depth-bin" << std::endl
165 <<
" When this flag is enabled, depth is saved in little-endian binary format." << std::endl
166 <<
" By default, depth is saved in NumPy (.npz) format." << std::endl
168 <<
" --pcl-in-bin-fmt,-pcl-bin" << std::endl
169 <<
" When this flag is enabled, point cloud is saved in little-endian binary format." << std::endl
170#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
171 <<
" There is also the possibility to save the point cloud in NumPy (npz) format" << std::endl
172 <<
" using --pcl-in-npz-fmt flag." << std::endl
174#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_IO) && defined(VISP_HAVE_PCL_COMMON)
175 <<
" By default, point cloud is saved in pcd format using PCL 3rd-party library." << std::endl
178#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
179 <<
" --pcl-in-npz-fmt,-pcl-npz" << std::endl
180 <<
" When this flag is enabled, point cloud is saved in NumPy (npz) format." << std::endl
181 <<
" There is also the possibility to save the point cloud in little-endian binary format" << std::endl
182 <<
" using --pcl-in-bin-fmt flag." << std::endl
184#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_IO) && defined(VISP_HAVE_PCL_COMMON)
185 <<
" By default, point cloud is saved in pcd format using PCL 3rd-party library." << std::endl
188 <<
" --stream-width,-sw <stream width>" << std::endl
189 <<
" Set camera image width resolution." << std::endl
190 <<
" Default: " << stream_width << std::endl
192 <<
" --stream-height,-sh <stream height>" << std::endl
193 <<
" Set camera image height resolution." << std::endl
194 <<
" Default: " << stream_height << std::endl
196 <<
" --stream-fps,-f <fps>" << std::endl
197 <<
" Set camera framerate in Hz." << std::endl
198 <<
" Default: " << stream_fps << std::endl
200 <<
" --display-colored-depth,-colored-depth" << std::endl
201 <<
" Display depth using a cumulative histogram." << std::endl
202 <<
" Warning: this operation is time consuming" << std::endl
204 <<
" --help,-h" << std::endl
205 <<
" Display this helper message." << std::endl
207 std::cout <<
"EXAMPLE " << std::endl
208 <<
"- Save aligned color + depth + point cloud in data folder" << std::endl
209 <<
" " << argv[0] <<
" --save --save-color --save-depth --save-pcl --display-colored-depth --output-folder data --aligned" << std::endl
210 <<
"- Save color + infrared + depth + point cloud in bin format in data folder" << std::endl
211 <<
" " << argv[0] <<
" --save --save-color --save-depth --save-infrared --save-pcl --display-colored-depth --depth-in-bin-fmt --pcl-in-bin-fmt --output-folder data" << std::endl
215 std::cout <<
"Error" << std::endl
217 <<
"Unsupported parameter " << argv[
error] << std::endl;
221bool getOptions(
int argc,
const char *argv[],
bool &save, std::string &numbering_pattern, std::string &output_folder,
222 bool &use_aligned_stream,
bool &save_color,
bool &save_depth,
bool &save_pcl,
223 bool &save_infrared,
bool &step_by_step,
int &stream_width,
int &stream_height,
int &stream_fps,
224 bool &depth_bin_fmt,
bool &pcl_bin_fmt,
bool &pcl_npz_fmt,
bool &img_jpeg_fmt,
225 bool &display_colored_depth)
227 for (
int i = 1;
i < argc;
i++) {
228 if ((std::string(argv[i]) ==
"--save") || (std::string(argv[i]) ==
"-s")) {
231 else if (((std::string(argv[i]) ==
"--pattern") || (std::string(argv[i]) ==
"-e")) && (i + 1 < argc)) {
232 numbering_pattern = std::string(argv[++i]);
234 else if ((std::string(argv[i]) ==
"--aligned") || (std::string(argv[i]) ==
"-a")) {
235 use_aligned_stream =
true;
237 else if (((std::string(argv[i]) ==
"--output-folder") || (std::string(argv[i]) ==
"-o")) && (i + 1 < argc)) {
238 output_folder = std::string(argv[++i]);
240 else if ((std::string(argv[i]) ==
"--save-color") || (std::string(argv[i]) ==
"-c")) {
243 else if ((std::string(argv[i]) ==
"--save-depth") || (std::string(argv[i]) ==
"-d")) {
246 else if ((std::string(argv[i]) ==
"--save-infrared") || (std::string(argv[i]) ==
"-i")) {
247 save_infrared =
true;
249 else if ((std::string(argv[i]) ==
"--save-pcl") || (std::string(argv[i]) ==
"-p")) {
252 else if ((std::string(argv[i]) ==
"--img-in-jpeg-fmt") || (std::string(argv[i]) ==
"-j")) {
255 else if ((std::string(argv[i]) ==
"--depth-in-bin-fmt") || (std::string(argv[i]) ==
"-depth-bin")) {
256 depth_bin_fmt =
true;
258 else if ((std::string(argv[i]) ==
"--pcl-in-bin-fmt") || (std::string(argv[i]) ==
"-pcl-bin")) {
261#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
262 else if ((std::string(argv[i]) ==
"--pcl-in-npz-fmt") || (std::string(argv[i]) ==
"-pcl-npz")) {
266 else if ((std::string(argv[i]) ==
"--step-by-step") || (std::string(argv[i]) ==
"-C")) {
269 else if (((std::string(argv[i]) ==
"--stream-width") || (std::string(argv[i]) ==
"-sw")) && (i + 1 < argc)) {
270 stream_width = std::atoi(argv[++i]);
272 else if (((std::string(argv[i]) ==
"--stream-height") || (std::string(argv[i]) ==
"-sh")) && (i + 1 < argc)) {
273 stream_height = std::atoi(argv[++i]);
275 else if (((std::string(argv[i]) ==
"--stream-fps") || (std::string(argv[i]) ==
"-f")) && (i + 1 < argc)) {
276 stream_fps = std::atoi(argv[++i]);
278 else if ((std::string(argv[i]) ==
"--display-colored-depth") || (std::string(argv[i]) ==
"--colored-depth")) {
279 display_colored_depth =
true;
281 else if (std::string(argv[i]) ==
"--help" || std::string(argv[i]) ==
"-h") {
282 usage(argv, 0, stream_width, stream_height, stream_fps);
286 usage(argv, i, stream_width, stream_height, stream_fps);
292#if !(defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_IO) && defined(VISP_HAVE_PCL_COMMON))
293#if !(defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX))
302 if (pcl_npz_fmt && pcl_bin_fmt) {
303 std::cout <<
"\nError: Cannot save point clound in NumPy (npz) and in little-endian binary format (bin) simultaneously." << std::endl;
304 std::cout <<
"Command line options --pcl-in-bin-fmt and --pcl-in-npz-fmt are exclusive." << std::endl;
305 std::cout <<
"Use only one of these two options." << std::endl;
310#if !(defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX))
311 depth_bin_format =
true;
314#if !(defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX))
321#ifndef DOXYGEN_SHOULD_SKIP_THIS
331 : m_cancelled(false), m_cond(), m_queueColor(), m_queueDepth(), m_queuePointCloud(), m_queueInfrared(),
332 m_maxQueueSize(1024 * 8), m_mutex()
337 std::lock_guard<std::mutex> lock(m_mutex);
343 void push(
const std::unique_ptr<vpImage<vpRGBa>> &ptr_colorImg,
344 const std::unique_ptr<vpImage<uint16_t>> &ptr_depthImg,
345#
if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
346 const pcl::PointCloud<pcl::PointXYZ>::Ptr &pointCloud,
348 const std::unique_ptr<std::vector<vpColVector>> &ptr_pointCloud,
350 const std::unique_ptr<vpImage<unsigned char>> &ptr_infraredImg)
352 std::lock_guard<std::mutex> lock(m_mutex);
355 m_queueColor.push(*ptr_colorImg);
358 m_queueDepth.push(*ptr_depthImg);
360#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
362 m_queuePointCloud.push(pointCloud);
365 if (ptr_pointCloud) {
366 m_queuePointCloud.push(*ptr_pointCloud);
369 if (ptr_infraredImg) {
370 m_queueInfrared.push(*ptr_infraredImg);
374 while (m_queueColor.size() > m_maxQueueSize) {
379 while (m_queueDepth.size() > m_maxQueueSize) {
384 while (m_queuePointCloud.size() > m_maxQueueSize) {
385 m_queuePointCloud.pop();
389 while (m_queueInfrared.size() > m_maxQueueSize) {
390 m_queueInfrared.pop();
397 void pop(std::unique_ptr<vpImage<vpRGBa>> &ptr_colorImg,
398 std::unique_ptr<vpImage<uint16_t>> &ptr_depthImg,
399#
if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
400 pcl::PointCloud<pcl::PointXYZ>::Ptr &pointCloud,
402 std::unique_ptr<std::vector<vpColVector>> &ptr_pointCloud,
404 std::unique_ptr<vpImage<unsigned char>> &ptr_infraredImg)
406 std::unique_lock<std::mutex> lock(m_mutex);
409 while (m_queueColor.empty() && m_queueDepth.empty() && m_queuePointCloud.empty() && m_queueInfrared.empty()) {
411 throw vpCancelled_t();
417 throw vpCancelled_t();
421 if (!m_queueColor.empty()) {
422 ptr_colorImg = std::make_unique<vpImage<vpRGBa>>(m_queueColor.front());
425 if (!m_queueDepth.empty()) {
426 ptr_depthImg = std::make_unique<vpImage<uint16_t>>(m_queueDepth.front());
429#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
430 if (!m_queuePointCloud.empty()) {
431 pointCloud = m_queuePointCloud.front();
432 m_queuePointCloud.pop();
435 if (!m_queuePointCloud.empty()) {
436 ptr_pointCloud = std::make_unique<std::vector<vpColVector>>(m_queuePointCloud.front());
437 m_queuePointCloud.pop();
440 if (!m_queueInfrared.empty()) {
441 ptr_infraredImg = std::make_unique<vpImage<unsigned char>>(m_queueInfrared.front());
442 m_queueInfrared.pop();
448 std::lock_guard<std::mutex> lock(m_mutex);
449 return m_queueColor.empty() && m_queueDepth.empty() && m_queuePointCloud.empty() && m_queueInfrared.empty();
452 void setMaxQueueSize(
const size_t max_queue_size) { m_maxQueueSize = max_queue_size; }
456 std::condition_variable m_cond;
457 std::queue<vpImage<vpRGBa>> m_queueColor;
458 std::queue<vpImage<uint16_t>> m_queueDepth;
459#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
460 std::queue<pcl::PointCloud<pcl::PointXYZ>::Ptr> m_queuePointCloud;
462 std::queue<std::vector<vpColVector>> m_queuePointCloud;
464 std::queue<vpImage<unsigned char>> m_queueInfrared;
465 size_t m_maxQueueSize;
472 vpStorageWorker(vpFrameQueue &queue,
const std::string &output_pattern,
const std::string &directory,
bool save_color,
473 bool save_depth,
bool save_pcl,
bool save_infrared,
bool depth_bin_fmt,
474 bool pcl_bin_fmt,
bool pcl_npz_fmt,
bool img_jpeg_fmt,
485 : m_queue(queue), m_output_pattern(output_pattern), m_directory(directory), m_cpt(0), m_save_color(save_color), m_save_depth(save_depth),
486 m_save_pcl(save_pcl), m_save_infrared(save_infrared), m_depth_bin_fmt(depth_bin_fmt),
487 m_pcl_bin_fmt(pcl_bin_fmt), m_pcl_npz_fmt(pcl_npz_fmt),
488 m_img_jpeg_fmt(img_jpeg_fmt)
499 std::unique_ptr<vpImage<vpRGBa>> ptr_colorImg;
500 std::unique_ptr<vpImage<uint16_t>> ptr_depthImg;
501#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
502 pcl::PointCloud<pcl::PointXYZ>::Ptr ptr_pointCloud;
504 std::unique_ptr<std::vector<vpColVector>> ptr_pointCloud;
506 std::unique_ptr<vpImage<unsigned char>> ptr_infraredImg;
508 std::vector<float> vec_pcl;
510 std::string image_filename_ext = m_img_jpeg_fmt ?
".jpg" :
".png";
512 m_queue.pop(ptr_colorImg, ptr_depthImg, ptr_pointCloud, ptr_infraredImg);
514 if (!m_directory.empty()) {
517 if (m_save_color && ptr_colorImg) {
518 std::string filename_color =
vpIoTools::formatString(m_directory +
"/color_image_" + m_output_pattern + image_filename_ext, m_cpt);
522 if (m_save_depth && ptr_depthImg) {
523 if (m_depth_bin_fmt) {
525 std::string filename_depth =
vpIoTools::formatString(m_directory +
"/depth_image_" + m_output_pattern +
".bin", m_cpt);
527 std::ofstream file_depth(filename_depth.c_str(), std::ios::out | std::ios::binary);
528 if (file_depth.is_open()) {
529 unsigned int height = ptr_depthImg->getHeight(),
width = ptr_depthImg->getWidth();
534 for (
unsigned int i = 0;
i <
height;
i++) {
535 for (
unsigned int j = 0;
j <
width;
j++) {
536 value = (*ptr_depthImg)[
i][
j];
542#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
544 std::string filename_depth =
vpIoTools::formatString(m_directory +
"/depth_image_" + m_output_pattern +
".npz", m_cpt);
547 std::vector<char> vec_filename(filename_depth.begin(), filename_depth.end());
552 visp::cnpy::npz_save(filename_depth,
"filename", &vec_filename[0], { vec_filename.size() },
"w");
554 std::vector<char> vec_current_time(current_time.begin(), current_time.end());
555 visp::cnpy::npz_save(filename_depth,
"timestamp", &vec_current_time, { vec_current_time.size() },
"a");
557 unsigned int height = ptr_depthImg->getHeight();
558 unsigned int width = ptr_depthImg->getWidth();
559 unsigned int channel = 1;
565 std::vector<uint16_t> I_depth_raw_vec(ptr_depthImg->bitmap, ptr_depthImg->bitmap + ptr_depthImg->getSize());
570 throw(vpIoException(
vpIoException::ioError,
"Cannot manage non-binary files when npz I/O functions are disabled."));
575 if (m_save_pcl && ptr_pointCloud) {
577#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
578 uint32_t
width = ptr_pointCloud->width;
579 uint32_t
height = ptr_pointCloud->height;
581 uint32_t
width = m_size_width;
582 uint32_t
height = m_size_height;
586#if defined(VISP_HAVE_MINIZ) && defined(VISP_HAVE_WORKING_REGEX)
587 std::string filename_pcl =
vpIoTools::formatString(m_directory +
"/point_cloud_" + m_output_pattern +
".npz", m_cpt);
590 std::vector<char> vec_filename(filename_pcl.begin(), filename_pcl.end());
597 std::vector<char> vec_current_time(current_time.begin(), current_time.end());
598 visp::cnpy::npz_save(filename_pcl,
"timestamp", &vec_current_time, { vec_current_time.size() },
"a");
600 const uint32_t channels = 3;
605 vec_pcl.resize(height * width * channels);
606#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
609 for (uint32_t i = 0;
i <
height;
i++) {
610 for (uint32_t j = 0;
j <
width;
j++) {
611 pcl::PointXYZ pt = (*ptr_pointCloud)(
j,
i);
612 vec_pcl[channels * (
i*
width +
j) + 0] = pt.x;
613 vec_pcl[channels * (
i*
width +
j) + 1] = pt.y;
614 vec_pcl[channels * (
i*
width +
j) + 2] = pt.z;
618 for (uint32_t i = 0;
i <
height;
i++) {
619 for (uint32_t j = 0;
j <
width;
j++) {
620 vec_pcl[channels * (
i*
width +
j) + 0] =
static_cast<float>((*ptr_pointCloud)[i*width + j][0]);
621 vec_pcl[channels * (
i*
width +
j) + 1] =
static_cast<float>((*ptr_pointCloud)[i*width + j][1]);
622 vec_pcl[channels * (
i*
width +
j) + 2] =
static_cast<float>((*ptr_pointCloud)[i*width + j][2]);
632 else if (m_pcl_bin_fmt) {
633 std::string filename_pcl =
vpIoTools::formatString(m_directory +
"/point_cloud_" + m_output_pattern +
".bin", m_cpt);
635 std::ofstream file_pointcloud(filename_pcl.c_str(), std::ios::out | std::ios::binary);
637 if (file_pointcloud.is_open()) {
638#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
640 char is_dense = ptr_pointCloud->is_dense;
644 file_pointcloud.write((
char *)(&is_dense),
sizeof(is_dense));
646 for (uint32_t i = 0;
i <
height;
i++) {
647 for (uint32_t j = 0;
j <
width;
j++) {
648 pcl::PointXYZ pt = (*ptr_pointCloud)(
j,
i);
657 const char is_dense = 1;
661 file_pointcloud.write((
char *)(&is_dense),
sizeof(is_dense));
663 for (uint32_t i = 0;
i <
height;
i++) {
664 for (uint32_t j = 0;
j <
width;
j++) {
665 float x =
static_cast<float>((*ptr_pointCloud)[
i *
width +
j][0]);
666 float y =
static_cast<float>((*ptr_pointCloud)[
i *
width +
j][1]);
667 float z =
static_cast<float>((*ptr_pointCloud)[
i *
width +
j][2]);
678#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_IO) && defined(VISP_HAVE_PCL_COMMON)
679 std::string filename_pcl =
vpIoTools::formatString(m_directory +
"/point_cloud_" + m_output_pattern +
".pcd", m_cpt);
680 pcl::io::savePCDFileBinary(filename_pcl, *ptr_pointCloud);
682 std::cout <<
"Error: unable to save point cloud in pcd format. PCL io module not available." << std::endl;
687 if (m_save_infrared && ptr_infraredImg) {
688 std::string filename_infrared =
vpIoTools::formatString(m_directory +
"/infrared_image_" + m_output_pattern + image_filename_ext, m_cpt);
697 catch (
const vpFrameQueue::vpCancelled_t &) {
698 std::cout <<
"Receive cancel vpFrameQueue." << std::endl;
703 vpFrameQueue &m_queue;
704 std::string m_output_pattern;
705 std::string m_directory;
710 bool m_save_infrared;
711 bool m_depth_bin_fmt;
724int main(
int argc,
const char *argv[])
727 std::string output_pattern =
"%04d";
729 std::string output_folder_custom =
"";
730 bool use_aligned_stream =
false;
731 bool save_color =
false;
732 bool save_depth =
false;
733 bool save_pcl =
false;
734 bool save_infrared =
false;
735 bool step_by_step =
false;
736 int stream_width = 640;
737 int stream_height = 480;
739 bool depth_bin_fmt =
false;
740 bool pcl_bin_fmt =
false;
741 bool pcl_npz_fmt =
false;
742 bool img_jpeg_fmt =
false;
743 bool display_colored_depth =
false;
746 if (!getOptions(argc, argv, save, output_pattern, output_folder_custom, use_aligned_stream, save_color, save_depth,
747 save_pcl, save_infrared, step_by_step, stream_width, stream_height, stream_fps,
748 depth_bin_fmt, pcl_bin_fmt, pcl_npz_fmt, img_jpeg_fmt, display_colored_depth)) {
752 if (!output_folder_custom.empty()) {
753 output_folder = output_folder_custom +
"/" + output_folder;
757 std::cout <<
"Options summary" << std::endl;
758 std::cout <<
" Realsense device " << std::endl;
759 std::cout <<
" Stream width : " << stream_width << std::endl;
760 std::cout <<
" Stream height : " << stream_height << std::endl;
761 std::cout <<
" Stream framerate : " << stream_fps << std::endl;
762 std::cout <<
" Considered data " << std::endl;
763 std::cout <<
" Color stream : " << (save_color ?
"yes" :
"no") << std::endl;
764 std::cout <<
" Depth stream : " << (save_depth ?
"yes" :
"no") << std::endl;
765 std::cout <<
" Infrared stream : " << (save_infrared ?
"yes" :
"no") << std::endl;
766 std::cout <<
" Point cloud : " << (save_pcl ?
"yes" :
"no") << std::endl;
767 std::cout <<
" Color and depth aligned: " << (use_aligned_stream ?
"yes" :
"no") << std::endl;
768 std::cout <<
" Data visualization " << std::endl;
769 std::cout <<
" Colored depth : " << (display_colored_depth ?
"yes" :
"no") << std::endl;
770 std::cout <<
" Save dataset " << (save ?
"yes" :
"no") << std::endl;
772 std::cout <<
" Output folder : " << output_folder << std::endl;
773 std::cout <<
" File numbering pattern : " << output_pattern << std::endl;
774 std::cout <<
" Color images format : " << (save_color ? (img_jpeg_fmt ?
"jpeg" :
"png") :
"N/A") << std::endl;
775 std::cout <<
" Depth images format : " << (save_depth ? (depth_bin_fmt ?
"bin" :
"npz") :
"N/A") << std::endl;
776 std::cout <<
" Infrared images format : " << (save_infrared ? (img_jpeg_fmt ?
"jpeg" :
"png") :
"N/A") << std::endl;
777 std::cout <<
" Point cloud format : " << (save_pcl ? (pcl_npz_fmt ?
"npz" : (pcl_bin_fmt ?
"bin" :
"pcd")) :
"N/A") << std::endl;
778 std::cout <<
" Save after each click : " << (step_by_step ?
"yes" :
"no") << std::endl << std::endl;
784 config.enable_stream(RS2_STREAM_COLOR, stream_width, stream_height, RS2_FORMAT_RGBA8, stream_fps);
785 config.enable_stream(RS2_STREAM_DEPTH, stream_width, stream_height, RS2_FORMAT_Z16, stream_fps);
786 config.enable_stream(RS2_STREAM_INFRARED, stream_width, stream_height, RS2_FORMAT_Y8, stream_fps);
787 realsense.
open(config);
795#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
804 d1->init(I_color, 0, 0,
"RealSense color stream");
805 if (display_colored_depth) {
806 d2->init(I_depth_color, I_color.getWidth() + 80, 0,
"RealSense depth stream");
809 d2->init(I_depth_gray, I_color.getWidth() + 80, 0,
"RealSense depth stream");
812 rs2::align align_to(RS2_STREAM_COLOR);
813 if (use_aligned_stream && save_infrared) {
814 std::cerr <<
"Cannot use aligned streams with infrared acquisition currently."
815 <<
"\nInfrared stream acquisition is disabled!"
817 save_infrared =
false;
820 d3->init(I_infrared, I_color.getWidth() + 80, I_color.getHeight() + 70,
"RealSense infrared stream");
824#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
825 pcl::PointCloud<pcl::PointXYZ>::Ptr pointCloud(
new pcl::PointCloud<pcl::PointXYZ>);
827 std::vector<vpColVector> pointCloud;
833 if (use_aligned_stream) {
834#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
835 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap,
nullptr, pointCloud,
nullptr,
838 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap, &pointCloud,
nullptr,
843#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
844 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap,
nullptr, pointCloud,
845 (
unsigned char *)I_infrared.bitmap,
nullptr);
847 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap, &pointCloud,
848 (
unsigned char *)I_infrared.bitmap);
854 if (display_colored_depth) {
867 std::ostringstream oss_time;
868 oss_time << delta_time <<
" ms ; fps=" << 1000/delta_time;
878 if (display_colored_depth) {
900 xml_camera.
save(cam_color, output_folder +
"/camera.xml",
"color_camera", stream_width, stream_height);
902 if (use_aligned_stream) {
903 xml_camera.
save(cam_color, output_folder +
"/camera.xml",
"depth_camera", stream_width, stream_height);
907 xml_camera.
save(cam_depth, output_folder +
"/camera.xml",
"depth_camera", stream_width, stream_height);
911 xml_camera.
save(cam_infrared, output_folder +
"/camera.xml",
"infrared_camera", stream_width, stream_height);
914 if (!use_aligned_stream) {
917 std::ofstream file(std::string(output_folder +
"/depth_M_color.txt"));
923 infrared_M_color = realsense.
getTransformation(RS2_STREAM_COLOR, RS2_STREAM_INFRARED);
924 std::ofstream file(std::string(output_folder +
"/infrared_M_color.txt"));
925 infrared_M_color.
save(file);
929 vpFrameQueue save_queue;
930 vpStorageWorker storage(std::ref(save_queue), output_pattern, std::cref(output_folder), save_color, save_depth,
931 save_pcl, save_infrared, depth_bin_fmt, pcl_bin_fmt, pcl_npz_fmt, img_jpeg_fmt, stream_width, stream_height);
932 std::thread storage_thread(&vpStorageWorker::run, &storage);
937 std::unique_ptr<vpImage<vpRGBa>> ptr_colorImg;
938 std::unique_ptr<vpImage<uint16_t>> ptr_depthImg;
939 std::unique_ptr<std::vector<vpColVector>> ptr_pointCloud;
940 std::unique_ptr<vpImage<unsigned char>> ptr_infraredImg;
942 std::vector<double> vec_delta_time;
945 if (use_aligned_stream) {
946#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
947 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap,
nullptr, pointCloud,
nullptr,
950 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap, &pointCloud,
nullptr,
955#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
956 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap,
nullptr, pointCloud,
957 (
unsigned char *)I_infrared.bitmap,
nullptr);
959 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap, &pointCloud,
960 (
unsigned char *)I_infrared.bitmap);
964 if (display_colored_depth) {
970 for (
unsigned int i = 0;
i < I_depth_raw.getRows();
i++) {
971 for (
unsigned int j = 0;
j < I_depth_raw.getCols();
j++) {
972 I_depth_gray[
i][
j] = I_depth_raw[
i][
j] >> 8;
978 if (display_colored_depth) {
990 std::stringstream ss;
991 ss <<
"Images saved: " << nb_saves;
995 if (save && !step_by_step) {
997 ptr_colorImg = std::make_unique<vpImage<vpRGBa>>(I_color);
1000 ptr_depthImg = std::make_unique<vpImage<uint16_t>>(I_depth_raw);
1002 if (save_infrared) {
1003 ptr_infraredImg = std::make_unique<vpImage<unsigned char>>(I_infrared);
1006#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
1007 pcl::PointCloud<pcl::PointXYZ>::Ptr pointCloud_copy;
1009 pointCloud_copy = pointCloud->makeShared();
1011 save_queue.push(ptr_colorImg, ptr_depthImg, pointCloud_copy, ptr_infraredImg);
1014 ptr_pointCloud = std::make_unique<std::vector<vpColVector>>(pointCloud);
1016 save_queue.push(ptr_colorImg, ptr_depthImg, ptr_pointCloud, ptr_infraredImg);
1021 vec_delta_time.push_back(delta_time);
1022 std::ostringstream oss_time;
1023 oss_time << delta_time <<
" ms ; fps=" << 1000/delta_time;
1027 if (display_colored_depth) {
1037 if (!step_by_step) {
1040 save_queue.cancel();
1049 ptr_colorImg = std::make_unique<vpImage<vpRGBa>>(I_color);
1052 ptr_depthImg = std::make_unique<vpImage<uint16_t>>(I_depth_raw);
1054 if (save_infrared) {
1055 ptr_infraredImg = std::make_unique<vpImage<unsigned char>>(I_infrared);
1058#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_COMMON)
1059 pcl::PointCloud<pcl::PointXYZ>::Ptr pointCloud_copy;
1061 pointCloud_copy = pointCloud->makeShared();
1063 save_queue.push(ptr_colorImg, ptr_depthImg, pointCloud_copy, ptr_infraredImg);
1066 ptr_pointCloud = std::make_unique<std::vector<vpColVector>>(pointCloud);
1068 save_queue.push(ptr_colorImg, ptr_depthImg, ptr_pointCloud, ptr_infraredImg);
1078 save_queue.cancel();
1085 std::cout <<
"\nSaving dataset in " << output_folder <<
" folder in progress...\n" << std::endl;
1089 std::cout <<
"Acquisition time, mean=" << mean_vec_delta_time <<
" ms ; median="
1090 << median_vec_delta_time <<
" ms ; std=" << std_vec_delta_time <<
" ms" << std::endl;
1091 std::cout <<
"FPS, mean=" << 1000/mean_vec_delta_time <<
" fps ; median="
1092 << 1000/median_vec_delta_time <<
" fps" << std::endl;
1094 storage_thread.join();
1096 std::cout <<
"\nDataset was successfully saved in " << output_folder <<
" folder\n" << std::endl;
1099#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
1100 if (d1 !=
nullptr) {
1103 if (d2 !=
nullptr) {
1106 if (d3 !=
nullptr) {
1111 return EXIT_SUCCESS;
1116 std::cerr <<
"Need libRealSense or libRealSense2 and C++11 and displayX or displayGDI!" << std::endl;
1118#if !defined(VISP_HAVE_PUGIXML)
1119 std::cout <<
"pugixml built-in 3rdparty is requested." << std::endl;
1120#elif !((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
1121 std::cout <<
"At least c++14 standard is requested." << std::endl;
1123 return EXIT_SUCCESS;
Generic class defining intrinsic camera parameters.
Class that defines generic functionalities for display.
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Implementation of an homogeneous matrix and operations on such kind of matrices.
void save(std::ofstream &f) const
static void createDepthHistogram(const vpImage< uint16_t > &src_depth, vpImage< vpRGBa > &dest_rgba)
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
static double getMedian(const std::vector< double > &v)
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
static double getMean(const std::vector< double > &v)
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())
vpHomogeneousMatrix getTransformation(const rs2_stream &from, const rs2_stream &to, int from_index=-1) const
XML parser to load and save intrinsic camera parameters.
int save(const vpCameraParameters &cam, const std::string &filename, const std::string &camera_name, unsigned int image_width=0, unsigned int image_height=0, const std::string &additionalInfo="", bool verbose=true)
VISP_EXPORT void npz_save(const std::string &zipname, std::string fname, const std::vector< std::string > &data_vec, const std::vector< size_t > &shape, const std::string &mode="w")
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT double measureTimeMs()
VISP_EXPORT std::string getDateTime(const std::string &format="%Y/%m/%d %H:%M:%S")