Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tutorial-face-detector-live-threaded.cpp
1 #include <iostream>
3 
4 #include <visp3/core/vpImageConvert.h>
5 #include <visp3/core/vpMutex.h>
6 #include <visp3/core/vpThread.h>
7 #include <visp3/core/vpTime.h>
8 #include <visp3/gui/vpDisplayX.h>
9 #include <visp3/gui/vpDisplayGDI.h>
10 #include <visp3/detection/vpDetectorFace.h>
11 #include <visp3/sensor/vpV4l2Grabber.h>
12 
13 #if (VISP_HAVE_OPENCV_VERSION >= 0x020200) && (defined(VISP_HAVE_PTHREAD) || defined(_WIN32))
14 
15 #include <opencv2/highgui/highgui.hpp>
16 
17 // Shared vars
18 typedef enum {
19  capture_waiting,
20  capture_started,
21  capture_stopped
22 } t_CaptureState;
23 t_CaptureState s_capture_state = capture_waiting;
24 bool s_face_available = false;
25 #if defined(VISP_HAVE_V4L2)
27 #elif defined(VISP_HAVE_OPENCV)
28 cv::Mat s_frame;
29 #endif
30 vpMutex s_mutex_capture;
31 vpMutex s_mutex_face;
32 vpRect s_face_bbox;
33 
34 vpThread::Return captureFunction(vpThread::Args args)
35 {
36 #if defined(VISP_HAVE_V4L2)
37  vpV4l2Grabber cap = *((vpV4l2Grabber *) args);
38 #elif defined(VISP_HAVE_OPENCV)
39  cv::VideoCapture cap = *((cv::VideoCapture *) args);
40 #endif
41 
42  // If the image is larger than 640 by 480, we subsample
43 #if defined(VISP_HAVE_V4L2)
45 #elif defined(VISP_HAVE_OPENCV)
46  cv::Mat frame_;
47 #endif
48  bool stop_capture_ = false;
49 
50  double start_time = vpTime::measureTimeSecond();
51  while ((vpTime::measureTimeSecond() - start_time) < 30 && !stop_capture_) {
52  // Capture in progress
53  cap >> frame_; // get a new frame from camera
54 
55  // Update shared data
56  {
57  vpMutex::vpScopedLock lock(s_mutex_capture);
58  if (s_capture_state == capture_stopped)
59  stop_capture_ = true;
60  else
61  s_capture_state = capture_started;
62  s_frame = frame_;
63  }
64  }
65  {
66  vpMutex::vpScopedLock lock(s_mutex_capture);
67  s_capture_state = capture_stopped;
68  }
69 
70  std::cout << "End of capture thread" << std::endl;
71  return 0;
72 }
73 
74 vpThread::Return displayFunction(vpThread::Args args)
75 {
76  (void)args; // Avoid warning: unused parameter args
78 
79  t_CaptureState capture_state_;
80  bool display_initialized_ = false;
81  bool face_available_ = false;
82  vpRect face_bbox_;
83 #if defined(VISP_HAVE_X11)
84  vpDisplayX *d_ = NULL;
85 #elif defined(VISP_HAVE_GDI)
86  vpDisplayGDI *d_ = NULL;
87 #endif
88 
89  do {
90  s_mutex_capture.lock();
91  capture_state_ = s_capture_state;
92  s_mutex_capture.unlock();
93 
94  // Check if a frame is available
95  if (capture_state_ == capture_started) {
96  // Get the frame and convert it to a ViSP image used by the display class
97  {
98  vpMutex::vpScopedLock lock(s_mutex_capture);
99 #if defined(VISP_HAVE_V4L2)
100  I_ = s_frame;
101 #elif defined(VISP_HAVE_OPENCV)
102  vpImageConvert::convert(s_frame, I_);
103 #endif
104  }
105 
106  // Check if we need to initialize the display with the first frame
107  if (! display_initialized_) {
108  // Initialize the display
109 #if defined(VISP_HAVE_X11)
110  d_ = new vpDisplayX(I_);
111  display_initialized_ = true;
112 #elif defined(VISP_HAVE_GDI)
113  d_ = new vpDisplayGDI(I_);
114  display_initialized_ = true;
115 #endif
116  }
117 
118  // Display the image
119  vpDisplay::display(I_);
120 
121  // Check if a face was detected
122  {
123  vpMutex::vpScopedLock lock(s_mutex_face);
124  face_available_ = s_face_available;
125  face_bbox_ = s_face_bbox;
126  }
127  if (face_available_) {
128  // Access to the face bounding box to display it
129  vpDisplay::displayRectangle(I_, face_bbox_, vpColor::green, false, 4);
130  face_available_ = false;
131  }
132 
133  // Trigger end of acquisition with a mouse click
134  vpDisplay::displayText(I_, 10, 10, "Click to exit...", vpColor::red);
135  if (vpDisplay::getClick(I_, false)) {
136  vpMutex::vpScopedLock lock(s_mutex_capture);
137  s_capture_state = capture_stopped;
138  }
139 
140  // Update the display
141  vpDisplay::flush(I_);
142  }
143  else {
144  vpTime::wait(2); // Sleep 2ms
145  }
146  } while(capture_state_ != capture_stopped);
147 
148 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)
149  delete d_;
150 #endif
151 
152  std::cout << "End of display thread" << std::endl;
153  return 0;
154 }
155 
157 vpThread::Return detectionFunction(vpThread::Args args)
158 {
159  std::string opt_face_cascade_name = *((std::string *) args);
160 
161  vpDetectorFace face_detector_;
162  face_detector_.setCascadeClassifierFile(opt_face_cascade_name);
163 
164  t_CaptureState capture_state_;
165 #if defined(VISP_HAVE_V4L2)
166  vpImage<unsigned char> frame_;
167 #elif defined(VISP_HAVE_OPENCV)
168  cv::Mat frame_;
169 #endif
170  do {
171  s_mutex_capture.lock();
172  capture_state_ = s_capture_state;
173  s_mutex_capture.unlock();
174 
175  // Check if a frame is available
176  if (capture_state_ == capture_started) {
177  // Backup the frame
178  {
179  vpMutex::vpScopedLock lock(s_mutex_capture);
180  frame_ = s_frame;
181  }
182 
183  // Detect faces
184  bool face_found_ = face_detector_.detect(frame_);
185  if (face_found_) {
186  vpMutex::vpScopedLock lock(s_mutex_face);
187  s_face_available = true;
188  s_face_bbox = face_detector_.getBBox(0); // Get largest face bounding box
189  }
190  }
191  else {
192  vpTime::wait(2); // Sleep 2ms
193  }
194  } while(capture_state_ != capture_stopped);
195  std::cout << "End of face detection thread" << std::endl;
196 
197  return 0;
198 }
200 
202 int main(int argc, const char* argv[])
203 {
204  std::string opt_face_cascade_name = "./haarcascade_frontalface_alt.xml";
205  unsigned int opt_device = 0;
206  unsigned int opt_scale = 2; // Default value is 2 in the constructor. Turn it to 1 to avoid subsampling
207 
208  for (int i=0; i<argc; i++) {
209  if (std::string(argv[i]) == "--haar")
210  opt_face_cascade_name = std::string(argv[i+1]);
211  else if (std::string(argv[i]) == "--device")
212  opt_device = (unsigned int)atoi(argv[i+1]);
213  else if (std::string(argv[i]) == "--scale")
214  opt_scale = (unsigned int)atoi(argv[i+1]);
215  else if (std::string(argv[i]) == "--help") {
216  std::cout << "Usage: " << argv[0] << " [--haar <haarcascade xml filename>] [--device <camera device>] [--scale <subsampling factor>] [--help]" << std::endl;
217  return 0;
218  }
219  }
220 
221  // Instanciate the capture
222 #if defined(VISP_HAVE_V4L2)
223  vpV4l2Grabber cap;
224  std::ostringstream device;
225  device << "/dev/video" << opt_device;
226  cap.setDevice(device.str());
227  cap.setScale(opt_scale);
228 #elif defined(VISP_HAVE_OPENCV)
229  cv::VideoCapture cap;
230  cap.open(opt_device);
231 # if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
232  int width = (int)cap.get(cv::CAP_PROP_FRAME_WIDTH);
233  int height = (int)cap.get(cv::CAP_PROP_FRAME_HEIGHT);
234  cap.set(cv::CAP_PROP_FRAME_WIDTH, width/opt_scale);
235  cap.set(cv::CAP_PROP_FRAME_HEIGHT, height/opt_scale);
236 # else
237  int width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
238  int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
239  cap.set(CV_CAP_PROP_FRAME_WIDTH, width/opt_scale);
240  cap.set(CV_CAP_PROP_FRAME_HEIGHT, height/opt_scale);
241 # endif
242 #endif
243 
244  // Start the threads
245  vpThread thread_capture((vpThread::Fn)captureFunction, (vpThread::Args)&cap);
246  vpThread thread_display((vpThread::Fn)displayFunction);
247  vpThread thread_detection((vpThread::Fn)detectionFunction, (vpThread::Args)&opt_face_cascade_name);
248 
249  // Wait until thread ends up
250  thread_capture.join();
251  thread_display.join();
252  thread_detection.join();
253 
254  return 0;
255 }
257 
258 #else
259 int main()
260 {
261 # ifndef VISP_HAVE_OPENCV
262  std::cout << "You should install OpenCV to make this example working..." << std::endl;
263 # elif !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
264  std::cout << "You should enable pthread usage and rebuild ViSP..." << std::endl;
265 # else
266  std::cout << "Multi-threading seems not supported on this platform" << std::endl;
267 # endif
268 }
269 
270 #endif
Class that allows protection by mutex.
Definition: vpMutex.h:163
VISP_EXPORT int wait(double t0, double t)
Definition: vpTime.cpp:157
void lock()
Definition: vpMutex.h:90
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
void setCascadeClassifierFile(const std::string &filename)
void open(vpImage< unsigned char > &I)
void * Return
Definition: vpThread.h:36
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
VISP_EXPORT double measureTimeSecond()
Definition: vpTime.cpp:255
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
void unlock()
Definition: vpMutex.h:106
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:153
void setDevice(const std::string &devname)
static const vpColor green
Definition: vpColor.h:166
static void flush(const vpImage< unsigned char > &I)
void *(* Fn)(Args)
Definition: vpThread.h:37
static const vpColor red
Definition: vpColor.h:163
bool detect(const vpImage< unsigned char > &I)
void * Args
Definition: vpThread.h:35
static void display(const vpImage< unsigned char > &I)
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
void setScale(unsigned scale=vpV4l2Grabber::DEFAULT_SCALE)
Class that is a wrapper over the Video4Linux2 (V4L2) driver.
Defines a rectangle in the plane.
Definition: vpRect.h:82
vpRect getBBox(size_t i) const