feat 人脸检测

This commit is contained in:
2024-08-26 15:08:30 +08:00
parent f80d36c9b2
commit 7493e5a3a3
29 changed files with 422 additions and 205 deletions

View File

@@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.Middle", "Src\Dlhis.M
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dlhis.DataPermission.Model", "Src\Dlhis.DataPermission.Model\Dlhis.DataPermission.Model.csproj", "{CA1427E2-CC70-4489-8653-1C05630C8392}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.InfoCheck.Api", "Src\Dlhis.InfoCheck.Api\Dlhis.InfoCheck.Api.csproj", "{A501D16E-638F-4156-989C-2BACCC2FAC2B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -129,6 +131,10 @@ Global
{CA1427E2-CC70-4489-8653-1C05630C8392}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA1427E2-CC70-4489-8653-1C05630C8392}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA1427E2-CC70-4489-8653-1C05630C8392}.Release|Any CPU.Build.0 = Release|Any CPU
{A501D16E-638F-4156-989C-2BACCC2FAC2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A501D16E-638F-4156-989C-2BACCC2FAC2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A501D16E-638F-4156-989C-2BACCC2FAC2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A501D16E-638F-4156-989C-2BACCC2FAC2B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -148,6 +154,7 @@ Global
{69E8A91A-5D05-4327-BC24-038523C7628C} = {489252FB-A44B-46EE-B065-21CDCB724441}
{053BF7B2-B1A0-435F-9C77-2EF5622CC5C5} = {65E76F97-E78A-4C95-B788-4091236B1A79}
{4D656761-8CE7-4316-A3DF-8C1722D69CCE} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A}
{A501D16E-638F-4156-989C-2BACCC2FAC2B} = {4EBCE46B-CE3A-4A47-9432-82A1854CA58A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7439494A-E2FD-4FEA-8ABF-74AE57A4A5A0}

View File

@@ -25,6 +25,7 @@
<ItemGroup>
<ProjectReference Include="..\Dlhis.Entity\Dlhis.Entity.csproj" />
<ProjectReference Include="..\Dlhis.InfoCheck.Api\Dlhis.InfoCheck.Api.csproj" />
<ProjectReference Include="..\Dlhis.Scheduled.Api\Dlhis.Scheduled.Api.csproj" />
<ProjectReference Include="..\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj" />
</ItemGroup>

View File

@@ -1,4 +1,5 @@
using Dlhis.Basic.Organization.Request;
using System.ComponentModel.DataAnnotations;
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response;
using Dlhis.Basic.Organization.Services;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
@@ -43,4 +44,15 @@ public class FactorySettingController : ControllerBase
{
await _factorySettingService.SaveAsync(request);
}
/// <summary>
/// 根据factory获取配置
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
[HttpGet("single")]
public async Task<FactorySettingResponse> GetFactorySettingAsync([Required(ErrorMessage = "厂区不可为空")] string factory)
{
return await _factorySettingService.GetFactorySettingAsync(factory);
}
}

View File

@@ -1,48 +0,0 @@
using Dlhis.Basic.Device.Filters;
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Services;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Basic.Organization.Controllers;
/// <summary>
/// 外包人员配置
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class GainfoOutsourceSettingController : ControllerBase
{
private readonly IGainfoOutsourceSettingService _gainfoOutSourceService;
public GainfoOutsourceSettingController(IGainfoOutsourceSettingService gainfoOutSourceService)
{
_gainfoOutSourceService = gainfoOutSourceService;
}
/// <summary>
/// 保存配置
/// </summary>
/// <param name="request"></param>
[HttpPost("save")]
[AssignPermissionLimit]
[Transactional]
[CrossTenant]
public async Task SaveAsync(GainfoOutsourceSettingSaveRequest request)
{
await _gainfoOutSourceService.SaveAsync(request);
}
/// <summary>
/// 获取当前厂区配置
/// </summary>
/// <returns></returns>
[HttpGet("current")]
public async Task<object> GetSettingAsync()
{
return await _gainfoOutSourceService.GetSettingAsync();
}
}

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Dlhis.Entity.Basic.Dto;
namespace Dlhis.Basic.Organization.Request;
@@ -16,4 +17,9 @@ public class FactorySettingSaveRequest
/// 档案二维码过期时间
/// </summary>
public int? UserQrCodeExpiration { get; set; }
/// <summary>
/// 人脸检测配置
/// </summary>
public FaceImageDetectionDto FaceImageDetection { get; set; }
}

