Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
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):
// 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 14-Jul-12 8:04am

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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:
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
  Permalink  
v5

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

  Print Answers RSS
0 Sergey Alexandrovich Kryukov 380
1 OriginalGriff 250
2 DamithSL 210
3 Kornfeld Eliyahu Peter 200
4 Peter Leow 95
0 OriginalGriff 7,315
1 DamithSL 5,199
2 Sergey Alexandrovich Kryukov 4,917
3 Maciej Los 4,866
4 Kornfeld Eliyahu Peter 4,514


Advertise | Privacy | Mobile
Web01 | 2.8.141223.1 | Last Updated 2 Aug 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100