Sign in to follow this  
ff8

Blur

Recommended Posts

hello everyone i want to make simple blur ,how can i do it ? i googled for this but i didn't find any good one :P bye

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Well, if I were to explain all your choices here I would finish writing yet another book on the subject.

Blur operations are a kind of image filtering operation.

The usual (but not unique) way of doing these filtering operations is as a weighed average.

For each pixel at position (x,y) in your destination image, you take the pixels at and around that position in your source image, multiply the numbers that specify their colour by a factor (not necesarily the same for all these pixels), and add all these values to produce the output pixel.

Of course, the trick is in knowing how much pixels around the destination to take, and what the factors should be.

For example, To make it simple, you could take the pixels at (x-1,y), (x+1, y), (x,y), (x,y-1), (x,y+1) and multiply all of them by (1/5). This way, you are producing an image that's the average of all those pixels, and that will create a blur effect. Not necesarily the kind of blur you may want and certainly not the "best".

How to choose these factors (how many pixels around, and which factors to use) will create a whole lot of possibilities.

Probably, searching for "gaussian blur" will give you a more complex, higher quality blur to think about.

Share this post


Link to post
Share on other sites
i am sorry but i still don't understand it :( i search for it but i can't get it :'(
can anyone give me simple code for this effect ?
bye

Share this post


Link to post
Share on other sites
I want pure blur not motion blur :P.
I think NeHe's tutorial was about motion blur .
bye

Share this post


Link to post
Share on other sites
An easy way to do it: render the scene, copy it to a texture, clear the colour buffer, then render the texture using trilinear filtering.

A harder and *much* slower way: render the scene, copy it to a texture, copy the texture data to a buffer, create a buffer with an equal size, iterate over the entire image adding up the values for the new pixels using some number of pixels around the current one, as well as the current one, and dividing the total by the number of pixels in the sum, then use glDrawPixels to draw the blurred result.

The first way is easy, and a lot faster, but the second lets you choose exactly how blurred the final result is, but you shouldn't use it if you need your app running in realtime. ;)

Share this post


Link to post
Share on other sites
There are several ways to perform blur as some of the gentlemen above have pointed out. Before I provide any source code, tell me something; what is your target graphic hardware?

Share this post


Link to post
Share on other sites
Thank you all for your replies,
Quote:

There are several ways to perform blur as some of the gentlemen above have pointed out. Before I provide any source code, tell me something; what is your target graphic hardware?

My grapic card is ATI X600 XT.
I hope to see your code :D.

Quote:

A harder and *much* slower way: render the scene, copy it to a texture, copy the texture data to a buffer, create a buffer with an equal size, iterate over the entire image adding up the values for the new pixels using some number of pixels around the current one, as well as the current one, and dividing the total by the number of pixels in the sum, then use glDrawPixels to draw the blurred result.

Can you explain it more ?if you don't mind .

Share this post


Link to post
Share on other sites
I recently wrote a blur method for my image class. I started off with a google search for gaussian blur techniques and found plenty of hits from which to develop my routine. There is no shortage of pages out there for this topic.

My routine is *not* pretty, but it works for my app. It uses fixed filter settings and a macro that clamps to my fixed texture size of 128x128. Again, not pretty and certainly not flexible. I have posted a quick executable up also for you to see this routine in action and the effect you can get (B for blur/W wireframe/PgUp/Dn to move). I *highly* recommend you write something better and use this only as a guide ;-)

hth
F451


// macro to keep gaussian blur array elements in fixed image range (128x128)
#define ac(c) ((c<0)?(c+1):((c>127)?(c-1):c))

// filter for gaussian blur function
float filter[3][3]={{0.1f,0.3f,0.1f},
{0.3f,4.0f,0.3f},
{0.1f,0.3f,0.1f}};


// struct for storing RGB values of a pixel when blurring
struct RGB {
float redRGB;
float greenRGB;
float blueRGB;
};
// array for storing current pixel and surrounding pixel RGB values
RGB currRGB[3][3];

