tfjs-image-recognition-base
Advanced tools
Comparing version 0.0.0 to 0.1.0
@@ -1,33 +0,10 @@ | ||
import { Rect } from './Rect'; | ||
import { Dimensions } from './types'; | ||
export declare class BoundingBox { | ||
private _left; | ||
private _top; | ||
private _right; | ||
private _bottom; | ||
constructor(_left: number, _top: number, _right: number, _bottom: number); | ||
readonly left: number; | ||
readonly top: number; | ||
readonly right: number; | ||
readonly bottom: number; | ||
readonly width: number; | ||
readonly height: number; | ||
readonly area: number; | ||
toSquare(): BoundingBox; | ||
round(): BoundingBox; | ||
padAtBorders(imageHeight: number, imageWidth: number): { | ||
dy: number; | ||
edy: number; | ||
dx: number; | ||
edx: number; | ||
y: number; | ||
ey: number; | ||
x: number; | ||
ex: number; | ||
w: number; | ||
h: number; | ||
}; | ||
calibrate(region: BoundingBox): BoundingBox; | ||
rescale(s: Dimensions | number): BoundingBox; | ||
toRect(): Rect; | ||
import { Box } from './Box'; | ||
export interface IBoundingBox { | ||
left: number; | ||
top: number; | ||
right: number; | ||
bottom: number; | ||
} | ||
export declare class BoundingBox extends Box<BoundingBox> implements IBoundingBox { | ||
constructor(left: number, top: number, right: number, bottom: number); | ||
} |
@@ -1,118 +0,11 @@ | ||
import { isDimensions } from '../utils'; | ||
import { Rect } from './Rect'; | ||
var BoundingBox = /** @class */ (function () { | ||
function BoundingBox(_left, _top, _right, _bottom) { | ||
this._left = _left; | ||
this._top = _top; | ||
this._right = _right; | ||
this._bottom = _bottom; | ||
import * as tslib_1 from "tslib"; | ||
import { Box } from './Box'; | ||
var BoundingBox = /** @class */ (function (_super) { | ||
tslib_1.__extends(BoundingBox, _super); | ||
function BoundingBox(left, top, right, bottom) { | ||
return _super.call(this, { left: left, top: top, right: right, bottom: bottom }) || this; | ||
} | ||
Object.defineProperty(BoundingBox.prototype, "left", { | ||
get: function () { | ||
return this._left; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(BoundingBox.prototype, "top", { | ||
get: function () { | ||
return this._top; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(BoundingBox.prototype, "right", { | ||
get: function () { | ||
return this._right; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(BoundingBox.prototype, "bottom", { | ||
get: function () { | ||
return this._bottom; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(BoundingBox.prototype, "width", { | ||
get: function () { | ||
return this.right - this.left; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(BoundingBox.prototype, "height", { | ||
get: function () { | ||
return this.bottom - this.top; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(BoundingBox.prototype, "area", { | ||
get: function () { | ||
return this.width * this.height; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
BoundingBox.prototype.toSquare = function () { | ||
var _a = this, left = _a.left, top = _a.top, right = _a.right, bottom = _a.bottom; | ||
var off = (Math.abs(this.width - this.height) / 2); | ||
if (this.width < this.height) { | ||
left -= off; | ||
right += off; | ||
} | ||
if (this.height < this.width) { | ||
top -= off; | ||
bottom += off; | ||
} | ||
return new BoundingBox(left, top, right, bottom); | ||
}; | ||
BoundingBox.prototype.round = function () { | ||
return new BoundingBox(Math.round(this.left), Math.round(this.top), Math.round(this.right), Math.round(this.bottom)); | ||
}; | ||
BoundingBox.prototype.padAtBorders = function (imageHeight, imageWidth) { | ||
var w = this.width + 1; | ||
var h = this.height + 1; | ||
var dx = 1; | ||
var dy = 1; | ||
var edx = w; | ||
var edy = h; | ||
var x = this.left; | ||
var y = this.top; | ||
var ex = this.right; | ||
var ey = this.bottom; | ||
if (ex > imageWidth) { | ||
edx = -ex + imageWidth + w; | ||
ex = imageWidth; | ||
} | ||
if (ey > imageHeight) { | ||
edy = -ey + imageHeight + h; | ||
ey = imageHeight; | ||
} | ||
if (x < 1) { | ||
edy = 2 - x; | ||
x = 1; | ||
} | ||
if (y < 1) { | ||
edy = 2 - y; | ||
y = 1; | ||
} | ||
return { dy: dy, edy: edy, dx: dx, edx: edx, y: y, ey: ey, x: x, ex: ex, w: w, h: h }; | ||
}; | ||
BoundingBox.prototype.calibrate = function (region) { | ||
return new BoundingBox(this.left + (region.left * this.width), this.top + (region.top * this.height), this.right + (region.right * this.width), this.bottom + (region.bottom * this.height)).toSquare().round(); | ||
}; | ||
BoundingBox.prototype.rescale = function (s) { | ||
var scaleX = isDimensions(s) ? s.width : s; | ||
var scaleY = isDimensions(s) ? s.height : s; | ||
return new BoundingBox(this.left * scaleX, this.top * scaleY, this.right * scaleX, this.bottom * scaleY); | ||
}; | ||
BoundingBox.prototype.toRect = function () { | ||
return new Rect(this.left, this.top, this.width, this.height); | ||
}; | ||
return BoundingBox; | ||
}()); | ||
}(Box)); | ||
export { BoundingBox }; | ||
//# sourceMappingURL=BoundingBox.js.map |
@@ -0,5 +1,8 @@ | ||
export * from './Box'; | ||
export * from './BoundingBox'; | ||
export * from './LabeledBox'; | ||
export * from './ObjectDetection'; | ||
export * from './Point'; | ||
export * from './PredictedBox'; | ||
export * from './Rect'; | ||
export * from './types'; |
@@ -0,5 +1,8 @@ | ||
export * from './Box'; | ||
export * from './BoundingBox'; | ||
export * from './LabeledBox'; | ||
export * from './ObjectDetection'; | ||
export * from './Point'; | ||
export * from './PredictedBox'; | ||
export * from './Rect'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
import { BoundingBox } from './BoundingBox'; | ||
import { Box } from './Box'; | ||
export interface IRect { | ||
@@ -8,15 +8,4 @@ x: number; | ||
} | ||
export declare class Rect implements IRect { | ||
x: number; | ||
y: number; | ||
width: number; | ||
height: number; | ||
export declare class Rect extends Box<Rect> implements IRect { | ||
constructor(x: number, y: number, width: number, height: number); | ||
readonly right: number; | ||
readonly bottom: number; | ||
toSquare(): Rect; | ||
pad(padX: number, padY: number): Rect; | ||
floor(): Rect; | ||
toBoundingBox(): BoundingBox; | ||
clipAtImageBorders(imgWidth: number, imgHeight: number): Rect; | ||
} |
@@ -1,59 +0,11 @@ | ||
import { BoundingBox } from './BoundingBox'; | ||
var Rect = /** @class */ (function () { | ||
import * as tslib_1 from "tslib"; | ||
import { Box } from './Box'; | ||
var Rect = /** @class */ (function (_super) { | ||
tslib_1.__extends(Rect, _super); | ||
function Rect(x, y, width, height) { | ||
this.x = x; | ||
this.y = y; | ||
this.width = width; | ||
this.height = height; | ||
return _super.call(this, { x: x, y: y, width: width, height: height }) || this; | ||
} | ||
Object.defineProperty(Rect.prototype, "right", { | ||
get: function () { | ||
return this.x + this.width; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Rect.prototype, "bottom", { | ||
get: function () { | ||
return this.y + this.height; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Rect.prototype.toSquare = function () { | ||
var _a = this, x = _a.x, y = _a.y, width = _a.width, height = _a.height; | ||
var diff = Math.abs(width - height); | ||
if (width < height) { | ||
x -= (diff / 2); | ||
width += diff; | ||
} | ||
if (height < width) { | ||
y -= (diff / 2); | ||
height += diff; | ||
} | ||
return new Rect(x, y, width, height); | ||
}; | ||
Rect.prototype.pad = function (padX, padY) { | ||
var _a = this, x = _a.x, y = _a.y, width = _a.width, height = _a.height; | ||
return new Rect(x - (padX / 2), y - (padY / 2), width + padX, height + padY); | ||
}; | ||
Rect.prototype.floor = function () { | ||
return new Rect(Math.floor(this.x), Math.floor(this.y), Math.floor(this.width), Math.floor(this.height)); | ||
}; | ||
Rect.prototype.toBoundingBox = function () { | ||
return new BoundingBox(this.x, this.y, this.x + this.width, this.y + this.height); | ||
}; | ||
Rect.prototype.clipAtImageBorders = function (imgWidth, imgHeight) { | ||
var _a = this, x = _a.x, y = _a.y, right = _a.right, bottom = _a.bottom; | ||
var clippedX = Math.max(x, 0); | ||
var clippedY = Math.max(y, 0); | ||
var newWidth = right - clippedX; | ||
var newHeight = bottom - clippedY; | ||
var clippedWidth = Math.min(newWidth, imgWidth - clippedX); | ||
var clippedHeight = Math.min(newHeight, imgHeight - clippedY); | ||
return (new Rect(clippedX, clippedY, clippedWidth, clippedHeight)).floor(); | ||
}; | ||
return Rect; | ||
}()); | ||
}(Box)); | ||
export { Rect }; | ||
//# sourceMappingURL=Rect.js.map |
@@ -1,1 +0,1 @@ | ||
export declare function imageToSquare(input: HTMLImageElement | HTMLCanvasElement, inputSize: number): HTMLCanvasElement; | ||
export declare function imageToSquare(input: HTMLImageElement | HTMLCanvasElement, inputSize: number, centerImage?: boolean): HTMLCanvasElement; |
import { createCanvas, createCanvasFromMedia } from './createCanvas'; | ||
import { getContext2dOrThrow } from './getContext2dOrThrow'; | ||
import { getMediaDimensions } from './getMediaDimensions'; | ||
export function imageToSquare(input, inputSize) { | ||
export function imageToSquare(input, inputSize, centerImage) { | ||
if (centerImage === void 0) { centerImage = false; } | ||
if (!(input instanceof HTMLImageElement || input instanceof HTMLCanvasElement)) { | ||
@@ -14,5 +15,8 @@ throw new Error('imageToSquare - expected arg0 to be HTMLImageElement | HTMLCanvasElement'); | ||
var inputCanvas = input instanceof HTMLCanvasElement ? input : createCanvasFromMedia(input); | ||
getContext2dOrThrow(targetCanvas).drawImage(inputCanvas, 0, 0, width, height); | ||
var offset = Math.abs(width - height) / 2; | ||
var dx = centerImage && width < height ? offset : 0; | ||
var dy = centerImage && height < width ? offset : 0; | ||
getContext2dOrThrow(targetCanvas).drawImage(inputCanvas, dx, dy, width, height); | ||
return targetCanvas; | ||
} | ||
//# sourceMappingURL=imageToSquare.js.map |
import * as tf from '@tensorflow/tfjs-core'; | ||
import { Point } from '../classes/Point'; | ||
import { Dimensions } from '../classes/types'; | ||
import { TResolvedNetInput } from './types'; | ||
export declare class NetInput { | ||
private _inputs; | ||
private _imageTensors; | ||
private _canvases; | ||
private _isManaged; | ||
private _isBatchInput; | ||
private _batchSize; | ||
private _treatAsBatchInput; | ||
private _inputDimensions; | ||
private _paddings; | ||
private _inputSize; | ||
constructor(inputs: tf.Tensor4D | Array<TResolvedNetInput>, isBatchInput?: boolean, keepCanvases?: boolean); | ||
readonly inputs: tf.Tensor3D[]; | ||
constructor(inputs: Array<TResolvedNetInput>, treatAsBatchInput?: boolean); | ||
readonly imageTensors: Array<tf.Tensor3D | tf.Tensor4D>; | ||
readonly canvases: HTMLCanvasElement[]; | ||
readonly isManaged: boolean; | ||
readonly isBatchInput: boolean; | ||
readonly batchSize: number; | ||
readonly inputDimensions: number[][]; | ||
readonly paddings: Point[]; | ||
readonly inputSize: number; | ||
readonly relativePaddings: Point[]; | ||
readonly inputSize: number | undefined; | ||
readonly reshapedInputDimensions: Dimensions[]; | ||
getInput(batchIdx: number): tf.Tensor3D | tf.Tensor4D | HTMLCanvasElement; | ||
getInputDimensions(batchIdx: number): number[]; | ||
getInputHeight(batchIdx: number): number; | ||
getInputWidth(batchIdx: number): number; | ||
getPaddings(batchIdx: number): Point; | ||
getRelativePaddings(batchIdx: number): Point; | ||
getReshapedInputDimensions(batchIdx: number): Dimensions; | ||
toBatchTensor(inputSize: number, isCenterInputs?: boolean): tf.Tensor4D; | ||
/** | ||
* By setting the isManaged flag, all newly created tensors will be | ||
* automatically disposed after the batch tensor has been created | ||
* Create a batch tensor from all input canvases and tensors | ||
* with size [batchSize, inputSize, inputSize, 3]. | ||
* | ||
* @param inputSize Height and width of the tensor. | ||
* @param isCenterImage (optional, default: false) If true, add an equal amount of padding on | ||
* both sides of the minor dimension oof the image. | ||
* @returns The batch tensor. | ||
*/ | ||
managed(): this; | ||
dispose(): void; | ||
toBatchTensor(inputSize: number, isCenterInputs?: boolean): tf.Tensor4D; | ||
} |
import * as tf from '@tensorflow/tfjs-core'; | ||
import { Point } from '../classes/Point'; | ||
import { padToSquare } from '../ops/padToSquare'; | ||
import { isTensor3D, isTensor4D } from '../utils'; | ||
import { computeReshapedDimensions } from '../utils'; | ||
import { computeReshapedDimensions, isTensor3D, isTensor4D, range } from '../utils'; | ||
import { createCanvasFromMedia } from './createCanvas'; | ||
import { imageToSquare } from './imageToSquare'; | ||
var NetInput = /** @class */ (function () { | ||
function NetInput(inputs, isBatchInput, keepCanvases) { | ||
if (isBatchInput === void 0) { isBatchInput = false; } | ||
if (keepCanvases === void 0) { keepCanvases = false; } | ||
function NetInput(inputs, treatAsBatchInput) { | ||
if (treatAsBatchInput === void 0) { treatAsBatchInput = false; } | ||
var _this = this; | ||
this._inputs = []; | ||
this._imageTensors = []; | ||
this._canvases = []; | ||
this._isManaged = false; | ||
this._isBatchInput = false; | ||
this._treatAsBatchInput = false; | ||
this._inputDimensions = []; | ||
this._paddings = []; | ||
if (isTensor4D(inputs)) { | ||
this._inputs = tf.unstack(inputs); | ||
if (!Array.isArray(inputs)) { | ||
throw new Error("NetInput.constructor - expected inputs to be an Array of TResolvedNetInput or to be instanceof tf.Tensor4D, instead have " + inputs); | ||
} | ||
if (Array.isArray(inputs)) { | ||
this._inputs = inputs.map(function (input, idx) { | ||
if (isTensor3D(input)) { | ||
// TODO: make sure not to dispose original tensors passed in by the user | ||
return tf.clone(input); | ||
this._treatAsBatchInput = treatAsBatchInput; | ||
this._batchSize = inputs.length; | ||
inputs.forEach(function (input, idx) { | ||
if (isTensor3D(input)) { | ||
_this._imageTensors[idx] = input; | ||
_this._inputDimensions[idx] = input.shape; | ||
return; | ||
} | ||
if (isTensor4D(input)) { | ||
var batchSize = input.shape[0]; | ||
if (batchSize !== 1) { | ||
throw new Error("NetInput - tf.Tensor4D with batchSize " + batchSize + " passed, but not supported in input array"); | ||
} | ||
if (isTensor4D(input)) { | ||
var shape = input.shape; | ||
var batchSize = shape[0]; | ||
if (batchSize !== 1) { | ||
throw new Error("NetInput - tf.Tensor4D with batchSize " + batchSize + " passed, but not supported in input array"); | ||
} | ||
return input.reshape(shape.slice(1)); | ||
} | ||
var canvas = input instanceof HTMLCanvasElement ? input : createCanvasFromMedia(input); | ||
if (keepCanvases) { | ||
_this._canvases[idx] = canvas; | ||
} | ||
return tf.fromPixels(canvas); | ||
}); | ||
} | ||
this._isBatchInput = this.batchSize > 1 || isBatchInput; | ||
this._inputDimensions = this._inputs.map(function (t) { return t.shape; }); | ||
_this._imageTensors[idx] = input; | ||
_this._inputDimensions[idx] = input.shape.slice(1); | ||
return; | ||
} | ||
var canvas = input instanceof HTMLCanvasElement ? input : createCanvasFromMedia(input); | ||
_this._canvases[idx] = canvas; | ||
_this._inputDimensions[idx] = [canvas.height, canvas.width, 3]; | ||
}); | ||
} | ||
Object.defineProperty(NetInput.prototype, "inputs", { | ||
Object.defineProperty(NetInput.prototype, "imageTensors", { | ||
get: function () { | ||
return this._inputs; | ||
return this._imageTensors; | ||
}, | ||
@@ -59,12 +53,5 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(NetInput.prototype, "isManaged", { | ||
get: function () { | ||
return this._isManaged; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NetInput.prototype, "isBatchInput", { | ||
get: function () { | ||
return this._isBatchInput; | ||
return this.batchSize > 1 || this._treatAsBatchInput; | ||
}, | ||
@@ -76,3 +63,3 @@ enumerable: true, | ||
get: function () { | ||
return this._inputs.length; | ||
return this._batchSize; | ||
}, | ||
@@ -89,9 +76,2 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(NetInput.prototype, "paddings", { | ||
get: function () { | ||
return this._paddings; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NetInput.prototype, "inputSize", { | ||
@@ -104,14 +84,6 @@ get: function () { | ||
}); | ||
Object.defineProperty(NetInput.prototype, "relativePaddings", { | ||
get: function () { | ||
var _this = this; | ||
return Array(this.inputs.length).fill(0).map(function (_, batchIdx) { return _this.getRelativePaddings(batchIdx); }); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NetInput.prototype, "reshapedInputDimensions", { | ||
get: function () { | ||
var _this = this; | ||
return Array(this.inputs.length).fill(0).map(function (_, batchIdx) { return _this.getReshapedInputDimensions(batchIdx); }); | ||
return range(this.batchSize, 0, 1).map(function (_, batchIdx) { return _this.getReshapedInputDimensions(batchIdx); }); | ||
}, | ||
@@ -121,2 +93,5 @@ enumerable: true, | ||
}); | ||
NetInput.prototype.getInput = function (batchIdx) { | ||
return this.canvases[batchIdx] || this.imageTensors[batchIdx]; | ||
}; | ||
NetInput.prototype.getInputDimensions = function (batchIdx) { | ||
@@ -131,8 +106,2 @@ return this._inputDimensions[batchIdx]; | ||
}; | ||
NetInput.prototype.getPaddings = function (batchIdx) { | ||
return this._paddings[batchIdx]; | ||
}; | ||
NetInput.prototype.getRelativePaddings = function (batchIdx) { | ||
return new Point((this.getPaddings(batchIdx).x + this.getInputWidth(batchIdx)) / this.getInputWidth(batchIdx), (this.getPaddings(batchIdx).y + this.getInputHeight(batchIdx)) / this.getInputHeight(batchIdx)); | ||
}; | ||
NetInput.prototype.getReshapedInputDimensions = function (batchIdx) { | ||
@@ -146,2 +115,11 @@ if (typeof this.inputSize !== 'number') { | ||
}; | ||
/** | ||
* Create a batch tensor from all input canvases and tensors | ||
* with size [batchSize, inputSize, inputSize, 3]. | ||
* | ||
* @param inputSize Height and width of the tensor. | ||
* @param isCenterImage (optional, default: false) If true, add an equal amount of padding on | ||
* both sides of the minor dimension oof the image. | ||
* @returns The batch tensor. | ||
*/ | ||
NetInput.prototype.toBatchTensor = function (inputSize, isCenterInputs) { | ||
@@ -152,31 +130,21 @@ var _this = this; | ||
return tf.tidy(function () { | ||
var inputTensors = _this._inputs.map(function (inputTensor) { | ||
var _a = inputTensor.shape, originalHeight = _a[0], originalWidth = _a[1]; | ||
var imgTensor = inputTensor.expandDims().toFloat(); | ||
imgTensor = padToSquare(imgTensor, isCenterInputs); | ||
var _b = imgTensor.shape.slice(1), heightAfterPadding = _b[0], widthAfterPadding = _b[1]; | ||
if (heightAfterPadding !== inputSize || widthAfterPadding !== inputSize) { | ||
imgTensor = tf.image.resizeBilinear(imgTensor, [inputSize, inputSize]); | ||
var inputTensors = range(_this.batchSize, 0, 1).map(function (batchIdx) { | ||
var input = _this.getInput(batchIdx); | ||
if (input instanceof tf.Tensor) { | ||
var imgTensor = isTensor4D(input) ? input : input.expandDims(); | ||
imgTensor = padToSquare(imgTensor, isCenterInputs); | ||
if (imgTensor.shape[1] !== inputSize || imgTensor.shape[2] !== inputSize) { | ||
imgTensor = tf.image.resizeBilinear(imgTensor, [inputSize, inputSize]); | ||
} | ||
return imgTensor.as3D(inputSize, inputSize, 3); | ||
} | ||
_this._paddings.push(new Point(widthAfterPadding - originalWidth, heightAfterPadding - originalHeight)); | ||
return imgTensor; | ||
if (input instanceof HTMLCanvasElement) { | ||
return tf.fromPixels(imageToSquare(input, inputSize, isCenterInputs)); | ||
} | ||
throw new Error("toBatchTensor - at batchIdx " + batchIdx + ", expected input to be instanceof tf.Tensor or instanceof HTMLCanvasElement, instead have " + input); | ||
}); | ||
var batchTensor = tf.stack(inputTensors).as4D(_this.batchSize, inputSize, inputSize, 3); | ||
if (_this.isManaged) { | ||
_this.dispose(); | ||
} | ||
var batchTensor = tf.stack(inputTensors.map(function (t) { return t.toFloat(); })).as4D(_this.batchSize, inputSize, inputSize, 3); | ||
return batchTensor; | ||
}); | ||
}; | ||
/** | ||
* By setting the isManaged flag, all newly created tensors will be | ||
* automatically disposed after the batch tensor has been created | ||
*/ | ||
NetInput.prototype.managed = function () { | ||
this._isManaged = true; | ||
return this; | ||
}; | ||
NetInput.prototype.dispose = function () { | ||
this._inputs.forEach(function (t) { return t.dispose(); }); | ||
}; | ||
return NetInput; | ||
@@ -183,0 +151,0 @@ }()); |
@@ -8,6 +8,4 @@ import { NetInput } from './NetInput'; | ||
* @param input The input, which can be a media element or an array of different media elements. | ||
* @param manageCreatedInput If a new NetInput instance is created from the inputs, this flag | ||
* determines, whether to set the NetInput as managed or not. | ||
* @returns A NetInput instance, which can be passed into one of the neural networks. | ||
*/ | ||
export declare function toNetInput(inputs: TNetInput, manageCreatedInput?: boolean, keepCanvases?: boolean): Promise<NetInput>; | ||
export declare function toNetInput(inputs: TNetInput): Promise<NetInput>; |
@@ -12,11 +12,7 @@ import * as tslib_1 from "tslib"; | ||
* @param input The input, which can be a media element or an array of different media elements. | ||
* @param manageCreatedInput If a new NetInput instance is created from the inputs, this flag | ||
* determines, whether to set the NetInput as managed or not. | ||
* @returns A NetInput instance, which can be passed into one of the neural networks. | ||
*/ | ||
export function toNetInput(inputs, manageCreatedInput, keepCanvases) { | ||
if (manageCreatedInput === void 0) { manageCreatedInput = false; } | ||
if (keepCanvases === void 0) { keepCanvases = false; } | ||
export function toNetInput(inputs) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var afterCreate, inputArgArray, getIdxHint, inputArray; | ||
var inputArgArray, getIdxHint, inputArray; | ||
return tslib_1.__generator(this, function (_a) { | ||
@@ -28,8 +24,2 @@ switch (_a.label) { | ||
} | ||
afterCreate = function (netInput) { return manageCreatedInput | ||
? netInput.managed() | ||
: netInput; }; | ||
if (isTensor4D(inputs)) { | ||
return [2 /*return*/, afterCreate(new NetInput(inputs))]; | ||
} | ||
inputArgArray = Array.isArray(inputs) | ||
@@ -63,3 +53,3 @@ ? inputs | ||
_a.sent(); | ||
return [2 /*return*/, afterCreate(new NetInput(inputArray, Array.isArray(inputs), keepCanvases))]; | ||
return [2 /*return*/, new NetInput(inputArray, Array.isArray(inputs))]; | ||
} | ||
@@ -66,0 +56,0 @@ }); |
@@ -1,2 +0,2 @@ | ||
import { BoundingBox } from '../classes/BoundingBox'; | ||
export declare function iou(box1: BoundingBox, box2: BoundingBox, isIOU?: boolean): number; | ||
import { Box } from '../classes/Box'; | ||
export declare function iou(box1: Box, box2: Box, isIOU?: boolean): number; |
@@ -1,2 +0,2 @@ | ||
import { BoundingBox } from '../classes/BoundingBox'; | ||
export declare function nonMaxSuppression(boxes: BoundingBox[], scores: number[], iouThreshold: number, isIOU?: boolean): number[]; | ||
import { Box } from '../classes/Box'; | ||
export declare function nonMaxSuppression(boxes: Box[], scores: number[], iouThreshold: number, isIOU?: boolean): number[]; |
@@ -6,5 +6,6 @@ import * as tf from '@tensorflow/tfjs-core'; | ||
* @param imgTensor The image tensor. | ||
* @param isCenterImage (optional, default: false) If true, add padding on both sides of the image, such that the image. | ||
* @param isCenterImage (optional, default: false) If true, add an equal amount of padding on | ||
* both sides of the minor dimension oof the image. | ||
* @returns The padded tensor with width === height. | ||
*/ | ||
export declare function padToSquare(imgTensor: tf.Tensor4D, isCenterImage?: boolean): tf.Tensor4D; |
@@ -6,3 +6,4 @@ import * as tf from '@tensorflow/tfjs-core'; | ||
* @param imgTensor The image tensor. | ||
* @param isCenterImage (optional, default: false) If true, add padding on both sides of the image, such that the image. | ||
* @param isCenterImage (optional, default: false) If true, add an equal amount of padding on | ||
* both sides of the minor dimension oof the image. | ||
* @returns The padded tensor with width === height. | ||
@@ -9,0 +10,0 @@ */ |
@@ -0,8 +1,9 @@ | ||
import * as tf from '@tensorflow/tfjs-core'; | ||
import { Point } from '../classes/Point'; | ||
import { Dimensions } from '../classes/types'; | ||
export declare function isTensor(tensor: any, dim: number): boolean; | ||
export declare function isTensor1D(tensor: any): boolean; | ||
export declare function isTensor2D(tensor: any): boolean; | ||
export declare function isTensor3D(tensor: any): boolean; | ||
export declare function isTensor4D(tensor: any): boolean; | ||
export declare function isTensor1D(tensor: any): tensor is tf.Tensor1D; | ||
export declare function isTensor2D(tensor: any): tensor is tf.Tensor2D; | ||
export declare function isTensor3D(tensor: any): tensor is tf.Tensor3D; | ||
export declare function isTensor4D(tensor: any): tensor is tf.Tensor4D; | ||
export declare function isFloat(num: number): boolean; | ||
@@ -17,1 +18,4 @@ export declare function isEven(num: number): boolean; | ||
export declare function getCenterPoint(pts: Point[]): Point; | ||
export declare function range(num: number, start: number, step: number): number[]; | ||
export declare function isValidNumber(num: any): boolean; | ||
export declare function isValidProbablitiy(num: any): boolean; |
@@ -44,2 +44,11 @@ import * as tf from '@tensorflow/tfjs-core'; | ||
} | ||
export function range(num, start, step) { | ||
return Array(num).fill(0).map(function (_, i) { return start + (i * step); }); | ||
} | ||
export function isValidNumber(num) { | ||
return !!num && num !== Infinity && num !== -Infinity && !isNaN(num) || num === 0; | ||
} | ||
export function isValidProbablitiy(num) { | ||
return isValidNumber(num) && 0 <= num && num <= 1.0; | ||
} | ||
//# sourceMappingURL=index.js.map |
const dataFiles = [ | ||
'test/*.png', | ||
'test/*.json' | ||
].map(pattern => ({ | ||
@@ -4,0 +5,0 @@ pattern, |
{ | ||
"name": "tfjs-image-recognition-base", | ||
"version": "0.0.0", | ||
"version": "0.1.0", | ||
"description": "A shared codebase for face-api.js and tfjs-tiny-yolo-v2.", | ||
@@ -5,0 +5,0 @@ "main": "./build/index.js", |
@@ -1,118 +0,14 @@ | ||
import { isDimensions } from '../utils'; | ||
import { Rect } from './Rect'; | ||
import { Dimensions } from './types'; | ||
import { Box } from './Box'; | ||
export class BoundingBox { | ||
constructor( | ||
private _left: number, | ||
private _top: number, | ||
private _right: number, | ||
private _bottom: number | ||
) {} | ||
export interface IBoundingBox { | ||
left: number | ||
top: number | ||
right: number | ||
bottom: number | ||
} | ||
public get left() : number { | ||
return this._left | ||
export class BoundingBox extends Box<BoundingBox> implements IBoundingBox { | ||
constructor(left: number, top: number, right: number, bottom: number) { | ||
super({ left, top, right, bottom }) | ||
} | ||
public get top() : number { | ||
return this._top | ||
} | ||
public get right() : number { | ||
return this._right | ||
} | ||
public get bottom() : number { | ||
return this._bottom | ||
} | ||
public get width() : number { | ||
return this.right - this.left | ||
} | ||
public get height() : number { | ||
return this.bottom - this.top | ||
} | ||
public get area() : number { | ||
return this.width * this.height | ||
} | ||
public toSquare(): BoundingBox { | ||
let { left, top, right, bottom } = this | ||
const off = (Math.abs(this.width - this.height) / 2) | ||
if (this.width < this.height) { | ||
left -= off | ||
right += off | ||
} | ||
if (this.height < this.width) { | ||
top -= off | ||
bottom += off | ||
} | ||
return new BoundingBox(left, top, right, bottom) | ||
} | ||
public round(): BoundingBox { | ||
return new BoundingBox( | ||
Math.round(this.left), | ||
Math.round(this.top), | ||
Math.round(this.right), | ||
Math.round(this.bottom) | ||
) | ||
} | ||
public padAtBorders(imageHeight: number, imageWidth: number) { | ||
const w = this.width + 1 | ||
const h = this.height + 1 | ||
let dx = 1 | ||
let dy = 1 | ||
let edx = w | ||
let edy = h | ||
let x = this.left | ||
let y = this.top | ||
let ex = this.right | ||
let ey = this.bottom | ||
if (ex > imageWidth) { | ||
edx = -ex + imageWidth + w | ||
ex = imageWidth | ||
} | ||
if (ey > imageHeight) { | ||
edy = -ey + imageHeight + h | ||
ey = imageHeight | ||
} | ||
if (x < 1) { | ||
edy = 2 - x | ||
x = 1 | ||
} | ||
if (y < 1) { | ||
edy = 2 - y | ||
y = 1 | ||
} | ||
return { dy, edy, dx, edx, y, ey, x, ex, w, h } | ||
} | ||
public calibrate(region: BoundingBox) { | ||
return new BoundingBox( | ||
this.left + (region.left * this.width), | ||
this.top + (region.top * this.height), | ||
this.right + (region.right * this.width), | ||
this.bottom + (region.bottom * this.height) | ||
).toSquare().round() | ||
} | ||
public rescale(s: Dimensions | number) { | ||
const scaleX = isDimensions(s) ? (s as Dimensions).width : s as number | ||
const scaleY = isDimensions(s) ? (s as Dimensions).height : s as number | ||
return new BoundingBox(this.left * scaleX, this.top * scaleY, this.right * scaleX, this.bottom * scaleY) | ||
} | ||
public toRect(): Rect { | ||
return new Rect(this.left, this.top, this.width, this.height) | ||
} | ||
} |
@@ -0,5 +1,8 @@ | ||
export * from './Box' | ||
export * from './BoundingBox' | ||
export * from './LabeledBox' | ||
export * from './ObjectDetection' | ||
export * from './Point' | ||
export * from './PredictedBox' | ||
export * from './Rect' | ||
export * from './types' |
@@ -1,2 +0,2 @@ | ||
import { BoundingBox } from './BoundingBox'; | ||
import { Box } from './Box'; | ||
@@ -10,67 +10,6 @@ export interface IRect { | ||
export class Rect implements IRect { | ||
public x: number | ||
public y: number | ||
public width: number | ||
public height: number | ||
export class Rect extends Box<Rect> implements IRect { | ||
constructor(x: number, y: number, width: number, height: number) { | ||
this.x = x | ||
this.y = y | ||
this.width = width | ||
this.height = height | ||
super({ x, y, width, height }) | ||
} | ||
public get right() { | ||
return this.x + this.width | ||
} | ||
public get bottom() { | ||
return this.y + this.height | ||
} | ||
public toSquare(): Rect { | ||
let { x, y, width, height } = this | ||
const diff = Math.abs(width - height) | ||
if (width < height) { | ||
x -= (diff / 2) | ||
width += diff | ||
} | ||
if (height < width) { | ||
y -= (diff / 2) | ||
height += diff | ||
} | ||
return new Rect(x, y, width, height) | ||
} | ||
public pad(padX: number, padY: number): Rect { | ||
let { x, y, width, height } = this | ||
return new Rect(x - (padX / 2), y - (padY / 2), width + padX, height + padY) | ||
} | ||
public floor(): Rect { | ||
return new Rect( | ||
Math.floor(this.x), | ||
Math.floor(this.y), | ||
Math.floor(this.width), | ||
Math.floor(this.height) | ||
) | ||
} | ||
public toBoundingBox(): BoundingBox { | ||
return new BoundingBox(this.x, this.y, this.x + this.width, this.y + this.height) | ||
} | ||
public clipAtImageBorders(imgWidth: number, imgHeight: number): Rect { | ||
const { x, y, right, bottom } = this | ||
const clippedX = Math.max(x, 0) | ||
const clippedY = Math.max(y, 0) | ||
const newWidth = right - clippedX | ||
const newHeight = bottom - clippedY | ||
const clippedWidth = Math.min(newWidth, imgWidth - clippedX) | ||
const clippedHeight = Math.min(newHeight, imgHeight - clippedY) | ||
return (new Rect(clippedX, clippedY, clippedWidth, clippedHeight)).floor() | ||
} | ||
} |
@@ -5,3 +5,3 @@ import { createCanvas, createCanvasFromMedia } from './createCanvas'; | ||
export function imageToSquare(input: HTMLImageElement | HTMLCanvasElement, inputSize: number) { | ||
export function imageToSquare(input: HTMLImageElement | HTMLCanvasElement, inputSize: number, centerImage: boolean = false) { | ||
@@ -19,5 +19,9 @@ if (!(input instanceof HTMLImageElement || input instanceof HTMLCanvasElement)) { | ||
const inputCanvas = input instanceof HTMLCanvasElement ? input : createCanvasFromMedia(input) | ||
getContext2dOrThrow(targetCanvas).drawImage(inputCanvas, 0, 0, width, height) | ||
const offset = Math.abs(width - height) / 2 | ||
const dx = centerImage && width < height ? offset : 0 | ||
const dy = centerImage && height < width ? offset : 0 | ||
getContext2dOrThrow(targetCanvas).drawImage(inputCanvas, dx, dy, width, height) | ||
return targetCanvas | ||
} |
import * as tf from '@tensorflow/tfjs-core'; | ||
import { Point } from '../classes/Point'; | ||
import { Dimensions } from '../classes/types'; | ||
import { padToSquare } from '../ops/padToSquare'; | ||
import { isTensor3D, isTensor4D } from '../utils'; | ||
import { computeReshapedDimensions } from '../utils'; | ||
import { computeReshapedDimensions, isTensor3D, isTensor4D, range } from '../utils'; | ||
import { createCanvasFromMedia } from './createCanvas'; | ||
import { imageToSquare } from './imageToSquare'; | ||
import { TResolvedNetInput } from './types'; | ||
export class NetInput { | ||
private _inputs: tf.Tensor3D[] = [] | ||
private _imageTensors: Array<tf.Tensor3D | tf.Tensor4D> = [] | ||
private _canvases: HTMLCanvasElement[] = [] | ||
private _isManaged: boolean = false | ||
private _isBatchInput: boolean = false | ||
private _batchSize: number | ||
private _treatAsBatchInput: boolean = false | ||
private _inputDimensions: number[][] = [] | ||
private _paddings: Point[] = [] | ||
private _inputSize: number | ||
constructor( | ||
inputs: tf.Tensor4D | Array<TResolvedNetInput>, | ||
isBatchInput: boolean = false, | ||
keepCanvases: boolean = false | ||
inputs: Array<TResolvedNetInput>, | ||
treatAsBatchInput: boolean = false | ||
) { | ||
if (isTensor4D(inputs)) { | ||
this._inputs = tf.unstack(inputs as tf.Tensor4D) as tf.Tensor3D[] | ||
if (!Array.isArray(inputs)) { | ||
throw new Error(`NetInput.constructor - expected inputs to be an Array of TResolvedNetInput or to be instanceof tf.Tensor4D, instead have ${inputs}`) | ||
} | ||
if (Array.isArray(inputs)) { | ||
this._inputs = inputs.map((input, idx) => { | ||
if (isTensor3D(input)) { | ||
// TODO: make sure not to dispose original tensors passed in by the user | ||
return tf.clone(input as tf.Tensor3D) | ||
} | ||
this._treatAsBatchInput = treatAsBatchInput | ||
this._batchSize = inputs.length | ||
if (isTensor4D(input)) { | ||
const shape = (input as tf.Tensor4D).shape | ||
const batchSize = shape[0] | ||
if (batchSize !== 1) { | ||
throw new Error(`NetInput - tf.Tensor4D with batchSize ${batchSize} passed, but not supported in input array`) | ||
} | ||
inputs.forEach((input, idx) => { | ||
return (input as tf.Tensor4D).reshape(shape.slice(1) as [number, number, number]) as tf.Tensor3D | ||
} | ||
if (isTensor3D(input)) { | ||
this._imageTensors[idx] = input | ||
this._inputDimensions[idx] = input.shape | ||
return | ||
} | ||
const canvas = input instanceof HTMLCanvasElement ? input : createCanvasFromMedia(input as HTMLImageElement | HTMLVideoElement) | ||
if (keepCanvases) { | ||
this._canvases[idx] = canvas | ||
if (isTensor4D(input)) { | ||
const batchSize = input.shape[0] | ||
if (batchSize !== 1) { | ||
throw new Error(`NetInput - tf.Tensor4D with batchSize ${batchSize} passed, but not supported in input array`) | ||
} | ||
return tf.fromPixels(canvas) | ||
}) | ||
} | ||
this._isBatchInput = this.batchSize > 1 || isBatchInput | ||
this._inputDimensions = this._inputs.map(t => t.shape) | ||
this._imageTensors[idx] = input | ||
this._inputDimensions[idx] = input.shape.slice(1) | ||
return | ||
} | ||
const canvas = input instanceof HTMLCanvasElement ? input : createCanvasFromMedia(input as HTMLImageElement | HTMLVideoElement) | ||
this._canvases[idx] = canvas | ||
this._inputDimensions[idx] = [canvas.height, canvas.width, 3] | ||
}) | ||
} | ||
public get inputs(): tf.Tensor3D[] { | ||
return this._inputs | ||
public get imageTensors(): Array<tf.Tensor3D | tf.Tensor4D> { | ||
return this._imageTensors | ||
} | ||
@@ -67,12 +63,8 @@ | ||
public get isManaged(): boolean { | ||
return this._isManaged | ||
} | ||
public get isBatchInput(): boolean { | ||
return this._isBatchInput | ||
return this.batchSize > 1 || this._treatAsBatchInput | ||
} | ||
public get batchSize(): number { | ||
return this._inputs.length | ||
return this._batchSize | ||
} | ||
@@ -84,18 +76,8 @@ | ||
public get paddings(): Point[] { | ||
return this._paddings | ||
} | ||
public get inputSize(): number { | ||
public get inputSize(): number | undefined { | ||
return this._inputSize | ||
} | ||
public get relativePaddings(): Point[] { | ||
return Array(this.inputs.length).fill(0).map( | ||
(_, batchIdx) => this.getRelativePaddings(batchIdx) | ||
) | ||
} | ||
public get reshapedInputDimensions(): Dimensions[] { | ||
return Array(this.inputs.length).fill(0).map( | ||
return range(this.batchSize, 0, 1).map( | ||
(_, batchIdx) => this.getReshapedInputDimensions(batchIdx) | ||
@@ -105,2 +87,6 @@ ) | ||
public getInput(batchIdx: number): tf.Tensor3D | tf.Tensor4D | HTMLCanvasElement { | ||
return this.canvases[batchIdx] || this.imageTensors[batchIdx] | ||
} | ||
public getInputDimensions(batchIdx: number): number[] { | ||
@@ -118,13 +104,2 @@ return this._inputDimensions[batchIdx] | ||
public getPaddings(batchIdx: number): Point { | ||
return this._paddings[batchIdx] | ||
} | ||
public getRelativePaddings(batchIdx: number): Point { | ||
return new Point( | ||
(this.getPaddings(batchIdx).x + this.getInputWidth(batchIdx)) / this.getInputWidth(batchIdx), | ||
(this.getPaddings(batchIdx).y + this.getInputHeight(batchIdx)) / this.getInputHeight(batchIdx) | ||
) | ||
} | ||
public getReshapedInputDimensions(batchIdx: number): Dimensions { | ||
@@ -140,2 +115,11 @@ if (typeof this.inputSize !== 'number') { | ||
/** | ||
* Create a batch tensor from all input canvases and tensors | ||
* with size [batchSize, inputSize, inputSize, 3]. | ||
* | ||
* @param inputSize Height and width of the tensor. | ||
* @param isCenterImage (optional, default: false) If true, add an equal amount of padding on | ||
* both sides of the minor dimension oof the image. | ||
* @returns The batch tensor. | ||
*/ | ||
public toBatchTensor(inputSize: number, isCenterInputs: boolean = true): tf.Tensor4D { | ||
@@ -147,43 +131,28 @@ | ||
const inputTensors = this._inputs.map((inputTensor: tf.Tensor3D) => { | ||
const [originalHeight, originalWidth] = inputTensor.shape | ||
const inputTensors = range(this.batchSize, 0, 1).map(batchIdx => { | ||
const input = this.getInput(batchIdx) | ||
let imgTensor = inputTensor.expandDims().toFloat() as tf.Tensor4D | ||
imgTensor = padToSquare(imgTensor, isCenterInputs) | ||
if (input instanceof tf.Tensor) { | ||
let imgTensor = isTensor4D(input) ? input : input.expandDims<tf.Rank.R4>() | ||
imgTensor = padToSquare(imgTensor, isCenterInputs) | ||
const [heightAfterPadding, widthAfterPadding] = imgTensor.shape.slice(1) | ||
if (imgTensor.shape[1] !== inputSize || imgTensor.shape[2] !== inputSize) { | ||
imgTensor = tf.image.resizeBilinear(imgTensor, [inputSize, inputSize]) | ||
} | ||
if (heightAfterPadding !== inputSize || widthAfterPadding !== inputSize) { | ||
imgTensor = tf.image.resizeBilinear(imgTensor, [inputSize, inputSize]) | ||
return imgTensor.as3D(inputSize, inputSize, 3) | ||
} | ||
this._paddings.push(new Point( | ||
widthAfterPadding - originalWidth, | ||
heightAfterPadding - originalHeight | ||
)) | ||
return imgTensor | ||
if (input instanceof HTMLCanvasElement) { | ||
return tf.fromPixels(imageToSquare(input, inputSize, isCenterInputs)) | ||
} | ||
throw new Error(`toBatchTensor - at batchIdx ${batchIdx}, expected input to be instanceof tf.Tensor or instanceof HTMLCanvasElement, instead have ${input}`) | ||
}) | ||
const batchTensor = tf.stack(inputTensors).as4D(this.batchSize, inputSize, inputSize, 3) | ||
const batchTensor = tf.stack(inputTensors.map(t => t.toFloat())).as4D(this.batchSize, inputSize, inputSize, 3) | ||
if (this.isManaged) { | ||
this.dispose() | ||
} | ||
return batchTensor | ||
}) | ||
} | ||
/** | ||
* By setting the isManaged flag, all newly created tensors will be | ||
* automatically disposed after the batch tensor has been created | ||
*/ | ||
public managed() { | ||
this._isManaged = true | ||
return this | ||
} | ||
public dispose() { | ||
this._inputs.forEach(t => t.dispose()) | ||
} | ||
} |
@@ -1,3 +0,1 @@ | ||
import * as tf from '@tensorflow/tfjs-core'; | ||
import { isTensor3D, isTensor4D } from '../utils'; | ||
@@ -15,11 +13,5 @@ import { awaitMediaLoaded } from './awaitMediaLoaded'; | ||
* @param input The input, which can be a media element or an array of different media elements. | ||
* @param manageCreatedInput If a new NetInput instance is created from the inputs, this flag | ||
* determines, whether to set the NetInput as managed or not. | ||
* @returns A NetInput instance, which can be passed into one of the neural networks. | ||
*/ | ||
export async function toNetInput( | ||
inputs: TNetInput, | ||
manageCreatedInput: boolean = false, | ||
keepCanvases: boolean = false | ||
): Promise<NetInput> { | ||
export async function toNetInput(inputs: TNetInput): Promise<NetInput> { | ||
if (inputs instanceof NetInput) { | ||
@@ -29,10 +21,2 @@ return inputs | ||
const afterCreate = (netInput: NetInput) => manageCreatedInput | ||
? netInput.managed() | ||
: netInput | ||
if (isTensor4D(inputs)) { | ||
return afterCreate(new NetInput(inputs as tf.Tensor4D)) | ||
} | ||
let inputArgArray = Array.isArray(inputs) | ||
@@ -74,3 +58,3 @@ ? inputs | ||
return afterCreate(new NetInput(inputArray, Array.isArray(inputs), keepCanvases)) | ||
return new NetInput(inputArray, Array.isArray(inputs)) | ||
} |
@@ -1,4 +0,4 @@ | ||
import { BoundingBox } from '../classes/BoundingBox'; | ||
import { Box } from '../classes/Box'; | ||
export function iou(box1: BoundingBox, box2: BoundingBox, isIOU: boolean = true) { | ||
export function iou(box1: Box, box2: Box, isIOU: boolean = true) { | ||
const width = Math.max(0.0, Math.min(box1.right, box2.right) - Math.max(box1.left, box2.left)) | ||
@@ -5,0 +5,0 @@ const height = Math.max(0.0, Math.min(box1.bottom, box2.bottom) - Math.max(box1.top, box2.top)) |
@@ -1,6 +0,6 @@ | ||
import { BoundingBox } from '../classes/BoundingBox'; | ||
import { Box } from '../classes/Box'; | ||
import { iou } from './iou'; | ||
export function nonMaxSuppression( | ||
boxes: BoundingBox[], | ||
boxes: Box[], | ||
scores: number[], | ||
@@ -7,0 +7,0 @@ iouThreshold: number, |
@@ -7,3 +7,4 @@ import * as tf from '@tensorflow/tfjs-core'; | ||
* @param imgTensor The image tensor. | ||
* @param isCenterImage (optional, default: false) If true, add padding on both sides of the image, such that the image. | ||
* @param isCenterImage (optional, default: false) If true, add an equal amount of padding on | ||
* both sides of the minor dimension oof the image. | ||
* @returns The padded tensor with width === height. | ||
@@ -10,0 +11,0 @@ */ |
@@ -10,15 +10,15 @@ import * as tf from '@tensorflow/tfjs-core'; | ||
export function isTensor1D(tensor: any) { | ||
export function isTensor1D(tensor: any): tensor is tf.Tensor1D { | ||
return isTensor(tensor, 1) | ||
} | ||
export function isTensor2D(tensor: any) { | ||
export function isTensor2D(tensor: any): tensor is tf.Tensor2D { | ||
return isTensor(tensor, 2) | ||
} | ||
export function isTensor3D(tensor: any) { | ||
export function isTensor3D(tensor: any): tensor is tf.Tensor3D { | ||
return isTensor(tensor, 3) | ||
} | ||
export function isTensor4D(tensor: any) { | ||
export function isTensor4D(tensor: any): tensor is tf.Tensor4D { | ||
return isTensor(tensor, 4) | ||
@@ -55,2 +55,14 @@ } | ||
.div(new Point(pts.length, pts.length)) | ||
} | ||
export function range(num: number, start: number, step: number): number[] { | ||
return Array(num).fill(0).map((_, i) => start + (i * step)) | ||
} | ||
export function isValidNumber(num: any) { | ||
return !!num && num !== Infinity && num !== -Infinity && !isNaN(num) || num === 0 | ||
} | ||
export function isValidProbablitiy(num: any) { | ||
return isValidNumber(num) && 0 <= num && num <= 1.0 | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
172496
192
3096