当前位置:   article > 正文

C# 超简单的离线人脸识别库。( 基于 SeetaFace6 )_c# seetaface

c# seetaface

目录​​​​​​​

介绍

1. 关于

2. 快速开始

2.1 受支持的 .NET 框架 和 操作系统

2.2 简单的人脸信息检测

3、基本说明

4、模型设置

5、调用说明 

5.1对象生命周期

5.2线程安全

5.3初始化配置

5.4输出内部日志


介绍

github地址:https://github.com/ViewFaceCore/ViewFaceCore

C# 超简单的离线人脸识别库。( 基于 SeetaFace6 )

1. 关于

一个基于 SeetaFace6 的 .NET 人脸识别解决方案
本项目受到了 SeetaFaceEngine.Net 的启发
开源、免费、跨平台 (win/linux)

2. 快速开始

2.1 受支持的 .NET 框架 和 操作系统

目标框架    最低版本    操作系统
.NET Framework    4.0    win ( x64/x86 )
.NET Standard    2.0    win ( x64/x86 )
.NET / .NET Core    3.1、5.0、6.0、7.0    win ( x64/x86 )、linux ( arm/arm64/x64 )

2.2 简单的人脸信息检测

以 Windows x64平台 为例,一个简单的人脸检测Demo。

1、使用 nuget 安装依赖

包名称                                                  说明
ViewFaceCore                                      ViewFaceCore .NET 核心库
ViewFaceCore.all_models                    人脸检测的模型支持(图省事可以直接安装这个)
ViewFaceCore.runtime.win.x64            Windows-x64 的本机运行时,其它平台自行选择安装,可安装多个
ViewFaceCore.Extension.SkiaSharp     SkiaSharp图像处理扩展,ImageSharp、SkiaSharp、System.Drawing三选一

2、获取人脸信息

using SkiaSharp;
using System;
using ViewFaceCore.Core;
using ViewFaceCore.Model;

namespace ViewFaceCore.Demo.ConsoleApp
{
    internal class Program
    {
        private readonly static string imagePath = @"images/Jay_3.jpg";

        static void Main(string[] args)
        {
            using var bitmap = SKBitmap.Decode(imagePath);
            using FaceDetector faceDetector = new FaceDetector();
            FaceInfo[] infos = faceDetector.Detect(bitmap);
            Console.WriteLine($"识别到的人脸数量:{infos.Length} 个人脸信息:\n");
            Console.WriteLine($"No.\t人脸置信度\t位置信息");
            for (int i = 0; i < infos.Length; i++)
            {
                Console.WriteLine($"{i}\t{infos[i].Score:f8}\t{infos[i].Location}");
            }
            Console.ReadKey();
        }
    }
}

  1. using SkiaSharp;
  2. using System;
  3. using ViewFaceCore.Core;
  4. using ViewFaceCore.Model;
  5. namespace ViewFaceCore.Demo.ConsoleApp
  6. {
  7. internal class Program
  8. {
  9. private readonly static string imagePath = @"images/Jay_3.jpg";
  10. static void Main(string[] args)
  11. {
  12. using var bitmap = SKBitmap.Decode(imagePath);
  13. using FaceDetector faceDetector = new FaceDetector();
  14. FaceInfo[] infos = faceDetector.Detect(bitmap);
  15. Console.WriteLine($"识别到的人脸数量:{infos.Length} 个人脸信息:\n");
  16. Console.WriteLine($"No.\t人脸置信度\t位置信息");
  17. for (int i = 0; i < infos.Length; i++)
  18. {
  19. Console.WriteLine($"{i}\t{infos[i].Score:f8}\t{infos[i].Location}");
  20. }
  21. Console.ReadKey();
  22. }
  23. }
  24. }

3、基本说明

