Click here to Skip to main content
15,892,927 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
I am writing a software filter object and trying to implement a light bloom effect. I'm using a simple, two pass convolution approach which works fine except that the effect radius is tiny and I can't seem to control the radius. I've played with larger box filters and adjusted the weights of the various pixels, but none of that seems to have any effect. The effect seems to have a maximum size (which is not very big) and then all changes to the parameters just serve to make it smaller.

I'd like to be able to create a light bloom with an arbitrary radius. After a LOT of experimentation and searching online, I'm starting to wonder if this just can't be done. I've been thinking about alternate approaches--plasmas, gradients, and various seeding schemes--but I'd like to hound this path into the ground first. Does anyone out there know how to create an arbitrarily sized light bloom (in software)?

The javascript is as follows (this operates on an HTML5 canvas):
JavaScript
// the kernel functions are called via Array.map on this.backBuffer.data, a canvas surface color array
this.kernelFirstPass = function(val, index, array)
{
    if(index<pitch || index>=array.length-pitch || index%pitch<4 || index%pitch>pitch-5 || index%4==3)
        return;
    var c = 1,
        l1 = 1,
        l2 = 1,
        l3 = 1,
        r1 = 1,
        r2 = 1,
        r3 = 1;
    var avg =
    (
        c*this.frontBuffer.data[index]+
        l1*this.frontBuffer.data[index-4]+
        l2*this.frontBuffer.data[index-8]+
        l3*this.frontBuffer.data[index-12]+
        l1*this.frontBuffer.data[index+4]+
        l2*this.frontBuffer.data[index+8]+
        l3*this.frontBuffer.data[index+12]
    )/(c+l1+l2+l3+l1+l2+l3);
    //this.frontBuffer.data[index] = avg;
    array[index] = avg;
}
this.kernelSecondPass = function(val, index, array)
{
    if(index<pitch || index>=array.length-pitch || index%pitch<4 || index%pitch>=pitch-4 || index%4==3)
        return;
    var c = 1,
        l1 = 1,
        l2 = 1,
        l3 = 1,
        r1 = 1,
        r2 = 1,
        r3 = 1;
    var avg =
    (
        c*array[index]+
        l1*array[index-pitch]+
        l2*array[index-(pitch*2)]+
        l3*array[index-(pitch*3)]+
        l1*array[index+pitch]+
        l2*array[index+(pitch*2)]+
        l3*array[index+(pitch*3)]
    )/(c+l1+l2+l3+l1+l2+l3);
    array[index] = avg;
}
Posted

1 solution

I see nothing wrong with this code (except the rejection tests - see below). It does implement a separable 7x7 box filter on an RGBA image (components stored in this order).

The box filter has a strong blurring effect that has exactly the size of the kernel and you will see its effect increasing with the radius. Directly proportional. Changing the coefficients will indeed lower the blur but this will become noticeable for very skewed distributions (like the Binomial 1 6 15 20 15 6 1, which approximates a Gaussian).

The running time of the uniform filter, when implemented this way, is proportional to the radius. This can get slow for large radii. You can do better by means of the integral image trick (http://en.wikipedia.org/wiki/Summed_area_table[^]).

About the tests
I disagree with the fact that they are identical for the two passes and I see a problem in the second pass: nothing prevents index-(pitch*3) to be negative, among others.

My solution would be to convert the index to the pair of coordinates ((index%pitch)/4, index/pitch), and check if they remain in their respective range [0..pitch/4[ and [0..length/pitch[ after offsets are added. This leads to the following conditions, for the 2r+1 x 2r+1 filter:

First pass:
JavaScript
index%4 == 3 || (index%pitch)/4 - r < 0 || (index%pitch)/4 + r >= pitch/4


Second pass:
index%4 == 3 || index/pitch - r < 0 || index/pitch + r >= length/pitch
 
Share this answer
 
v5

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900