【HarmonyOS 5】VisionKit人臉活體檢測(cè)詳解
##鴻蒙開發(fā)能力 ##HarmonyOS SDK應(yīng)用服務(wù)##鴻蒙金融類應(yīng)用 (金融理財(cái)#
一、VisionKit人臉活體檢測(cè)是什么?
VisionKit是HamronyOS提供的場(chǎng)景化視覺服務(wù)工具包。
華為將常見的解決方案,通常需要三方應(yīng)用使用SDK進(jìn)行集成。華為以Kit的形式集成在HarmoyOS系統(tǒng)中,方便三方應(yīng)用快速開發(fā)和賦能。
而VisionKit中包含人臉活體檢測(cè)的功能接口interactiveLiveness 。人臉活體檢測(cè)見名知意,主要是為了檢測(cè)當(dāng)前人是否為活人本人,而不是照片,硅膠面具,AI視頻仿真的可能。
雖然該算法接口已通過中金金融(CECA)認(rèn)證。但是官方還是建議添加額外的安全措施后,在使用該人臉檢測(cè)接口,盡量不要直接使用在高風(fēng)險(xiǎn)性的支付和金融場(chǎng)景中。推薦在低危險(xiǎn)場(chǎng)景,例如登錄,考勤,實(shí)名認(rèn)證等業(yè)務(wù)場(chǎng)景進(jìn)行使用。
需要注意的是**,人臉活體檢測(cè),不支持模擬器和預(yù)覽器。**
詳情參見官方接口:
[https://developer.huawei.com/consumer/cn/doc/harmonyos-references/vision-interactive-liveness] [https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/vision-interactiveliveness] 
二、人臉活體檢測(cè)如何使用?
人臉活體檢測(cè)功能interactiveLiveness ,起始版本為 5.0.0 (API12),可通過@kit.VisionKit模塊導(dǎo)入,支持動(dòng)作活體檢測(cè)模式(INTERACTIVE_MODE),動(dòng)作數(shù)量可配置為 3 或 4 個(gè),包含點(diǎn)頭、張嘴、眨眼等 6 種動(dòng)作。
通過InteractiveLivenessConfig配置檢測(cè)模式、跳轉(zhuǎn)路徑、語音播報(bào)等參數(shù),提供startLivenessDetection和getInteractiveLivenessResult接口,能抵御照片、視頻等GJ,適用于身份驗(yàn)證場(chǎng)景,需申請(qǐng)ohos.permission.CAMERA相機(jī)權(quán)限,錯(cuò)誤碼可參考 Vision Kit 錯(cuò)誤碼文檔。
Vision Kit 錯(cuò)誤碼文檔
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/vision-error-code
1. 核心接口為人臉頁面喚起接口:
interactiveLiveness.startLivenessDetection,該接口需要配置config進(jìn)行設(shè)置人臉的模式,動(dòng)作等操作。
(1) Promise 方式:僅返回跳轉(zhuǎn)結(jié)果(boolean)。
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}`);
})
(2) Promise + 回調(diào)方式:同時(shí)返回跳轉(zhuǎn)結(jié)果和檢測(cè)結(jié)果(僅適用于 BACK_MODE)。
interactiveLiveness.startLivenessDetection(routerOptions, (err: BusinessError, result: interactiveLiveness.InteractiveLivenessResult | undefined) = > {
if(err.code !== 0 && !result) {
hilog.error(0x0001, "LivenessCollectionIndex", `Failed to detect. Code:${err.code},message:${err.message}`);
return;
}
hilog.info(0x0001, 'LivenessCollectionIndex', `Succeeded in detecting result:${result}`);
})
2. InteractiveLivenessConfig配置接口:
調(diào)用人臉活體檢測(cè),需要填入該配置對(duì)象,進(jìn)行相關(guān)設(shè)置,參數(shù)見以下表格:
檢測(cè)模式(DetectionMode)
名稱 值 說明 SILENT_MODE "SILENT_MODE" 靜默活體檢測(cè)(暫未支持) INTERACTIVE_MODE "INTERACTIVE_MODE" 動(dòng)作活體檢測(cè)(默認(rèn)模式) 動(dòng)作數(shù)量(ActionsNumber)
名稱 值 說明 ONE_ACTION 1 隨機(jī)1個(gè)動(dòng)作(暫未支持) TWO_ACTION 2 隨機(jī)2個(gè)動(dòng)作(暫未支持) THREE_ACTION 3 隨機(jī)3個(gè)動(dòng)作([眨眼,注視]不同時(shí)存在且不相鄰,相鄰動(dòng)作不重復(fù)) FOUR_ACTION 4 隨機(jī)4個(gè)動(dòng)作(眨眼僅1次,注視最多1次,[眨眼,注視]不相鄰,相鄰動(dòng)作不重復(fù)) 跳轉(zhuǎn)模式(RouteRedirectionMode)
名稱 值 說明 BACK_MODE "back" 檢測(cè)完成后調(diào)用router.back返回上一頁 REPLACE_MODE "replace" 檢測(cè)完成后調(diào)用router.replaceUrl跳轉(zhuǎn)(默認(rèn)模式) 配置項(xiàng)(InteractiveLivenessConfig)
名稱 類型 必填/可選 說明 isSilentMode DetectionMode 必填 檢測(cè)模式(默認(rèn)INTERACTIVE_MODE) actionsNum ActionsNumber 可選 動(dòng)作數(shù)量(3或4,默認(rèn)3) successfulRouteUrl string 可選 檢測(cè)成功跳轉(zhuǎn)路徑(未填則用系統(tǒng)默認(rèn)頁面) failedRouteUrl string 可選 檢測(cè)失敗跳轉(zhuǎn)路徑(未填則用系統(tǒng)默認(rèn)頁面) routeMode RouteRedirectionMode 可選 跳轉(zhuǎn)模式(默認(rèn)REPLACE_MODE) challenge string 可選 安全攝像頭場(chǎng)景挑戰(zhàn)值(16-128位,空值表示不使用) speechSwitch boolean 可選 語音播報(bào)開關(guān)(默認(rèn)開啟) isPrivacyMode boolean 可選 隱私模式(需申請(qǐng)ohos.permission.PRIVACY_WINDOW權(quán)限,默認(rèn)關(guān)閉)
人臉活體檢測(cè)的配置項(xiàng)對(duì)象除了isSilentMode是必填,其他屬性均為可選:
import { interactiveLiveness } from '@kit.VisionKit';
let isSilentMode = "INTERACTIVE_MODE" as interactiveLiveness.DetectionMode;
let routeMode = "replace" as interactiveLiveness.RouteRedirectionMode;
let actionsNum = 3 as interactiveLiveness.ActionsNumber;
let routerOptions: interactiveLiveness.InteractiveLivenessConfig= {
isSilentMode: isSilentMode,
routeMode: routeMode,
actionsNum: actionsNum,
failedRouteUrl: "pages/FailPage",
successfulRouteUrl: "pages/SuccessPage"
}
3. getInteractiveLivenessResult獲取人臉活體檢測(cè)結(jié)果:
在調(diào)用人臉活體檢測(cè)成功后,可通過該接口獲取檢測(cè)結(jié)果。結(jié)果內(nèi)容如下表格所示:
| 名稱 | 類型 | 只讀 | 可選 | 說明 |
|---|---|---|---|---|
| livenessType | LivenessType | 是 | 否 | 活體檢測(cè)模式,值包括:-0(INTERACTIVE_LIVENESS,動(dòng)作活體檢測(cè))-1(SILENT_LIVENESS,靜默活體檢測(cè),暫未支持)-2(NOT_LIVENESS,非活體) |
| mPixelMap | image.PixelMap | 是 | 是 | 檢測(cè)成功后返回的最具有活體特征的圖片(如包含人臉關(guān)鍵點(diǎn)的特征圖),檢測(cè)失敗時(shí)無此數(shù)據(jù)。 |
| securedImageBuffer | ArrayBuffer | 是 | 是 | 安全攝像頭場(chǎng)景下返回的安全流數(shù)據(jù)(加密后的圖像特征數(shù)據(jù)),非安全場(chǎng)景無此數(shù)據(jù)。 |
| certificate | Array | 是 | 是 | 安全攝像頭場(chǎng)景下返回的證書鏈(用于驗(yàn)證安全流的合法性),非安全場(chǎng)景無此數(shù)據(jù)。 |
let successResult = interactiveLiveness.getInteractiveLivenessResult();
successResult.then(data = > {
hilog.info(0x0001, "LivenessCollectionIndex", `Succeeded in detecting.`);
}).catch((err: BusinessError) = > {
hilog.error(0x0001, "LivenessCollectionIndex", `Failed to detect. Code:${err.code},message:${err.message}`);
})
三、DEMO源碼示例
import { interactiveLiveness } from '@kit.VisionKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
@Entry
@Component
struct FaceLivenessDemo {
@State userGrant: boolean = false // 權(quán)限狀態(tài)
@State detectionResult: string = "" // 檢測(cè)結(jié)果展示
@State actionCount: interactiveLiveness.ActionsNumber = interactiveLiveness.ActionsNumber.THREE_ACTION; // 動(dòng)作數(shù)量(3或4)
@State speechEnabled: boolean = true // 語音播報(bào)開關(guān)
// 表示人臉活體檢測(cè)完成后使用router.back返回到上一頁。
@State routeMode: interactiveLiveness.RouteRedirectionMode = interactiveLiveness.RouteRedirectionMode.BACK_MODE; // 跳轉(zhuǎn)模式
// 權(quán)限申請(qǐng)邏輯
private async requestPermissions() {
const context = getContext() as common.UIAbilityContext;
const atManager = abilityAccessCtrl.createAtManager();
const results = await atManager.requestPermissionsFromUser(context, ["ohos.permission.CAMERA"]);
this.userGrant = results.authResults.every(status = > status === 0);
}
// 檢測(cè)配置生成
private generateDetectionConfig(): interactiveLiveness.InteractiveLivenessConfig {
return {
// 表示的是人臉活體檢測(cè)模式,默認(rèn)動(dòng)作活體檢測(cè)模式。
// INTERACTIVE_MODE表示動(dòng)作活體檢測(cè)模式。
isSilentMode: interactiveLiveness.DetectionMode.INTERACTIVE_MODE,
// 表示動(dòng)作活體檢測(cè)的動(dòng)作數(shù)量,數(shù)量范圍3或4個(gè),默認(rèn)3個(gè)動(dòng)作。隨機(jī)生成,規(guī)則如下:
//
// 當(dāng)actionsNum=3時(shí),[眨眼,注視]組合中的動(dòng)作元素不會(huì)同時(shí)存在并且相鄰的動(dòng)作元素不會(huì)相同。
//
// 當(dāng)actionsNum=4時(shí),眨眼動(dòng)作元素有且僅有1次,注視動(dòng)作元素最多出現(xiàn)1次,[眨眼,注視]組合中的動(dòng)作元素不會(huì)相鄰,相鄰的動(dòng)作元素不會(huì)相同。
//
// 該參數(shù)只有當(dāng)isSilentMode是INTERACTIVE_MODE的時(shí)候有效。
actionsNum: this.actionCount,
// 表示人臉活體檢測(cè)成功后跳轉(zhuǎn)的頁面路徑。如果不填,系統(tǒng)有默認(rèn)的檢測(cè)成功頁面。
// successfulRouteUrl: "pages/result/success", // 自定義成功跳轉(zhuǎn)路徑(需提前創(chuàng)建頁面)
// 表示人臉活體檢測(cè)失敗后跳轉(zhuǎn)的頁面路徑。如果不填,系統(tǒng)有默認(rèn)的檢測(cè)失敗頁面。
// failedRouteUrl: "pages/result/fail", // 自定義失敗跳轉(zhuǎn)路徑(需提前創(chuàng)建頁面)
routeMode: this.routeMode, // 跳轉(zhuǎn)模式
// 語音播報(bào)的開關(guān)。
//
// true表示開啟語音播報(bào)。
// false表示關(guān)閉語音播報(bào)。
// 默認(rèn)開啟語音播報(bào)。
speechSwitch: this.speechEnabled, // 語音播報(bào)控制
// 挑戰(zhàn)值。僅用于安全攝像頭場(chǎng)景(對(duì)應(yīng)initializeAttestContext方法中的“userData”字段)的活體檢測(cè)。
//
// 使用安全攝像頭場(chǎng)景的前提需要開通Device Security服務(wù)。
//
// 長度范圍是16-128之間(challenge傳空或者undefined表示不使用安全攝像頭)。
// challenge: "自定義挑戰(zhàn)值1234567890abcdef", // 安全攝像頭場(chǎng)景可選
// 是否設(shè)置隱私模式。
//
// true:設(shè)置隱私模式。
// false:不設(shè)置隱私模式。
// 默認(rèn)值為false。
// isPrivacyMode: true // 隱私模式需額外權(quán)限 當(dāng)設(shè)置隱私模式時(shí),需要申請(qǐng)ohos.permission.PRIVACY_WINDOW權(quán)限。
};
}
// 啟動(dòng)檢測(cè)
private async startDetection() {
if (!this.userGrant) {
this.detectionResult = "請(qǐng)先申請(qǐng)相機(jī)權(quán)限";
return;
}
const config = this.generateDetectionConfig();
try {
const jumpSuccess = await interactiveLiveness.startLivenessDetection(config);
if (jumpSuccess) {
hilog.info(0x0001, "Detection", "跳轉(zhuǎn)檢測(cè)頁面成功");
// 檢測(cè)完成后獲取結(jié)果(需在返回頁面時(shí)調(diào)用)
const result = await interactiveLiveness.getInteractiveLivenessResult();
this.processResult(result);
}
} catch (err) {
const error = err as BusinessError;
hilog.error(0x0001, "Detection", `檢測(cè)失敗: 錯(cuò)誤碼${error.code}, 信息${error.message}`);
this.detectionResult = `檢測(cè)異常:錯(cuò)誤碼${error.code}`;
}
}
// 結(jié)果處理
private processResult(result: interactiveLiveness.InteractiveLivenessResult) {
let status = "";
let livenessType = result.livenessType;
switch (livenessType) {
case 0: // 動(dòng)作活體檢測(cè)成功
status = "活體檢測(cè)通過";
// 可在此處處理特征圖片或安全數(shù)據(jù)
break;
case 2: // 非活體
status = "檢測(cè)到非活體(照片/視頻GJ)";
break;
default:
status = "檢測(cè)結(jié)果異常";
}
this.detectionResult = status;
}
build() {
Column({ space: 40 })
{
// 權(quán)限申請(qǐng)按鈕
Button(this.userGrant ? "權(quán)限已授權(quán)" : "申請(qǐng)相機(jī)權(quán)限")
.fontSize(18)
.margin(10)
.padding(12)
.backgroundColor(this.userGrant ? Color.Green : Color.Blue)
.onClick(() = > this.requestPermissions())
// 動(dòng)作數(shù)量選擇
Row({ space: 20 }) {
Text("動(dòng)作數(shù)量:")
.fontSize(16)
Button("3個(gè)動(dòng)作")
.backgroundColor(this.actionCount === 3 ? Color.Blue : Color.White)
.border({ width: 1, color: Color.Gray })
.onClick(() = > this.actionCount = 3)
Button("4個(gè)動(dòng)作")
.backgroundColor(this.actionCount === 4 ? Color.Blue : Color.White)
.border({ width: 1, color: Color.Gray })
.onClick(() = > this.actionCount = 4)
}
// 語音播報(bào)開關(guān)
Toggle({ type: ToggleType.Checkbox, isOn: this.speechEnabled })
.onChange((isOn: boolean)= >{
this.speechEnabled = isOn;
})
// 跳轉(zhuǎn)模式選擇
Row({ space: 20 }) {
Text("跳轉(zhuǎn)模式:")
.fontSize(16)
Button("替換頁面")
.backgroundColor(this.routeMode === "replace" ? Color.Blue : Color.White)
.border({ width: 1, color: Color.Gray })
.onClick(() = > {
this.routeMode = interactiveLiveness.RouteRedirectionMode.REPLACE_MODE;
})
Button("返回上頁")
.backgroundColor(this.routeMode === "back" ? Color.Blue : Color.White)
.border({ width: 1, color: Color.Gray })
.onClick(() = > {
this.routeMode = interactiveLiveness.RouteRedirectionMode.BACK_MODE;
})
}
// 啟動(dòng)檢測(cè)按鈕
Button("開始人臉活體檢測(cè)")
.fontSize(20)
.padding(16)
.backgroundColor(Color.Orange)
.onClick(() = > this.startDetection())
// 結(jié)果顯示
Text(this.detectionResult)
.fontSize(16)
.margin({
top: 30
})
.foregroundColor(this.detectionResult.includes("通過") ? Color.Green : Color.Red)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
注意:
1. 人臉活體檢測(cè)支持兩種模式
INTERACTIVE_MODE(動(dòng)作活體檢測(cè)):默認(rèn)模式,需用戶完成 3 或 4 個(gè)隨機(jī)動(dòng)作(如眨眼、點(diǎn)頭等),通過動(dòng)作組合驗(yàn)證活體,規(guī)則限制避免相鄰動(dòng)作重復(fù)或特定組合(如眨眼和注視不相鄰)。
SILENT_MODE(靜默活體檢測(cè)):暫未支持,無需用戶做動(dòng)作,通過其他技術(shù)(如微表情、光線反射)檢測(cè)活體。
2. 配置人臉活體檢測(cè)的動(dòng)作數(shù)量和跳轉(zhuǎn)邏輯
通過InteractiveLivenessConfig中的actionsNum配置,可選值為 3(默認(rèn))或 4,3 個(gè)動(dòng)作時(shí)(眨眼,注視) 不同時(shí)存在且不相鄰,4 個(gè)動(dòng)作時(shí)眨眼僅 1 次,注視最多 1 次。
通過routeMode配置跳轉(zhuǎn)模式(BACK_MODE 返回上一頁或 REPLACE_MODE 替換跳轉(zhuǎn),默認(rèn) REPLACE_MODE)。
successfulRouteUrl和failedRouteUrl設(shè)置成功 / 失敗后的自定義跳轉(zhuǎn)路徑(未填則用系統(tǒng)默認(rèn)頁面)。
3. 常見錯(cuò)誤及處理:
201(Permission denied):未申請(qǐng)ohos.permission.CAMERA權(quán)限
1008301002(Route switching failed):路由配置錯(cuò)誤,檢查successfulRouteUrl/failedRouteUrl路徑是否正確,或routeMode是否與頁面路由匹配。
1008302000-1008302004(檢測(cè)相關(guān)錯(cuò)誤):檢測(cè)過程中算法初始化失敗、超時(shí)或動(dòng)作不符合規(guī)則,可通過回調(diào)或 Promise 的 catch 捕獲錯(cuò)誤碼,提示用戶重新檢測(cè)并檢查動(dòng)作合規(guī)性。
審核編輯 黃宇
-
鴻蒙
+關(guān)注
關(guān)注
60文章
2838瀏覽量
45329 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2146瀏覽量
35507
發(fā)布評(píng)論請(qǐng)先 登錄
基于級(jí)聯(lián)分類器的人臉檢測(cè)基本原理
可存儲(chǔ)1000張人臉特征的3D人臉識(shí)別模塊 支持小程序管理
【Milk-V Duo S 開發(fā)板免費(fèi)體驗(yàn)】人臉檢測(cè)
【Milk-V Duo S 開發(fā)板免費(fèi)體驗(yàn)】人臉檢測(cè)測(cè)試(視頻)
【HarmonyOS 5】鴻蒙應(yīng)用隱私保護(hù)詳解
【HarmonyOS 5】鴻蒙中進(jìn)度條的使用詳解
【HarmonyOS 5】鴻蒙星閃NearLink詳解
【HarmonyOS 5】鴻蒙mPaaS詳解
【HarmonyOS 5】鴻蒙中的UIAbility詳解(二)
【HarmonyOS 5】桌面快捷方式功能實(shí)現(xiàn)詳解
HarmonyOS 5 makeObserved接口詳解
【HarmonyOS 5】鴻蒙中的UIAbility詳解(三)
筑牢人臉信息安全防線|安全芯片如何賦能《人臉識(shí)別技術(shù)應(yīng)用安全管理辦法》落地

【HarmonyOS 5】VisionKit人臉活體檢測(cè)詳解
評(píng)論