I'm currently porting the image segmentation code described here, and it includes a gaussian blur. The gaussian blur code alone seemed useful enough to warrant a post, so here ya go. It's exponentially faster than the one here, which is the only other Javascript gaussian blur example I could find. Includes improvements by Einar Lielmanis.
Tuesday, January 5, 2010
Subscribe to:
Post Comments (Atom)
Nice. If you're still feeling adventurous, you may want to try van Vliet's approximation of the Gaussian filter [http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.12.2826]. A quick Google found some sample code:
ReplyDeletehttp://albumshaper.sourcearchive.com/documentation/2.1-5/blur_8cpp-source.html
I think the GIMP uses this for it's IIR G-blur too.
This comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi,
ReplyDeleteI implemented the algorithm mentioned by Dan in a form that is suitable for Paul's demo (see below). If you find any way to improve the performance, please let me know. Sorry for the deleted postings, I keep finding tiny improvements. :)
Best, Martin
function smooth(src, dst, sigma)
{
var width = src.width;
var width4 = 4 * width;
var height = src.height;
var srcData = src.getContext("2d").getImageData(0, 0, width, height);
var data = srcData.data;
var ctx = dst.getContext("2d");
// compute coefficients as a function of sigma
var q;
if (sigma < 0.0) {
sigma = 0.0;
}
if (sigma >= 2.5) {
q = 0.98711 * sigma - 0.96330;
}
else if (sigma >= 0.5) {
q = 3.97156 - 4.14554 * Math.sqrt(1.0 - 0.26891 * sigma);
}
else {
q = 2 * sigma * (3.97156 - 4.14554 * Math.sqrt(1.0 - 0.26891 * 0.5));
}
//compute b0, b1, b2, and b3
var qq = q * q;
var qqq = qq * q;
var b0 = 1.57825 + (2.44413 * q) + (1.4281 * qq ) + (0.422205 * qqq);
var b1 = ((2.44413 * q) + (2.85619 * qq) + (1.26661 * qqq)) / b0;
var b2 = (-((1.4281 * qq) + (1.26661 * qqq))) / b0;
var b3 = (0.422205 * qqq) / b0;
var bigB = 1.0 - (b1 + b2 + b3);
// horizontal
for (var c = 0; c < 3; c++) {
for (var y = 0; y < height; y++) {
// forward
var index = y * width4 + c;
var indexLast = y * width4 + 4 * (width - 1) + c;
var pixel = data[index];
var ppixel = pixel;
var pppixel = ppixel;
var ppppixel = pppixel;
for (; index <= indexLast; index += 4) {
pixel = bigB * data[index] + b1 * ppixel + b2 * pppixel + b3 * ppppixel;
data[index] = pixel;
ppppixel = pppixel;
pppixel = ppixel;
ppixel = pixel;
}
// backward
index = y * width4 + 4 * (width - 1) + c;
indexLast = y * width4 + c;
pixel = data[index];
ppixel = pixel;
pppixel = ppixel;
ppppixel = pppixel;
for (; index >= indexLast; index -= 4) {
pixel = bigB * data[index] + b1 * ppixel + b2 * pppixel + b3 * ppppixel;
data[index] = pixel;
ppppixel = pppixel;
pppixel = ppixel;
ppixel = pixel;
}
}
}
// vertical
for (var c = 0; c < 3; c++) {
for (var x = 0; x < width; x++) {
// forward
var index = 4 * x + c;
var indexLast = (height - 1) * width4 + 4 * x + c;
var pixel = data[index];
var ppixel = pixel;
var pppixel = ppixel;
var ppppixel = pppixel;
for (; index <= indexLast; index += width4) {
pixel = bigB * data[index] + b1 * ppixel + b2 * pppixel + b3 * ppppixel;
data[index] = pixel;
ppppixel = pppixel;
pppixel = ppixel;
ppixel = pixel;
}
// backward
index = (height - 1) * width4 + 4 * x + c;
indexLast = 4 * x + c;
pixel = data[index];
ppixel = pixel;
pppixel = ppixel;
ppppixel = pppixel;
for (; index >= indexLast; index -= width4) {
pixel = bigB * data[index] + b1 * ppixel + b2 * pppixel + b3 * ppppixel;
data[index] = pixel;
ppppixel = pppixel;
pppixel = ppixel;
ppixel = pixel;
}
}
}
ctx.putImageData(srcData, 0, 0);
}