Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
tutorial-hsv-segmentation.cpp
1 
3 #include <iostream>
4 #include <visp3/core/vpConfig.h>
5 
6 #include <visp3/core/vpCameraParameters.h>
7 #include <visp3/core/vpImageConvert.h>
8 #include <visp3/core/vpImageTools.h>
9 #include <visp3/core/vpPixelMeterConversion.h>
10 #include <visp3/core/vpColorDepthConversion.h>
11 #include <visp3/gui/vpDisplayX.h>
12 #include <visp3/io/vpVideoReader.h>
13 #include <visp3/sensor/vpRealSense2.h>
14 
15 int main(int argc, const char *argv[])
16 {
17 #if defined(VISP_HAVE_X11)
18 #ifdef ENABLE_VISP_NAMESPACE
19  using namespace VISP_NAMESPACE_NAME;
20 #endif
21 
22  std::string opt_hsv_filename = "calib/hsv-thresholds.yml";
23  std::string opt_video_filename;
24  bool show_helper = false;
25 
26  for (int i = 1; i < argc; i++) {
27  if ((std::string(argv[i]) == "--hsv-thresholds") && ((i+1) < argc)) {
28  opt_hsv_filename = std::string(argv[++i]);
29  }
30  else if (std::string(argv[i]) == "--video") {
31  if ((i+1) < argc) {
32  opt_video_filename = std::string(argv[++i]);
33  }
34  else {
35  show_helper = true;
36  std::cout << "ERROR \nMissing input video name after parameter " << std::string(argv[i]) << std::endl;
37  }
38  }
39  else if (show_helper || std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
40  std::cout << "\nSYNOPSIS " << std::endl
41  << argv[0]
42  << " [--video <input video>]"
43  << " [--hsv-thresholds <filename.yml>]"
44  << " [--help,-h]"
45  << std::endl;
46  std::cout << "\nOPTIONS " << std::endl
47  << " --video <input video>" << std::endl
48  << " Name of the input video filename." << std::endl
49  << " When this option is not set, we use librealsense to stream images from a Realsense camera. " << std::endl
50  << " Example: --video image-%04d.jpg" << std::endl
51  << std::endl
52  << " --hsv-thresholds <filename.yaml>" << std::endl
53  << " Path to a yaml filename that contains H <min,max>, S <min,max>, V <min,max> threshold values." << std::endl
54  << " An Example of such a file could be:" << std::endl
55  << " rows: 6" << std::endl
56  << " cols: 1" << std::endl
57  << " data:" << std::endl
58  << " - [0]" << std::endl
59  << " - [42]" << std::endl
60  << " - [177]" << std::endl
61  << " - [237]" << std::endl
62  << " - [148]" << std::endl
63  << " - [208]" << std::endl
64  << std::endl
65  << " --help, -h" << std::endl
66  << " Display this helper message." << std::endl
67  << std::endl;
68  return EXIT_SUCCESS;
69  }
70  }
71 
72  bool use_realsense = false;
73 #if defined(VISP_HAVE_REALSENSE2)
74  use_realsense = true;
75 #endif
76  if (use_realsense) {
77  if (!opt_video_filename.empty()) {
78  use_realsense = false;
79  }
80  }
81  else if (opt_video_filename.empty()) {
82  std::cout << "Error: you should use --image <input image> option to specify an input image..." << std::endl;
83  return EXIT_FAILURE;
84  }
85 
86  vpColVector hsv_values;
87  if (vpColVector::loadYAML(opt_hsv_filename, hsv_values)) {
88  std::cout << "Load HSV threshold values from " << opt_hsv_filename << std::endl;
89  std::cout << "HSV low/high values: " << hsv_values.t() << std::endl;
90  }
91  else {
92  std::cout << "Warning: unable to load HSV thresholds values from " << opt_hsv_filename << std::endl;
93  return EXIT_FAILURE;
94  }
95 
97  int width = 848;
98  int height = 480;
99 
100  vpVideoReader g;
101 #if defined(VISP_HAVE_REALSENSE2)
102  vpRealSense2 rs;
103 #endif
104 
105  if (use_realsense) {
106 #if defined(VISP_HAVE_REALSENSE2)
107  int fps = 60;
108  rs2::config config;
109  config.enable_stream(RS2_STREAM_COLOR, width, height, RS2_FORMAT_RGBA8, fps);
110  config.disable_stream(RS2_STREAM_DEPTH);
111  config.disable_stream(RS2_STREAM_INFRARED, 1);
112  config.disable_stream(RS2_STREAM_INFRARED, 2);
113  rs.open(config);
114  rs.acquire(I);
115 #endif
116  }
117  else {
118  try {
119  g.setFileName(opt_video_filename);
120  g.open(I);
121  }
122  catch (const vpException &e) {
123  std::cout << e.getStringMessage() << std::endl;
124  return EXIT_FAILURE;
125  }
126  width = I.getWidth();
127  height = I.getHeight();
128  }
129 
130  vpImage<unsigned char> H(height, width);
131  vpImage<unsigned char> S(height, width);
132  vpImage<unsigned char> V(height, width);
133  vpImage<unsigned char> mask(height, width);
134  vpImage<vpRGBa> I_segmented(height, width);
135 
136  vpDisplayX d_I(I, 0, 0, "Current frame");
137  vpDisplayX d_I_segmented(I_segmented, I.getWidth()+75, 0, "HSV segmented frame");
138 
139  bool quit = false;
140  double loop_time = 0., total_loop_time = 0.;
141  long nb_iter = 0;
142 
143  while (!quit) {
144  double t = vpTime::measureTimeMs();
145  if (use_realsense) {
146 #if defined(VISP_HAVE_REALSENSE2)
147  rs.acquire(I);
148 #endif
149  }
150  else {
151  if (!g.end()) {
152  g.acquire(I);
153  }
154  }
155  vpImageConvert::RGBaToHSV(reinterpret_cast<unsigned char *>(I.bitmap),
156  reinterpret_cast<unsigned char *>(H.bitmap),
157  reinterpret_cast<unsigned char *>(S.bitmap),
158  reinterpret_cast<unsigned char *>(V.bitmap), I.getSize());
159 
160  vpImageTools::inRange(reinterpret_cast<unsigned char *>(H.bitmap),
161  reinterpret_cast<unsigned char *>(S.bitmap),
162  reinterpret_cast<unsigned char *>(V.bitmap),
163  hsv_values,
164  reinterpret_cast<unsigned char *>(mask.bitmap),
165  mask.getSize());
166 
167  vpImageTools::inMask(I, mask, I_segmented);
168 
170  vpDisplay::display(I_segmented);
171  vpDisplay::displayText(I, 20, 20, "Click to quit...", vpColor::red);
172 
173  if (vpDisplay::getClick(I, false)) {
174  quit = true;
175  }
176 
177  vpDisplay::flush(I);
178  vpDisplay::flush(I_segmented);
179  nb_iter++;
180  loop_time = vpTime::measureTimeMs() - t;
181  total_loop_time += loop_time;
182 }
183 
184  std::cout << "Mean loop time: " << total_loop_time / nb_iter << std::endl;
185 #else
186  (void)argc;
187  (void)argv;
188  std::cout << "This tutorial needs X11 3rdparty that is not enabled" << std::endl;
189 #endif
190  return EXIT_SUCCESS;
191 }
static bool loadYAML(const std::string &filename, vpArray2D< double > &A, char *header=nullptr)
Definition: vpArray2D.h:783
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
vpRowVector t() const
static const vpColor red
Definition: vpColor.h:217
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)
error that can be emitted by ViSP classes.
Definition: vpException.h:60
const std::string & getStringMessage() const
Definition: vpException.cpp:67
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
static int inMask(const vpImage< unsigned char > &I, const vpImage< unsigned char > &mask, vpImage< unsigned char > &I_mask)
static int inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value, const vpColVector &hsv_range, unsigned char *mask, unsigned int size)
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getSize() const
Definition: vpImage.h:221
Type * bitmap
points toward the bitmap
Definition: vpImage.h:135
unsigned int getHeight() const
Definition: vpImage.h:181
void acquire(vpImage< unsigned char > &grey, double *ts=nullptr)
bool open(const rs2::config &cfg=rs2::config())
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void acquire(vpImage< vpRGBa > &I)
void open(vpImage< vpRGBa > &I)
void setFileName(const std::string &filename)
VISP_EXPORT double measureTimeMs()