View File

@@ -1,3 +1,5 @@
using Dlhis.Entity.Basic.Dto;
namespace Dlhis.Basic.Organization.Response;
public class FactorySettingResponse
@@ -15,4 +17,9 @@ public class FactorySettingResponse
/// 档案二维码过期时间
/// </summary>
public int? UserQrCodeExpiration { get; set; }
/// <summary>
/// 人脸检测
/// </summary>
public FaceImageDetectionDto FaceImageDetection { get; set; }
}

View File

@@ -8,4 +8,6 @@ public interface IFactorySettingService : IScopeDependency
Task<List<FactorySettingResponse>> GetListAsync();
Task SaveAsync(FactorySettingSaveRequest request);
Task<FactorySettingResponse> GetFactorySettingAsync(string factory);
}

View File

@@ -1,10 +0,0 @@
using Dlhis.Basic.Organization.Request;
namespace Dlhis.Basic.Organization.Services;
public interface IGainfoOutsourceSettingService : IScopeDependency
{
Task SaveAsync(GainfoOutsourceSettingSaveRequest request);
Task<object> GetSettingAsync();
}

View File

@@ -1,8 +1,13 @@
using System.Reflection;
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response;
using Dlhis.Entity.Basic.Dto;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Sys.Entities;
using Dlhis.Sys.Api;
using Dlhis.Sys.Api.Response;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using Mapster;
namespace Dlhis.Basic.Organization.Services.Implements;
@@ -20,24 +25,7 @@ public class FactorySettingService : IFactorySettingService
public async Task<List<FactorySettingResponse>> GetListAsync()
{
var apiResult = await _tenantApi.GetMyTenantsAsync();
var factories = apiResult.Data;
var factoryCodes = factories.Select(x => x.Code).ToList();
var settings = await _dbContext.Queryable<FactorySettingEntity>().Where(x => factoryCodes.Contains(x.TenantId))
.ToListAsync();
return factories.Select(item =>
{
var factory = factories.FirstOrDefault(x => x.Code == item.Code);
return new FactorySettingResponse
{
Factory = factory?.Code,
FactoryName = factory?.Name,
EnableOutsourceDown = settings.FirstOrDefault(x => x.TenantId == item.Code)?.EnableOutsourceDown ?? false,
UserQrCodeExpiration = settings.FirstOrDefault(x => x.TenantId == item.Code)?.UserQrCodeExpiration
};
}).ToList();
return await GetFactorySettingsAsync();
}
public async Task SaveAsync(FactorySettingSaveRequest request)
@@ -58,4 +46,60 @@ public class FactorySettingService : IFactorySettingService
await _dbContext.UpdateAsync(setting);
}
}
public async Task<FactorySettingResponse> GetFactorySettingAsync(string factory)
{
var settings = await GetFactorySettingsAsync(factory);
var setting = settings.FirstOrDefault() ?? new FactorySettingResponse();
setting.UserQrCodeExpiration ??= 60 * 1000 * 60;
setting.FaceImageDetection ??= new FaceImageDetectionDto
{
Enable = true,
Detections = typeof(FaceQualityTypeEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Select(x => new FaceImageDetection
{
Type = Enum.Parse<FaceQualityTypeEnumType>(x!.GetValue(null)!.ToString()!),
Level = FaceQualityLevelEnumType.Medium
}).ToList()
};
return setting;
}
//************************************************************************************************************************************************************
private async Task<List<FactorySettingResponse>> GetFactorySettingsAsync(string factory = null)
{
List<TenantResponse> factories;
if (factory.IsPresent())
{
factories = new List<TenantResponse> { new() { Code = factory } };
}
else
{
var apiResult = await _tenantApi.GetMyTenantsAsync();
factories = apiResult.Data;
}
var factoryCodes = factories.Select(x => x.Code).ToList();
var settings = await _dbContext.Queryable<FactorySettingEntity>()
.Where(x => factoryCodes.Contains(x.TenantId))
.ToListAsync();
return factories.Select(item =>
{
var currentFactory = factories.FirstOrDefault(x => x.Code == item.Code);
var currentSetting = settings.FirstOrDefault(x => x.TenantId == item.Code);
return new FactorySettingResponse
{
Factory = currentFactory?.Code,
FactoryName = currentFactory?.Name,
EnableOutsourceDown = currentSetting?.EnableOutsourceDown ?? false,
UserQrCodeExpiration = currentSetting?.UserQrCodeExpiration,
FaceImageDetection = currentSetting?.FaceImageDetection
};
}).ToList();
}
}

