C#集成ViewFaceCore人脸检测识别库

2025-12-13 0 132

前言#

人脸检测识别现在已经很成熟了,C# 上有 ViewFaceCore 这个很方便的库,但这种涉及到 native 调用的库,一般会有一些坑,本文记录一下开发和部署的过程。

本文的项目是AIHub,关于本项目的开发过程,可以参考之前的文章:项目完成小结:使用Blazor和gRPC开发大模型客户端

而且经过最近一个月的工作,我把这个项目重构了一遍,界面换成了 Ant Design ,增加了很多功能,更多的我会在后续的博客文章中分享。

先看效果#

多目标检测,我一下就想到了以前读书时很火的「少女时代」

C#集成ViewFaceCore人脸检测识别库

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

作者:DealiAxy

出处:https://www.cnblogs.com/deali/p/17716884.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 C#集成ViewFaceCore人脸检测识别库 https://www.zuozi.net/36452.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务