如何在浏览器中使用 OpenCV.js 运行深度学习模型。教程参考了人脸检测和人脸识别模型管道的示例。
人脸检测
人脸检测网络以 BGR 图像作为输入,并生成一组可能包含人脸的边界框。我们只需要选择具有高置信度的边界框即可。
人脸识别
网络名为 OpenFace(项目GitHub - cmusatyalab/openface: Face recognition with deep neural networks.)。人脸识别模型接收大小为 的 RGB 人脸图像96x96
。然后它返回128
- 维单位向量,该向量将输入人脸表示为单位多维球面上的一个点。因此,两个人脸之间的差异是两个输出向量之间的角度。
样本
整个示例都是一个 HTML 页面,其中包含使用 OpenCV.js 功能的 JavaScript 代码。您可以在下面看到此页面的插入内容。按下Start
按钮开始演示。按下Add a person
可命名被识别为未知的人。接下来我们将讨论代码的主要部分。
运行人脸检测网络来检测输入图像上的人脸。
function detectFaces(img) {
netDet.setInputSize(new cv.Size(img.cols, img.rows));
var out = new cv.Mat();
netDet.detect(img, out);
var faces = [];
for (var i = 0, n = out.data32F.length; i < n; i += 15) {
var left = out.data32F[i];
var top = out.data32F[i + 1];
var right = (out.data32F[i] + out.data32F[i + 2]);
var bottom = (out.data32F[i + 1] + out.data32F[i + 3]);
left = Math.min(Math.max(0, left), img.cols - 1);
top = Math.min(Math.max(0, top), img.rows - 1);
right = Math.min(Math.max(0, right), img.cols - 1);
bottom = Math.min(Math.max(0, bottom), img.rows - 1);
if (left < right && top < bottom) {
faces.push({
x: left,
y: top,
width: right - left,
height: bottom - top,
x1: out.data32F[i + 4] < 0 || out.data32F[i + 4] > img.cols - 1 ? -1 : out.data32F[i + 4],
y1: out.data32F[i + 5] < 0 || out.data32F[i + 5] > img.rows - 1 ? -1 : out.data32F[i + 5],
x2: out.data32F[i + 6] < 0 || out.data32F[i + 6] > img.cols - 1 ? -1 : out.data32F[i + 6],
y2: out.data32F[i + 7] < 0 || out.data32F[i + 7] > img.rows - 1 ? -1 : out.data32F[i + 7],
x3: out.data32F[i + 8] < 0 || out.data32F[i + 8] > img.cols - 1 ? -1 : out.data32F[i + 8],
y3: out.data32F[i + 9] < 0 || out.data32F[i + 9] > img.rows - 1 ? -1 : out.data32F[i + 9],
x4: out.data32F[i + 10] < 0 || out.data32F[i + 10] > img.cols - 1 ? -1 : out.data32F[i + 10],
y4: out.data32F[i + 11] < 0 || out.data32F[i + 11] > img.rows - 1 ? -1 : out.data32F[i + 11],
x5: out.data32F[i + 12] < 0 || out.data32F[i + 12] > img.cols - 1 ? -1 : out.data32F[i + 12],
y5: out.data32F[i + 13] < 0 || out.data32F[i + 13] > img.rows - 1 ? -1 : out.data32F[i + 13],
confidence: out.data32F[i + 14]
})
}
}
out.delete();
return faces;
};
您可以调整输入 blob 的大小来平衡检测质量和效率。输入 blob 越大,检测到的人脸就越小。
128
输入人脸图像,运行人脸识别网络,得到维单位特征向量。
function face2vec(face) {
var blob = cv.blobFromImage(face, 1.0, {width: 112, height: 112}, [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 = 30; // Threshold for face recognition.
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; // Target number of frames processed per second.
function captureFrame() {
var begin = Date.now();
cap.read(frame); // Read a frame from camera
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]);
if(rect.x1>0 && rect.y1>0)
cv.circle(frame, {x: rect.x1, y: rect.y1}, 2, [255, 0, 0, 255], 2)
if(rect.x2>0 && rect.y2>0)
cv.circle(frame, {x: rect.x2, y: rect.y2}, 2, [0, 0, 255, 255], 2)
if(rect.x3>0 && rect.y3>0)
cv.circle(frame, {x: rect.x3, y: rect.y3}, 2, [0, 255, 0, 255], 2)
if(rect.x4>0 && rect.y4>0)
cv.circle(frame, {x: rect.x4, y: rect.y4}, 2, [255, 0, 255, 255], 2)
if(rect.x5>0 && rect.y5>0)
cv.circle(frame, {x: rect.x5, y: rect.y5}, 2, [0, 255, 255, 255], 2)
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);
// Loop this function.
if (isRunning) {
var delay = 1000 / FPS - (Date.now() - begin);
setTimeout(captureFrame, delay);
}
};
我们应用程序的主循环接收来自摄像头的帧,并对帧上检测到的每个面部进行识别。我们在初始化 OpenCV.js 并下载深度学习模型时启动此功能。