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