同系列文章:
前言
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc、grpc-java、grpc-go。其中 C 版本支持 C、C++、Node.js、Python、Ruby、Objective-C、PHP 和 C# 语言。
gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特性,这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
服务定义
FrService.proto
syntax = "proto3"; option csharp_namespace = "Com.FirstSolver.FR"; option java_multiple_files = true; option java_package = "Com.FirstSolver.FR"; option java_outer_classname = "FrServiceProto"; option optimize_for = SPEED; // 优化:速度 package splash; // --------------- 服务定义 --------------- service FrService { // 比较当前图像和目标图像,给出相似度得分+人脸框位置 rpc Compare(stream FaceIdRequestMsg) returns (stream FaceIdResponseMsg) {} } // --------------- 消息定义 --------------- // 图像数据 message FaceIdRequestMsg { // 图像编号 int32 index = 1; // 图像数据 bytes photo = 2; } // 人脸矩形框 message FrFaceRect { int32 top = 1; int32 bottom = 2; int32 left = 3; int32 right = 4; } // 比对结果 message FaceIdResponseMsg { // 图像编号 int32 index = 1; // 比对状态 int32 status = 2; // 相似度得分 float score = 3; // 人脸框位置 FrFaceRect face = 4; }
编译命令文件
generate_protos.bat
@rem 自动生成C#代码 setlocal @rem 更改当前目录为批处理本身的目录 cd /d %~dp0 set TOOLS_PATH=packages\Grpc.Tools.1.6.1\tools\windows_x64 %TOOLS_PATH%\protoc.exe --proto_path=./FrService/protos --csharp_out=FrService ./FrService/protos/FrService.proto --grpc_out=FrService --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe endlocal
服务实现
FrServiceImpl.cs
using Com.FirstSolver.Splash; using Grpc.Core; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Threading.Tasks; namespace Com.FirstSolver.FR { public class FrServiceImpl : FrService.FrServiceBase, IDisposable { public delegate void FaceIdCompareEventHandler(object sender, FaceIdCompareEventArgs e); public event FaceIdCompareEventHandler OnFaceIdCompareEvent = null; /// <summary> /// 人证比对引擎 /// </summary> protected HWFRCore FaceReader = null; /// <summary> /// 构造函数 /// </summary> public FrServiceImpl() { // 初始化人证比对引擎 FaceReader = new HWFRCore(); } // 人证比对 public override async Task Compare(IAsyncStreamReader<FaceIdRequestMsg> requestStream, IServerStreamWriter<FaceIdResponseMsg> responseStream, ServerCallContext context) { FaceIdCompareEventArgs Args = new FaceIdCompareEventArgs(); byte[] ReferenceFeature = null; while (await requestStream.MoveNext()) { Args.CountAll++; FaceIdRequestMsg RequestMsg = requestStream.Current; FaceIdResponseMsg ResponseMsg = new FaceIdResponseMsg() { Index = RequestMsg.Index, Status = 0 }; try { using (MemoryStream ms = new MemoryStream(RequestMsg.Photo.ToByteArray())) { using (Bitmap bmp = new Bitmap(ms)) { byte[] GrayLinearArray = bmp.ToGrayLinearArray(out byte[] RgbLinearArray); // 检测人脸 bool IsOK = false; byte[] SourceFeature = null; if (FaceReader.DetectOne(GrayLinearArray, RgbLinearArray, bmp.Width, bmp.Height, out FR_TFACEINFO FaceInfo) == 1) { // 提取人脸特征 SourceFeature = FaceReader.ExtractFeature(GrayLinearArray, bmp.Width, bmp.Height, ref FaceInfo); if (SourceFeature != null) IsOK = true; } if (IsOK) { FR_TRECT Face = FaceInfo.m_FaceRect; ResponseMsg.Status = 1; // 成功 ResponseMsg.Face = new FrFaceRect() { Top = Face.top, Bottom = Face.bottom, Left = Face.left, Right = Face.right }; if (RequestMsg.Index == 1) { // 用于比对的基准图像 ReferenceFeature = SourceFeature; } else if (ReferenceFeature != null) { // 比对人脸特征 if (FaceReader.Compare(SourceFeature, ReferenceFeature, out float fScore)) { ResponseMsg.Score = fScore; Args.CountPass++; } else { ResponseMsg.Status = 0; // 失败 Args.CountDeny++; } } else { Args.CountException++; } } } } } catch { Args.CountException++; } await responseStream.WriteAsync(ResponseMsg); } // End While OnFaceIdCompareEvent?.Invoke(this, Args); } /// <summary> /// 资源释放 /// </summary> public void Dispose() { // 关闭人证比对引擎 if (FaceReader != null) FaceReader.Dispose(); } } public class FaceIdCompareEventArgs { /// <summary> /// 图像处理数 /// </summary> public int CountAll = 0; /// <summary> /// 比对通过数 /// </summary> public int CountPass = 0; /// <summary> /// 比对失败数 /// </summary> public int CountDeny = 0; /// <summary> /// 比对异常数 /// </summary> public int CountException = 0; } }