Implementation:Tencent Ncnn Arcface Example
| Knowledge Sources | |
|---|---|
| Domains | Vision, Face_Recognition |
| Last Updated | 2026-02-09 19:00 GMT |
Overview
Concrete tool for face recognition inference using YOLOv8-face detection and ArcFace embedding extraction with ncnn.
Description
This example implements a two-stage face verification pipeline. Stage one uses a YOLOv8-face model to detect face bounding boxes and 5-point facial keypoints, with letterbox preprocessing (resize to 320x320 with padding), NMS post-processing, and confidence thresholding. Stage two crops and aligns detected faces using an affine warp based on the 5 landmark points (eyes, nose, mouth corners) aligned to the standard ArcFace reference template, then feeds the 112x112 aligned face through an ArcFace ResNet model to extract 512-dimensional L2-normalized embeddings. The embeddings from two input images are compared via cosine similarity to determine if the faces match. The ArcFace model is converted from ONNX via onnx2ncnn (not PNNX, which produces NaN outputs for this model). The YOLOv8-face model is converted from the derronqi/yolov8-face project.
Usage
Use this example to verify whether two face images belong to the same person. It takes two image paths as input and outputs a cosine similarity score.
Code Reference
Source Location
- Repository: Tencent_Ncnn
- File: examples/arcface.cpp
- Lines: 1-657
Signature
static int get_face(const cv::Mat& rgb, DetectionResult& result);
static int get_embedding(const cv::Mat& rgb, std::vector<float>& result);
static int norm_crop(cv::Mat& output, const cv::Mat& input, const float* lmk, int image_size = 112);
static inline float get_similarity(std::vector<float> f1, std::vector<float> f2);
int main(int argc, char** argv);
Import
#include "layer.h"
#include "net.h"
#include "mat.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| face1_path | const char* (argv[1]) | Yes | Path to first face image |
| face2_path | const char* (argv[2]) | Yes | Path to second face image |
Outputs
| Name | Type | Description |
|---|---|---|
| similarity | float | Cosine similarity score between two face embeddings (higher = more similar) |
| face count | int | Number of detected faces printed per image |
| bounding boxes | Bbox | Detected face coordinates printed to stdout |
Usage Examples
Running the Example
./arcface face1.jpg face2.jpg
Key Code Pattern
// Stage 1: Face detection with YOLOv8-face
ncnn::Net yoloface;
yoloface.load_param("yolov8-face.param");
yoloface.load_model("yolov8-face.bin");
ImagePreProcessResults preproc_img = preprocess_yolo_kpts(input_image, ARCFACE_EXAMPLE_YOLO_INFER_SIZE);
ncnn::Extractor ex = yoloface.create_extractor();
ex.input("in0", preproc_img.result);
ncnn::Mat out;
ex.extract("out0", out);
DetectionResult result = parse_yolo_keypoints_results(out, input_image, preproc_img, 0.5, 0.4, class_names);
// Stage 2: Face alignment and embedding
norm_crop(aligned_face, face_img, result.keypoints[0].data());
ncnn::Net arcface;
arcface.load_param("arcfaceresnet.param");
arcface.load_model("arcfaceresnet.bin");
ncnn::Mat in = ncnn::Mat::from_pixels_resize(aligned_face.data, ncnn::Mat::PIXEL_BGR2RGB, cols, rows, 112, 112);
ncnn::Extractor ex2 = arcface.create_extractor();
ex2.input("data", in);
ncnn::Mat out2;
ex2.extract("fc1", out2); // 512-dim embedding
// Compare
float similarity = get_similarity(embedding1, embedding2);