mirror of https://github.com/vladmandic/human
optimize centernet
parent
fb81d557e4
commit
a3359460e2
|
@ -9,8 +9,10 @@
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### **release 2.5.2** 2021/11/15 mandic00@live.com
|
### **HEAD -> main** 2021/11/16 mandic00@live.com
|
||||||
|
|
||||||
|
- add extra face rotation prior to mesh
|
||||||
|
- release 2.5.2
|
||||||
- improve error handling
|
- improve error handling
|
||||||
|
|
||||||
### **2.5.2** 2021/11/14 mandic00@live.com
|
### **2.5.2** 2021/11/14 mandic00@live.com
|
||||||
|
|
|
@ -44,12 +44,12 @@ async function main() {
|
||||||
const inputImage = await canvas.loadImage(input); // load image using canvas library
|
const inputImage = await canvas.loadImage(input); // load image using canvas library
|
||||||
log.info('Loaded image', input, inputImage.width, inputImage.height);
|
log.info('Loaded image', input, inputImage.width, inputImage.height);
|
||||||
const inputCanvas = new canvas.Canvas(inputImage.width, inputImage.height); // create canvas
|
const inputCanvas = new canvas.Canvas(inputImage.width, inputImage.height); // create canvas
|
||||||
const ctx = inputCanvas.getContext('2d');
|
const inputCtx = inputCanvas.getContext('2d');
|
||||||
ctx.drawImage(inputImage, 0, 0); // draw input image onto canvas
|
inputCtx.drawImage(inputImage, 0, 0); // draw input image onto canvas
|
||||||
|
const imageData = inputCtx.getImageData(0, 0, inputCanvas.width, inputCanvas.height);
|
||||||
|
|
||||||
// run detection
|
// run detection
|
||||||
const result = await human.detect(inputCanvas);
|
const result = await human.detect(imageData);
|
||||||
|
|
||||||
// run segmentation
|
// run segmentation
|
||||||
// const seg = await human.segmentation(inputCanvas);
|
// const seg = await human.segmentation(inputCanvas);
|
||||||
// log.data('Segmentation:', { data: seg.data.length, alpha: typeof seg.alpha, canvas: typeof seg.canvas });
|
// log.data('Segmentation:', { data: seg.data.length, alpha: typeof seg.alpha, canvas: typeof seg.canvas });
|
||||||
|
@ -65,11 +65,14 @@ async function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw detected results onto canvas and save it to a file
|
// draw detected results onto canvas and save it to a file
|
||||||
human.draw.all(inputCanvas, result); // use human build-in method to draw results as overlays on canvas
|
const outputCanvas = new canvas.Canvas(inputImage.width, inputImage.height); // create canvas
|
||||||
|
const outputCtx = outputCanvas.getContext('2d');
|
||||||
|
outputCtx.drawImage(result.canvas || inputImage, 0, 0); // draw input image onto canvas
|
||||||
|
human.draw.all(outputCanvas, result); // use human build-in method to draw results as overlays on canvas
|
||||||
const outFile = fs.createWriteStream(output); // write canvas to new image file
|
const outFile = fs.createWriteStream(output); // write canvas to new image file
|
||||||
outFile.on('finish', () => log.state('Output image:', output, inputCanvas.width, inputCanvas.height));
|
outFile.on('finish', () => log.state('Output image:', output, outputCanvas.width, outputCanvas.height));
|
||||||
outFile.on('error', (err) => log.error('Output error:', output, err));
|
outFile.on('error', (err) => log.error('Output error:', output, err));
|
||||||
const stream = inputCanvas.createJPEGStream({ quality: 0.5, progressive: true, chromaSubsampling: true });
|
const stream = outputCanvas.createJPEGStream({ quality: 0.5, progressive: true, chromaSubsampling: true });
|
||||||
stream.pipe(outFile);
|
stream.pipe(outFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import { log, join, now } from '../util/util';
|
import { log, join, now } from '../util/util';
|
||||||
import type { BodyKeypoint, BodyResult, Box, Point } from '../result';
|
import type { BodyKeypoint, BodyResult, Box, Point } from '../result';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import { log, join, now } from '../util/util';
|
import { log, join, now } from '../util/util';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as coords from './efficientposecoords';
|
import * as coords from './efficientposecoords';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { BodyResult, Point } from '../result';
|
import type { BodyResult, Point } from '../result';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
import { log, join } from '../util/util';
|
import { log, join } from '../util/util';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as util from './facemeshutil';
|
import * as util from './facemeshutil';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as coords from './facemeshcoords';
|
import * as coords from './facemeshcoords';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Box, Point } from '../result';
|
import type { Box, Point } from '../result';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
import { log, join, now } from '../util/util';
|
import { log, join, now } from '../util/util';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import type { Config } from '../config';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
|
|
||||||
const annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];
|
const annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];
|
||||||
let model: GraphModel | null;
|
let model: GraphModel | null;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import { log, join, now } from '../util/util';
|
import { log, join, now } from '../util/util';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { log, join, now } from '../util/util';
|
import { log, join, now } from '../util/util';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as util from './handposeutil';
|
import * as util from './handposeutil';
|
||||||
import * as anchors from './handposeanchors';
|
import * as anchors from './handposeanchors';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||||
import type { Point } from '../result';
|
import type { Point } from '../result';
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as util from './handposeutil';
|
import * as util from './handposeutil';
|
||||||
import type * as detector from './handposedetector';
|
import type * as detector from './handposedetector';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
import { now } from '../util/util';
|
import { now } from '../util/util';
|
||||||
|
|
|
@ -15,7 +15,7 @@ import type { Config } from '../config';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
import * as fingerPose from './fingerpose';
|
import * as fingerPose from './fingerpose';
|
||||||
import { fakeOps } from '../tfjs/backend';
|
import { fakeOps } from '../tfjs/backend';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
|
|
||||||
const models: [GraphModel | null, GraphModel | null] = [null, null];
|
const models: [GraphModel | null, GraphModel | null] = [null, null];
|
||||||
const modelOutputNodes = ['StatefulPartitionedCall/Postprocessor/Slice', 'StatefulPartitionedCall/Postprocessor/ExpandDims_1'];
|
const modelOutputNodes = ['StatefulPartitionedCall/Postprocessor/Slice', 'StatefulPartitionedCall/Postprocessor/ExpandDims_1'];
|
||||||
|
|
|
@ -33,26 +33,20 @@ export async function load(config: Config): Promise<GraphModel> {
|
||||||
|
|
||||||
async function process(res: Tensor | null, outputShape, config: Config) {
|
async function process(res: Tensor | null, outputShape, config: Config) {
|
||||||
if (!res) return [];
|
if (!res) return [];
|
||||||
|
const t: Record<string, Tensor> = {};
|
||||||
const results: Array<ObjectResult> = [];
|
const results: Array<ObjectResult> = [];
|
||||||
const detections = await res.array();
|
const detections = await res.array();
|
||||||
const squeezeT = tf.squeeze(res);
|
t.squeeze = tf.squeeze(res);
|
||||||
tf.dispose(res);
|
const arr = tf.split(t.squeeze, 6, 1) as Tensor[]; // x1, y1, x2, y2, score, class
|
||||||
const arr = tf.split(squeezeT, 6, 1); // x1, y1, x2, y2, score, class
|
t.stack = tf.stack([arr[1], arr[0], arr[3], arr[2]], 1); // reorder dims as tf.nms expects y, x
|
||||||
tf.dispose(squeezeT);
|
t.boxes = tf.squeeze(t.stack);
|
||||||
const stackT = tf.stack([arr[1], arr[0], arr[3], arr[2]], 1); // reorder dims as tf.nms expects y, x
|
t.scores = tf.squeeze(arr[4]);
|
||||||
const boxesT = tf.squeeze(stackT);
|
t.classes = tf.squeeze(arr[5]);
|
||||||
tf.dispose(stackT);
|
tf.dispose([res, ...arr]);
|
||||||
const scoresT = tf.squeeze(arr[4]);
|
t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, t.scores, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);
|
||||||
const classesT = tf.squeeze(arr[5]);
|
const nms = await t.nms.data();
|
||||||
arr.forEach((t) => tf.dispose(t));
|
|
||||||
const nmsT = await tf.image.nonMaxSuppressionAsync(boxesT, scoresT, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);
|
|
||||||
tf.dispose(boxesT);
|
|
||||||
tf.dispose(scoresT);
|
|
||||||
tf.dispose(classesT);
|
|
||||||
const nms = await nmsT.data();
|
|
||||||
tf.dispose(nmsT);
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const id of nms) {
|
for (const id of Array.from(nms)) {
|
||||||
const score = Math.trunc(100 * detections[0][id][4]) / 100;
|
const score = Math.trunc(100 * detections[0][id][4]) / 100;
|
||||||
const classVal = detections[0][id][5];
|
const classVal = detections[0][id][5];
|
||||||
const label = labels[classVal].label;
|
const label = labels[classVal].label;
|
||||||
|
@ -74,6 +68,7 @@ async function process(res: Tensor | null, outputShape, config: Config) {
|
||||||
];
|
];
|
||||||
results.push({ id: i++, score, class: classVal, label, box, boxRaw });
|
results.push({ id: i++, score, class: classVal, label, box, boxRaw });
|
||||||
}
|
}
|
||||||
|
Object.keys(t).forEach((tensor) => tf.dispose(t[tensor]));
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { log, join, now } from '../util/util';
|
import { log, join, now } from '../util/util';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import { labels } from './labels';
|
import { labels } from './labels';
|
||||||
import type { ObjectResult, Box } from '../result';
|
import type { ObjectResult, Box } from '../result';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import { log, join } from '../util/util';
|
import { log, join } from '../util/util';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as image from '../image/image';
|
import * as image from '../image/image';
|
||||||
import * as constants from '../tfjs/constants';
|
import { constants } from '../tfjs/constants';
|
||||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { log, now } from '../util/util';
|
||||||
import { env } from '../util/env';
|
import { env } from '../util/env';
|
||||||
import * as humangl from './humangl';
|
import * as humangl from './humangl';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
|
import * as constants from './constants';
|
||||||
|
|
||||||
function registerCustomOps() {
|
function registerCustomOps() {
|
||||||
if (!env.kernels.includes('mod')) {
|
if (!env.kernels.includes('mod')) {
|
||||||
|
@ -87,6 +88,7 @@ export async function check(instance: Human, force = false) {
|
||||||
try {
|
try {
|
||||||
await tf.setBackend(instance.config.backend);
|
await tf.setBackend(instance.config.backend);
|
||||||
await tf.ready();
|
await tf.ready();
|
||||||
|
constants.init();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log('error: cannot set backend:', instance.config.backend, err);
|
log('error: cannot set backend:', instance.config.backend, err);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import type { Tensor } from './types';
|
import type { Tensor } from './types';
|
||||||
|
|
||||||
export const tf255: Tensor = tf.scalar(255, 'float32');
|
export const constants: Record<string, Tensor | number | number[]> = {
|
||||||
export const tf1: Tensor = tf.scalar(1, 'float32');
|
tf255: 255,
|
||||||
export const tf2: Tensor = tf.scalar(2, 'float32');
|
tf1: 1,
|
||||||
export const tf05: Tensor = tf.scalar(0.5, 'float32');
|
tf2: 2,
|
||||||
export const tf127: Tensor = tf.scalar(127.5, 'float32');
|
tf05: 0.5,
|
||||||
export const rgb: Tensor = tf.tensor1d([0.2989, 0.5870, 0.1140], 'float32'); // factors for red/green/blue colors when converting to grayscale
|
tf127: 127.5,
|
||||||
|
rgb: [0.2989, 0.5870, 0.1140],
|
||||||
|
};
|
||||||
|
|
||||||
|
export function init() {
|
||||||
|
constants.tf255 = tf.scalar(255, 'float32');
|
||||||
|
constants.tf1 = tf.scalar(1, 'float32');
|
||||||
|
constants.tf2 = tf.scalar(2, 'float32');
|
||||||
|
constants.tf05 = tf.scalar(0.5, 'float32');
|
||||||
|
constants.tf127 = tf.scalar(127.5, 'float32');
|
||||||
|
constants.rgb = tf.tensor1d([0.2989, 0.5870, 0.1140], 'float32'); // factors for red/green/blue colors when converting to grayscale
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue