Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions examples/computer_vision/yunetFaceDetection/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Face detection with yunet

### Face detection in OpenFrameworks using dnn

It turns out that doing face detection in 2025 is much more efficient with neural networks than cascades.
So here is an OF example that uses opencv's facedetectoryn (for yunet).

You will need the file with the pre-trained model. The model version must be compatible with your opencv version.

How to find out your opencv version?
* It will be printed out during the ofApp::setup() function.
* 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
* 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.

The versions are coded in the ofApp::setup() function. Different versions might require editing the code.

### Expected behavior

The camera starts, and a red square will be drawn around the faces found.
17 changes: 17 additions & 0 deletions examples/computer_vision/yunetFaceDetection/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){

//Use ofGLFWWindowSettings for more options like multi-monitor fullscreen
ofGLWindowSettings settings;
settings.setSize(640, 480);
settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN

auto window = ofCreateWindow(settings);

ofRunApp(window, std::make_shared<ofApp>());
ofRunMainLoop();

}
112 changes: 112 additions & 0 deletions examples/computer_vision/yunetFaceDetection/src/ofApp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// in ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
ofSetLogLevel(OF_LOG_VERBOSE);

cout << "OpenCV version: " << cv::getVersionMajor() << "." << cv::getVersionMinor() << "."<< cv::getVersionRevision() << "\n";

// 1. Setup Live Video
camWidth = 640;
camHeight = 480;
grabber.setup(camWidth, camHeight);

// 2. Load the YuNet Model via the FaceDetectorYN wrapper

string modelPath;

if (cv::getVersionMajor()>=4) {
if (cv::getVersionMinor()<=6) {
// opencv 4.6.0
modelPath = ofToDataPath("face_detection_yunet_2022mar.onnx");
} else {
// opencv 4.9.0 and greater
modelPath = ofToDataPath("face_detection_yunet_2023mar.onnx");

}
}



//string modelPath = ofToDataPath("yunet.onnx");
cv::Size inputSize = cv::Size(320, 320); // The size the network prefers
float scoreThreshold = 0.6; // Confidence threshold
float nmsThreshold = 0.3; // Non-Maximum Suppression threshold
int topK = 5000; // Keep top 5000 detections before NMS

// Call the static 'create' method to initialize the detector
detector = cv::FaceDetectorYN::create(
modelPath,
"", // config file (not needed for this model)
inputSize,
scoreThreshold,
nmsThreshold,
topK
);

if (detector.empty()) {
ofLogError() << "Failed to load YuNet model. Make sure 'face_detection_yunet_2023mar.onnx' is in bin/data/";
} else {
ofLogNotice() << "cv::FaceDetectorYN loaded successfully.";
}
}

//--------------------------------------------------------------
void ofApp::update(){
grabber.update();

if (grabber.isFrameNew()) {
// Clear previous detections
detectedFaces.clear();

//
// 1. Load pixels from the grabber into our ofxCvColorImage
colorImg.setFromPixels(grabber.getPixels());

// 2. Get the cv::Mat from the wrapper image
cv::Mat frame = colorImg.getCvMat();

// 3. Resize the detector's input.
detector->setInputSize(cv::Size(frame.cols, frame.rows));

// 4. Detect!
cv::Mat faces;
detector->detect(frame, faces);
if (faces.rows > 0) {
for (int i = 0; i < faces.rows; i++) {
// The format is:
// [0-3] = bbox (x, y, w, h)
// [4-13] = 10 facial landmarks
// [14] = score

int x = static_cast<int>(faces.at<float>(i, 0));
int y = static_cast<int>(faces.at<float>(i, 1));
int w = static_cast<int>(faces.at<float>(i, 2));
int h = static_cast<int>(faces.at<float>(i, 3));

detectedFaces.push_back(ofRectangle(x, y, w, h));
}
}
}
}

//--------------------------------------------------------------
void ofApp::draw(){
ofSetColor(255);
grabber.draw(0, 0); // Draw the live video

// Draw the detected faces
ofNoFill();
ofSetLineWidth(2);
ofSetColor(ofColor::red);

for (auto& rect : detectedFaces) {
ofDrawRectangle(rect);
}

// Draw info
ofSetColor(ofColor::white);
ofDrawBitmapString("FPS: " + ofToString(ofGetFrameRate(), 0), 20, 30);
ofDrawBitmapString("Detections: " + ofToString(detectedFaces.size()), 20, 50);
}
35 changes: 35 additions & 0 deletions examples/computer_vision/yunetFaceDetection/src/ofApp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// in ofApp.h
#pragma once

#include "ofMain.h"
#include "ofxOpenCv.h"
#include "ofVideoGrabber.h"

// include the dnn and objdetect headers
#include "opencv2/objdetect.hpp"
#include "opencv2/imgproc.hpp"

class ofApp : public ofBaseApp{

public:
void setup();
void update();
void draw();

ofVideoGrabber grabber;
int camWidth;
int camHeight;


//
// We use a Ptr (a smart pointer) to hold the detector
cv::Ptr<cv::FaceDetectorYN> detector;
//
// -----------------------------
//

// Vector to store the final, processed face rectangles
std::vector<ofRectangle> detectedFaces;

ofxCvColorImage colorImg;
};