如何利用OpenCV在浏览器中运行深度学习网络

发布于:2024-12-18 ⋅ 阅读:(8) ⋅ 点赞:(0)

如何在浏览器中使用 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 并下载深度学习模型时启动此功能。