gaussian kernel for bilinear filtering

Posted By: Joey

gaussian kernel for bilinear filtering - 06/06/11 20:12

hey,

since blurring is quite important in many shaders I thought I could give you a little speedup. Cards can filter samples in a bilinear way, thus saving you half the samples when calculating something like a gaussian blur. so here
Code:
samples[width_] := Module[{t, p, l, w},
  w = Max[Round[width], 1];
  t = Table[
    N[PDF[NormalDistribution[0, w/2.2], x]], {x, -w - .5, w + .5}];
  p = Partition[t, 2];
  {#[[1]] + #[[2]], 1 - #[[1]]/(#1[[1]] + #1[[2]])} & /@ p
  ]


is the generating code for anyone who wants to use it and here are some sample kernels:
4
Code:
{{0.0653515, 0.833874}, {0.433296, 0.631295}, {0.433296, 
  0.368705}, {0.0653515, 0.166126}}


6
Code:
{{0.0341105, 0.724721}, {0.149481, 0.641251}, {0.312518, 
  0.548249}, {0.312518, 0.451751}, {0.149481, 0.358749}, {0.0341105, 
  0.275279}}


10
Code:
{{0.0178401, 0.631295}, {0.0457636, 0.60307}, {0.0927521, 
  0.574141}, {0.148539, 0.544695}, {0.187973, 0.514934}, {0.187973, 
  0.485066}, {0.148539, 0.455305}, {0.0927521, 0.425859}, {0.0457636, 
  0.39693}, {0.0178401, 0.368705}}


16
Code:
{{0.0105133, 0.579974}, {0.0191392, 0.569459}, {0.0319842, 
  0.558881}, {0.0490657, 0.548249}, {0.0690956, 0.537573}, {0.0893212,
   0.526863}, {0.105996, 0.516128}, {0.115467, 0.505378}, {0.115467, 
  0.494622}, {0.105996, 0.483872}, {0.0893212, 0.473137}, {0.0690956, 
  0.462427}, {0.0490657, 0.451751}, {0.0319842, 0.441119}, {0.0191392,
   0.430541}, {0.0105133, 0.420026}}



If you need any specific sizes you can ask me. Usage is as follows:
Code:
static const float2 kernel[NUM]=...; // here goes the sample output I posted above

for(int i = 0; i < NUM; i++)
{
	pixel = tex2D(mytex,texcoord0 + float2(kernel[i].y-NUM+2*i,0)/resolution_x)*kernel[i].x;
	color += pixel;
}



same goes for the y direction, so you need to do two passes. Could be that the kernel is off one pixel, I'm not sure atm, but the shader gurus (for whom this is intended) should be able to tell.

Joey

btw. you could replace the NormalDistribution by anything you like.


Posted By: HeelX

Re: gaussian kernel for bilinear filtering - 06/06/11 20:47

First, it is not "bilinear", but "seperated". Bilinear sampling refers to texture filtering whereas seperability refers to the fact that a square-kernel could be seperate into a vector and a transposed vector, which, multiplied, generate the original kernel again. That way, a convolution K * I can be replaced by the convolution v * ( v^T * I), which requires less arithmetics.

The problem you have is that your kernel is always even. That way, you never sample the pixel on which the kernel is applied to. You could shift the kernel pivot, so that you sample the original pixel, but then you have an odd weighting scheme for the surrounding pixels and you are weighting more the next right (or left pixel), so an odd NUM value is beneficial.

Second, I don't get why you sample in an intended fashion bilinear texture samples (this time this is the correct term) by adding a fraction on the tex-coord:

... texcoord0 + float2(kernel[i].y ...

Why don't you simply use vecViewport to get the pixel size and sample "real" neighbour pixels.

Third, you are sampling in a tapped fashion. Since your NUM value is storing the number of samples, you are going a length of NUM to the left (or up) and the double of the i-counter to the right (or down). You should divide both values by 2 to get a non-tapped sampling.

Fourth, since the gaussian bell is symmetric, it is totally sufficient to store only the weights of the half of the bell. Though, I don't know if the arithmetic overhead then generates more instructions, but I would only store half the kernel weights.

Best regards,
-Christian
Posted By: Slin

Re: gaussian kernel for bilinear filtering - 06/06/11 21:20

I am not sure about every point but I think in most points you are wrong HeelX.
But now I am confused.
The trick however is to sample between the pixels to take advantage of the bilineral filtering which allows you to use half the samples by keeping the same quality.
Posted By: HeelX

Re: gaussian kernel for bilinear filtering - 06/06/11 21:30

Ah. I thought this was an ordinary filter smile stupid me!

So can anyone tell me a reason why I get the same result with less samples when using the interpolated values?
Posted By: Joey

Re: gaussian kernel for bilinear filtering - 06/06/11 21:54

well, imagine i want to sample pixel a and pixel b and weight them both by 50% (average them). i can do that by two tex2D's or by one, sampling halfway between them (assuming they're neighbours). now imagine i want to weight them differently, say 90% a and 10% b. i can still do that with only one tex2D, now 10% away from a in direction of b.
that's what i'm calculating. instead of just the weights for each pixel i store a sampling position and a combined weight. also, the kernel is not symmetric (the weights are, but then, it's only some bytes). you could calculate everything in a shader, only storing one side of the gaussian convolution and reconstructing the rest, of course. but that will definitely be slower, way slower.
i think i see how you misunderstood my idea, so i'm sorry for not being more precise ^^.

edit: by the way, odd numbers work fine as well.
Posted By: HeelX

Re: gaussian kernel for bilinear filtering - 06/06/11 23:01

Interesting, never heard of this. Do you have a paper or reference? Does this work for box blurs, too?

I am doing a very exhaustive (yet seperated) box-blur stage in my SSAO shader (with depth/normal checking) and if there is a chance that I can do that with less lookups, this would be very awesome.
Posted By: JibbSmart

Re: gaussian kernel for bilinear filtering - 06/07/11 01:03

I've been using something like this for my anti-aliasing (so pp effects can be used with it, the effect isn't just on the edges of objects, and it can be toggled on/off instantly) -- I render the scene to a bmap with twice the dimensions of the screen, and then render the result to the screen using one sample per pixel -- each sample being in the corner between four pixels on the larger bmap. It works like a charm. I also use it for my bloom, whether I'm using anti-aliasing or not.

Jibb
Posted By: Joey

Re: gaussian kernel for bilinear filtering - 06/07/11 06:16

yeah, it's really really useful. You find it for instance in gpu gems 3, though I don't remember where exactly. Sure, it also works for box blurs, in this case it's very simple: always sample halfway between the pixels for every second pixel. No need to store weights either, just divide by the number of pixels in the end.
© 2024 lite-C Forums