示例:人脸检测与跟踪框
简介
本章节将通过一个完整的 示例,详细讲解如何实现最基础的人脸检测功能:在摄像头实时画面上动态绘制跟踪人脸的矩形框。这是所有人脸识别应用的起点。
我们将采用双线程(Worker)模型来构建此应用,将人脸处理与UI 渲染分离,这是确保复杂应用流畅运行的最佳实践。基本流程如下:
- 主线程 (
main.js): 启动两个工作线程:一个用于人脸处理,一个用于 UI。 - 人脸线程 (
faceworker.js): 独立负责初始化dxFacial组件并驱动其内部循环。 - UI 线程 (
uiworker.js): 负责 UI 初始化,并周期性地从dxFacial获取人脸位置数据,然后绘制跟踪框。
代码实现
main.js:启动入口
import log from "../dxmodules/dxLogger.js";
import bus from "../dxmodules/dxEventBus.js";
function init() {
bus.newWorker("screen", "/app/code/src/worker/uiworker.js");
bus.newWorker("face", "/app/code/src/worker/faceworker.js");
}
try {
init();
} catch (error) {
log.error(error);
}
代码解析
入口文件 main.js 的逻辑非常简单,它只做一件事:创建并启动两个独立的 Worker 线程,分别用于处理 UI (uiworker.js) 和人脸识别 (faceworker.js)。这种分离可以防止耗时的人脸算法阻塞 UI 刷新,保证界面的流畅性。
faceworker.js:人脸引擎处理线程
import face from "../../dxmodules/dxFacial.js";
import log from "../../dxmodules/dxLogger.js";
import std from "../../dxmodules/dxStd.js";
try {
face.init();
} catch (error) {
log.error(error);
}
std.setInterval(() => {
try {
face.loop();
} catch (error) {
log.error(error);
}
}, 20);
代码解析
人脸处理线程 (faceworker.js) 的职责非常专一:
- 初始化
dxFacial组件:调用face.init()来启动人脸识别引擎。 - 周期性驱动引擎:通过
std.setInterval定时调用face.loop()。这个函数是dxFacial组件的“心跳”,它驱动引擎内部处理摄像头数据、执行检测/识别算法,并管理事件队列。即使当前示例不处理识别事件,这个轮询也必须存在,否则引擎将不会工作。
uiworker.js:UI 渲染与交互线程
import log from "../../dxmodules/dxLogger.js";
import std from "../../dxmodules/dxStd.js";
import dxui from "../../dxmodules/dxUi.js";
import face from "../../dxmodules/dxFacial.js";
let faceview = null;
try {
dxui.init({ orientation: 1 });
let mainview = dxui.View.build("mainview", dxui.Utils.LAYER.MAIN);
mainview.bgOpa(0); // background opacity
mainview.scroll(false);
faceview = dxui.View.build("faceview", mainview);
faceview.bgOpa(0);
faceview.radius(0);
faceview.padAll(0);
faceview.setSize(200, 200);
faceview.borderWidth(5);
faceview.setBorderColor(0xff0000);
faceview.hide();
dxui.loadMain(mainview);
} catch (error) {
log.error(error);
}
function showFaceView() {
// [{"id":4,"status":1,"rect":[8,224,360,668],"qualityScore":26,"livingScore":41}]
let detectionData = face.getDetectionData();
if (faceview && detectionData && detectionData.length > 0) {
faceview.show();
faceview.setPos(detectionData[0].rect[0], detectionData[0].rect[1]);
faceview.setSize(
detectionData[0].rect[2] - detectionData[0].rect[0],
detectionData[0].rect[3] - detectionData[0].rect[1]
);
} else if (faceview) {
faceview.hide();
}
}
std.setInterval(() => {
try {
showFaceView();
dxui.handler();
} catch (error) {
log.error(error);
}
}, 15);
核心逻辑详解
1. 透明 UI 与摄像头画面叠加
这是实现该功能最关键的一点。摄像头的实时视频流默认渲染在屏幕的最底层。为了能在视频上叠加 UI(如人脸框),我们的 UI 主容器 (mainview) 背景必须设置为完全透明 (mainview.bgOpa(0))。否则,UI 将会完全遮挡住摄像头画面,导致无法看到人脸。
同时,用于绘制人脸框的 faceview 也设置了透明背景和红色边框,这样它就表现为一个中空的矩形。