大家好,我是 V 哥。
今天给大家介绍在 HarmonyOS 原生鸿蒙开发中,实现人脸识别功能,这个功能在常用的 APP 开发中上镜率还是很高的,在传统的 Android 或 iOS 开发中,通常我们要借助第三方库来实现,而在鸿蒙原生开发中,天然的集成了这个功能,使用起来也超级方便,接下来听 V 哥细细说来。
在鸿蒙 NEXT 中实现人脸识别功能,可通过 CoreVision Kit 的 FaceDetector 模块实现。以下是基于 API 12+ 的实现流程及核心代码示例:
一、开发准备
- 配置权限
在module.json5
中添加以下权限:
"requestPermissions": [{ "name": "ohos.permission.READ_MEDIA" }, // 读取图片权限{ "name": "ohos.permission.CAMERA" }, // 相机权限{ "name": "ohos.permission.ACCESS_BIOMETRIC" } // 生物认证权限]
- 导入依赖
使用鸿蒙 NEXT 的视觉服务接口:
import { faceDetector } from '@kit.CoreVisionKit';import image from '@kit.ImageKit'; // 图像处理模块
二、核心实现步骤
1. 初始化人脸检测器
// 初始化参数配置
let faceDetectConfig: faceDetector.FaceDetectOptions = {maxFaceNum: 5, // 最大检测人脸数featureLevel: faceDetector.FeatureLevel.TYPE_FULL, // 检测全部特征algorithmMode: faceDetector.AlgorithmMode.TYPE_MODE_ACCURATE // 高精度模式
};// 创建检测器实例
let detector = faceDetector.createFaceDetector(faceDetectConfig);
2. 获取图像数据
通过相机或相册获取图像,转换为 PixelMap
格式:
// 示例:从相册选择图片并转换为 PixelMap
async function getImagePixelMap() {let imageSource = image.createImageSource(selectedImageUri);let decodeOptions = {desiredSize: { width: 1024, height: 1024 } // 调整尺寸优化性能};let pixelMap = await imageSource.createPixelMap(decodeOptions);return pixelMap;
}
3. 执行人脸检测
async function detectFaces(pixelMap: image.PixelMap) {try {// 执行检测let faces: faceDetector.Face[] = await detector.detect(pixelMap);// 处理检测结果faces.forEach((face: faceDetector.Face) => {console.log("人脸置信度: " + face.confidence);console.log("人脸坐标框: " + JSON.stringify(face.rect));console.log("五官坐标点: " + JSON.stringify(face.landmarks));});} catch (error) {console.error("人脸检测失败: " + error.code + ", 信息: " + error.message);}
}
4. 身份验证集成
结合生物认证接口验证机主身份:
import userAuth from '@kit.BiometricAuthenticationKit';// 检查是否支持人脸识别
let status = userAuth.getAvailableStatus(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL3
);
if (status.isAvailable) {// 执行人脸认证userAuth.executeAuth(userAuth.UserAuthType.FACE,userAuth.AuthTrustLevel.ATL3,(err, result) => {if (result?.result === userAuth.AuthResult.SUCCESS) {console.log("身份验证通过");}});
}
三、以下是一个完整示例代码
- Index.ets 主页面(示例代码是使用元服务项目实现)
import { authentication } from '@kit.AccountKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';const DOMAIN = 0x0000;export const pathStack: NavPathStack = new NavPathStack();@Entry
@ComponentV2
struct Index {build() {Navigation(pathStack) {Column({ space: 20 }) {Button("人脸活体检测-示例").width("80%").borderRadius(10).onClick(() => {pathStack.pushPath({ name: "live" })})}.height('100%').width('100%')}.title("元服务")}aboutToAppear() {hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');this.loginWithHuaweiID();}/*** Sample code for using HUAWEI ID to log in to atomic service.* According to the Atomic Service Review Guide, when a atomic service has an account system,* the option to log in with a HUAWEI ID must be provided.* The following presets the atomic service to use the HUAWEI ID silent login function.* To enable the atomic service to log in successfully using the HUAWEI ID, please refer* to the HarmonyOS HUAWEI ID Access Guide to configure the client ID and fingerprint certificate.*/private loginWithHuaweiID() {// Create a login request and set parametersconst loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest();// Whether to forcibly launch the HUAWEI ID login page when the user is not logged in with the HUAWEI IDloginRequest.forceLogin = false;// Execute login requestconst controller = new authentication.AuthenticationController();controller.executeRequest(loginRequest).then((data) => {const loginWithHuaweiIDResponse = data as authentication.LoginWithHuaweiIDResponse;const authCode = loginWithHuaweiIDResponse.data?.authorizationCode;// Send authCode to the backend in exchange for unionID, session}).catch((error: BusinessError) => {hilog.error(DOMAIN, 'testTag', 'error: %{public}s', JSON.stringify(error));if (error.code === authentication.AuthenticationErrorCode.ACCOUNT_NOT_LOGGED_IN) {// HUAWEI ID is not logged in, it is recommended to jump to the login guide page}});}
}
- LiveDetectPage.ets 页面
import { common, abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { interactiveLiveness } from '@kit.VisionKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
@Builder export function buildPage(){LiveDetectPage()
}
@Component
export struct LiveDetectPage {private context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;// 权限private array: Array<Permissions> = ["ohos.permission.CAMERA"];// 动作个数@State actionsNum: number = 0;/*** 是否是静默模式* 静默模式(SILENT_MODE):表示静默活体检测模式,暂未支持。* 交互模式(INTERACTIVE_MODE):表示动作活体检测模式。*/@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() {NavDestination() {// 层叠布局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) {// 如果存在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).textAlign(TextAlign.Center).fontFamily("HarmonyHeiTi").fontWeight("Medium").margin({ bottom: 200 })}// 开始检测的按钮Button("开始检测").type(ButtonType.Normal).borderRadius(10).width('60%').height(40).fontSize(16).margin({ bottom: 56 }).onClick(() => {this.privateStartDetection();})}.height("100%")}}.title('活体检测').onWillShow(() => {// 释放结果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}// 如果可以使用该能力(活体检测能力)// syscap配置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", '当前设备不支持活体检测API');}}/*** 返回从用户获取到的权限列表,遍历该列表,如果包含了ohos.permission.CAMERA权限,则调用privateRouterLibrary方法*/private privateStartDetection() {abilityAccessCtrl.createAtManager().requestPermissionsFromUser(this.context, this.array).then((res) => {for (let i = 0; i < res.permissions.length; i++) {if (res.permissions[i] === "ohos.permission.CAMERA" && res.authResults[i] === 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接口调用完会释放资源// 如果可以使用活体检测能力(syscap配置)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", '该设备不支持活体检测API。');}}/*** 结果重置*/private resultRelease() {this.resultInfo = {livenessType: 0}this.failResult = {"code": 1008302000,"message": ""}}
}
注意,需要在module.json5中配置权限。
四、注意事项
- 真机调试
需使用支持人脸识别的真机(如 P50 系列)测试,模拟器不支持)。 - 性能优化
- 降低图像分辨率以提升检测速度。
- 使用
AlgorithmMode.TYPE_MODE_FAST
快速模式平衡性能与精度。
- 特征比对
进阶场景可通过FaceComparator
比对两张人脸相似度。
五、扩展场景
- 活体检测:通过
VisionKit
监测眨眼、转头动作。 - 暗光增强:结合
ImageKit
调整图像亮度/对比度强化识别效果。
通过上述步骤,可快速实现基础人脸识别功能,并根据需求扩展至复杂场景。
六、小结一下
以上就是在鸿蒙 NEXT 开发中实现人脸识别功能,也称为活体检测,通过鸿蒙 NEXT 提供的能力,可以轻松实现,兄弟们,可以抓紧试试(请自备真机测试)。学习鸿蒙可以关注威哥写的《鸿蒙 HarmonyOS NEXT 开发之路》卷1,卷2已上市,卷3正在加紧印刷中。如果你还没有拿下鸿蒙认证,快到碗里来(https://developer.huawei.com/consumer/cn/training/classDetail/042cb1cc4d7d44ecbdbd902fd1275dcc)。