Source: crop-to-box.js

const hasard = require('hasard');
const CropAugmenter = require('./crop');

/**
* Crop the image considering input's "boxes" parameter and with
* a variation given by sigma
*
* @param {Object} opts options
* @param {NumberArgument} [opts.cornersVariation] length-2 x lenght-2 variate (in percent) of box
* ex : [[x1, y1], [x2, y2]] will cropp a box of size (x1+x2 +1)*width x (y1+y2 +1)*height
* Positive numbers will increase the size of the box
* @param {NumberArgument} opts.sigma sigma af a normal distribution of cornersVariation
* @param {NumberArgument} opts.mean mean of a normal distribution of cornersVariation
* @param {NumberArgument} [opts.boxIndex] index of the box to use, by default, will be randomly decided
* @example
// Simple usage, will crop a random box among boxes,
// and return it as the new image
// will throw an error if no boxes
const cropper = ia.cropToBox();
* @example
// default parameter is sigma, here 10% variation
ia.cropToBox(0.1);
* @example
// here 20% variation, in the normal distribution
// and by average width of the cropped box will be 20% larger (10% + 10%) and same for height
ia.cropToBox({sigma: 0.2, mean: 0.1});
*/

class CropToBoxAugmenter extends CropAugmenter {
	constructor(opts, ia) {
		let o;
		if (typeof (opts) === 'number' || hasard.isHasard(opts)) {
			o = {sigma: opts};
		} else {
			o = opts;
		}

		super(o, ia);
		const {sigma, mean = 0, boxIndex, cornersVariation} = o;

		this.sigma = this.toSize2(sigma);
		this.mean = this.toSize2(mean);
		this.cornersVariation = cornersVariation;
		this.boxIndex = boxIndex;
	}

	buildParams({boxes}) {
		return new hasard.Object({
			cornersVariation: this.cornersVariation || hasard.array({
				size: 2,
				value: new hasard.Array([
					new hasard.Number({
						type: 'normal',
						mean: hasard.getProperty(0, this.mean),
						std: hasard.getProperty(0, this.sigma)
					}),
					new hasard.Number({
						type: 'normal',
						mean: hasard.getProperty(1, this.mean),
						std: hasard.getProperty(1, this.sigma)
					})
				])
			}),
			box: hasard.getProperty(this.boxIndex || hasard.integer(0, boxes.length - 1), boxes)
		});
	}

	checkParams() {
		// Override
	}

	getRect({width, height, params}) {
		const {cornersVariation} = params;
		const {box} = params;
		const x = Math.round(Math.max(0, box[0] - (cornersVariation[0][0] * box[2])));
		const y = Math.round(Math.max(0, box[1] - (cornersVariation[0][1] * box[3])));
		const w = Math.round(Math.min(width - x, box[2] + ((cornersVariation[0][0] + cornersVariation[1][0]) * box[2])));
		const h = Math.round(Math.min(height - y, box[3] + ((cornersVariation[0][1] + cornersVariation[1][1]) * box[3])));

		return {
			x,
			y,
			w,
			h
		};
	}
}

module.exports = CropToBoxAugmenter;