UNPKG

face-api.js

Version:

JavaScript API for face detection and face recognition in the browser with tensorflow.js

97 lines 4.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tf = require("@tensorflow/tfjs-core"); var classes_1 = require("../classes"); var ops_1 = require("../ops"); var config_1 = require("./config"); var getSizesForScale_1 = require("./getSizesForScale"); var MtcnnBox_1 = require("./MtcnnBox"); var normalize_1 = require("./normalize"); var PNet_1 = require("./PNet"); function rescaleAndNormalize(x, scale) { return tf.tidy(function () { var _a = getSizesForScale_1.getSizesForScale(scale, x.shape.slice(1)), height = _a.height, width = _a.width; var resized = tf.image.resizeBilinear(x, [height, width]); var normalized = normalize_1.normalize(resized); return tf.transpose(normalized, [0, 2, 1, 3]); }); } function extractBoundingBoxes(scoresTensor, regionsTensor, scale, scoreThreshold) { // TODO: fix this!, maybe better to use tf.gather here var indices = []; var scoresData = scoresTensor.arraySync(); for (var y = 0; y < scoresTensor.shape[0]; y++) { for (var x = 0; x < scoresTensor.shape[1]; x++) { if (scoresData[y][x] >= scoreThreshold) { indices.push(new classes_1.Point(x, y)); } } } var boundingBoxes = indices.map(function (idx) { var cell = new classes_1.BoundingBox(Math.round((idx.y * config_1.CELL_STRIDE + 1) / scale), Math.round((idx.x * config_1.CELL_STRIDE + 1) / scale), Math.round((idx.y * config_1.CELL_STRIDE + config_1.CELL_SIZE) / scale), Math.round((idx.x * config_1.CELL_STRIDE + config_1.CELL_SIZE) / scale)); var score = scoresData[idx.y][idx.x]; var regionsData = regionsTensor.arraySync(); var region = new MtcnnBox_1.MtcnnBox(regionsData[idx.y][idx.x][0], regionsData[idx.y][idx.x][1], regionsData[idx.y][idx.x][2], regionsData[idx.y][idx.x][3]); return { cell: cell, score: score, region: region }; }); return boundingBoxes; } function stage1(imgTensor, scales, scoreThreshold, params, stats) { stats.stage1 = []; var pnetOutputs = scales.map(function (scale) { return tf.tidy(function () { var statsForScale = { scale: scale }; var resized = rescaleAndNormalize(imgTensor, scale); var ts = Date.now(); var _a = PNet_1.PNet(resized, params), prob = _a.prob, regions = _a.regions; statsForScale.pnet = Date.now() - ts; var scoresTensor = tf.unstack(tf.unstack(prob, 3)[1])[0]; var regionsTensor = tf.unstack(regions)[0]; return { scoresTensor: scoresTensor, regionsTensor: regionsTensor, scale: scale, statsForScale: statsForScale }; }); }); var boxesForScale = pnetOutputs.map(function (_a) { var scoresTensor = _a.scoresTensor, regionsTensor = _a.regionsTensor, scale = _a.scale, statsForScale = _a.statsForScale; var boundingBoxes = extractBoundingBoxes(scoresTensor, regionsTensor, scale, scoreThreshold); scoresTensor.dispose(); regionsTensor.dispose(); if (!boundingBoxes.length) { stats.stage1.push(statsForScale); return []; } var ts = Date.now(); var indices = ops_1.nonMaxSuppression(boundingBoxes.map(function (bbox) { return bbox.cell; }), boundingBoxes.map(function (bbox) { return bbox.score; }), 0.5); statsForScale.nms = Date.now() - ts; statsForScale.numBoxes = indices.length; stats.stage1.push(statsForScale); return indices.map(function (boxIdx) { return boundingBoxes[boxIdx]; }); }); var allBoxes = boxesForScale.reduce(function (all, boxes) { return all.concat(boxes); }, []); var finalBoxes = []; var finalScores = []; if (allBoxes.length > 0) { var ts = Date.now(); var indices = ops_1.nonMaxSuppression(allBoxes.map(function (bbox) { return bbox.cell; }), allBoxes.map(function (bbox) { return bbox.score; }), 0.7); stats.stage1_nms = Date.now() - ts; finalScores = indices.map(function (idx) { return allBoxes[idx].score; }); finalBoxes = indices .map(function (idx) { return allBoxes[idx]; }) .map(function (_a) { var cell = _a.cell, region = _a.region; return new classes_1.BoundingBox(cell.left + (region.left * cell.width), cell.top + (region.top * cell.height), cell.right + (region.right * cell.width), cell.bottom + (region.bottom * cell.height)).toSquare().round(); }); } return { boxes: finalBoxes, scores: finalScores }; } exports.stage1 = stage1; //# sourceMappingURL=stage1.js.map