为了兼容各个平台,我们分别编号好了各个平台的SeetaFace6以及ViewFaceBridge(用于通过C#调用C++写的SeetaFace6)。并打包好,发布到nuget上面。使用时,按需安装对应平台的nuget包。比如windows x64平台,安装对应的nuget包ViewFaceCore.runtime.win.x64。runtime可以同时安装多个平台,但是不能不安装,至少需要安装一个当前平台对应的runtime。
支持的平台以及nuget包如下表所示:

Nuget包名输出目录说明
ViewFaceCore.runtime.win.x64viewfacecore/win/x64Windows,x64
ViewFaceCore.runtime.win.x86viewfacecore/win/x86Windows,x86
ViewFaceCore.runtime.ubuntu.20.04.x64viewfacecore/linux/x64Linux,x64;支持Ubuntu20.04+、Debian10+、Deepin20+等较新的debian系Linux系统
ViewFaceCore.runtime.linux.armviewfacecore/linux/armLinux,armhf;支持树莓派,nanopi等
ViewFaceCore.runtime.linux.arm64viewfacecore/linux/arm64Linux,arm64;支持树莓派,nanopi等

4、模型设置

Nuget包名说明
ViewFaceCore.all_models包含全部模型。不知道装哪一个时,装这个就行了,但是包特别大(300多MB)
ViewFaceCore.model.age_predictor年龄预测
ViewFaceCore.model.eye_state眼睛状态检测
ViewFaceCore.model.gender_predictor性别预测
ViewFaceCore.model.face_detector人脸检测
ViewFaceCore.model.mask_detector口罩检测
ViewFaceCore.model.face_landmarker_mask_pts5戴口罩关键定定位,5个关键点
ViewFaceCore.model.face_landmarker_pts5关键定定位,5个关键点
ViewFaceCore.model.face_landmarker_pts68关键定定位,68个关键点
ViewFaceCore.model.face_recognizer人脸识别,68个关键点
ViewFaceCore.model.face_recognizer_light人脸识别,5个关键点
ViewFaceCore.model.face_recognizer_mask人脸识别,戴口罩
ViewFaceCore.model.fas_first活体检测,局部
ViewFaceCore.model.fas_second活体检测,全局
ViewFaceCore.model.pose_estimation姿态检测
ViewFaceCore.model.quality_lbn质量检测

5、调用说明 

5.1对象生命周期

这里的对象的生命周期指的是人脸识别中各个功能对象的生命周期,并不是C#中GC和对象的生命周期。虽然也和C#中对象生命周期密不可分,但是这并不是这一小节的主题,这里不会过多的解释C#语言本身的特性。
用FaceDetector举个例子。在FaceDetector的构造函数中

public FaceDetector(FaceDetectConfig config = null)
{
    this.DetectConfig = config ?? new FaceDetectConfig();
    _handle = ViewFaceNative.GetFaceDetectorHandler(this.DetectConfig.FaceSize
        , this.DetectConfig.Threshold
        , this.DetectConfig.MaxWidth
        , this.DetectConfig.MaxHeight
        , (int)this.DetectConfig.DeviceType);
    if (_handle == IntPtr.Zero)
    {
        throw new Exception("Get face detector handler failed.");
    }
}
通过Native调用的方式,调用C++项目ViewFaceBridge中的函数GetFaceDetectorHandler获取SeetaFace6中seeta::v6::FaceDetector对象的IntPtr句柄。
ViewFaceBridge中的函数GetFaceDetectorHandler函数代码如下:

View_Api seeta::v6::FaceDetector *GetFaceDetectorHandler(const double faceSize = 20, const double threshold = 0.9, const double maxWidth = 2000, const double maxHeight = 2000, const SeetaDevice deviceType = SEETA_DEVICE_AUTO)
{
    seeta::v6::FaceDetector *faceDetector = new seeta::v6::FaceDetector(ModelSetting(modelPath + "face_detector.csta", deviceType));
    faceDetector->set(FaceDetector::Property::PROPERTY_MIN_FACE_SIZE, faceSize);
    faceDetector->set(FaceDetector::Property::PROPERTY_THRESHOLD, threshold);
    faceDetector->set(FaceDetector::Property::PROPERTY_MAX_IMAGE_WIDTH, maxWidth);
    faceDetector->set(FaceDetector::Property::PROPERTY_MAX_IMAGE_HEIGHT, maxHeight);
    return faceDetector;
}
当对象使用完毕后,FaceDetector中Dispose方法中通过Native调用DisposeFaceDetector函数,释放掉seeta::v6::FaceDetector对象。

View_Api void DisposeFaceDetector(seeta::v6::FaceDetector *handler)
{
    _dispose(handler);
}
综上所述,在编写代码的过程中,一定要使用using语句或在结束后调用Dispose释放掉对象。且SeetaFace6对象的构造和释放会比较耗时,其中涉及到模型加载、计算等,建议尽可能的复用对象以及在需要频繁使用新对象的场景中使用对象池。
对象复用,又涉及到线程安全的问题。更多关于线程安全的细节,请继续阅读下一节。

5.2线程安全

线程安全也是开发中需要重点关注的特性。然而,线程安全在不同的上下文解释中总会有不同解释。为了避免理解的偏差,这里用几种不同的用例去解释识别器的使用。

1. 对象可以跨线程传递。线程1构造的识别器,可以在线程2中调用。
2. 对象的构造可以并发构造,即可以多个线程同时构造识别器。
3. 单个对象的接口调用不可以并发调用,即单个对象,在多个线程同时使用是被禁止的。
来源:入门教程 1.5 线程安全性 http://leanote.com/blog/post/5e7d6cecab64412ae60016ef#title-11

因为SeetaFace6本身不支持多线程调用,所以在这个库设计的时候,在每个不支持并发操作的功能中通过加锁限制并发调用。可以认为,在单个对象的不同操作中,是线程安全的。

5.3初始化配置

在一些场景下,比如不支持AVX2指令集、需要拿取内部日志等场景下,默认设置并不能满足要求。为此,我们提供了一个全局配置项:GlobalConfig,下面的小节将具体介绍支持的特性。

5.4输出内部日志

在生产环境或者某些不方便调试场景下,又出现一些莫名其妙的问题的时候,不妨看看内部日志,说不定有不一样的收获。

static void Config()
{
    //打印内部日志
    GlobalConfig.SetLog((msg) =>
    {
        Console.WriteLine($"[内部日志]{msg}");
    });
}

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/229406
推荐阅读
相关标签
  

闽ICP备14008679号