华为HarmonyOS实现人脸活体检测
两种模式人脸活体检测分为静默活体检测和动作后提检测两种模式
https://i-blog.csdnimg.cn/direct/b0a01e2c78384567a49ff183e61c974b.png
场景介绍
人脸活体检测支持动作活体检测模式。
动作活体检测支持及时捕获人脸,必要用户配合做指定动作就可以判定是真实活体,还黑白活体攻击(好比:打印图片、人脸翻拍视频以及人脸面具等)。
注意
我们提供的活体检测是一项纯端侧算法、试用期免费的体系基础服务,推荐您使用在考勤打卡、辅助登录和实名认证等低危业务场景中。
因端侧算法在HarmonyOS NEXT/5.0.x尚未完成权威机构检测认证,鉴于付出和金融应用的高风险性,发起开发者基于现有的安全性,针对差别的功能场景进行风险评估和风控计谋评估,并采取必要的安全措施。
图1 活体检测表示图
https://img-blog.csdnimg.cn/img_convert/cd95b4933c2306f5db5f553550ba9e02.png
开发步调
[*]将实现人脸活体检测相关的类添加至工程。
[*]import { interactiveLiveness } from '@kit.VisionKit';
[*]在module.json5文件中添加CAMERA权限,此中reason,abilities标签必填,设置方式参见requestPermissions标签阐明。
[*]"requestPermissions":[
[*]{
[*]"name": "ohos.permission.CAMERA",
[*]"reason": "$string:camera_desc",
[*]"usedScene": {"abilities": []}
[*]}
[*]]
[*]简单设置页面的布局,选择人脸活体检测验证完后的跳转模式。如果使用back跳转模式,表示的是在检测结束后使用router.back()返回。如果使用replace跳转模式,表示的是检测结束后使用router.replaceUrl()去跳转相应页面。默认选择的是replace跳转模式。
[*]Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
[*]Text("验证完的跳转模式:")
[*].fontSize(18)
[*].width("25%")
[*]Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
[*]Row() {
[*]Radio({ value: "replace", group: "routeMode" }).checked(true)
[*].height(24)
[*].width(24)
[*].onChange((isChecked: boolean) => {
[*]this.routeMode = "replace"
[*]})
[*]Text("replace")
[*].fontSize(16)
[*]}
[*].margin({ right: 15 })
[*]
[*]Row() {
[*]Radio({ value: "back", group: "routeMode" }).checked(false)
[*].height(24)
[*].width(24)
[*].onChange((isChecked: boolean) => {
[*]this.routeMode = "back";
[*]})
[*]Text("back")
[*].fontSize(16)
[*]}
[*]}
[*].width("75%")
[*]}
[*]如果选择动作活体模式,可填写验证的动作个数。
[*]Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
[*]Text("动作数量:")
[*].fontSize(18)
[*].width("25%")
[*]TextInput({
[*]placeholder: this.actionsNum != 0 ? this.actionsNum.toString() : "动作数量为3或4个"
[*]})
[*].type(InputType.Number)
[*].placeholderFont({
[*]size: 18,
[*]weight: FontWeight.Normal,
[*]family: "HarmonyHeiTi",
[*]style: FontStyle.Normal
[*]})
[*].fontSize(18)
[*].fontWeight(FontWeight.Bold)
[*].fontFamily("HarmonyHeiTi")
[*].fontStyle(FontStyle.Normal)
[*].width("65%")
[*].onChange((value: string) => {
[*]this.actionsNum = Number(value) as interactiveLiveness.ActionsNumber;
[*]})
[*]}
[*]点击“开始检测“按钮,触发点击事件。
[*]Button("开始检测", { type: ButtonType.Normal, stateEffect: true })
[*].width(192)
[*].height(40)
[*].fontSize(16)
[*].backgroundColor(0x317aff)
[*].borderRadius(20)
[*].margin({
[*]bottom: 56
[*]})
[*].onClick(() => {
[*]this.privateStartDetection();
[*]})
[*]触发CAMERA权限校验。
[*]// 校验CAMERA权限
[*]private privateStartDetection() {
[*]abilityAccessCtrl.createAtManager().requestPermissionsFromUser(this.context, this.array).then((res) => {
[*]for (let i = 0; i < res.permissions.length; i++) {
[*]if (res.permissions === "ohos.permission.CAMERA" && res.authResults === 0) {
[*]this.privateRouterLibrary();
[*]}
[*]}
[*]}).catch((err: BusinessError) => {
[*]hilog.error(0x0001, "LivenessCollectionIndex", `Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
[*]})
[*]}
[*]设置人脸活体检测控件的设置项InteractiveLivenessConfig,用于跳转到人脸活体检测控件。
设置中具体的参数可参考API文档。
[*]let routerOptions: interactiveLiveness.InteractiveLivenessConfig = {
[*]isSilentMode: this.isSilentMode as interactiveLiveness.DetectionMode,
[*]routeMode: this.routeMode as interactiveLiveness.RouteRedirectionMode,
[*]actionsNum: this.actionsNum
[*]};
[*]调用interactiveLiveness的startLivenessDetection接口,判定跳转到人脸活体检测控件是否乐成。
[*]// 跳转到人脸活体检测控件
[*]private privateRouterLibrary() {
[*]if (canIUse("SystemCapability.AI.Component.LivenessDetect")) {
[*]interactiveLiveness.startLivenessDetection(routerOptions).then((DetectState: boolean) => {
[*]hilog.info(0x0001, "LivenessCollectionIndex", `Succeeded in jumping.`);
[*]}).catch((err: BusinessError) => {
[*]hilog.error(0x0001, "LivenessCollectionIndex", `Failed to jump. Code:${err.code},message:${err.message}`);
[*]})
[*]} else {
[*]hilog.error(0x0001, "LivenessCollectionIndex", 'this api is not supported on this device');
[*]}
[*]}
[*]检测结束后回到当前界面,可调用interactiveLiveness的getInteractiveLivenessResult接口,验证人脸活体检测的结果。
[*]// 获取验证结果
[*]private getDetectionResultInfo() {
[*]// getInteractiveLivenessResult接口调用完会释放资源
[*]if (canIUse("SystemCapability.AI.Component.LivenessDetect")) {
[*]let resultInfo = interactiveLiveness.getInteractiveLivenessResult();
[*]resultInfo.then(data => {
[*]this.resultInfo = data;
[*]}).catch((err: BusinessError) => {
[*]this.failResult = {
[*]"code": err.code,
[*]"message": err.message
[*]}
[*]})
[*]} else {
[*]hilog.error(0x0001, "LivenessCollectionIndex", 'this api is not supported on this device');
[*]}
[*]}
开发实例
[*]import { common, abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
[*]import { interactiveLiveness } from '@kit.VisionKit';
[*]import { BusinessError } from '@kit.BasicServicesKit';
[*]import { hilog } from '@kit.PerformanceAnalysisKit';
[*]
[*]@Entry
[*]@Component
[*]struct LivenessIndex {
[*]private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
[*]private array: Array<Permissions> = ["ohos.permission.CAMERA"];
[*]@State actionsNum: number = 0;
[*]@State isSilentMode: string = "INTERACTIVE_MODE";
[*]@State routeMode: string = "replace";
[*]@State resultInfo: interactiveLiveness.InteractiveLivenessResult = {
[*]livenessType: 0
[*]};
[*]@State failResult: Record<string, number | string> = {
[*]"code": 1008302000,
[*]"message": ""
[*]};
[*]
[*]build() {
[*]Stack({
[*]alignContent: Alignment.Top
[*]}) {
[*]Column() {
[*]Row() {
[*]Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
[*]Text("验证完的跳转模式:")
[*].fontSize(18)
[*].width("25%")
[*]Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
[*]Row() {
[*]Radio({ value: "replace", group: "routeMode" }).checked(true)
[*].height(24)
[*].width(24)
[*].onChange((isChecked: boolean) => {
[*]this.routeMode = "replace"
[*]})
[*]Text("replace")
[*].fontSize(16)
[*]}
[*].margin({ right: 15 })
[*]
[*]Row() {
[*]Radio({ value: "back", group: "routeMode" }).checked(false)
[*].height(24)
[*].width(24)
[*].onChange((isChecked: boolean) => {
[*]this.routeMode = "back";
[*]})
[*]Text("back")
[*].fontSize(16)
[*]}
[*]}
[*].width("75%")
[*]}
[*]}
[*].margin({ bottom: 30 })
[*]
[*]Row() {
[*]Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
[*]Text("动作数量:")
[*].fontSize(18)
[*].width("25%")
[*]TextInput({
[*]placeholder: this.actionsNum != 0 ? this.actionsNum.toString() : "动作数量为3或4个"
[*]})
[*].type(InputType.Number)
[*].placeholderFont({
[*]size: 18,
[*]weight: FontWeight.Normal,
[*]family: "HarmonyHeiTi",
[*]style: FontStyle.Normal
[*]})
[*].fontSize(18)
[*].fontWeight(FontWeight.Bold)
[*].fontFamily("HarmonyHeiTi")
[*].fontStyle(FontStyle.Normal)
[*].width("65%")
[*].onChange((value: string) => {
[*]this.actionsNum = Number(value) as interactiveLiveness.ActionsNumber;
[*]})
[*]}
[*]}
[*]}
[*].margin({ left: 24, top: 80 })
[*].zIndex(1)
[*]
[*]Stack({
[*]alignContent: Alignment.Bottom
[*]}) {
[*]if (this.resultInfo?.mPixelMap) {
[*]Image(this.resultInfo?.mPixelMap)
[*].width(260)
[*].height(260)
[*].align(Alignment.Center)
[*].margin({ bottom: 260 })
[*]Circle()
[*].width(300)
[*].height(300)
[*].fillOpacity(0)
[*].strokeWidth(60)
[*].stroke(Color.White)
[*].margin({ bottom: 250, left: 0 })
[*]}
[*]
[*]Text(this.resultInfo.mPixelMap ?
[*]"检测乐成" :
[*]this.failResult.code != 1008302000 ?
[*]"检测失败" :
[*]"")
[*].width("100%")
[*].height(26)
[*].fontSize(20)
[*].fontColor("#000000")
[*].fontFamily("HarmonyHeiTi")
[*].margin({ top: 50 })
[*].textAlign(TextAlign.Center)
[*].fontWeight("Medium")
[*].margin({ bottom: 240 })
[*]
[*]if(this.failResult.code != 1008302000) {
[*]Text(this.failResult.message as string)
[*].width("100%")
[*].height(26)
[*].fontSize(16)
[*].fontColor(Color.Gray)
[*].textAlign(TextAlign.Center)
[*].fontFamily("HarmonyHeiTi")
[*].fontWeight("Medium")
[*].margin({ bottom: 200 })
[*]}
[*]
[*]Button("开始检测", { type: ButtonType.Normal, stateEffect: true })
[*].width(192)
[*].height(40)
[*].fontSize(16)
[*].backgroundColor(0x317aff)
[*].borderRadius(20)
[*].margin({
[*]bottom: 56
[*]})
[*].onClick(() => {
[*]this.privateStartDetection();
[*]})
[*]}
[*].height("100%")
[*]}
[*]}
[*]
[*]onPageShow() {
[*]this.resultRelease();
[*]this.getDetectionResultInfo();
[*]}
[*]
[*]// 跳转到人脸活体检测控件
[*]private privateRouterLibrary() {
[*]let routerOptions: interactiveLiveness.InteractiveLivenessConfig = {
[*]isSilentMode: this.isSilentMode as interactiveLiveness.DetectionMode,
[*]routeMode: this.routeMode as interactiveLiveness.RouteRedirectionMode,
[*]actionsNum: this.actionsNum
[*]}
[*]
[*]if (canIUse("SystemCapability.AI.Component.LivenessDetect")) {
[*]interactiveLiveness.startLivenessDetection(routerOptions).then((DetectState: boolean) => {
[*]hilog.info(0x0001, "LivenessCollectionIndex", `Succeeded in jumping.`);
[*]}).catch((err: BusinessError) => {
[*]hilog.error(0x0001, "LivenessCollectionIndex", `Failed to jump. Code:${err.code},message:${err.message}`);
[*]})
[*]} else {
[*]hilog.error(0x0001, "LivenessCollectionIndex", 'this api is not supported on this device');
[*]}
[*]}
[*]
[*]// 校验CAMERA权限
[*]private privateStartDetection() {
[*]abilityAccessCtrl.createAtManager().requestPermissionsFromUser(this.context, this.array).then((res) => {
[*]for (let i = 0; i < res.permissions.length; i++) {
[*]if (res.permissions === "ohos.permission.CAMERA" && res.authResults === 0) {
[*]this.privateRouterLibrary();
[*]}
[*]}
[*]}).catch((err: BusinessError) => {
[*]hilog.error(0x0001, "LivenessCollectionIndex", `Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
[*]})
[*]}
[*]
[*]// 获取验证结果
[*]private getDetectionResultInfo() {
[*]// getInteractiveLivenessResult接口调用完会释放资源
[*]if (canIUse("SystemCapability.AI.Component.LivenessDetect")) {
[*]let resultInfo = interactiveLiveness.getInteractiveLivenessResult();
[*]resultInfo.then(data => {
[*]this.resultInfo = data;
[*]}).catch((err: BusinessError) => {
[*]this.failResult = {
[*]"code": err.code,
[*]"message": err.message
[*]}
[*]})
[*]} else {
[*]hilog.error(0x0001, "LivenessCollectionIndex", 'this api is not supported on this device');
[*]}
[*]}
[*]
[*]// result release
[*]private resultRelease() {
[*]this.resultInfo = {
[*]livenessType: 0
[*]}
[*]this.failResult = {
[*]"code": 1008302000,
[*]"message": ""
[*]}
[*]}
[*]}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]