1 #include <visp3/core/vpConfig.h>
3 #include <visp3/core/vpIoTools.h>
4 #include <visp3/detection/vpDetectorDNNOpenCV.h>
5 #include <visp3/gui/vpDisplayGDI.h>
6 #include <visp3/gui/vpDisplayOpenCV.h>
7 #include <visp3/gui/vpDisplayX.h>
9 #if defined(HAVE_OPENCV_VIDEOIO)
10 #include <opencv2/videoio.hpp>
13 #ifdef VISP_HAVE_NLOHMANN_JSON
14 #include <nlohmann/json.hpp>
15 using json = nlohmann::json;
18 #ifdef ENABLE_VISP_NAMESPACE
24 DETECTION_CONTAINER_MAP = 0,
25 DETECTION_CONTAINER_VECTOR = 1,
26 DETECTION_CONTAINER_BOTH = 2,
27 DETECTION_CONTAINER_COUNT = 3
28 } ChosenDetectionContainer;
30 std::string chosenDetectionContainerToString(
const ChosenDetectionContainer &choice)
33 case DETECTION_CONTAINER_MAP:
35 case DETECTION_CONTAINER_VECTOR:
37 case DETECTION_CONTAINER_BOTH:
45 ChosenDetectionContainer chosenDetectionContainerFromString(
const std::string &choiceStr)
47 ChosenDetectionContainer choice(DETECTION_CONTAINER_COUNT);
48 bool hasFoundMatch =
false;
49 for (
unsigned int i = 0; i < DETECTION_CONTAINER_COUNT && !hasFoundMatch; i++) {
50 ChosenDetectionContainer candidate = (ChosenDetectionContainer)i;
59 std::string getAvailableDetectionContainer()
61 std::string availableContainers(
"< ");
62 for (
unsigned int i = 0; i < DETECTION_CONTAINER_COUNT - 1; i++) {
63 std::string name = chosenDetectionContainerToString((ChosenDetectionContainer)i);
64 availableContainers += name +
" , ";
66 availableContainers +=
67 chosenDetectionContainerToString((ChosenDetectionContainer)(DETECTION_CONTAINER_COUNT - 1)) +
" >";
68 return availableContainers;
71 int main(
int argc,
const char *argv[])
74 #if defined(HAVE_OPENCV_DNN) && defined(HAVE_OPENCV_VIDEOIO) && \
75 ((__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
77 std::string opt_device(
"0");
79 std::string opt_dnn_model =
"opencv_face_detector_uint8.pb";
80 std::string opt_dnn_config =
"opencv_face_detector.pbtxt";
81 std::string opt_dnn_framework =
"none";
82 std::string opt_dnn_label_file =
"";
85 int opt_dnn_width = 300, opt_dnn_height = 300;
86 double opt_dnn_meanR = 104.0, opt_dnn_meanG = 177.0, opt_dnn_meanB = 123.0;
87 double opt_dnn_scale_factor = 1.0;
88 bool opt_dnn_swapRB =
false;
89 bool opt_step_by_step =
false;
90 float opt_dnn_confThresh = 0.5f;
91 float opt_dnn_nmsThresh = 0.4f;
92 double opt_dnn_filterThresh = 0.25;
93 ChosenDetectionContainer opt_dnn_containerType = DETECTION_CONTAINER_MAP;
94 bool opt_verbose =
false;
95 std::string opt_input_json =
"";
96 std::string opt_output_json =
"";
98 for (
int i = 1; i < argc; i++) {
99 if (std::string(argv[i]) ==
"--device" && i + 1 < argc) {
100 opt_device = std::string(argv[++i]);
102 else if (std::string(argv[i]) ==
"--step-by-step") {
103 opt_step_by_step =
true;
105 else if (std::string(argv[i]) ==
"--model" && i + 1 < argc) {
106 opt_dnn_model = std::string(argv[++i]);
108 else if (std::string(argv[i]) ==
"--type" && i + 1 < argc) {
111 else if (std::string(argv[i]) ==
"--config" && i + 1 < argc) {
112 opt_dnn_config = std::string(argv[++i]);
113 if (opt_dnn_config.find(
"none") != std::string::npos) {
114 opt_dnn_config = std::string();
117 else if (std::string(argv[i]) ==
"--framework" && i + 1 < argc) {
118 opt_dnn_framework = std::string(argv[++i]);
119 if (opt_dnn_framework.find(
"none") != std::string::npos) {
120 opt_dnn_framework = std::string();
123 else if (std::string(argv[i]) ==
"--width" && i + 1 < argc) {
124 opt_dnn_width = atoi(argv[++i]);
126 else if (std::string(argv[i]) ==
"--height" && i + 1 < argc) {
127 opt_dnn_height = atoi(argv[++i]);
129 else if (std::string(argv[i]) ==
"--mean" && i + 3 < argc) {
130 opt_dnn_meanR = atof(argv[++i]);
131 opt_dnn_meanG = atof(argv[++i]);
132 opt_dnn_meanB = atof(argv[++i]);
134 else if (std::string(argv[i]) ==
"--scale" && i + 1 < argc) {
135 opt_dnn_scale_factor = atof(argv[++i]);
137 else if (std::string(argv[i]) ==
"--swapRB") {
138 opt_dnn_swapRB =
true;
140 else if (std::string(argv[i]) ==
"--confThresh" && i + 1 < argc) {
141 opt_dnn_confThresh = (float)atof(argv[++i]);
143 else if (std::string(argv[i]) ==
"--nmsThresh" && i + 1 < argc) {
144 opt_dnn_nmsThresh = (float)atof(argv[++i]);
146 else if (std::string(argv[i]) ==
"--filterThresh" && i + 1 < argc) {
147 opt_dnn_filterThresh = atof(argv[++i]);
149 else if (std::string(argv[i]) ==
"--labels" && i + 1 < argc) {
150 opt_dnn_label_file = std::string(argv[++i]);
152 else if (std::string(argv[i]) ==
"--container" && i + 1 < argc) {
153 opt_dnn_containerType = chosenDetectionContainerFromString(std::string(argv[++i]));
155 else if (std::string(argv[i]) ==
"--input-json" && i + 1 < argc) {
156 opt_input_json = std::string(std::string(argv[++i]));
158 else if (std::string(argv[i]) ==
"--output-json" && i + 1 < argc) {
159 opt_output_json = std::string(std::string(argv[++i]));
161 else if (std::string(argv[i]) ==
"--verbose" || std::string(argv[i]) ==
"-v") {
164 else if (std::string(argv[i]) ==
"--help" || std::string(argv[i]) ==
"-h") {
165 std::cout <<
"\nSYNOPSIS " << std::endl
166 << argv[0] <<
" [--device <video>]"
167 <<
" [--model <dnn weights file>]"
168 <<
" [--type <dnn type>]"
169 <<
" [--config <dnn config file]"
170 <<
" [--framework <name>]"
171 <<
" [--width <blob width>] [--height <blob height>]"
172 <<
" [--mean <meanR meanG meanB>]"
173 <<
" [--scale <scale factor>]"
175 <<
" [--confThresh <threshold>]"
176 <<
" [--nmsThresh <threshold>]"
177 <<
" [--filterThresh <threshold>]"
178 <<
" [--labels <file>]"
179 <<
" [--container <type>]"
180 <<
" [--input-json <path_to_input_json>]"
181 <<
" [--output-json <path_to_output_json>]"
182 <<
" [--step-by-step]"
183 <<
" [--verbose, -v]"
184 <<
" [--help, -h]" << std::endl;
185 std::cout <<
"\nOPTIONS " << std::endl
186 <<
" --device <video>" << std::endl
187 <<
" Camera device number or video name used to stream images." << std::endl
188 <<
" To use the first camera found on the bus set 0. On Ubuntu setting 0" << std::endl
189 <<
" will use /dev/video0 device. To use a video simply put the name of" << std::endl
190 <<
" the video, like \"path/my-video.mp4\" or \"path/image-%04d.png\"" << std::endl
191 <<
" if your video is a sequence of images." << std::endl
192 <<
" Default: " << opt_device << std::endl
194 <<
" --model <dnn weights file>" << std::endl
195 <<
" Path to dnn network trained weights." << std::endl
196 <<
" Default: " << opt_dnn_model << std::endl
198 <<
" --type <dnn type>" << std::endl
199 <<
" Type of dnn network. Admissible values are in " << std::endl
201 <<
" Default: " << opt_dnn_type << std::endl
203 <<
" --config <dnn config file>" << std::endl
204 <<
" Path to dnn network config file or \"none\" not to use one. " << std::endl
205 <<
" Default: " << opt_dnn_config << std::endl
207 <<
" --framework <name>" << std::endl
208 <<
" Framework name or \"none\" not to specify one. " << std::endl
209 <<
" Default: " << opt_dnn_framework << std::endl
211 <<
" --width <blob width>" << std::endl
212 <<
" Input images will be resized to this width. " << std::endl
213 <<
" Default: " << opt_dnn_width << std::endl
215 <<
" --height <blob height>" << std::endl
216 <<
" Input images will be resized to this height. " << std::endl
217 <<
" Default: " << opt_dnn_height << std::endl
219 <<
" --mean <meanR meanG meanB>" << std::endl
220 <<
" Mean RGB subtraction values. " << std::endl
221 <<
" Default: " << opt_dnn_meanR <<
" " << opt_dnn_meanG <<
" " << opt_dnn_meanB << std::endl
223 <<
" --scale <scale factor>" << std::endl
224 <<
" Scale factor used to normalize the range of pixel values. " << std::endl
225 <<
" Default: " << opt_dnn_scale_factor << std::endl
227 <<
" --swapRB" << std::endl
228 <<
" When used this option allows to swap Red and Blue channels. " << std::endl
230 <<
" --confThresh <threshold>" << std::endl
231 <<
" Confidence threshold. " << std::endl
232 <<
" Default: " << opt_dnn_confThresh << std::endl
234 <<
" --nmsThresh <threshold>" << std::endl
235 <<
" Non maximum suppression threshold. " << std::endl
236 <<
" Default: " << opt_dnn_nmsThresh << std::endl
238 <<
" --filterThresh <threshold >" << std::endl
239 <<
" Filter threshold. Set 0. to disable." << std::endl
240 <<
" Default: " << opt_dnn_filterThresh << std::endl
242 <<
" --labels <file>" << std::endl
243 <<
" Path to label file either in txt or yaml format. Keep empty if unknown." << std::endl
244 <<
" Default: \"" << opt_dnn_label_file <<
"\"" << std::endl
246 <<
" --container <type>" << std::endl
247 <<
" Container type in " << getAvailableDetectionContainer() << std::endl
248 <<
" Default: " << chosenDetectionContainerToString(opt_dnn_containerType) << std::endl
250 <<
" --input-json <path_to_input_json>" << std::endl
251 <<
" Input JSON file used to configure the DNN. If set, the other arguments will be used to override the values set in the json file." << std::endl
252 <<
" Default: empty" << std::endl
254 <<
" --output-json <type>" << std::endl
255 <<
" Output JSON file where will be saved the DNN configuration. If empty, does not save the configuration." << std::endl
256 <<
" Default: empty" << std::endl
258 <<
" --step-by-step" << std::endl
259 <<
" Enable step by step mode, waiting for a user click to process next image." << std::endl
261 <<
" --verbose, -v" << std::endl
262 <<
" Enable verbose mode." << std::endl
264 <<
" --help, -h" << std::endl
265 <<
" Display this helper message." << std::endl
271 std::cout <<
"Video device : " << opt_device << std::endl;
272 std::cout <<
"Label file (optional): " << (opt_dnn_label_file.empty() ?
"None" : opt_dnn_label_file) << std::endl;
274 cv::VideoCapture capture;
275 bool hasCaptureOpeningSucceeded;
277 hasCaptureOpeningSucceeded = capture.open(std::atoi(opt_device.c_str()));
280 hasCaptureOpeningSucceeded = capture.open(opt_device);
282 if (!hasCaptureOpeningSucceeded) {
283 std::cout <<
"Capture from camera: " << opt_device <<
" didn't work" << std::endl;
288 #if defined(VISP_HAVE_X11)
290 #elif defined(VISP_HAVE_GDI)
292 #elif defined(HAVE_OPENCV_HIGHGUI)
299 "The file containing the classes labels \"" + opt_dnn_label_file +
"\" does not exist !"));
303 #ifdef VISP_HAVE_NLOHMANN_JSON
304 if (!opt_input_json.empty()) {
310 if (!opt_input_json.empty()) {
311 std::cerr <<
"Error: NLOHMANN JSON library is not installed, please install it following ViSP documentation to configure the vpDetectorDNNOpenCV from a JSON file." << std::endl;
318 , cv::Size(opt_dnn_width, opt_dnn_height), opt_dnn_filterThresh, cv::Scalar(opt_dnn_meanR, opt_dnn_meanG, opt_dnn_meanB)
319 , opt_dnn_scale_factor, opt_dnn_swapRB, opt_dnn_type
320 , opt_dnn_model, opt_dnn_config, opt_dnn_framework
328 #ifdef VISP_HAVE_NLOHMANN_JSON
329 if (!opt_output_json.empty()) {
333 if (!opt_output_json.empty()) {
334 std::cerr <<
"Error: NLOHMANN JSON library is not installed, please install it following ViSP documentation to save the configuration in a JSON file." << std::endl;
349 std::cout <<
"Process image: " << I.
getWidth() <<
" x " << I.
getHeight() << std::endl;
356 std::cout <<
"Process new image" << std::endl;
361 if (opt_dnn_containerType == DETECTION_CONTAINER_MAP || opt_dnn_containerType == DETECTION_CONTAINER_BOTH) {
364 std::map<std::string, std::vector<vpDetectorDNNOpenCV::DetectedFeatures2D> > detections;
365 dnn.
detect(frame, detections);
370 for (
auto key_val : detections) {
372 std::cout <<
" Class name : " << key_val.first << std::endl;
376 std::cout <<
" Bounding box : " << detection.
getBoundingBox() << std::endl;
377 std::cout <<
" Class Id : " << detection.
getClassId() << std::endl;
379 std::cout <<
" Class name : " << detection.
getClassName().value() << std::endl;
387 std::ostringstream oss_map;
388 oss_map <<
"Detection time (map): " << t <<
" ms";
391 std::cout <<
" " << oss_map.str() << std::endl;
397 if (opt_dnn_containerType == DETECTION_CONTAINER_VECTOR || opt_dnn_containerType == DETECTION_CONTAINER_BOTH) {
400 std::vector<vpDetectorDNNOpenCV::DetectedFeatures2D> detections_vec;
401 dnn.
detect(frame, detections_vec);
406 for (
auto detection : detections_vec) {
408 std::cout <<
" Bounding box : " << detection.
getBoundingBox() << std::endl;
409 std::cout <<
" Class Id : " << detection.
getClassId() << std::endl;
410 std::optional<std::string> classname_opt = detection.
getClassName();
411 std::cout <<
" Class name : " << (classname_opt ? *classname_opt :
"Not known") << std::endl;
418 std::ostringstream oss_vec;
419 oss_vec <<
"Detection time (vector): " << t_vector <<
" ms";
422 std::cout <<
" " << oss_vec.str() << std::endl;
429 if (opt_step_by_step) {
451 std::cout << e.
what() << std::endl;
Structure containing the bounding box, expressed in pixels, confidence and class information about an...
void display(const vpImage< Type > &img, const vpColor &color=vpColor::blue, unsigned int thickness=1) const
vpRect getBoundingBox() const
std::optional< std::string > getClassName() const
double getConfidenceScore() const
unsigned int getClassId() const
Structure containing some information required for the configuration of a vpDetectorDNNOpenCV object.
void initFromJSON(const std::string &jsonPath)
DNNResultsParsingType
Enumeration listing the types of DNN for which the vpDetectorDNNOpenCV furnishes the methods permitti...
static DNNResultsParsingType dnnResultsParsingTypeFromString(const std::string &name)
const NetConfig & getNetConfig() const
void setNetConfig(const NetConfig &config)
virtual bool detect(const vpImage< unsigned char > &I, std::vector< DetectedFeatures2D > &output)
Object detection using OpenCV DNN module.
static std::string getAvailableDnnResultsParsingTypes()
Get the list of the parsing methods / types of DNNs supported by the vpDetectorDNNOpenCV class.
void saveConfigurationInJSON(const std::string &jsonPath) const
Save the network configuration in a JSON file.
Display for windows using GDI (available on any windows 32 platform).
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
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)
virtual void setDownScalingFactor(unsigned int scale)
static void display(const vpImage< unsigned char > &I)
static void setTitle(const vpImage< unsigned char > &I, const std::string &windowtitle)
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.
const char * what() const
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
unsigned int getWidth() const
unsigned int getSize() const
unsigned int getHeight() const
static bool isNumber(const std::string &str)
VISP_EXPORT double measureTimeMs()