OpenCV  4.10.0
开源计算机视觉
加载中...
搜索中...
无匹配项
如何在浏览器中运行深度神经网络

上一教程: YOLO DNN
下一教程: 自定义深度学习层支持

原始作者Dmitry Kurtaev
兼容性OpenCV >= 3.3.1

简介

本教程将向我们展示如何使用 OpenCV.js 直接在浏览器中运行深度学习模型。教程参考了人脸检测和人脸识别模型管道的示例。

人脸检测

人脸检测网络以 BGR 图像作为输入,并生成可能包含人脸的一组边界框。我们只需要选择置信度高的框即可。

人脸识别

网络称为 OpenFace(项目 https://github.com/cmusatyalab/openface)。人脸识别模型接收大小为 96x96 的 RGB 人脸图像。然后它返回一个 128 维的单位向量,该向量将输入人脸表示为单位多维球体上的一个点。因此,两个人脸之间的差异是两个输出向量之间的角度。

示例

整个示例是一个 HTML 页面,其中包含 JavaScript 代码来使用 OpenCV.js 功能。您可以在下面看到此页面的插入。按下 开始 按钮开始演示。按下 添加人 为被识别为未知的人命名。接下来我们将讨论代码的主要部分。

  1. 运行人脸检测网络以检测输入图像上的人脸。
    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 越大,可以检测到的较小人脸就越少。
  2. 运行人脸识别网络以通过输入人脸图像接收 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;
    };
  3. 执行识别。
    function recognize(face) {
    var vec = face2vec(face);
    var bestMatchName = 'unknown';
    var bestMatchScore = 30; // 人脸识别的阈值。
    for (name in persons) {
    var personVec = persons[name];
    var score = vec.dot(personVec);
    if (score > bestMatchScore) {
    bestMatchScore = score;
    bestMatchName = name;
    }
    }
    vec.delete();
    return bestMatchName;
    };
    将新的特征向量与已注册的特征向量进行匹配。返回与匹配度最高的人的名称。
  4. 主循环。
    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]);
    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);
    // 循环此函数。
    if (isRunning) {
    var delay = 1000 / FPS - (Date.now() - begin);
    setTimeout(captureFrame, delay);
    }
    };
    应用程序的主循环从相机接收帧,并对帧中检测到的每个面进行识别。我们在 OpenCV.js 初始化并下载深度学习模型后,启动此函数一次。