上一个教程 : YOLO DNNs
下一个教程 : 自定义深度学习层支持
原作者 | Dmitry Kurtaev |
---|---|
兼容性 | OpenCV >= 3.3.1 |
简介
本教程将向我们展示如何在浏览器中使用 OpenCV.js 运行深度学习模型。教程参考了人脸检测和人脸识别模型管道的示例。
人脸检测
人脸检测网络将 BGR 图像作为输入,并生成一组可能包含人脸的边界框。我们需要做的只是选择具有较强置信度的边界框。
人脸识别
网络名为 OpenFace(项目 https://github.com/cmusatyalab/openface)。人脸识别模型接收大小为 96x96
的 RGB 人脸图像。然后返回 128
维单位向量,将输入的人脸表示为单位多维球体上的一个点。因此,两个人脸之间的差异就是两个输出向量之间的夹角。
样本
所有示例都是 HTML 页面,其中包含使用 OpenCV.js 功能的 JavaScript 代码。您可以在下面看到该页面的插入内容。按开始
按钮开始演示。按添加一个人
,命名一个被识别为未知的人。接下来我们将讨论代码的主要部分。
原页面可以实现这个功能,但是这里跳接的时候无法还原这个功能,所以只能把原页面地址给出了:
https://docs.opencv.org/4.8.0/d5/d86/tutorial_dnn_javascript.html
- 运行人脸检测网络,检测输入图像上的人脸。
function detectFaces(img) {
var blob = cv.blobFromImage(img, 1, {width: 192, height: 144}, [104, 117, 123, 0], false, false);
netDet.setInput(blob);
var out = netDet.forward();
var faces = [];
for (var i = 0, n = out.data32F.length; i < n; i += 7) {
var confidence = out.data32F[i + 2];
var left = out.data32F[i + 3] * img.cols;
var top = out.data32F[i + 4] * img.rows;
var right = out.data32F[i + 5] * img.cols;
var bottom = out.data32F[i + 6] * img.rows;
left = Math.min(Math.max(0, left), img.cols - 1);
right = Math.min(Math.max(0, right), img.cols - 1);
bottom = Math.min(Math.max(0, bottom), img.rows - 1);
top = Math.min(Math.max(0, top), img.rows - 1);
if (confidence > 0.5 && left < right && top < bottom) {
faces.push({x: left, y: top, width: right - left, height: bottom - top})
}
}
blob.delete();
out.delete();
return faces;
};
您可以调整输入 blob 的大小,以平衡检测质量和效率。输入 blob 越大,检测到的人脸可能越少。
- 运行人脸识别网络,接收输入人脸图像的 128 维单位特征向量。
function face2vec(face) {
var blob = cv.blobFromImage(face, 1.0 / 255, {width: 96, height: 96}, [0, 0, 0, 0], true, false)
netRecogn.setInput(blob);
var vec = netRecogn.forward();
blob.delete();
return vec;
};
- 执行识别。
function recognize(face) {
var vec = face2vec(face);
var bestMatchName = 'unknown';
var bestMatchScore = 0.5; // 实际上,最小值是-1,但我们将其作为阈值。
for (name in persons) {
var personVec = persons[name];
var score = vec.dot(personVec);
if (score > bestMatchScore) {
bestMatchScore = score;
bestMatchName = name;
}
}
vec.delete();
return bestMatchName;
};
将新的特征向量与已注册的特征向量匹配。返回匹配度最高的人的姓名。
- 主循环
var isRunning = false;
const FPS = 30; // 每秒处理的目标帧数。
function captureFrame() {
var begin = Date.now();
cap.read(frame); // 从摄像机读取一帧图像
cv.cvtColor(frame, frameBGR, cv.COLOR_RGBA2BGR);
var faces = detectFaces(frameBGR);
faces.forEach(function(rect) {
cv.rectangle(frame, {x: rect.x, y: rect.y}, {x: rect.x + rect.width, y: rect.y + rect.height}, [0, 255, 0, 255]);
var face = frameBGR.roi(rect);
var name = recognize(face);
cv.putText(frame, name, {x: rect.x, y: rect.y}, cv.FONT_HERSHEY_SIMPLEX, 1.0, [0, 255, 0, 255]);
});
cv.imshow(output, frame);
// 循环此函数。
if (isRunning) {
var delay = 1000 / FPS - (Date.now() - begin);
setTimeout(captureFrame, delay);
}
};
应用程序的主循环接收来自摄像头的帧,并对帧上检测到的每个人脸进行识别。我们在初始化 OpenCV.js 和下载深度学习模型时启动该函数。