This is my final Project for the Udacity C++ Nanodegree Program. This project captures video stream from a webcam, detect faces, and visualize the detection as bounding boxes around the faces in each frame. The main idea is to use concurrency to allow for real-time detection. There are three main threads running in paralell:
- Video capturing and image preprocessing, then adding the image to a frame buffer (message queue).
- Reading from the frame buffer once an image is available, and apply face detection with OpenCV Multi-scale Face Detector, then add the results to a display buffer (another message queue).
- Reading from the display buffer once a detection result is available, and overlay the detection bounding boxes on top of the frame, then display it.
Note that the main goal is not to have the most accurate face detector, as there are many state-of-the-art face detection models better than the basic OpenCV face detector,
but the goal is to apply C++ memory management and concurrency concepts to optimize the processing time for the whole cycle of (Catpture -> Detect -> Display). If you want to have a more accurate face detector, you can simply add your detector to the Function Detect()
under class Detector
.
All the cpp and header files are under src/
directory, and organized as follows:
main.cpp
starts the application, get user arguments and pass them to theDetector::Run()
method to start the detection loop and launch new threads for differnt tasks.Detector.h
andDetector.cpp
has the basic functions for video stream capturingDetector::Capture()
, face detectionDetector::Detect()
, and displayDetector::Display()
MessageQueue.h
has a template class for a generic message queue. It has the methodsMessageQueue::Send()
andMessageQueue::Recieve()
to add and remove elements from the queue, in addition toMessageQueue::SetMaxQueueSize()
to set the maximum size of the queue, andMessageQueue::GetQueueSize()
to get current size of the queue.
- cmake >= 2.8
- All OSes: click here for installation instructions
- make >= 4.1 (Linux, Mac), 3.81 (Windows)
- Linux: make is installed by default on most Linux distros
- Mac: install Xcode command line tools to get make
- Windows: Click here for installation instructions
- OpenCV >= 4.1
- The OpenCV 4.1.0 source code can be found here
- gcc/g++ >= 5.4
- Linux: gcc / g++ is installed by default on most Linux distros
- Mac: same deal as make - install Xcode command line tools
- Windows: recommend using MinGW
Note: This application is tested on Ubuntu 18.04 and OpenCV versions 4.1.0 and 3.2.0
- Clone this repo.
- Make a build directory in the top level directory:
mkdir build && cd build
- Compile:
cmake .. && make
- Connect your webcam and run the application specifying your camera id:
./face_detection --camera={YOUR_CAMERA_ID}
, for example./face_detection --camera=0
. - To stop the application, press Esc
This project satisfies all the required rubric points, and many of the optional rubric points as shown in the following table:
Optional Rubric Criteria | Details |
---|---|
The project demonstrates an understanding of C++ functions and control structures. | The project code is organized into classes and functions for example class Detector and class MessageQueue both have many fnuctions for different tasks. A variety of control structures are used, for example if conditions and while loops in functions Detector::Run() and Detector::Capture() . |
The project uses Object Oriented Programming techniques. | The project is organized into 2 main classes Detector and MessageQueue , both has many classs methods and class attributes. |
Classes use appropriate access specifiers for class members. | All class data members are explicitly specified as public, or private. |
Classes encapsulate behavior. | Appropriate data and functions are grouped into classes, for example we have classes Detector and MessageQueue for different tasks. and member data that is subject to an invariant is hidden from the user, for example all the private attributes under calss Detector , which are only accessed via member functions. |
Templates generalize functions in the project. | The class MessageQueue is declared with a template that allows it to accept a generic parameter. |
The project makes use of references in function declarations. | Methods LoadModel and Detect under class Detector use pass by reference. |
The project uses destructors appropriately. | Class Detector uses a destructor to wait for the vector of futures, and release the camera capture. |
The project uses move semantics to move data, instead of copying it, where possible. | std::move() is used in MessageQueue::Send() and MessageQueue::Receive() , and used while sending and receiving objects to the message queue, for example in Detector::Capture() and Detector::Display() |
The project uses multithreading. | std::async() is used to start threads for Detector::Capture() and Detector::Display() |
A mutex or lock is used in the project. | Mutexes and Locks are used in MessageQueue::Send() and MessageQueue::Receive() , in addition to many places in class Detector for example here and here |
A condition variable is used in the project. | A condition variable is used in calss MessageQueue to handle sending and receiving messages. |