FaceRecoTrackService 是一个基于 .NET 8.0 开发的高性能人脸识别与追踪服务系统。该系统集成了深度学习模型(YOLOv8 人脸检测 + ArcFace 特征提取)、向量数据库(Qdrant)和关系型数据库(PostgreSQL),实现了完整的人脸注册、识别和轨迹追踪功能。识别阶段默认采用本地余弦相似度比对(不依赖 Qdrant 相似度检索)。
- 高精度人脸检测:基于 YOLOv8s-face 模型,支持实时人脸检测
- 特征向量提取:使用 ArcFace 模型提取 512 维特征向量
- 相似度比对:本地余弦相似度比对(从 PostgreSQL 读取向量)
- 实时监控识别:通过 FTP 文件夹监控,自动处理新的人脸快照
- 轨迹追踪记录:记录人员在不同摄像头间的移动轨迹和时间信息
- 清晰度筛选:自动过滤模糊人脸,确保识别质量
- RESTful API:提供完整的 HTTP API 接口,支持人脸注册、查询、删除和轨迹查询
- 框架:.NET 8.0 (ASP.NET Core)
- 数据库:PostgreSQL 10.0+
- 向量数据库:Qdrant 1.16+
- 深度学习:ONNX Runtime 1.23+
- 图像处理:EmguCV 4.12+, SkiaSharp 3.119+
- API 文档:Swagger/OpenAPI
- Windows 10/11 或 Windows Server 2016+
- .NET 8.0 Runtime(单文件发布版本无需安装)
- PostgreSQL 10.0+ 数据库
- Qdrant 向量数据库服务
-
安装 PostgreSQL
- 下载并安装 PostgreSQL:https://www.postgresql.org/download/
- 创建数据库(或使用默认的 postgres 数据库)
-
安装 Qdrant
- 使用 Docker:
docker run -p 6333:6333 qdrant/qdrant - 或下载 Windows 版本:https://qdrant.tech/documentation/guides/installation/
- 使用 Docker:
-
准备模型文件
- 确保
res/model/目录包含以下模型文件:yolov8s-face.onnx- 人脸检测模型
arcface.onnx- 人脸特征提取模型(112x112 输入,512 维输出)
- 确保
编辑 appsettings.json 文件,配置以下关键参数:
{
"ConnectionStrings": {
"Postgres": "Host=localhost;Port=5432;Username=postgres;Password=your_password;Database=postgres"
},
"Qdrant": {
"Host": "localhost",
"Port": 6334,
"CollectionName": "face_collection",
"UseHttps": false,
"ApiKey": "",
"RecreateOnVectorSizeMismatch": true
},
"FaceRecognition": {
"YoloModelPath": "res/model/yolov8s-face.onnx",
"FaceNetModelPath": "res/model/arcface.onnx",
"DetectionConfidence": 0.45,
"IouThreshold": 0.45,
"FaceExpandRatio": 20,
"BaseSharpnessThreshold": 15.0,
"SizeThresholdCoefficient": 0.0002,
"VectorSize": 512,
"FeatureInputWidth": 112,
"FeatureInputHeight": 112,
"EnableHistogramEqualization": false,
"OnnxIntraOpNumThreads": 0,
"OnnxInterOpNumThreads": 0,
"EnableDebugSaveFaces": false,
"DebugSaveDir": "snapshots/registrations"
},
"Pipeline": {
"PollIntervalMs": 2000,
"SnapshotWorkerCount": 2,
"SnapshotQueueSize": 200,
"MinFaceCount": 1,
"TopK": 5,
"SimilarityThreshold": 0.87,
"FallbackSimilarityThreshold": 0.78,
"SnapshotSaveDir": "snapshots",
"DeleteProcessedSnapshots": true
},
"FtpFolder": {
"Path": "res/ftp",
"IncludeSubdirectories": true,
"FilePatterns": [ "*.jpg", "*.jpeg", "*.png" ],
"DefaultCameraName": "unknown",
"DefaultLocation": "unknown"
}
}字段说明(逐项)
-
ConnectionStrings -
ConnectionStrings.Postgres:PostgreSQL 连接字符串(主机、端口、账号、密码、数据库名)。 -
Qdrant -
Qdrant.Host:Qdrant 服务地址。 -
Qdrant.Port:Qdrant 服务端口(默认 6334)。 -
Qdrant.CollectionName:向量集合名称(人脸向量存储的集合)。 -
Qdrant.UseHttps:是否启用 HTTPS 连接。 -
Qdrant.ApiKey:Qdrant API Key(如未启用可留空)。 -
Qdrant.RecreateOnVectorSizeMismatch:向量维度不一致时是否重建集合。 -
FaceRecognition -
FaceRecognition.YoloModelPath:YOLO 人脸检测模型文件路径。 -
FaceRecognition.FaceNetModelPath:特征提取模型文件路径(ArcFace)。 -
FaceRecognition.DetectionConfidence:人脸检测置信度阈值(越大越严格)。 -
FaceRecognition.IouThreshold:NMS 交并比阈值。 -
FaceRecognition.FaceExpandRatio:人脸裁剪时向外扩展像素数。 -
FaceRecognition.BaseSharpnessThreshold:基础清晰度阈值(拉普拉斯方差基准)。 -
FaceRecognition.SizeThresholdCoefficient:清晰度动态阈值系数(随人脸尺寸变化)。 -
FaceRecognition.VectorSize:特征向量维度(需与模型输出一致)。 -
FaceRecognition.FeatureInputWidth:特征模型输入宽度(ArcFace 默认 112)。 -
FaceRecognition.FeatureInputHeight:特征模型输入高度(ArcFace 默认 112)。 -
FaceRecognition.EnableHistogramEqualization:是否启用直方图均衡化(ArcFace 通常关闭)。 -
FaceRecognition.OnnxIntraOpNumThreads:ONNX IntraOp 线程数(0 为默认)。 -
FaceRecognition.OnnxInterOpNumThreads:ONNX InterOp 线程数(0 为默认)。 -
FaceRecognition.EnableDebugSaveFaces:是否保存调试用的人脸裁剪图片。 -
FaceRecognition.DebugSaveDir:调试人脸图片保存目录。 -
Pipeline -
Pipeline.PollIntervalMs:FTP 目录轮询间隔(毫秒)。 -
Pipeline.MinFaceCount:图片中最少人脸数量要求。 -
Pipeline.SnapshotWorkerCount:并行处理快照的工作线程数。 -
Pipeline.SnapshotQueueSize:快照处理队列容量。 -
Pipeline.TopK:相似度检索返回的 TopK 数量(若启用向量库检索)。 -
Pipeline.SimilarityThreshold:主相似度阈值(用于判定同一人)。 -
Pipeline.FallbackSimilarityThreshold:备用相似度阈值(主阈值无结果时使用)。 -
Pipeline.SnapshotSaveDir:快照保存目录。 -
Pipeline.DeleteProcessedSnapshots:是否删除已处理的快照文件。 -
FtpFolder -
FtpFolder.Path:监控的 FTP 本地目录路径。 -
FtpFolder.IncludeSubdirectories:是否递归子目录。 -
FtpFolder.FilePatterns:监控的文件后缀模式(支持通配符)。 -
FtpFolder.DefaultCameraName:未解析到摄像头信息时的默认名称。 -
FtpFolder.DefaultLocation:未解析到地点信息时的默认位置。
-
运行打包脚本:
build.bat
-
打包完成后,在
dist/FaceTrackService/目录下找到:FaceTrackService.exe- 单文件可执行程序res/- 模型文件目录appsettings.json- 配置文件
-
将整个
publish目录复制到目标服务器
dotnet publish FaceRecoTrackService/FaceRecoTrackService.csproj ^
--configuration Release ^
--runtime win-x64 ^
--self-contained true ^
--output dist/FaceTrackService ^
/p:PublishSingleFile=true ^
/p:IncludeNativeLibrariesForSelfExtract=true ^
/p:EnableCompressionInSingleFile=true-
直接运行
cd dist/FaceTrackService FaceTrackService.exe -
作为 Windows 服务运行(需要额外配置)
- 使用脚本(在发布目录
scripts/下):register-service.bat- 注册服务service-status.bat- 查看服务状态stop-service.bat- 关闭服务restart-service.bat- 重启服务
- 或使用 NSSM / Windows Service Wrapper
- 使用脚本(在发布目录
-
访问 API 文档
- 开发环境:http://localhost:5000/swagger
- 生产环境:根据配置的端口访问
通过 API 接口注册新的人脸信息,系统会:
- 检测图片中的人脸
- 筛选清晰的人脸(基于拉普拉斯方差)
- 提取人脸特征向量(512 维)
- 将信息存储到 PostgreSQL(含向量)和 Qdrant
API 端点:POST /api/face/register
请求示例:
{
"base64Image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
"userName": "张三",
"ip": "192.168.1.100",
"description": "测试用户",
"isTest": false
}响应示例:
{
"success": true,
"message": "注册成功",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}系统通过后台服务 FtpRecognitionWorker 持续监控指定文件夹:
- 轮询间隔:默认 2000ms(可配置)
- 自动检测新的人脸快照文件
- 提取人脸特征并与已注册人脸进行本地相似度匹配(余弦相似度)
- 记录识别结果到轨迹表
工作流程:
- 监控
FtpFolder.Path目录下的图片文件 - 检测图片中的人脸
- 从 PostgreSQL 读取已注册向量并计算相似度
- 如果相似度超过阈值,记录轨迹信息
- 处理完成后可选择删除已处理的快照文件
根据人员 ID 查询其在不同摄像头间的移动轨迹。
API 端点:GET /api/track/{id}?pageNum=1&pageSize=20
响应示例:
{
"success": true,
"message": "查询guid轨迹成功",
"data": {
"list": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"抓拍时间": "2026-01-24 10:30:15",
"抓拍地点": "大厅",
"抓拍摄像头": "192.168.1.101",
"录像摄像头": "192.168.1.101",
"录像开始时间": "2026-01-24 10:30:15",
"录像结束时间": "2026-01-24 10:35:20"
}
],
"pagesize": 20,
"pagenum": 1,
"total": 1
}
}- 查询人脸数量:
GET /api/face/count- 获取 PostgreSQL 中注册的人脸数量 - 查询 Qdrant 数量:
GET /api/face/qdrant/count- 获取 Qdrant 向量库中的向量数量 - 获取人脸信息:
GET /api/face/getfaceinfo/{id}- 根据 ID 获取人脸详细信息 - 删除人脸:
DELETE /api/face/deletefaceinfo/{id}- 删除指定的人脸信息(同时删除 PostgreSQL 和 Qdrant 中的数据)
- URL:
POST /api/face/register - 请求体:
{ "base64Image": "string (Base64编码的图片)", "userName": "string (用户名)", "ip": "string (可选,IP地址)", "description": "string (可选,描述信息)", "isTest": "boolean (可选,是否测试数据)" } - 响应:返回注册成功的人脸 ID(GUID)
- URL:
GET /api/face/count - 响应:返回 PostgreSQL 中的人脸记录数量
- URL:
GET /api/face/qdrant/count - 响应:返回 Qdrant 集合中的向量数量
- URL:
GET /api/face/getfaceinfo/{id} - 参数:
id- 人脸唯一标识(GUID) - 响应:返回人脸详细信息(不包含 Base64 图片)
- URL:
DELETE /api/face/deletefaceinfo/{id} - 参数:
id- 人脸唯一标识(GUID) - 响应:返回删除结果
- URL:
GET /api/track/{id}?pageNum=1&pageSize=20 - 参数:
id- 人员唯一标识(GUID)pageNum- 页码(默认:1)pageSize- 每页数量(默认:20)
- 响应:返回分页的轨迹记录列表
FaceRecoTrackService/
├── API/
│ └── Controllers/ # API 控制器
│ ├── FaceController.cs # 人脸管理接口
│ └── TrackController.cs # 轨迹查询接口
├── Core/
│ ├── Algorithms/ # 核心算法
│ │ ├── FaceDetector.cs # 人脸检测器
│ │ ├── FaceFeatureService.cs # 特征提取服务
│ │ ├── ImageUtils.cs # 图像工具类
│ │ └── SharpnessEvaluator.cs # 清晰度评估器
│ ├── Dtos/ # 数据传输对象
│ ├── Models/ # 数据模型
│ └── Options/ # 配置选项类
├── Infrastructure/
│ ├── Database/ # 数据库上下文
│ ├── External/ # 外部服务客户端
│ └── Repositories/ # 数据仓储
├── Services/ # 业务服务
│ ├── FaceRegistrationService.cs # 人脸注册服务
│ ├── FaceDeletionService.cs # 人脸删除服务
│ ├── FaceQueryService.cs # 人脸查询服务
│ ├── FtpRecognitionWorker.cs # FTP 监控后台服务
│ ├── TrackQueryService.cs # 轨迹查询服务
│ └── TrackRecordService.cs # 轨迹记录服务
├── Utils/ # 工具类
│ └── QdrantUtil/ # Qdrant 工具
├── res/ # 资源文件
│ └── model/ # AI 模型文件
│ ├── yolov8s-face.onnx
│ └── arcface.onnx
├── Program.cs # 程序入口
└── appsettings.json # 配置文件
- 功能:使用 YOLOv8s-face ONNX 模型检测图片中的人脸
- 主要方法:
DetectFaces(SKImage image)- 检测人脸并返回检测结果列表CropAndFilterSharpFaces()- 裁剪人脸并筛选清晰的人脸
- 功能:使用 ArcFace 模型提取人脸特征向量(默认 112x112 输入、512 维输出)
- 主要方法:
ExtractFeaturesFromStream(Stream imageStream)- 从流中提取特征向量ExtractFeatures(string imagePath)- 从文件路径提取特征向量CalculateSimilarity(float[] feat1, float[] feat2)- 计算两个向量的余弦相似度
- 功能:基于拉普拉斯方差评估人脸清晰度
- 主要方法:
IsSharp()- 判断人脸是否清晰GetDynamicThreshold()- 根据人脸尺寸计算动态阈值
- 功能:持续监控 FTP 文件夹,自动处理新的人脸快照
- 工作流程:
- 定期扫描配置的文件夹
- 检测新文件并读取图片
- 使用 FaceDetector 检测人脸
- 提取特征并在 PostgreSQL 中进行本地相似度匹配
- 记录轨迹信息到数据库
- 功能:管理 Qdrant 向量数据库的连接和操作
- 主要操作:
- 创建/确保集合存在
- 插入/更新向量点
- 删除/计数(相似度搜索可选)
PostgreSQL 表结构: 系统会在启动时自动创建所需的表结构。主要表包括:
face_persons- 人脸信息表track_records- 轨迹记录表camera_mappings- 摄像头映射表
迁移步骤:
- 备份原数据库数据
- 在新环境中创建 PostgreSQL 数据库
- 启动服务,系统会自动创建表结构
- 如需迁移数据,使用 PostgreSQL 的
pg_dump和pg_restore工具
迁移步骤:
- 导出原 Qdrant 集合数据:
curl -X POST "http://old-qdrant:6333/collections/{collection_name}/points/scroll" \ -H "Content-Type: application/json" \ -d '{"limit": 10000}'
- 在新环境中创建同名集合
- 导入数据到新 Qdrant 实例
确保以下模型文件存在于 res/model/ 目录:
yolov8s-face.onnx- 人脸检测模型(约 20-30MB)arcface.onnx- 特征提取模型(约 90-100MB)
根据新环境修改 appsettings.json:
- 数据库连接字符串
- Qdrant 服务器地址和端口
- FTP 监控路径
- 其他业务配置参数
必需组件:
- .NET 8.0 Runtime(单文件发布无需)
- PostgreSQL 客户端库(已包含在发布包中)
- ONNX Runtime(已包含在发布包中)
- EmguCV 运行时(已包含在发布包中)
网络要求:
- 确保服务可以访问 PostgreSQL 数据库(默认端口 5432)
- 确保服务可以访问 Qdrant 服务(默认端口 6333/6334)
- 如果使用 HTTPS,确保证书配置正确
当前版本针对 Windows x64 平台编译。如需移植到 Linux:
-
修改项目文件:
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
-
修改打包脚本:
- 将运行时标识符改为
linux-x64 - 注意文件路径分隔符(Linux 使用
/)
- 将运行时标识符改为
-
依赖库调整:
- EmguCV 需要使用 Linux 版本
- 确保所有原生库都有 Linux 版本
本服务启动时会自动创建数据库表结构(见 PgSchemaInitializer),核心表如下:
用于存储注册的人脸信息与基础描述。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | PK | 人脸唯一 ID |
| user_name | text | NOT NULL | 用户名 |
| ip | text | NOT NULL | IP 地址 |
| description | text | NULL | 描述信息 |
| is_test | boolean | NOT NULL | 是否测试数据 |
| image_base64 | text | NULL | 原始人脸 Base64 |
| face_vector | real[] | NULL | 人脸特征向量 |
| created_at | timestamptz | NOT NULL | 创建时间 |
用于将抓拍摄像头映射到录像摄像头和房间。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| snap_camera_ip | text | PK | 抓拍摄像头 IP |
| record_camera_ip | text | NOT NULL | 录像摄像头 IP |
| room_name | text | NULL | 房间名称 |
用于记录人脸抓拍与轨迹信息。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | bigserial | PK | 轨迹记录主键 |
| person_id | uuid | NOT NULL | 关联 face_persons.id |
| snap_time | timestamptz | NOT NULL | 抓拍时间(由文件名解析) |
| snap_location | text | NULL | 抓拍地点 |
| snap_camera_ip | text | NOT NULL | 抓拍摄像头 IP |
| record_camera_ip | text | NULL | 录像摄像头 IP |
| record_start_time | timestamptz | NOT NULL | 录像开始时间 |
| record_end_time | timestamptz | NULL | 录像结束时间 |
| created_at | timestamptz | NOT NULL | 记录创建时间 |
| 索引 | 字段 | 说明 |
|---|---|---|
| idx_track_person_time | (person_id, snap_time DESC) | 按人员+时间倒序查询轨迹 |
face_persons1:Ntrack_recordscamera_mapping为抓拍 IP 的辅助映射,未设置时使用默认配置或文件名解析结果
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| YoloModelPath | string | "res/model/yolov8s-face.onnx" | YOLO 人脸检测模型路径 |
| FaceNetModelPath | string | "res/model/arcface.onnx" | ArcFace 特征提取模型路径 |
| DetectionConfidence | float | 0.45 | 人脸检测置信度阈值 |
| IouThreshold | float | 0.45 | NMS 交并比阈值 |
| FaceExpandRatio | int | 20 | 人脸裁剪扩展像素数 |
| BaseSharpnessThreshold | double | 15.0 | 基础清晰度阈值 |
| SizeThresholdCoefficient | double | 0.0002 | 尺寸阈值系数 |
| VectorSize | int | 512 | 特征向量维度 |
| FeatureInputWidth | int | 112 | 特征模型输入宽度 |
| FeatureInputHeight | int | 112 | 特征模型输入高度 |
| EnableHistogramEqualization | bool | false | 是否启用直方图均衡化 |
| OnnxIntraOpNumThreads | int | 0 | ONNX IntraOp 线程数 |
| OnnxInterOpNumThreads | int | 0 | ONNX InterOp 线程数 |
| EnableDebugSaveFaces | bool | false | 是否保存调试人脸图片 |
| DebugSaveDir | string | "snapshots/registrations" | 调试图片保存目录 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PollIntervalMs | int | 2000 | FTP 文件夹轮询间隔(毫秒) |
| SnapshotWorkerCount | int | 2 | 识别工作线程数 |
| SnapshotQueueSize | int | 200 | 快照处理队列容量 |
| MinFaceCount | int | 1 | 最少人脸数量要求 |
| TopK | int | 5 | 相似度搜索返回的 Top K 结果(启用向量库检索时) |
| SimilarityThreshold | float | 0.87 | 主要相似度阈值 |
| FallbackSimilarityThreshold | float | 0.78 | 备用相似度阈值 |
| SnapshotSaveDir | string | "snapshots" | 快照保存目录 |
| DeleteProcessedSnapshots | bool | true | 是否删除已处理的快照文件 |
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| Path | string | "res/ftp" | 监控的文件夹路径 |
| IncludeSubdirectories | bool | true | 是否包含子目录 |
| FilePatterns | string[] | [".jpg", ".jpeg", "*.png"] | 文件匹配模式 |
| DefaultCameraName | string | "unknown" | 默认摄像头名称 |
| DefaultLocation | string | "unknown" | 默认位置名称 |
症状:启动时提示模型文件不存在或加载失败
解决方案:
- 检查
res/model/目录是否存在 - 确认模型文件路径配置正确
- 检查文件权限
症状:无法连接到 PostgreSQL 数据库
解决方案:
- 检查连接字符串配置
- 确认 PostgreSQL 服务正在运行
- 检查网络连接和防火墙设置
- 验证用户名和密码
症状:无法连接到 Qdrant 服务
解决方案:
- 检查 Qdrant 服务是否运行
- 验证主机和端口配置
- 检查 API Key(如果启用)
症状:注册或识别时无法检测到人脸
解决方案:
- 检查图片质量(清晰度、光照)
- 调整
DetectionConfidence参数 - 确认模型文件完整且未损坏
症状:识别结果不准确或误识别
解决方案:
- 调整
SimilarityThreshold和FallbackSimilarityThreshold - 检查特征向量维度是否匹配
- 确保注册时使用清晰的人脸图片
服务运行时会输出日志到控制台。建议在生产环境中配置日志文件输出:
在 appsettings.json 中配置:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
},
"File": {
"Path": "logs/app.log",
"Append": true
}
}
}-
添加新的 API 接口:
- 在
API/Controllers/中创建新的控制器 - 在
Services/中实现业务逻辑 - 在
Program.cs中注册服务
- 在
-
扩展数据模型:
- 在
Core/Models/中定义新模型 - 在
Infrastructure/Repositories/中实现数据访问 - 更新数据库初始化脚本
- 在
-
集成新的 AI 模型:
- 将模型文件放入
res/model/目录 - 创建对应的服务类加载和使用模型
- 在配置文件中添加模型路径配置
- 将模型文件放入
-
模型加载优化:
- 使用单例模式管理模型实例
- 避免重复加载模型
-
数据库优化:
- 为常用查询字段添加索引
- 使用连接池管理数据库连接
-
相似度匹配优化:
- 合理设置
SimilarityThreshold与FallbackSimilarityThreshold - 识别量大时可缓存已注册向量,减少频繁读库
- 合理设置
本项目为内部项目,版权归公司所有。
如有问题或建议,请联系开发团队。
- 初始版本发布
- 实现人脸注册、识别和轨迹追踪功能
- 支持单文件打包部署
- 集成 Swagger API 文档
最后更新:2026-01-24