C#集成ViewFaceCore人脸检测识别库
前言
人脸检测与识别现在已经很成熟了,C# 上有 ViewFaceCore 这个很方便的库,但这种涉及到 native 调用的库,一般会有一些坑,本文记录一下开发和部署的过程。
本文的项目是 AIHub
,关于本项目的开发过程,可以参考之前的文章:项目完成小结:使用Blazor和gRPC开发大模型客户端
而且经过最近一个月的工作,我把这个项目重构了一遍,界面换成了 Ant Design ,增加了很多功能,更多的我会在后续的博客文章中分享。
先看效果
多目标检测,我一下就想到了以前读书时很火的「少女时代」
ViewFaceCore简介
这是一个基于 SeetaFace6 的 .NET 人脸识别解决方案
SeetaFace6
是中科视拓最新开源的商业正式版本。突破了之前社区版和企业版版本不同步发布的情况,这次开源的v6版本正式与商用版本同步。
主要做了对 SeetaFace6 的 .Net 封装。
支持以下功能:
- 年龄预测
- 眼睛状态检测
- 性别预测
- 人脸检测
- 口罩检测 / 戴口罩关键定定位,5个关键点
- 人脸关键定定位 (5点 / 68点)
- 人脸识别 (5点 / 68点)
- 活体检测
- 姿态检测
- 质量检测
在 C# 中使用非常简单,不过因为是调用了C++的库,所以部署的时候会有点小坑,本文记录了这些小坑和解决方案。
添加依赖
先添加以下依赖
<PackageReference Include="ViewFaceCore" Version="0.3.8" />
<PackageReference Include="ViewFaceCore.all_models" Version="6.0.7" />
<PackageReference Include="ViewFaceCore.Extension.ImageSharp" Version="0.3.7" />
<PackageReference Include="ViewFaceCore.runtime.ubuntu.20.04.x64" Version="6.0.7" />
<PackageReference Include="ViewFaceCore.runtime.win.x64" Version="6.0.7" />
以 ViewFaceCore.runtime.
开头的运行时,需要根据开发和部署的环境来安装,我这里安装了 Windows 版和 Linux 版本。
注意 Linux 版本还依赖 libgomp1
这个库,如果使用的时候报错,需要先安装。
人脸检测
很简单,先创建个 FaceDetector
对象。
因为这个模型是调用了非托管资源,所以要记得使用 using
或者手动调用 Dispose
方法释放资源。
using FaceDetector _faceDetector = new();
然后传入图片对象就可以进行检测了,如果检测到人脸,会返回人脸框的四个坐标。
支持三种图片库:
- SkiaSharp
- ImageSharp
- System.Drawing
第三个是微软官方的,据说要 Obsolete 了,所以我一般用 ImageSharp ,纯 C# 实现,跨平台也好用。
需要安装 ViewFaceCore.Extension.ImageSharp
依赖以支持 ImageSharp 图片。
简单例子
先来一个最简单的例子,检测人脸,并把人脸框出来。
public async Task<byte[]> DrawFaceFrame(byte[] imageBuffer, string format = "jpg") {
using var inputStream = new MemoryStream(imageBuffer);
using var image = await Image.LoadAsync(inputStream);
var faceInfos = await _faceDetector.DetectAsync(image);
foreach (var face in faceInfos) {
image.Mutate(x => {
x.Draw(
Color.HotPink, 2.5f,
new RectangleF(face.Location.X, face.Location.Y, face.Location.Width, face.Location.Height)
);
});
}
using var outputStream = new MemoryStream();
await image.SaveAsync(outputStream, image.DetectEncoder($"demo.{format}"));
return outputStream.ToArray();
}
以上代码实现了传入 byte[] 类型的图片流,然后输出画了人脸框的图片,同样是 byte[]
类型。
非常滴简单,不过 ImageSharp 的文档太少了,还是得探索一下才知道咋画方框。
完整用法
以前文「先看效果」为例,先定义一下数据结构
public class FaceItem {
public FaceInfo FaceInfo { get; set; }
public FaceMarkPoint[] FaceMarkPoints { get; set; }
public float[]? FaceFeatures { get; set; }
public byte[]? ImageBuffer { get; set; }
}
public class FaceDetectResult {
public List<FaceItem> FaceItems { get; set; }
public byte[] ImageBuffer { get; set; }
}
需要使用 ViewFaceCore 里的三个对象
// 人脸检测
private readonly FaceDetector _faceDetector = new();
// 人脸标记点位
private readonly FaceLandmarker _faceMark = new();
// 人脸识别
private readonly FaceRecognizer _faceRecognizer = new();
关键代码
PS:代码写得很粗糙,性能一般般,只是凑合能用
/// <summary>
/// 人脸检测
/// </summary>
/// <param name="extractFeatures">是否提取人脸特征</param>
/// <param name="cropEveryFace">是否裁剪每个人脸小图</param>
/// <returns></returns>
public async Task<FaceDetectResult> Detect(
byte[] imageBuffer, string format = "jpg",
bool extractFeatures = false, bool cropEveryFace = false
) {
var font = GetFont("segoeui.ttf");
using var inputStream = new MemoryStream(imageBuffer);
using var image = await Image.LoadAsync<Rgba32>(inputStream);
using var resultImage = image.Clone();
var result = new FaceDetectResult { FaceItems = new List<FaceItem>() };
var faceInfos = await _faceDetector.DetectAsync(image);
foreach (var face in faceInfos) {
var faceItem = new FaceItem {
FaceInfo = face,
FaceMarkPoints = await _faceMark.MarkAsync(image, face)
};
// 提取人脸特征
if (extractFeatures) {
faceItem.FaceFeatures = await _faceRecognizer.ExtractAsync(image, faceItem.FaceMarkPoints);
}
// 裁剪人脸小图
if (cropEveryFace) {
using var faceImage = image.Clone();
var cropRect = GetCropRect(face, 5);
try {
faceImage.Mutate(x => x.Crop(cropRect));
}
catch (ArgumentException ex) {
faceImage.Mutate(x => x.Crop(GetCropRect(face, 0)));
}
using (var faceImageStream = new MemoryStream()) {
await faceImage.SaveAsync(faceImageStream, faceImage.DetectEncoder($"demo.{format}"));
faceItem.ImageBuffer = faceImageStream.ToArray();
}
}
result.FaceItems.Add(faceItem);
// 画人脸框
resultImage.Mutate(x => {
x.Draw(
Color.HotPink, 2.5f,
new RectangleF(face.Location.X, face.Location.Y, face.Location.Width, face.Location.Height)
);
x.DrawText(
$"face:{face.Score}", font, Color.HotPink,
new PointF(face.Location.X, face.Location.Y - 20)
);
});
}
using var outputStream = new MemoryStream();
await resultImage.SaveAsync(outputStream, resultImage.DetectEncoder($"demo.{format}"));
result.ImageBuffer = outputStream.ToArray();
return result;
}
字体和生成矩形的代码
ImageSharp 的文档非常缺乏,每一步都需要经过大量的搜索……
private Font GetFont(string fontFileName) {
var path = !string.IsNullOrWhiteSpace(_pathPrefix) ? Path.Combine(_pathPrefix, fontFileName) : fontFileName;
FontCollection collection = new();
FontFamily family = collection.Add(path);
return family.CreateFont(20, FontStyle.Bold);
}
private static Rectangle GetCropRect(FaceInfo faceInfo, int cropOffset) {
return new Rectangle(faceInfo.Location.X - cropOffset, faceInfo.Location.Y - cropOffset,
faceInfo.Location.Width + cropOffset * 2, faceInfo.Location.Height + cropOffset * 2);
}
人脸识别
人脸识别的思路:
- 检测到人脸
- 确定人脸关键点位置 (5点/68点)
- 根据关键点提取特征
- 在向量数据库中搜索该特征对应的人
最后一步使用了向量数据库,其实不用也行,人脸特征提取出来是 float[]
类型,理论上保存在任何地方都行,然后识别的时候把人脸特征拿出来与保存的特征库做遍历对比。
FaceRecognizer
对象提供了 Compare
功能,可以计算两个人脸特征的相似度。
这个特征其实是个向量,所以理论上是可以自己用其他算法来计算相似度,比如
- 基于距离的欧氏距离、曼哈顿距离、
- 夹角余弦
- 皮尔逊相关系数
在上面人脸检测的「完整用法」中,已经把检测人脸、关键点位置、特征提取这部分搞定了。
接下来需要做的
- 人脸信息录入,需要传统关系型数据库搭配向量数据库,或者是 PostgreSql 这类支持向量存储的数据库也行
- 人脸信息比对,使用向量数据库的向量搜索功能,或者自行实现向量搜索算法
因为篇幅限制,本文就不展开人脸识别这一块内容了,接下来有时间单独写一篇文章。
部署
接下来是填坑。
使用 docker 部署应用
本项目使用 .Net Core 7.0 所以对应使用 mcr.microsoft.com/dotnet/aspnet:7.0
基础镜像
这个镜像是基于 Debian11 系统制作
默认没有 libgomp1
这个库,需要自行添加
apt 软件源
首先准备 sources.list
文件,用于修改 apt 仓库为国内源
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free
# deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free
# # deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free
deb https://security.debian.org/debian-security bullseye-security main contrib non-free
# deb-src https://security.debian.org/debian-security bullseye-security main contrib non-free
dockerfile
在 base
构建阶段,安装 libgomp1
这个库
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
COPY ./sources.list /etc/apt/sources.list
RUN apt update && apt install libgomp1
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM base AS final
WORKDIR /app
COPY . .
ENTRYPOINT ["./AIHub.Blazor"]
docker-compose.yml
version: '3.6'
services:
web:
image: ${DOCKER_REGISTRY-}web
container_name: aihub
restart: always
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:80
build:
context: .
volumes:
- .:/app
networks:
- default
- swag
networks:
swag:
name: swag
external: true
default:
name: aihub
启动!
一切准备就绪。
C#,启动!
docker compose up --build -d
参考资料
- https://github.com/ViewFaceCore/ViewFaceCore/
- https://mirrors.tuna.tsinghua.edu.cn/help/debian/
- https://stackoverflow.com/questions/70183074/oserror-libgomp-so-1-not-found-when-importing-gluoncv-through-azure-app-service
- https://docs.sixlabors.com/api/ImageSharp.Drawing/SixLabors.ImageSharp.Drawing.Processing.DrawRectangleExtensions.html
C#集成ViewFaceCore人脸检测识别库的更多相关文章
- Emgu cv人脸检测识别
Emgu cv人脸检测识别 1.开发平台:WIN10 X64 VS2012 Emgucv版本:3.1 2.先给大家分享一个官网给的示例源代码: https://ncu.dl.sourcef ...
- Python学习案例之视频人脸检测识别
前言 上一篇博文与大家分享了简单的图片人脸识别技术,其实在实际应用中,很多是通过视频流的方式进行识别,比如人脸识别通道门禁考勤系统.人脸动态跟踪识别系统等等. 案例 这里我们还是使用 opencv 中 ...
- Python学习案例之人脸检测识别
前言 随着科技的发展,人脸识别技术在许多领域得到的非常广泛的应用,手机支付.银行身份验证.手机人脸解锁等等. 识别 废话少说,这里我们使用 opencv 中自带了 haar人脸特征分类器,利用训练好的 ...
- 基于AdaBoost算法——世纪晟结合Haar-like特征训练人脸检测识别
AdaBoost 算法是一种快速人脸检测算法,它将根据弱学习的反馈,适应性地调整假设的错误率,使在效率不降低的情况下,检测正确率得到了很大的提高. 系统在技术上的三个贡献: 1.用简单的Haa ...
- MTCNN人脸检测识别笔记
论文:Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks 论文链接:https:// ...
- Python视频人脸检测识别
案例 这里我们还是使用 opencv 中自带了 haar人脸特征分类器,通过读取一段视频来识别其中的人脸. 代码实现: 动图有点花,讲究着看吧: 如果是捕捉摄像头,只需要改变以下代码即可: c ...
- 人脸检测识别,人脸检测,人脸识别,离线检测,C#源码
百度网盘地址 微云地址 使用虹软人工智能开放平台技术开发完成
- 图片人脸检测——Dlib版(四)
上几篇给大家讲了OpenCV的图片人脸检测,而本文给大家带来的是比OpenCV更加精准的图片人脸检测Dlib库. 点击查看往期: <图片人脸检测——OpenCV版(二)> <视频人脸 ...
- MTCNN人脸检测 附完整C++代码
人脸检测 识别一直是图像算法领域一个主流话题. 前年 SeetaFace 开源了人脸识别引擎,一度成为热门话题. 虽然后来SeetaFace 又放出来 2.0版本,但是,我说但是... 没有训练代码, ...
- Python 3 利用 Dlib 实现人脸检测和剪切
0. 引言 利用 Python 开发,借助 Dlib 库进行人脸检测 / face detection 和剪切: 1. crop_faces_show.py : 将检测到的人脸剪切下来,依次排序平 ...
随机推荐
- P3498 [POI2010]KOR-Beads 题解
前言: 最近在做哈希的题,发现了这道好题,看题解里很多大佬的方法都很巧妙,自己就发一个较为朴素的方法吧. 题意: 题目传送门 给你一个序列,需要求出数 k,使划分的子串长度为 k 时,不同的子串数量最 ...
- 【技术积累】Mysql中的SQL高级技巧【一】
什么是多表查询?如何在MySQL中进行多表查询? 多表查询就是在一个查询中涉及到多个表,通过特定的关联方式连接多个表,并根据条件从中查询出所需要的数据. 多表查询是关系型数据库中最为基础的应用之一. ...
- C++ 单例模式的各种坑及最佳实践
单例模式是设计模式中最简单.常见的一种.其主要目的是确保整个进程中,只有一个类的实例,并且提供一个统一的访问接口.常用于 Logger 类.通信接口类等. 基本原理 限制用户直接访问类的构造函数,提供 ...
- GO 项目依赖管理:go module总结
转载请注明出处: 1.go module介绍 go module是go官方自带的go依赖管理库,在1.13版本正式推荐使用 go module可以将某个项目(文件夹)下的所有依赖整理成一个 go.mo ...
- sharding-jdbc分库连接数优化
一.背景: 配运平台组的快递订单履约中心(cp-eofc)及物流平台履约中心(jdl-uep-ofc)系统都使用了ShardingSphere生态的sharding-jdbc作为分库分表中间件, 整个 ...
- Federated Learning004
联邦学习--笔记004 2023.03.13周一 快中期答辩了(3.20),最近甲流高发期 毕设期间,今天学习了联邦学习的一篇论文---Differentially Private Federated ...
- 超详细整合SSM框架--(Spring + Spring MVC + MyBatis)
超详细整合SSM框架--(Spring + Spring MVC + MyBatis) 阅读该文章之前首先要清楚Spring框架,SpringMVC框架,Mybatis框架. SSM框架,是Sprin ...
- golang技术降本增效的手段
最近一年各大中小厂都在搞"优化",说到优化,目的还是"降本增效",降低成本,增加效益(效率). 技术层面,也有一些降本增效的常规操作. 比如池化.io缓冲区技术 ...
- 深度系统安装wine
step1: 输入命令: sudo dpkg --add-architecture i386 step2: 1.切换成管理员权限: sudo su 2.打开源文件 vi /etc/apt/source ...
- QLabel类中的常用方法&信号
setAlignment: 按固定值方式对齐文本 Qt.AlignLeft:水平方向靠左对齐 Qt.AlignRight:水平方向靠右对齐 Qt.AlignCenter:水平方向居中对齐 Qt.Ali ...