61 lines
1.5 KiB
JavaScript
61 lines
1.5 KiB
JavaScript
define(['./ImageRegion'], (ImageRegion) => {
|
|
'use strict';
|
|
|
|
function makeGaussianKernel(size) {
|
|
const sz = Math.ceil(size * 3);
|
|
const kernel = new Float32Array(sz * 2 + 1);
|
|
const norm = 1 / (size * Math.sqrt(Math.PI * 2));
|
|
const expNorm = -0.5 / (size * size);
|
|
for(let i = -sz; i <= sz; ++ i) {
|
|
kernel[i+sz] = Math.exp(i * i * expNorm) * norm;
|
|
}
|
|
return {kernel, sz};
|
|
}
|
|
|
|
function blur1D(region, size, {target = null} = {}) {
|
|
/* jshint -W073 */ // There are 4 dimensions to traverse in a hot loop
|
|
|
|
target = region.checkOrMakeTarget(target);
|
|
|
|
const {width, height, stepX, stepY, dim} = region;
|
|
const {kernel, sz} = makeGaussianKernel(size);
|
|
|
|
for(let x = 0; x < width; ++ x) {
|
|
const i0 = -Math.min(sz, x);
|
|
const i1 = Math.min(sz, width - x);
|
|
for(let d = 0; d < dim; ++ d) {
|
|
const psx = region.indexOf(x, 0, d);
|
|
const ptx = target.indexOf(x, 0, d);
|
|
for(let y = 0; y < height; ++ y) {
|
|
const ps = psx + y * stepY;
|
|
let accum = 0;
|
|
for(let i = i0; i < i1; ++ i) {
|
|
accum += region.values[ps+i*stepX] * kernel[i+sz];
|
|
}
|
|
target.values[ptx + y * target.stepY] = accum;
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
function blur2D(region, size, {target = null, temp = null} = {}) {
|
|
target = region.checkOrMakeTarget(target);
|
|
|
|
temp = blur1D(region, size, {target: temp});
|
|
blur1D(temp.transposed(), size, {target: target.transposed()});
|
|
return target;
|
|
}
|
|
|
|
ImageRegion.prototype.blur = function(size, options) {
|
|
return blur2D(this, size, options);
|
|
};
|
|
|
|
return {
|
|
makeGaussianKernel,
|
|
blur1D,
|
|
blur2D,
|
|
};
|
|
});
|