View File

@@ -1,9 +1,12 @@
using Dlhis.Basic.Device.Services;
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response;
using Dlhis.Entity.Basic.Dto;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Device.Enums;
using Dlhis.InfoCheck.Api;
using Dlhis.InfoCheck.Api.Requests;
using Dlhis.Scheduled.Api;
using Dlhis.Scheduled.Api.Request;
using Kurisu.AspNetCore.Authentication.Abstractions;
@@ -26,6 +29,8 @@ public class GainfoFaceService : IGainfoFaceService
private readonly ICurrentUser _currentUser;
private readonly IHangfireApi _hangfireApi;
private readonly IDevicePermissionService _devicePermissionService;
private readonly IFactorySettingService _factorySettingService;
private readonly IInfoCheckApi _infoCheckApi;
private readonly IDataProtectionProvider _dataProtectionProvider;
public GainfoFaceService(IGainfoStore gainfoStore,
@@ -35,6 +40,8 @@ public class GainfoFaceService : IGainfoFaceService
ICurrentUser currentUser,
IHangfireApi hangfireApi,
IDevicePermissionService devicePermissionService,
IFactorySettingService factorySettingService,
IInfoCheckApi infoCheckApi,
IDataProtectionProvider dataProtectionProvider)
{
_gainfoStore = gainfoStore;
@@ -45,10 +52,11 @@ public class GainfoFaceService : IGainfoFaceService
_currentUser = currentUser;
_hangfireApi = hangfireApi;
_devicePermissionService = devicePermissionService;
_factorySettingService = factorySettingService;
_infoCheckApi = infoCheckApi;
_dataProtectionProvider = dataProtectionProvider;
}
public async Task<GainfoFacePageSummaryResponse> GetPageAsync(GainfoFacePageRequest request)
{
var factories = request.Factories;
@@ -96,11 +104,12 @@ public class GainfoFaceService : IGainfoFaceService
var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.External)
.Where(x => x.IdNo == request.UserNo)
.FirstAsync();
.SingleAsync();
gainfo ??= await _gainfoStore.Queryable(GainfoStatusEnumType.Working)
.Where(x => x.IdNo == request.UserNo)
.FirstAsync();
.SingleAsync();
gainfo.ThrowIfNull("人员信息不存在");
var face = await _faceDbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
@@ -186,25 +195,20 @@ public class GainfoFaceService : IGainfoFaceService
public async Task UploadFaceAsync(GainfoUploadFaceRequest request)
{
var gainfo = await _gainfoStore.Queryable().Where(x => x.No == request.UserNo).FirstAsync();
var gainfo = await _gainfoStore.Queryable().Where(x => x.No == request.UserNo || x.Code == request.UserNo).SingleAsync();
gainfo.ThrowIfNull("人员档案信息不存在");
var userId = _currentUser.GetIntSubjectId();
await DetectFaceImageQualityAsync(request.Face);
var face = await _faceDbContext.Queryable<GainfoFaceEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
var taskType = face == null ? DeviceTaskEnumType.Add : DeviceTaskEnumType.Update;
if (face == null)
{
face = new GainfoFaceEntity
{
UserCode = gainfo.Code,
Face = request.Face,
CreateTime = DateTime.Now,
ModifiedTime = DateTime.Now,
CreatedBy = userId,
ModifiedBy = userId
Face = request.Face
};
await _faceDbContext.InsertAsync(face);
@@ -218,8 +222,6 @@ public class GainfoFaceService : IGainfoFaceService
}
face.Face = request.Face;
face.ModifiedBy = userId;
face.ModifiedTime = DateTime.Now;
await _faceDbContext.UpdateAsync(face);
}
@@ -236,9 +238,6 @@ public class GainfoFaceService : IGainfoFaceService
_logger.LogError(e, "上传face数据到sap失败:{message}", e.Message);
}
// var prefix = gainfo.Factory == "501" ? "jschuneng" : "jingke";
// var url = $"https://pay.aizhuhotel.com/{prefix}/api/face";
//生成任务
await _devicePermissionService.GenerateDeviceTasksAsync(gainfo.No, taskType, DeviceTaskSourceEnumType.Photo);
}
@@ -328,4 +327,42 @@ public class GainfoFaceService : IGainfoFaceService
return faceDictionary;
}
//*********************************************************************************************************************************************
/// <summary>
/// 人脸质量检测
/// </summary>
/// <param name="base64Image"></param>
/// <param name="factory"></param>
/// <exception cref="UserFriendlyException"></exception>
private async Task DetectFaceImageQualityAsync(string base64Image, string factory = null)
{
var currentFactory = factory ?? _currentUser.GetStringTenantId();
var factorySetting = await _factorySettingService.GetFactorySettingAsync(currentFactory);
if (factorySetting.FaceImageDetection.Enable)
{
List<string> r;
try
{
var result = await _infoCheckApi.FaceDetectAsync(new FaceDetectRequest
{
Base64 = base64Image,
CheckList = factorySetting.FaceImageDetection.Detections.Select(x => new FaceDetectCheckRequest
{
Type = (int)x.Type,
Level = (int)x.Level
}).ToList()
});
r = result.Data;
}
catch (Exception)
{
return;
}
r.IsPresent().ThrowIfTrue($"{r.Join("\r\n")}");
}
}
}

