OpenCV 4.12.0
開源計算機視覺
載入中...
搜尋中...
無匹配項
如何在瀏覽器中執行深度網路

上一篇教程: YOLO DNNs
下一篇教程: 自定義深度學習層支援

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

簡介

本教程將向我們展示如何使用 OpenCV.js 在瀏覽器中執行深度學習模型。教程參考了一個人臉檢測和人臉識別模型流水線的示例。

人臉檢測

人臉檢測網路將 BGR 影像作為輸入,並生成可能包含人臉的一組邊界框。我們所需要做的就是選擇具有高置信度的框。

人臉識別

網路被稱為 OpenFace (專案 https://github.com/cmusatyalab/openface)。人臉識別模型接收尺寸為 96x96 的 RGB 人臉影像。然後,它返回一個 128 維的單位向量,該向量將輸入人臉表示為單位多維球面上的一個點。因此,兩個人臉之間的差異是兩個輸出向量之間的角度。

示例

所有示例都是一個 HTML 頁面,其中包含使用 OpenCV.js 功能的 JavaScript 程式碼。您可以在下面看到此頁面的插入。按 Start 按鈕開始演示。按 Add a person 來命名一個被識別為未知的人。接下來我們將討論程式碼的主要部分。

  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 初始化並且深度學習模型已下載時,我們啟動此函式一次。