Implementation:Tencent Ncnn Retinaface Example
| Knowledge Sources | |
|---|---|
| Domains | Vision, Face_Detection |
| Last Updated | 2026-02-09 19:00 GMT |
Overview
Concrete tool for face detection with 5-point landmark localization using RetinaFace with ncnn.
Description
This example implements the RetinaFace face detector with a MobileNet-0.25 backbone (mnet.25-opt). The input image is converted from BGR to RGB and passed directly (without resizing) to the network. The model produces predictions at three feature pyramid strides (8, 16, 32), each with different anchor scales. For each stride level, prior anchor boxes are generated from base sizes, ratios, and scales, then bounding box deltas and 5-point facial landmark offsets (left eye, right eye, nose, left mouth corner, right mouth corner) are decoded from the network output. Anchor centers are computed with a base_size of 16 and ratio of 1.0, with scales of [2,1] for stride 8, [8,4] for stride 16, and [32,16] for stride 32. Proposals from all three strides are merged, sorted by confidence, and filtered via NMS with a threshold of 0.4. Detections are clipped to image boundaries. The probability threshold is set at 0.8. Results are visualized by drawing green bounding boxes and yellow landmark circles on the output image.
Usage
Use this example to detect faces in images and extract 5-point facial landmarks. Commonly used as a preprocessing step for face alignment before recognition.
Code Reference
Source Location
- Repository: Tencent_Ncnn
- File: examples/retinaface.cpp
- Lines: 1-425
Signature
static ncnn::Mat generate_anchors(int base_size, const ncnn::Mat& ratios, const ncnn::Mat& scales);
static void generate_proposals(const ncnn::Mat& anchors, int feat_stride, const ncnn::Mat& score_blob, const ncnn::Mat& bbox_blob, const ncnn::Mat& landmark_blob, float prob_threshold, std::vector<FaceObject>& faceobjects);
static int detect_retinaface(const cv::Mat& bgr, std::vector<FaceObject>& faceobjects);
static void draw_faceobjects(const cv::Mat& bgr, const std::vector<FaceObject>& faceobjects);
int main(int argc, char** argv);
Import
#include "net.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| imagepath | const char* (argv[1]) | Yes | Path to input image |
Outputs
| Name | Type | Description |
|---|---|---|
| faceobjects | std::vector<FaceObject> | Detected faces with bounding box (Rect_<float>), 5 landmark points (Point2f[5]), and confidence (float) |
| visualization | cv::Mat | Image with green bounding boxes and yellow landmark circles displayed via cv::imshow |
Usage Examples
Running the Example
./retinaface image.jpg
Key Code Pattern
ncnn::Net retinaface;
retinaface.opt.use_vulkan_compute = true;
retinaface.load_param("mnet.25-opt.param");
retinaface.load_model("mnet.25-opt.bin");
ncnn::Mat in = ncnn::Mat::from_pixels(bgr.data, ncnn::Mat::PIXEL_BGR2RGB, img_w, img_h);
ncnn::Extractor ex = retinaface.create_extractor();
ex.input("data", in);
// Decode from 3 stride levels (32, 16, 8)
std::vector<FaceObject> faceproposals;
for each stride:
{
ncnn::Mat score_blob, bbox_blob, landmark_blob;
ex.extract("face_rpn_cls_prob_reshape_stride32", score_blob);
ex.extract("face_rpn_bbox_pred_stride32", bbox_blob);
ex.extract("face_rpn_landmark_pred_stride32", landmark_blob);
ncnn::Mat anchors = generate_anchors(base_size, ratios, scales);
generate_proposals(anchors, feat_stride, score_blob, bbox_blob, landmark_blob, prob_threshold, faceobjects);
faceproposals.insert(faceproposals.end(), ...);
}
qsort_descent_inplace(faceproposals);
nms_sorted_bboxes(faceproposals, picked, nms_threshold);