View File

@@ -1,71 +0,0 @@
using Dlhis.Basic.Device.Services;
using Dlhis.Basic.Organization.Request;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Sys.Entities;
using Kurisu.AspNetCore.Authentication.Abstractions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Basic.Organization.Services.Implements;
public class GainfoOutsourceSettingService : IGainfoOutsourceSettingService
{
private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser;
private readonly IDevicePermissionService _devicePermissionService;
public GainfoOutsourceSettingService(IDbContext dbContext, ICurrentUser currentUser, IDevicePermissionService devicePermissionService)
{
_dbContext = dbContext;
_currentUser = currentUser;
_devicePermissionService = devicePermissionService;
}
public async Task SaveAsync(GainfoOutsourceSettingSaveRequest request)
{
var userNos = await _dbContext.Queryable<GainfoEntity>()
.Where(x => SqlFunc.Subqueryable<OutsourceEntity>().Where(p => p.Code == x.Code).Any())
.Select(x => x.No)
.ToListAsync();
await _devicePermissionService.GenerateDeviceTasksAsync(async () =>
{
var currentTenantId = _currentUser.GetStringTenantId();
(!request.Id.HasValue && await _dbContext.Queryable<FactorySettingEntity>()
.Where(x => x.TenantId == currentTenantId)
.AnyAsync()).ThrowIfTrue("保存失败,请检查参数");
if (!request.Id.HasValue)
{
var entity = new FactorySettingEntity
{
EnableOutsourceDown = request.EnableFactory,
TenantId = currentTenantId
};
await _dbContext.InsertAsync(entity);
}
else
{
var entity = await _dbContext.Queryable<FactorySettingEntity>().Where(x => x.Id == request.Id).SingleAsync();
entity.ThrowIfNull("数据不存在,保存失败");
entity.EnableOutsourceDown = request.EnableFactory;
await _dbContext.UpdateAsync(entity);
}
}, userNos);
}
public async Task<object> GetSettingAsync()
{
var currentTenantId = _currentUser.GetStringTenantId();
return await _dbContext.Queryable<FactorySettingEntity>().Where(x => x.TenantId == currentTenantId).Select(x => new
{
x.Id, EnableFactory = x.EnableOutsourceDown
}).SingleAsync();
}
}

View File

