@duetds/date-picker
Version:
Duet Date Picker is an open source version of Duet Design System’s accessible date picker.
89 lines (81 loc) • 3.02 kB
text/typescript
/**
* Implements Bezkrovny's ssim-specific logic.
*
* Refactor of the TypeScript SSIM implementation by Bezkrovny, modified to match the api of ssim.js
* and reduce duplication.
*
* The original work is available at: https://github.com/igor-bezkrovny/image-quantization which is
* itself a port of the Java SSIM implementation available at https://github.com/rhys-e/structural-similarity
* both under MIT license
*
* @namespace bezkrovnySsim
*/
import { average, variance, covariance } from "./math";
import { sub } from "./matlab";
import { Options, Matrix } from "./types";
/**
* Generates a SSIM map based on two input image matrices.
*
* Images must be a 2-Dimensional grayscale image
*
* This method produces a simliar output to `assets/ssim.m` (~1%) when running on Matlab. It's based
* of Igor Bezkrovny's TypeScript implementation
*
* @method bezkrovnySsim
* @param {Matrix} pixels1 - The reference matrix
* @param {Matrix} pixels2 - The second matrix to compare against
* @param {Options} options - The input options parameter
* @returns {Matrix} ssim_map - A matrix containing the map of computed SSIMs
* @public
* @memberOf bezkrovnySsim
*/
export function bezkrovnySsim(
pixels1: Matrix,
pixels2: Matrix,
options: Options
) {
const { windowSize } = options;
const width = Math.ceil(pixels1.width / windowSize);
const height = Math.ceil(pixels1.height / windowSize);
const data = new Array(width * height);
let counter = 0;
for (let y = 0; y < pixels1.height; y += windowSize) {
for (let x = 0; x < pixels1.width; x += windowSize) {
const windowWidth = Math.min(windowSize, pixels1.width - x);
const windowHeight = Math.min(windowSize, pixels1.height - y);
const values1 = sub(pixels1, x, windowHeight, y, windowWidth);
const values2 = sub(pixels2, x, windowHeight, y, windowWidth);
data[counter++] = windowSsim(values1, values2, options);
}
}
return { data, width, height };
}
/**
* Generates the per-window ssim value
*
* @method windowSsim
* @param {Matrix} values1 - The matrix of the ssim window to compute for image 1
* @param {Matrix} values2 - The matrix of the ssim window to compute for image 2
* @param {Options} options - The input options parameter
* @returns {Number} ssim - The ssim value at the current window
* @private
* @memberOf bezkrovnySsim
*/
function windowSsim(
{ data: values1 }: Matrix,
{ data: values2 }: Matrix,
{ bitDepth, k1, k2 }: Options
): number {
const L = 2 ** bitDepth - 1;
const c1 = (k1 * L) ** 2;
const c2 = (k2 * L) ** 2;
const average1 = average(values1);
const average2 = average(values2);
const σSqx = variance(values1, average1);
const σSqy = variance(values2, average2);
const σxy = covariance(values1, values2, average1, average2);
const numerator = (2 * average1 * average2 + c1) * (2 * σxy + c2);
const denom1 = average1 ** 2 + average2 ** 2 + c1;
const denom2 = σSqx + σSqy + c2;
return numerator / (denom1 * denom2);
}