UNPKG

@codait/max-image-segmenter

Version:

Identify objects in an image, additionally assigning each pixel of the image to a particular object.

466 lines (446 loc) 9.31 kB
'use strict';Object.defineProperty(exports,'__esModule',{value:true});/* globals tf, Image */ const IMAGESIZE = 512; const computeTargetSize = function (width, height) { const resizeRatio = IMAGESIZE / Math.max(width, height); return { width: Math.round(resizeRatio * width), height: Math.round(resizeRatio * height) } }; const getImageData = function (imageInput) { { return Promise.resolve(imageInput) } }; const imageToTensor = function (imageData) { return tf.tidy(() => { const imgTensor = tf.browser.fromPixels(imageData); const targetSize = computeTargetSize(imgTensor.shape[0], imgTensor.shape[1]); return imgTensor.resizeBilinear([targetSize.width, targetSize.height]).expandDims() }) }; /** * convert image to Tensor input required by the model * * @param {HTMLImageElement} imageInput - the image element */ const preprocess = function (imageInput) { return getImageData(imageInput) .then(imageToTensor) .then(inputTensor => { return Promise.resolve(inputTensor) }) .catch(err => { console.error(err); return Promise.reject(err) }) };/* globals tf */ let modelPath = null; { modelPath = `file://${__dirname}/../model/model.json`; } let model = null; let warmed = false; /** * load the image segmenter model */ const load = function (initialize) { if (!model) { // console.log('loading model...') // console.time('model load') return tf.loadGraphModel(modelPath) .then(m => { // console.timeEnd('model load') model = m; if (istrue(initialize)) { warmup(); } return Promise.resolve(model) }) .catch(err => { // console.timeEnd('model load') console.error(err); return Promise.reject(err) }) } else if (istrue(initialize) && !warmed) { warmup(); return Promise.resolve(model) } else { return Promise.resolve(model) } }; /** * run the model to get a prediction */ const run = function (imageTensor) { if (!imageTensor) { console.error('no image provided'); throw new Error('no image provided') } else if (!model) { console.error('model not available'); throw new Error('model not available') } else { // console.log('running model...') return tf.tidy(() => { // console.time('model inference') const results = model.predict(imageTensor.toInt()); // console.timeEnd('model inference') warmed = true; return results }) } }; /** * run inference on the TensorFlow.js model */ const inference = function (imageTensor) { return load(false).then(() => { try { const results = run(imageTensor); return Promise.resolve(results) } catch (err) { return Promise.reject(err) } }) }; const warmup = function () { try { run(tf.zeros([1, 512, 512, 3])); } catch (err) { } }; const istrue = function (param) { return param === null || typeof param === 'undefined' || (typeof param === 'string' && param.toLowerCase() === 'true') || (typeof param === 'boolean' && param) };const labels = [ 'background', 'airplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'dining table', 'dog', 'horse', 'motorbike', 'person', 'potted plant', 'sheep', 'sofa', 'train', 'tv' ]; const colors = [ [0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], [0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128], [64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0], [64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128], [0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0], [0, 64, 128], [128, 64, 128], [0, 192, 128], [128, 192, 128], [64, 64, 0], [192, 64, 0], [64, 192, 0], [192, 192, 0], [64, 64, 128], [192, 64, 128], [64, 192, 128], [192, 192, 128], [0, 0, 64], [128, 0, 64], [0, 128, 64], [128, 128, 64], [0, 0, 192], [128, 0, 192], [0, 128, 192], [128, 128, 192], [64, 0, 64], [192, 0, 64], [64, 128, 64], [192, 128, 64], [64, 0, 192], [192, 0, 192], [64, 128, 192], [192, 128, 192], [0, 64, 64], [128, 64, 64], [0, 192, 64], [128, 192, 64], [0, 64, 192], [128, 64, 192], [0, 192, 192], [128, 192, 192], [64, 64, 64], [192, 64, 64], [64, 192, 64], [192, 192, 64], [64, 64, 192], [192, 64, 192], [64, 192, 192], [192, 192, 192], [32, 0, 0], [160, 0, 0], [32, 128, 0], [160, 128, 0], [32, 0, 128], [160, 0, 128], [32, 128, 128], [160, 128, 128], [96, 0, 0], [224, 0, 0], [96, 128, 0], [224, 128, 0], [96, 0, 128], [224, 0, 128], [96, 128, 128], [224, 128, 128], [32, 64, 0], [160, 64, 0], [32, 192, 0], [160, 192, 0], [32, 64, 128], [160, 64, 128], [32, 192, 128], [160, 192, 128], [96, 64, 0], [224, 64, 0], [96, 192, 0], [224, 192, 0], [96, 64, 128], [224, 64, 128], [96, 192, 128], [224, 192, 128], [32, 0, 64], [160, 0, 64], [32, 128, 64], [160, 128, 64], [32, 0, 192], [160, 0, 192], [32, 128, 192], [160, 128, 192], [96, 0, 64], [224, 0, 64], [96, 128, 64], [224, 128, 64], [96, 0, 192], [224, 0, 192], [96, 128, 192], [224, 128, 192], [32, 64, 64], [160, 64, 64], [32, 192, 64], [160, 192, 64], [32, 64, 192], [160, 64, 192], [32, 192, 192], [160, 192, 192], [96, 64, 64], [224, 64, 64], [96, 192, 64], [224, 192, 64], [96, 64, 192], [224, 64, 192], [96, 192, 192], [224, 192, 192], [0, 32, 0], [128, 32, 0], [0, 160, 0], [128, 160, 0], [0, 32, 128], [128, 32, 128], [0, 160, 128], [128, 160, 128], [64, 32, 0], [192, 32, 0], [64, 160, 0], [192, 160, 0], [64, 32, 128], [192, 32, 128], [64, 160, 128], [192, 160, 128], [0, 96, 0], [128, 96, 0], [0, 224, 0], [128, 224, 0], [0, 96, 128], [128, 96, 128], [0, 224, 128], [128, 224, 128], [64, 96, 0], [192, 96, 0], [64, 224, 0], [192, 224, 0], [64, 96, 128], [192, 96, 128], [64, 224, 128], [192, 224, 128], [0, 32, 64], [128, 32, 64], [0, 160, 64], [128, 160, 64], [0, 32, 192], [128, 32, 192], [0, 160, 192], [128, 160, 192], [64, 32, 64], [192, 32, 64], [64, 160, 64], [192, 160, 64], [64, 32, 192], [192, 32, 192], [64, 160, 192], [192, 160, 192], [0, 96, 64], [128, 96, 64], [0, 224, 64], [128, 224, 64], [0, 96, 192], [128, 96, 192], [0, 224, 192], [128, 224, 192], [64, 96, 64], [192, 96, 64], [64, 224, 64], [192, 224, 64], [64, 96, 192], [192, 96, 192], [64, 224, 192], [192, 224, 192], [32, 32, 0], [160, 32, 0], [32, 160, 0], [160, 160, 0], [32, 32, 128], [160, 32, 128], [32, 160, 128], [160, 160, 128], [96, 32, 0], [224, 32, 0], [96, 160, 0], [224, 160, 0], [96, 32, 128], [224, 32, 128], [96, 160, 128], [224, 160, 128], [32, 96, 0], [160, 96, 0], [32, 224, 0], [160, 224, 0], [32, 96, 128], [160, 96, 128], [32, 224, 128], [160, 224, 128], [96, 96, 0], [224, 96, 0], [96, 224, 0], [224, 224, 0], [96, 96, 128], [224, 96, 128], [96, 224, 128], [224, 224, 128], [32, 32, 64], [160, 32, 64], [32, 160, 64], [160, 160, 64], [32, 32, 192], [160, 32, 192], [32, 160, 192], [160, 160, 192], [96, 32, 64], [224, 32, 64], [96, 160, 64], [224, 160, 64], [96, 32, 192], [224, 32, 192], [96, 160, 192], [224, 160, 192], [32, 96, 64], [160, 96, 64], [32, 224, 64], [160, 224, 64], [32, 96, 192], [160, 96, 192], [32, 224, 192], [160, 224, 192], [96, 96, 64], [224, 96, 64], [96, 224, 64], [224, 224, 64], [96, 96, 192], [224, 96, 192], [96, 224, 192], [224, 224, 192] ];const predictedObjs = function (segArray) { const segLabels = {}; segArray.forEach(arr => { arr.forEach(seg => { if (!segLabels[labels[seg]]) { segLabels[labels[seg]] = true; } }); }); return Object.keys(segLabels) }; /** * convert model Tensor output to image data for previewing * * @param {Tensor} inferenceResults - the output from running the model */ const postprocess = function (inferenceResults) { return inferenceResults.unstack()[0].array() .then(segArray => { return Promise.resolve({ segmentationMap: segArray, objectsDetected: predictedObjs(segArray), imageSize: { width: segArray[0].length, height: segArray.length } }) }) };const version="0.3.0";{ global.tf = require('@tensorflow/tfjs-node'); } const processInput = function (inputImage) { return preprocess(inputImage) }; const loadModel = function (init) { return load(init) }; const runInference = function (inputTensor) { return inference(inputTensor) }; const processOutput = function (inferenceResults) { return postprocess(inferenceResults) }; const predict = function (inputImage) { return processInput(inputImage) .then(runInference) .then(processOutput) .catch(err => { console.error(err); }) };exports.colorsMap=colors;exports.labelsMap=labels;exports.loadModel=loadModel;exports.predict=predict;exports.processInput=processInput;exports.processOutput=processOutput;exports.runInference=runInference;exports.version=version;