@@ -10,21 +10,26 @@ public class GainfoQrCodeService : IGainfoQrCodeService
{
private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser;
private readonly IFactorySettingService _factorySettingService;
public GainfoQrCodeService(IDbContext dbContext, ICurrentUser currentUser)
public GainfoQrCodeService(IDbContext dbContext, ICurrentUser currentUser, IFactorySettingService factorySettingService)
{
_dbContext = dbContext;
_currentUser = currentUser;
_factorySettingService = factorySettingService;
}
public async Task<string> GetMyQrCodeAsync(bool isNeedRefresh = false)
{
var jinkoCode = _currentUser.GetUserClaim("jinko-code");
jinkoCode = "0123456";
if (jinkoCode.IsEmpty())
{
return null;
}
var factory = _currentUser.GetStringTenantId();
var now = DateTime.Now;
var gainfoQrCode = await _dbContext.Queryable<GainfoQrCodeEntity>().SingleAsync(x => x.UserCode == jinkoCode);
@@ -39,7 +44,8 @@ public class GainfoQrCodeService : IGainfoQrCodeService
await _dbContext.InsertAsync(gainfoQrCode);
}
if (gainfoQrCode.ModifiedTime.AddMinutes(60) >= now && !isNeedRefresh)
var setting = await _factorySettingService.GetFactorySettingAsync(factory);
if (gainfoQrCode.ModifiedTime.AddMinutes(setting.UserQrCodeExpiration!.Value) >= now && !isNeedRefresh)
{
return gainfoQrCode.QrCode;
}

View File

@@ -22,7 +22,6 @@ public class Startup : DefaultStartup
public override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);
services.AddHttpContextAccessor();
services.AddRedis();
}
}

View File

@@ -8,7 +8,8 @@
"InternalRequest": {
"CommonRequestUrl": "http://localhost:5001",
"SysRequestUrl": "http://localhost:5003",
"ScheduledRequestUrl": "http://localhost:5010"
"ScheduledRequestUrl": "http://localhost:5010",
"InfoCheckRequestUrl":"http://localhost:5048"
},
"FaceUrlOptions": {
"Url": "http://localhost:5002/api/gainfos/face?token=",

View File

@@ -9,7 +9,8 @@
"InternalRequest": {
"CommonRequestUrl": "http://common",
"SysRequestUrl": "http://sys",
"ScheduledRequestUrl": "http://Scheduled"
"ScheduledRequestUrl": "http://Scheduled",
"InfoCheckRequestUrl": "http://192.168.199.115:5048"
},
"FaceUrlOptions": {
"Url": "https://yikatong.isawesome.cn/api/basic/gainfos/face?token=",

View File

@@ -0,0 +1,29 @@
using Dlhis.Entity.Basic.Enums;
namespace Dlhis.Entity.Basic.Dto;
public class FaceImageDetectionDto
{
/// <summary>
/// 开关
/// </summary>
public bool Enable { get; set; }
/// <summary>
/// 检查项
/// </summary>
public List<FaceImageDetection> Detections { get; set; }
}
public class FaceImageDetection
{
/// <summary>
/// 检查类型
/// </summary>
public FaceQualityTypeEnumType Type { get; set; }
/// <summary>
/// 要求登记
/// </summary>
public FaceQualityLevelEnumType Level { get; set; }
}

View File

@@ -0,0 +1,23 @@
using System.ComponentModel;
namespace Dlhis.Entity.Basic.Enums;
[Description("质量评估等级")]
public enum FaceQualityLevelEnumType
{
/// <summary>错误</summary>
[Description("错误")]
Error = -1,
/// <summary>质量差</summary>
[Description("质量差")]
Low = 0,
/// <summary>质量一般</summary>
[Description("质量一般")]
Medium = 1,
/// <summary>质量高</summary>
[Description("质量高")]
High = 2
}

View File

@@ -0,0 +1,46 @@
using System.ComponentModel;
namespace Dlhis.Entity.Basic.Enums;
/// <summary>
/// 人脸照片检测类型
/// </summary>
[Description("人脸照片质量类型类型")]
public enum FaceQualityTypeEnumType
{
/// <summary>
/// 亮度评估
/// </summary>
[Description("亮度")]
Brightness = 0,
/// <summary>
/// 完整度评估
/// </summary>
[Description("完整度")]
Integrity = 2,
/// <summary>
/// 姿态评估(深度)
/// </summary>
[Description("姿态")]
PoseEx = 4,
/// <summary>
/// 分辨率评估
/// </summary>
[Description("分辨率")]
Resolution = 5,
/// <summary>
/// 清晰度评估(深度
/// </summary>
[Description("清晰度")]
ClarityEx = 6,
/// <summary>
/// 遮挡评估
/// </summary>
[Description("遮挡")]
Structure = 7
}

View File

@@ -1,3 +1,4 @@
using Dlhis.Entity.Basic.Dto;
using Kurisu.AspNetCore.DataAccess.Entity;
using Kurisu.AspNetCore.DataAccess.SqlSugar;
using SqlSugar;
@@ -28,5 +29,11 @@ public class FactorySettingEntity : SugarBaseEntity, ITenantId
[SugarColumn(ColumnDescription = "电子餐券二维码过期时间", IsNullable = true)]
public int? EMealVoucherQrCodeExpiration { get; set; }
/// <summary>
/// 人脸检测配置
/// </summary>
[SugarColumn(ColumnDescription = "人脸检测配置", IsNullable = true, IsJson = true)]
public FaceImageDetectionDto FaceImageDetection { get; set; }
public string TenantId { get; set; }
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Kurisu.RemoteCall" Version="0.4.2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
using Dlhis.InfoCheck.Api.Requests;
using Kurisu.RemoteCall.Attributes;
using Kurisu.RemoteCall.Default;
namespace Dlhis.InfoCheck.Api;
/// <summary>
/// 信息检查
/// </summary>
[EnableRemoteClient(Name = "infocheck-service", BaseUrl = "${InternalRequest:InfoCheckRequestUrl}")]
public interface IInfoCheckApi
{
/// <summary>
/// 检测人脸质量
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Post("/api/face/detection")]
Task<DefaultApiResult<List<string>>> FaceDetectAsync(FaceDetectRequest request);
}

View File

@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.InfoCheck.Api.Requests;
public class FaceDetectRequest
{
[Required]
public string Base64 { get; set; }
public List<FaceDetectCheckRequest> CheckList { get; set; }
}
public class FaceDetectCheckRequest
{
public int Type { get; set; }
public int Level { get; set; }
}

View File

@@ -2,30 +2,25 @@ using Microsoft.AspNetCore.Mvc;
using SkiaSharp;
using ViewFaceCore.Core;
using ViewFaceCore.Model;
using ViewFaceCore.Exceptions;
using ViewFaceCore;
using ViewFaceCore.Configs;
using Microsoft.AspNetCore.Authorization;
using Dlhis.InfoCheck.Request;
using Dlhis.InfoCheck.Response;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.InfoCheck.Controllers;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class FaceController : ControllerBase
{
/// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// 人脸质量检测
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost("detection")]
public object FacialDetection(FaceDetectRequest request)
public IEnumerable<string> FacialDetection(FaceDetectRequest request)
{
var base64Bytes = Convert.FromBase64String(request.Base64);
using var stream = new MemoryStream(base64Bytes);
@@ -37,34 +32,30 @@ public class FaceController : ControllerBase
MarkType = MarkType.Light
});
//todo <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var info = faceDetector.Detect(bitmap).First();
var markPoints = faceMark.Mark(bitmap, info);
using var faceQuality = new FaceQuality();
var brightnessResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Brightness);
var resolutionResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Resolution);
//var clarityResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Clarity);
var clarityExResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.ClarityEx);
var integrityExResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Integrity);
var structureeResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Structure);
//var poseResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Pose);
var poseExeResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.PoseEx);
var qualityResult = new List<QualityResultEx>(6);
qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Brightness));
return new
qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Resolution));
//var clarityResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Clarity);
qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.ClarityEx));
qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Integrity));
qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.Structure));
//var poseResult = faceQuality.Detect(bitmap, info, markPoints, QualityType.Pose);
qualityResult.Add(faceQuality.DetectEx(bitmap, info, markPoints, QualityType.PoseEx));
return request.CheckList.Where(x =>
{
Brightness = brightnessResult,
Resolution = resolutionResult,
Clarity = clarityExResult,
Integrity = integrityExResult,
Structure = structureeResult,
Pose = poseExeResult
};
var r = qualityResult.First(item => item.Type == x.Type);
return r.Level < x.Level;
}).Select(x => x.Type.GetDescription().Replace("评估", string.Empty) + "不符合");
}
/// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD>
/// 图片识别对比
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
@@ -79,9 +70,7 @@ public class FaceController : ControllerBase
using var secondStream = new MemoryStream(secondBase64Bytes);
using var secondBitmap = SKBitmap.Decode(secondStream);
//<2F><>Ӧ<EFBFBD><D3A6>ֵ FaceType.Normal<61><6C>0.62<EFBFBD><EFBFBD>FaceType.Mask<73><6B>0.4<EFBFBD><EFBFBD>FaceType.Light<68><74>0.55
//FaceType = FaceType.Normal,
using var recognizer = new FaceRecognizer();
using var recognizer = new FaceRecognizer(new FaceRecognizeConfig());
using var faceDetector = new FaceDetector();
using var faceMark = new FaceLandmarker();