// Gaussian Blur of one pixel
void CIMAGE::GaussianBlurPixel(int x, int z)
{
// accumulators for RGB values
float newR, newG, newB;

// store current RGB values for 8 surrounding pixels plus the pixel we are working on
for (int ii=-1; ii<2; ii++) {
for (int jj=-1; jj<2; jj++) {
GetColor2(ac(x+ii),ac(z+jj),currRGB[ii+1][jj+1].redRGB,currRGB[ii+1][jj+1].greenRGB,currRGB[ii+1][jj+1].blueRGB);
}
}

// work neighbour pixels blending as we go
for (int ii=-1; ii<2; ii++) {
for (int jj=-1; jj<2; jj++) {
// adjust pixels using stored values and the formula : orig+((current-orig)*filter)
newR=(float)currRGB[ii+1][jj+1].redRGB+((currRGB[1][1].redRGB-currRGB[ii+1][jj+1].redRGB)*filter[ii+1][jj+1]);
newG=(float)currRGB[ii+1][jj+1].greenRGB+((currRGB[1][1].greenRGB-currRGB[ii+1][jj+1].greenRGB)*filter[ii+1][jj+1]);
newB=(float)currRGB[ii+1][jj+1].blueRGB+((currRGB[1][1].blueRGB-currRGB[ii+1][jj+1].blueRGB)*filter[ii+1][jj+1]);
// assign new color
SetColor(ac(z+jj),ac(x+ii),(unsigned char)newR,(unsigned char)newG,(unsigned char)newB);
}
}
}

// Gaussian blur of a texture or image
// fixed 1 pixel blur ratio and filter settings
void CIMAGE::GaussianBlur()
{
// blur entire image if loaded
if (m_bIsLoaded) {
// traverse image blurring each pixel based on neighbours
for (unsigned int x=0; x<m_uiWidth; x++) {
for (unsigned int z=0; z<m_uiHeight; z++) {
GaussianBlurPixel(x,z);
}
}
// remake the texture if not new
if (m_ID > 0) {
glBindTexture(GL_TEXTURE_2D,m_ID);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,m_uiWidth,m_uiHeight,0,GL_RGB,GL_UNSIGNED_BYTE,m_imgData);
}
}
}


Share this post


Link to post
Share on other sites
Thank you Fahrenheit451 for your reply :),
I am so happy for the code :D ,just i have one question .

Can you give me the code for GetColor2(*) and SetColor(*)?
Thank you again :)

JavaCoolDude if you don't mind can you show me your GLSL code ?

bye

Share this post


Link to post
Share on other sites
If you have covered image loading on your OpenGL/C++ adventure then you will know that you load the image from a file and store the data in memory in an array. Those routines simply read the sequential RGB values for a pixel from that array, and likewise set the RGB values for a pixel. I pass the row and column of the array cell I want to access, but in the routine (because I too took them from a book I am working from) calculates the position of the cell as if it was accessing it as a one dimentional array. Looks confusing, but run a few simple 3x3 examples on paper and you will get it. Factor in that the cell you access is the red, then the cell+1 is the green, cell+2 is the blue, and potentially cell+3 for the alpha. Depends on the image/textures your working with.


inline void GetColor2(unsigned int z, unsigned int x, float &ucpRed, float &ucpGreen, float &ucpBlue)
{
unsigned int BPP= imageBPP/8;
if ((z<m_uiWidth)&&(x<m_uiHeight)) {
ucpRed = imgData[(( z*m_imageHeight)+x)*BPP];
ucpGreen= imgData[(((z*m_imageHeight)+x)*BPP)+1];
ucpBlue = imgData[(((z*m_imageHeight)+x)*BPP)+2];
}
}

inline void SetColor( unsigned int x, unsigned int y, unsigned char ucRed, unsigned char ucGreen, unsigned char ucBlue )
{
unsigned int BPP= imageBPP/8;
if( ( x<m_uiWidth ) && ( y<m_uiHeight ) ) {
imgData[( ( y*imageHeight )+x )*BPP] = ucRed;
imgData[( ( y*imageHeight )+x )*BPP+1]= ucGreen;
imgData[( ( y*imageHeight )+x )*BPP+2]= ucBlue;
}
}



hth
F451

Share this post


Link to post
Share on other sites
Quote:
Original post by ff8
Can you explain it more ?if you don't mind .


Just like Fahrenheit451's method, although you could always take it one step further and do the calculations for a circle, rather than a square (requires even more computation, but would look a little better as you start to move beyond the 3x3 square, not that you'd really notice it, since it gets very blurry very fast). ;)

Share this post


Link to post
Share on other sites
Nowadays I do write GLSL code just for debugging and making sure that things are properly working. I find it disturbing how many incompatibilities there are out there between sets of drivers running on the same hardware.
Anyways, here's the code:


<Shaders fragmentProcessor = "FRAGMENT_PROGRAM">

