119 lines
3 KiB
JavaScript
119 lines
3 KiB
JavaScript
// Calculate Gaussian blur of an image using IIR filter
|
|
// The method is taken from Intel's white paper and code example attached to it:
|
|
// https://software.intel.com/en-us/articles/iir-gaussian-blur-filter
|
|
// -implementation-using-intel-advanced-vector-extensions
|
|
|
|
var a0, a1, a2, a3, b1, b2, left_corner, right_corner;
|
|
|
|
function gaussCoef(sigma) {
|
|
if (sigma < 0.5) {
|
|
sigma = 0.5;
|
|
}
|
|
|
|
var a = Math.exp(0.726 * 0.726) / sigma,
|
|
g1 = Math.exp(-a),
|
|
g2 = Math.exp(-2 * a),
|
|
k = (1 - g1) * (1 - g1) / (1 + 2 * a * g1 - g2);
|
|
|
|
a0 = k;
|
|
a1 = k * (a - 1) * g1;
|
|
a2 = k * (a + 1) * g1;
|
|
a3 = -k * g2;
|
|
b1 = 2 * g1;
|
|
b2 = -g2;
|
|
left_corner = (a0 + a1) / (1 - b1 - b2);
|
|
right_corner = (a2 + a3) / (1 - b1 - b2);
|
|
|
|
// Attempt to force type to FP32.
|
|
return new Float32Array([ a0, a1, a2, a3, b1, b2, left_corner, right_corner ]);
|
|
}
|
|
|
|
function convolveMono16(src, out, line, coeff, width, height) {
|
|
// takes src image and writes the blurred and transposed result into out
|
|
|
|
var prev_src, curr_src, curr_out, prev_out, prev_prev_out;
|
|
var src_index, out_index, line_index;
|
|
var i, j;
|
|
var coeff_a0, coeff_a1, coeff_b1, coeff_b2;
|
|
|
|
for (i = 0; i < height; i++) {
|
|
src_index = i * width;
|
|
out_index = i;
|
|
line_index = 0;
|
|
|
|
// left to right
|
|
prev_src = src[src_index];
|
|
prev_prev_out = prev_src * coeff[6];
|
|
prev_out = prev_prev_out;
|
|
|
|
coeff_a0 = coeff[0];
|
|
coeff_a1 = coeff[1];
|
|
coeff_b1 = coeff[4];
|
|
coeff_b2 = coeff[5];
|
|
|
|
for (j = 0; j < width; j++) {
|
|
curr_src = src[src_index];
|
|
|
|
curr_out = curr_src * coeff_a0 +
|
|
prev_src * coeff_a1 +
|
|
prev_out * coeff_b1 +
|
|
prev_prev_out * coeff_b2;
|
|
|
|
prev_prev_out = prev_out;
|
|
prev_out = curr_out;
|
|
prev_src = curr_src;
|
|
|
|
line[line_index] = prev_out;
|
|
line_index++;
|
|
src_index++;
|
|
}
|
|
|
|
src_index--;
|
|
line_index--;
|
|
out_index += height * (width - 1);
|
|
|
|
// right to left
|
|
prev_src = src[src_index];
|
|
prev_prev_out = prev_src * coeff[7];
|
|
prev_out = prev_prev_out;
|
|
curr_src = prev_src;
|
|
|
|
coeff_a0 = coeff[2];
|
|
coeff_a1 = coeff[3];
|
|
|
|
for (j = width - 1; j >= 0; j--) {
|
|
curr_out = curr_src * coeff_a0 +
|
|
prev_src * coeff_a1 +
|
|
prev_out * coeff_b1 +
|
|
prev_prev_out * coeff_b2;
|
|
|
|
prev_prev_out = prev_out;
|
|
prev_out = curr_out;
|
|
|
|
prev_src = curr_src;
|
|
curr_src = src[src_index];
|
|
|
|
out[out_index] = line[line_index] + prev_out;
|
|
|
|
src_index--;
|
|
line_index--;
|
|
out_index -= height;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function blurMono16(src, width, height, radius) {
|
|
// Quick exit on zero radius
|
|
if (!radius) { return; }
|
|
|
|
var out = new Uint16Array(src.length),
|
|
tmp_line = new Float32Array(Math.max(width, height));
|
|
|
|
var coeff = gaussCoef(radius);
|
|
|
|
convolveMono16(src, out, tmp_line, coeff, width, height, radius);
|
|
convolveMono16(out, src, tmp_line, coeff, height, width, radius);
|
|
}
|
|
|
|
module.exports = blurMono16;
|