# Trying To Figure Out Bilateral Blur

This topic is 885 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi all,
Working my way through my d3d11 book, I've got an assignment to redo my working gaussian blur for a bilateral blur.
So I've digged and digged, googled and googled some more and the monkey explanation for me is:

- gaussian blur: predefined static weights for the surrounding pixels
- bilateral blur: weights depend on the difference in pixel colors and the distance the pixels are from the source pixel
(eventually leading to a 1.0 total weights for all neighbouring pixels)

So I started figuring out my existing gaussian blur, and that's clear (pseudo code):

	/*	float blurWeights[11] =
{
0.05f, 0.05f, 0.1f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.05f, 0.05f,
};

gCache = org. texture pixels
newPixelCol = float4(0, 0, 0, 0);

{
k = orgPixel.x + 5 + i

}
output = newPixelCol;
*/



And drawn out:

So, now how to get from there to the bilateral blur?

I've written things out in Excel to get a good understanding.
I came up with an idea to calculate the weight based in difference in pixel colors of the neighboring pixels, but my conclusion a few minutes ago, is that averaging the R, G and B differences will not work, because the average will always be 0.0f for all neighboring pictures.

And this is were I stopped / came so far...

My question;
- do you have any idea how I can somehow determine the difference in pixels so I can order them to share the weight of 1.0 over my 11 pixels, based on the sorted difference in pixel colors?

What I can think of, is taking the highest difference of one of the 3 components (R,G,B), that way I can sort all 10/11 pixels and lookup the weights in some sort of lookup table (predefined).

The aimed result is keeping the edges better, besides a nice blur (pixels that are 'a like' will be better visible that way)

Edited by cozzie

##### Share on other sites

A hint that should help - it's ok if your weights don't add up to 1.0, as long as you can normalize for this at the end.

If you know your weights sum to 1.0, you can use:

for( i=... )
result += sample[i] * weight[i];

Otherwise, you can use:

for( i=... )
{
result += sample[i] * weight[i];
totalWeight += weight[i];
}
result /= totalWeight;

Or:

for( i=... )
totalWeight += weight[i];
for( i=... )
weight[i] /= totalWeight;
//now the weights do sum to 1.0
for( i=... )
result += sample[i] * weight[i];

So for your blur, you could start out using the Gaussian weights as usual, and then modify them with something like:
weight *= 1-dot(abs(sample - sample

), 1/3.0)

Edited by Hodgman

##### Share on other sites

As always, thanks for thinking with me/ helping out hodgman.

I'm trying to understand what you're saying, regarding the normalization so the weights sum up to 1.0 I understand what you mean.

As a first attempt I'm trying to modify the weight based on your example (last line in the reply above).

When I only do this, the result is that everything's black :)

Probably because only doing this is not enough, if I just change the weights 'per neighbour pixel' (11 times), the end result won't sum up to 1.

Does this mean I have to to some sort of 'pre-pass' to determine the weights, or am I overlooking something?

Here's the full code of the horizonal blur pass, to give a better view:

cbuffer cbSettings
{
float gWeights[11] =
{
0.05f, 0.05f, 0.1f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.05f, 0.05f,
};
};

cbuffer cbFixed
{
static const int gBlurRadius = 5;
};


#define N 256
groupshared float4 gCache[CacheSize];

{
// fill local thread storage to reduce bandwidth. Blur N N pixels, needs N + 2 * BlurRadius for Blur radius

{
// clamp out of bound samples that occur at image borders
}
{
// clamp out of bound samples that occur at image borders
}

// clamp out of bound samples that occur at image borders

// wait for all threads to finish.
GroupMemoryBarrierWithGroupSync();

// Now blur each pixel.
float4 blurColor = float4(0, 0, 0, 0);

[unroll]
{

//tWeight *= 1 - dot(abs(gCache[k] - groupThreadID.x), 1/3.0f);			// TEST after reply Hodgman

blurColor += tWeight * gCache[k];
}

}


Edited by cozzie

##### Share on other sites

With some help, I've managed to find a few options/ solutions.

The three options:

	/*	OPTION 1

tWeight *= 1 - dot(abs(gCache[k] - gCache[groupThreadID.x]), 1/3.0f);			// TEST after reply Hodgman
*/

/*	OPTION 2

tWeight *= pow(abs(1 - dot(abs(gCache[k] - gCache[groupThreadID.x]), 1/3.0f)), 10);

*/

/*	OPTION 3

tWeight *= pow(abs(1 - dot(abs(gCache[k] - gCache[groupThreadID.x]), 1/3.0f)), 2);

*/



Where I personally find that option 1 gives the best result, then 3 (not 2 for sure).

I've also tried out something completely different, but this results in most pixels being 'pitch black' and the edges being visible-> white/ light greyish:

tWeight *= saturate(dot(abs(gCache[k] - gCache[groupThreadID.x]), 1));


Here are the outputs of the 3 options (in logical order):

And the normal gaussian blur version:

And the non-blurred scene:

What do you think?

Thanks everybody for the help.

Edited by cozzie

1. 1
2. 2
Rutin
19
3. 3
4. 4
khawk
15
5. 5

• 13
• 26
• 10
• 11
• 44
• ### Forum Statistics

• Total Topics
633743
• Total Posts
3013645
×