<FRAGMENT_SHADER>
<Uniform name = "texOffset" size = "4" type = "float"/>
<Uniform name = "GlowTexture" size = "1" type = "int" x = "0" />

<RawData>
uniform sampler2D GlowTexture;
uniform vec4 texOffset;


void main(void)
{
vec4 blurFilter[9],
finalColor = vec4(0.0,0.0,0.0,0.0);

float xOffset = texOffset.x*texOffset.z,
yOffset = texOffset.y*texOffset.w;

blurFilter[0] = vec4( 4.0*xOffset, 4.0*yOffset, 0.0, 0.0217);
blurFilter[1] = vec4( 3.0*xOffset, 3.0*yOffset, 0.0, 0.0434);
blurFilter[2] = vec4( 2.0*xOffset, 2.0*yOffset, 0.0, 0.0869);
blurFilter[3] = vec4( 1.0*xOffset, 1.0*yOffset, 0.0, 0.1739);
blurFilter[4] = vec4( 0.0, 0.0, 0.0, 0.3478);
blurFilter[5] = vec4(-1.0*xOffset,-1.0*yOffset, 0.0, 0.1739);
blurFilter[6] = vec4(-2.0*xOffset,-2.0*yOffset, 0.0, 0.0869);
blurFilter[7] = vec4(-3.0*xOffset,-3.0*yOffset, 0.0, 0.0434);
blurFilter[8] = vec4(-4.0*xOffset,-4.0*yOffset, 0.0, 0.0217);

for (int i = 0;i< 9;i++)
finalColor += texture2D(GlowTexture, gl_TexCoord[0].xy + blurFilter[i].xy) * blurFilter[i].w;

gl_FragColor = finalColor*1.15;
}
</RawData>
</FRAGMENT_SHADER>

<!-- Assembly is l33t :P -->

<FRAGMENT_PROGRAM>
<Attributes local = "false" name = "texOffset" />

<RawData>!!ARBfp1.0
PARAM textureOffset = program.env[0];
PARAM offsetCoeffs[9] = {{ 4.0, 4.0, 0.0, 0.0217},
{ 3.0, 3.0, 0.0, 0.0434},
{ 2.0, 2.0, 0.0, 0.0869},
{ 1.0, 1.0, 0.0, 0.1739},
{ 0.0, 0.0, 0.0, 0.3478},
{-1.0,-1.0, 0.0, 0.1739},
{-2.0,-2.0, 0.0, 0.0869},
{-3.0,-3.0, 0.0, 0.0434},
{-4.0,-4.0, 0.0, 0.0217}};

TEMP texCoords, colorSample, cumulativeColor;
TEMP scale, sampler;

MOV cumulativeColor, 0.0;

MUL scale.x , textureOffset.x, textureOffset.z;
MUL scale.y , textureOffset.y, textureOffset.w;

MAD sampler, scale, offsetCoeffs[0], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[0].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[1], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[1].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[2], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[2].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[3], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[3].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[4], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[4].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[5], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[5].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[6], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[6].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[7], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[7].w, cumulativeColor;

MAD sampler, scale, offsetCoeffs[8], fragment.texcoord[0];
TEX colorSample, sampler, texture[0], 2D;
MAD cumulativeColor, colorSample, offsetCoeffs[8].w, cumulativeColor;
MUL result.color, cumulativeColor, 1.15;

END
</RawData>
</FRAGMENT_PROGRAM>
</Shaders>





The x and y components of texOffset are 1.0f/blurTextureWidth and 1.0f/blurTextureHeight.
The z and w are equal to 1 and 0 or 0 and 1 depending on whetheir we want to blur the target in the x or y direction.
You need to refresh those values, z and w, everytime you call your shaders to obtain proper blur.
This is how I do it:



blurShader.updateElementsf("texOffset", 4, Tuple4f(1.0f/blurScreenWidth,
1.0f/blurScreenHeight,
!vertical, vertical));



Take care

Share this post


Link to post
Share on other sites
My method would probably encompass:

render the scene to a pbuffer or something, with a smaller size than what you're wanting [you can also get antialiasing by making it larger] and then draw that pbuffer to the screen by a full 2D quad.

That should work on everything down to the bottom of the GeForce series...

CJM

Share this post


Link to post
Share on other sites
Hello :), thank you for your reply.
I used to use this way before but you can't have the full control of your blur.
Thank you again :).
bye

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this