Skip to content

Commit 3cd9f0f

Browse files
authored
Added Yunet face detection example (#8484)
1 parent 3f45723 commit 3cd9f0f

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Face detection with yunet
2+
3+
### Face detection in OpenFrameworks using dnn
4+
5+
It turns out that doing face detection in 2025 is much more efficient with neural networks than cascades.
6+
So here is an OF example that uses opencv's facedetectoryn (for yunet).
7+
8+
You will need the file with the pre-trained model. The model version must be compatible with your opencv version.
9+
10+
How to find out your opencv version?
11+
* It will be printed out during the ofApp::setup() function.
12+
* If you have a version greater than 4.9, you can download the current [face_detection_yunet_2023mar.onnx](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet) model
13+
* If your version is 4.6 or earlier, download the [2022](https://github.com/opencv/opencv_zoo/blob/088c3571ec70df15100a5e4c26894d95951e92e9/models/face_detection_yunet/face_detection_yunet_2022mar.onnx) version of the model.
14+
15+
The versions are coded in the ofApp::setup() function. Different versions might require editing the code.
16+
17+
### Expected behavior
18+
19+
The camera starts, and a red square will be drawn around the faces found.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "ofMain.h"
2+
#include "ofApp.h"
3+
4+
//========================================================================
5+
int main( ){
6+
7+
//Use ofGLFWWindowSettings for more options like multi-monitor fullscreen
8+
ofGLWindowSettings settings;
9+
settings.setSize(640, 480);
10+
settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN
11+
12+
auto window = ofCreateWindow(settings);
13+
14+
ofRunApp(window, std::make_shared<ofApp>());
15+
ofRunMainLoop();
16+
17+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// in ofApp.cpp
2+
#include "ofApp.h"
3+
4+
//--------------------------------------------------------------
5+
void ofApp::setup(){
6+
ofSetLogLevel(OF_LOG_VERBOSE);
7+
8+
cout << "OpenCV version: " << cv::getVersionMajor() << "." << cv::getVersionMinor() << "."<< cv::getVersionRevision() << "\n";
9+
10+
// 1. Setup Live Video
11+
camWidth = 640;
12+
camHeight = 480;
13+
grabber.setup(camWidth, camHeight);
14+
15+
// 2. Load the YuNet Model via the FaceDetectorYN wrapper
16+
17+
string modelPath;
18+
19+
if (cv::getVersionMajor()>=4) {
20+
if (cv::getVersionMinor()<=6) {
21+
// opencv 4.6.0
22+
modelPath = ofToDataPath("face_detection_yunet_2022mar.onnx");
23+
} else {
24+
// opencv 4.9.0 and greater
25+
modelPath = ofToDataPath("face_detection_yunet_2023mar.onnx");
26+
27+
}
28+
}
29+
30+
31+
32+
//string modelPath = ofToDataPath("yunet.onnx");
33+
cv::Size inputSize = cv::Size(320, 320); // The size the network prefers
34+
float scoreThreshold = 0.6; // Confidence threshold
35+
float nmsThreshold = 0.3; // Non-Maximum Suppression threshold
36+
int topK = 5000; // Keep top 5000 detections before NMS
37+
38+
// Call the static 'create' method to initialize the detector
39+
detector = cv::FaceDetectorYN::create(
40+
modelPath,
41+
"", // config file (not needed for this model)
42+
inputSize,
43+
scoreThreshold,
44+
nmsThreshold,
45+
topK
46+
);
47+
48+
if (detector.empty()) {
49+
ofLogError() << "Failed to load YuNet model. Make sure 'face_detection_yunet_2023mar.onnx' is in bin/data/";
50+
} else {
51+
ofLogNotice() << "cv::FaceDetectorYN loaded successfully.";
52+
}
53+
}
54+
55+
//--------------------------------------------------------------
56+
void ofApp::update(){
57+
grabber.update();
58+
59+
if (grabber.isFrameNew()) {
60+
// Clear previous detections
61+
detectedFaces.clear();
62+
63+
//
64+
// 1. Load pixels from the grabber into our ofxCvColorImage
65+
colorImg.setFromPixels(grabber.getPixels());
66+
67+
// 2. Get the cv::Mat from the wrapper image
68+
cv::Mat frame = colorImg.getCvMat();
69+
70+
// 3. Resize the detector's input.
71+
detector->setInputSize(cv::Size(frame.cols, frame.rows));
72+
73+
// 4. Detect!
74+
cv::Mat faces;
75+
detector->detect(frame, faces);
76+
if (faces.rows > 0) {
77+
for (int i = 0; i < faces.rows; i++) {
78+
// The format is:
79+
// [0-3] = bbox (x, y, w, h)
80+
// [4-13] = 10 facial landmarks
81+
// [14] = score
82+
83+
int x = static_cast<int>(faces.at<float>(i, 0));
84+
int y = static_cast<int>(faces.at<float>(i, 1));
85+
int w = static_cast<int>(faces.at<float>(i, 2));
86+
int h = static_cast<int>(faces.at<float>(i, 3));
87+
88+
detectedFaces.push_back(ofRectangle(x, y, w, h));
89+
}
90+
}
91+
}
92+
}
93+
94+
//--------------------------------------------------------------
95+
void ofApp::draw(){
96+
ofSetColor(255);
97+
grabber.draw(0, 0); // Draw the live video
98+
99+
// Draw the detected faces
100+
ofNoFill();
101+
ofSetLineWidth(2);
102+
ofSetColor(ofColor::red);
103+
104+
for (auto& rect : detectedFaces) {
105+
ofDrawRectangle(rect);
106+
}
107+
108+
// Draw info
109+
ofSetColor(ofColor::white);
110+
ofDrawBitmapString("FPS: " + ofToString(ofGetFrameRate(), 0), 20, 30);
111+
ofDrawBitmapString("Detections: " + ofToString(detectedFaces.size()), 20, 50);
112+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// in ofApp.h
2+
#pragma once
3+
4+
#include "ofMain.h"
5+
#include "ofxOpenCv.h"
6+
#include "ofVideoGrabber.h"
7+
8+
// include the dnn and objdetect headers
9+
#include "opencv2/objdetect.hpp"
10+
#include "opencv2/imgproc.hpp"
11+
12+
class ofApp : public ofBaseApp{
13+
14+
public:
15+
void setup();
16+
void update();
17+
void draw();
18+
19+
ofVideoGrabber grabber;
20+
int camWidth;
21+
int camHeight;
22+
23+
24+
//
25+
// We use a Ptr (a smart pointer) to hold the detector
26+
cv::Ptr<cv::FaceDetectorYN> detector;
27+
//
28+
// -----------------------------
29+
//
30+
31+
// Vector to store the final, processed face rectangles
32+
std::vector<ofRectangle> detectedFaces;
33+
34+
ofxCvColorImage colorImg;
35+
};

0 commit comments

Comments
 (0)