目录
[2.1.编译 / 安装方式](#2.1.编译 / 安装方式)
[2.2.预训练模型下载(同 Python 版)](#2.2.预训练模型下载(同 Python 版))
1.简介
dlib 是一个跨平台的 C++ 机器学习 / 数值计算库,同时提供了 Python 绑定,以人脸检测 / 识别、特征点提取、机器学习算法 为核心优势,无需复杂配置即可实现工业级的计算机视觉功能。
核心功能:
- 人脸检测(HOG/SVM 或 CNN 模型)
- 人脸特征点标注(68 个关键点定位)
- 人脸识别(特征向量提取 + 相似度计算)
- 基本的图像处理、机器学习算法(如 SVM、决策树)
2.安装与集成
2.1.编译 / 安装方式
1.源码编译(跨平台)
下载 dlib 源码:https://github.com/davisking/dlib
编译并安装(需提前安装 cmake):
cpp
# 克隆源码
git clone https://github.com/davisking/dlib.git
cd dlib
# 创建编译目录
mkdir build && cd build
# 配置编译(Windows/Linux/macOS 通用)
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local # Linux/macOS
# Windows:cmake .. -DCMAKE_INSTALL_PREFIX=D:\dlib
# 编译并安装
cmake --build . --config Release --target install
2.CMake 直接引入
无需安装,将 dlib 源码放入项目目录,在 CMakeLists.txt 中直接引入:
cpp
cmake_minimum_required(VERSION 3.10)
project(face_recognition)
# 引入dlib
add_subdirectory(dlib)
# 链接OpenCV(可选,用于图像读取/显示)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
# 编译可执行文件
add_executable(face_rec main.cpp)
# 链接dlib和OpenCV
target_link_libraries(face_rec dlib::dlib ${OpenCV_LIBS})
2.2.预训练模型下载(同 Python 版)
- 68 特征点模型:shape_predictor_68_face_landmarks.dat
- CNN 人脸检测器:mmod_human_face_detector.dat(解压后使用)
- 人脸识别模型:dlib_face_recognition_resnet_model_v1.dat(解压后使用)
3.人脸识别完整代码
下面提供可直接编译运行的核心代码,包含「人脸检测→特征点提取→特征向量生成→相似度比对」全流程,适配新手的阅读习惯(注释详细)。
cpp
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/matrix.h>
#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
#include <cmath>
// 类型别名(简化代码)
using namespace dlib;
using namespace std;
using namespace cv;
// ---------------------- 核心函数:提取人脸128维特征向量 ----------------------
matrix<float, 0, 1> get_face_descriptor(const string& img_path,
frontal_face_detector& detector,
shape_predictor& sp,
face_recognition_model_v1& face_rec) {
// 1. 读取图片(dlib + OpenCV 结合,兼容更多格式)
cv::Mat img = cv::imread(img_path);
if (img.empty()) {
cerr << "错误:无法读取图片 " << img_path << endl;
return matrix<float, 0, 1>(); // 返回空矩阵
}
// 转换为dlib格式的图像
cv_image<bgr_pixel> dlib_img(img);
// 2. 检测人脸
std::vector<rectangle> faces = detector(dlib_img);
if (faces.empty()) {
cerr << "警告:" << img_path << " 未检测到人脸" << endl;
return matrix<float, 0, 1>();
}
// 3. 提取68特征点(仅处理第一张人脸)
full_object_detection shape = sp(dlib_img, faces[0]);
// 4. 生成128维特征向量
matrix<float, 0, 1> descriptor = face_rec.compute_face_descriptor(dlib_img, shape);
return descriptor;
}
// ---------------------- 核心函数:比对两个人脸特征向量 ----------------------
pair<double, bool> compare_faces(const matrix<float, 0, 1>& desc1,
const matrix<float, 0, 1>& desc2,
double threshold = 0.6) {
if (desc1.size() == 0 || desc2.size() == 0) {
return {0.0, false}; // 空向量直接返回不匹配
}
// 计算欧氏距离(dlib内置范数函数)
double distance = length(desc1 - desc2);
// 相似度(0-1,越高越像)
double similarity = 1 - distance;
// 判断是否为同一人(距离 < 阈值)
bool is_same = (distance < threshold);
return {similarity, is_same};
}
// ---------------------- 人脸对齐(提升准确率,可选) ----------------------
cv::Mat align_face(const cv::Mat& img, const full_object_detection& shape) {
// 标准5个特征点(对应dlib 68点的索引)
std::vector<cv::Point2f> src_pts = {
cv::Point2f(shape.part(36).x(), shape.part(36).y()), // 左眼内角
cv::Point2f(shape.part(45).x(), shape.part(45).y()), // 右眼内角
cv::Point2f(shape.part(30).x(), shape.part(30).y()), // 鼻尖
cv::Point2f(shape.part(48).x(), shape.part(48).y()), // 左嘴角
cv::Point2f(shape.part(54).x(), shape.part(54).y()) // 右嘴角
};
// 目标标准坐标
std::vector<cv::Point2f> dst_pts = {
cv::Point2f(30.2946f, 51.6963f),
cv::Point2f(65.5318f, 51.5014f),
cv::Point2f(48.0252f, 71.7366f),
cv::Point2f(33.5493f, 92.3655f),
cv::Point2f(62.7299f, 92.2041f)
};
// 计算仿射变换矩阵
cv::Mat transform = cv::estimateAffinePartial2D(src_pts, dst_pts);
// 应用变换(对齐后的人脸尺寸150x150)
cv::Mat aligned_face;
cv::warpAffine(img, aligned_face, transform, cv::Size(150, 150));
return aligned_face;
}
// ---------------------- 主函数:测试人脸识别 ----------------------
int main() {
try {
// 1. 加载预训练模型(替换为你的模型路径)
frontal_face_detector detector = get_frontal_face_detector(); // HOG检测器
shape_predictor sp;
deserialize("shape_predictor_68_face_landmarks.dat") >> sp; // 68特征点模型
face_recognition_model_v1 face_rec;
deserialize("dlib_face_recognition_resnet_model_v1.dat") >> face_rec; // 人脸识别模型
// 2. 提取两张人脸的特征向量
string img1_path = "person1.jpg"; // 人脸1
string img2_path = "person1_2.jpg"; // 同一个人(不同角度)
string img3_path = "person2.jpg"; // 另一个人
matrix<float, 0, 1> desc1 = get_face_descriptor(img1_path, detector, sp, face_rec);
matrix<float, 0, 1> desc2 = get_face_descriptor(img2_path, detector, sp, face_rec);
matrix<float, 0, 1> desc3 = get_face_descriptor(img3_path, detector, sp, face_rec);
// 3. 比对人脸
if (desc1.size() > 0 && desc2.size() > 0) {
auto [sim1, same1] = compare_faces(desc1, desc2);
cout << "\n人脸1 vs 人脸2:" << endl;
cout << " 欧氏距离:" << length(desc1 - desc2) << endl;
cout << " 相似度:" << sim1 << endl;
cout << " 是否为同一人:" << (same1 ? "是" : "否") << endl;
}
if (desc1.size() > 0 && desc3.size() > 0) {
auto [sim2, same2] = compare_faces(desc1, desc3);
cout << "\n人脸1 vs 人脸3:" << endl;
cout << " 欧氏距离:" << length(desc1 - desc3) << endl;
cout << " 相似度:" << sim2 << endl;
cout << " 是否为同一人:" << (same2 ? "是" : "否") << endl;
}
} catch (exception& e) {
cerr << "错误:" << e.what() << endl;
return 1;
}
return 0;
}
4.关键知识点
1.C++ 版核心 API 与 Python 的区别
| 功能 | C++ API | Python API |
|---|---|---|
| 人脸检测器 | get_frontal_face_detector() |
dlib.get_frontal_face_detector() |
| 特征点加载 | deserialize("xxx.dat") >> sp |
dlib.shape_predictor("xxx.dat") |
| 特征向量计算 | face_rec.compute_face_descriptor() |
face_rec.compute_face_descriptor() |
| 欧氏距离计算 | length(desc1 - desc2) |
np.linalg.norm(desc1 - desc2) |
2.性能优化(C++ 专属)
启用 O2/O3 优化 :在 CMakeLists.txt 中添加编译优化:
cpp
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -march=native") # Linux/macOS
# Windows:set(CMAKE_CXX_FLAGS_RELEASE "/O2 /MT")
GPU 加速:编译 dlib 时启用 CUDA(需安装 CUDA/cuDNN):
cpp
cmake .. -DUSE_CUDA=1 -DCMAKE_INSTALL_PREFIX=/usr/local
批量处理:C++ 支持直接操作内存缓冲区,可将多张人脸图像批量传入,减少 IO 开销。
5.提高dlib库人脸识别的准确率
5.1.基础优化:提升人脸数据质量
1.人脸预处理:对齐 + 裁剪 + 增强
dlib 的 68 个特征点天然支持人脸对齐(消除角度 / 尺度影响),这是提升准确率的关键步骤。
cpp
import dlib
import cv2
import numpy as np
def align_face(img, shape, desired_width=150, desired_height=150):
"""
基于68特征点进行人脸对齐(消除旋转、缩放、平移影响)
:param img: 原始图像
:param shape: dlib提取的68特征点
:return: 对齐后的人脸图像
"""
# 定义标准人脸特征点(参考坐标,确保对齐后五官位置统一)
standard_landmarks = np.array([
(30.2946, 51.6963), # 左眼内角
(65.5318, 51.5014), # 右眼内角
(48.0252, 71.7366), # 鼻尖
(33.5493, 92.3655), # 左嘴角
(62.7299, 92.2041) # 右嘴角
], dtype=np.float32)
# 提取待对齐人脸的5个关键特征点(对应标准点)
face_landmarks = np.array([
(shape.part(36).x, shape.part(36).y),
(shape.part(45).x, shape.part(45).y),
(shape.part(30).x, shape.part(30).y),
(shape.part(48).x, shape.part(48).y),
(shape.part(54).x, shape.part(54).y)
], dtype=np.float32)
# 计算仿射变换矩阵(实现对齐)
transform_matrix = cv2.estimateAffinePartial2D(face_landmarks, standard_landmarks)[0]
# 应用变换,得到对齐后的人脸
aligned_face = cv2.warpAffine(img, transform_matrix, (desired_width, desired_height))
return aligned_face
# 用法示例(整合到特征提取流程)
def get_aligned_face_descriptor(img_path):
"""提取对齐后的人脸特征向量(准确率更高)"""
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
faces = detector(gray, 1)
if len(faces) == 0:
return None
# 先对齐人脸,再提取特征
shape = predictor(gray, faces[0])
aligned_face = align_face(img, shape)
# 重新检测对齐后的人脸(确保特征提取准确)
aligned_gray = cv2.cvtColor(aligned_face, cv2.COLOR_BGR2GRAY)
aligned_faces = detector(aligned_gray, 1)
if len(aligned_faces) == 0:
return None
aligned_shape = predictor(aligned_gray, aligned_faces[0])
face_rec = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat")
descriptor = face_rec.compute_face_descriptor(aligned_face, aligned_shape)
return np.array(descriptor)
2.数据采集规范(训练 / 注册人脸库时)
- 数量:每人至少采集 3-5 张不同角度(正面、轻微左右偏)、不同光线(室内 / 室外)的人脸;
- 质量:人脸占画面≥70%,无遮挡(口罩、墨镜),无模糊,光线均匀(避免强光 / 逆光);
- 一致性:注册和识别时的人脸大小、角度尽量接近。
5.2.模型与算法优化
1.更换更精准的人脸检测器
dlib 默认的 HOG 检测器速度快但精度一般,可改用CNN 人脸检测器(对小人脸、侧脸、模糊人脸更友好):
cpp
# 下载CNN检测器模型:https://github.com/davisking/dlib-models/raw/master/mmod_human_face_detector.dat.bz2
cnn_detector = dlib.cnn_face_detection_model_v1("mmod_human_face_detector.dat")
# 检测人脸(返回结果需转换格式)
faces_cnn = cnn_detector(gray, 1)
# 转换为普通face_rectangle格式(兼容predictor)
faces = [dlib.rectangle(face.rect.left(), face.rect.top(), face.rect.right(), face.rect.bottom())
for face in faces_cnn]
C++ 版同样支持更精准的 CNN 人脸检测器,替换检测器部分代码即可:
cpp
// 加载CNN检测器模型
mmod_frontal_face_detector cnn_detector;
deserialize("mmod_human_face_detector.dat") >> cnn_detector;
// 检测人脸(返回mmod_rect类型,需转换为rectangle)
std::vector<mmod_rect> cnn_faces = cnn_detector(dlib_img);
std::vector<rectangle> faces;
for (auto& face : cnn_faces) {
faces.push_back(face.rect);
}
注意:CNN 检测器精度更高,但速度比 HOG 慢(CPU 下约慢 3-5 倍,GPU 加速后可弥补)。
2.优化匹配阈值(核心!)
dlib 默认的 0.6 是通用阈值,实际场景需根据自己的数据集调优:
- 步骤 1:收集一批 "同一人不同样本" 和 "不同人样本";
- 步骤 2:计算这批样本的欧氏距离,找到 "同一人最大距离" 和 "不同人最小距离" 的中间值;
- 步骤 3:微调阈值(如 0.55-0.65),平衡 "误识别率" 和 "漏识别率"。
cpp
# 阈值调优示例:计算最优阈值
def find_best_threshold(same_pairs, diff_pairs):
"""
:param same_pairs: 同一人的特征向量对列表 [(desc1, desc2), ...]
:param diff_pairs: 不同人的特征向量对列表 [(desc1, desc2), ...]
:return: 最优阈值
"""
# 计算所有同一人对的距离
same_distances = [np.linalg.norm(d1 - d2) for d1, d2 in same_pairs]
# 计算所有不同人对的距离
diff_distances = [np.linalg.norm(d1 - d2) for d1, d2 in diff_pairs]
# 找阈值:同一人最大距离 < 阈值 < 不同人最小距离
max_same = np.max(same_distances)
min_diff = np.min(diff_distances)
best_threshold = (max_same + min_diff) / 2
print(f"同一人最大距离:{max_same:.4f}")
print(f"不同人最小距离:{min_diff:.4f}")
print(f"推荐阈值:{best_threshold:.4f}")
return best_threshold
# 用法:
# same_pairs = [(desc1_1, desc1_2), (desc2_1, desc2_2), ...] # 同一人的不同样本
# diff_pairs = [(desc1, desc2), (desc1, desc3), ...] # 不同人的样本
# best_thresh = find_best_threshold(same_pairs, diff_pairs)
3.多特征融合(进阶)
对同一人脸提取多次特征(不同角度 / 缩放),取平均值作为最终特征向量,降低单次提取的误差:
cpp
def get_average_descriptor(img_path, times=3):
"""提取多次特征并取平均"""
descriptors = []
for _ in range(times):
desc = get_aligned_face_descriptor(img_path) # 复用对齐后的特征提取函数
if desc is not None:
descriptors.append(desc)
if len(descriptors) == 0:
return None
# 取平均值
avg_desc = np.mean(descriptors, axis=0)
return avg_desc
5.3.工程落地优化
1.去除背景干扰
- 识别前对人脸区域进行裁剪(只保留人脸部分,排除背景);
- 对人脸进行直方图均衡化,提升光线不足时的特征提取稳定性:
cpp
# 直方图均衡化(提升光线鲁棒性)
gray = cv2.cvtColor(aligned_face, cv2.COLOR_BGR2GRAY)
equalized_gray = cv2.equalizeHist(gray)
2.GPU 加速(大幅提升速度,间接提升准确率)
dlib 支持 CUDA 加速,安装带 GPU 的 dlib 版本后,特征提取速度提升 10-20 倍,可实时处理更高分辨率的人脸,减少因 "降分辨率" 导致的精度损失:
cpp
# 安装带CUDA的dlib(需先安装CUDA和cuDNN)
pip install dlib --no-cache-dir --force-reinstall
3.过滤低质量人脸
识别前先判断人脸质量,拒绝模糊 / 遮挡的人脸:
cpp
def is_face_quality_ok(face_img, threshold=30):
"""判断人脸是否清晰(基于拉普拉斯方差)"""
gray = cv2.cvtColor(face_img, cv2.COLOR_BGR2GRAY)
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
blur_score = np.var(laplacian)
return blur_score > threshold # 方差越大,越清晰
# 用法:在特征提取前过滤
aligned_face = align_face(img, shape)
if not is_face_quality_ok(aligned_face):
print("人脸模糊,跳过")
return None
6.总结
- C++ 版 dlib 是原生实现,性能远高于 Python 版,核心流程与 Python 一致:检测→特征点→特征向量→比对;
- 编译时需注意:引入 dlib/OpenCV 依赖、启用编译优化、按需开启 GPU 加速;
- 关键 API 差异:C++ 使用
deserialize加载模型,length()计算欧氏距离,需手动处理异;