View File

@@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Kurisu.AspNetCore" Version="0.9.11" />
<PackageReference Include="Kurisu.AspNetCore" Version="0.9.25" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.0" />
<PackageReference Include="ViewFaceCore" Version="0.3.8" />
<PackageReference Include="ViewFaceCore.all_models" Version="6.0.7" />

View File

@@ -1,6 +1,15 @@
namespace Dlhis.InfoCheck.Request;
using ViewFaceCore.Model;
namespace Dlhis.InfoCheck.Request;
public class FaceDetectRequest
{
public string Base64 { get; set; }
public List<FaceDetectCheckRequest> CheckList { get; set; }
}
public class FaceDetectCheckRequest
{
public QualityType Type { get; set; }
public QualityLevel Level { get; set; }
}

View File

@@ -2,7 +2,13 @@
public class FaceRecognizeRequest
{
/// <summary>
/// 第一张图片
/// </summary>
public string FirstBase64 { get; set; }
/// <summary>
/// 第二张图片
/// </summary>
public string SecondBase64 { get; set; }
}

View File

@@ -0,0 +1,36 @@
using ViewFaceCore.Model;
namespace Dlhis.InfoCheck.Response;
public class FacialDetectionResponse
{
/// <summary>
/// 亮度
/// </summary>
public QualityResult Brightness { get; set; }
/// <summary>
/// 分辨率
/// </summary>
public QualityResult Resolution { get; set; }
/// <summary>
/// 清晰度
/// </summary>
public QualityResult Clarity { get; set; }
/// <summary>
/// 完整度
/// </summary>
public QualityResult Integrity { get; set; }
/// <summary>
/// 遮挡
/// </summary>
public QualityResult Structure { get; set; }
/// <summary>
/// 姿态
/// </summary>
public QualityResult Pose { get; set; }
}

View File

@@ -0,0 +1,27 @@
using ViewFaceCore;
using ViewFaceCore.Core;
using ViewFaceCore.Model;
namespace Dlhis.InfoCheck;
public class QualityResultEx : QualityResult
{
public QualityType Type { get; set; }
}
public static class FaceQualityExtensions
{
public static QualityResultEx DetectEx<T>(this FaceQuality faceQuality, T image,
FaceInfo info,
FaceMarkPoint[] points,
QualityType type) where T : class
{
var result = faceQuality.Detect(image, info, points, type);
return new QualityResultEx
{
Level = result.Level,
Score = result.Score,
Type = type
};
}
}

View File

@@ -64,9 +64,6 @@ public class BalanceRecordCheckBackgroundService : BackgroundService
await db.Client.Ado.BeginTranAsync();
try
{
//设置为已同步
balanceRecord.IsSync = true;
await db.UpdateAsync(balanceRecord);
var r = await UploadAsync(balanceRecord);
if (r.Code != ApiStateCode.Success)
{
@@ -80,6 +77,10 @@ public class BalanceRecordCheckBackgroundService : BackgroundService
.Where(x => x.UserCode == d.UserCode)
.ExecuteCommandAsync(stoppingToken);
//eg:一定要在此处更新为已同步
balanceRecord.IsSync = true;
await db.UpdateAsync(balanceRecord);
await db.Client.Ado.CommitTranAsync();
}
catch (Exception e)