PDA

View Full Version : Blur Image

wagenheimer
01-03-2013, 08:08 PM
Hi!

I need to blur a texture using ZenGL. It does not need to be very fast because I need to blur it once and I will use it for several frames (I want to blur everything bellow a Game Dialog).

Andrey converted this code of a BoxBlur to me, it works very well, but it does have two side-effects!

- To works well I need to use it twice (or the blur will be very weak).
- The blurred image seems to be some pixels off, so I get a strange effect, it seems the background was moved.

procedure BoxBlur(var Texture: zglPTexture);
var
X, Y: Integer;
yLine, xLine: PByteArray;
data : PByteArray;
realWidth : Integer;
realHeight : Integer;
begin
realWidth := Round( Texture.Width / Texture.U );
realHeight := Round( Texture.Height / Texture.V );
tex_GetData(Texture, data);
for Y := 1 to realHeight - 2 do
begin
yLine := @data[ realWidth * ( Y - 1 ) * 4 ];
xLine := @data[ realWidth * Y * 4 ];
for X := 1 to realWidth - 2 do
begin
xLine^[X * 4 ] := (xLine^[X * 4 - 4] + xLine^[X * 4 + 4] + yLine^[X * 4 - 4] + yLine^[X * 4 + 4] + yLine^[X * 4 ] + xLine^[X * 4 - 4] + xLine^[X * 4 + 4] + xLine^[X * 4]) div 8;
xLine^[X * 4 + 1] := (xLine^[X * 4 - 3] + xLine^[X * 4 + 5] + yLine^[X * 4 - 3] + yLine^[X * 4 + 5] + yLine^[X * 4 + 1] + xLine^[X * 4 - 3] + xLine^[X * 4 + 5] + xLine^[X * 4 + 1]) div 8;
xLine^[X * 4 + 2] := (xLine^[X * 4 - 2] + xLine^[X * 4 + 6] + yLine^[X * 4 - 2] + yLine^[X * 4 + 6] + yLine^[X * 4 + 2] + xLine^[X * 4 - 2] + xLine^[X * 4 + 6] + xLine^[X * 4 + 2]) div 8;
end;
end;
tex_SetData(Texture, data, 0, 0, realWidth, Texture.Height);
zgl_FreeMem( data );
end;

Anybody have to suggest some alternative blurring routine? A Gaussian Blur seems to be ideal, but I wasn't able to convert it to ZenGL after some tries.

Thanks

laggyluk
01-03-2013, 10:18 PM
hm maybe try imagemagick?

User137
01-03-2013, 10:51 PM
Only blur algorithm i know that works well, reads 1+4 pixels RGB(A) values around it (up, down, left, right and self), and averages them. To get perfect result, you can't be writing to same data array that you are reading from, i mean after you have blurred top row, you would be using blurred values and nonblurred values mixed. So you need to allocate the texture memory again for writing, free the old data after blur, and then set the real texture use the newly allocated pointer.

To get even better blur, you can read the corners aswell, and average that 9 pixel data. That's obviously slower, but possibly not as slow as doing a second pass.

wagenheimer
02-03-2013, 02:18 AM
Thanks a lot User137! Your tips were very valuable! =)

To achieve the best result I did use the 17 pixels around the current pixel.

Here is the final code :

procedure BoxBlur(var Texture: zglPTexture);
var
X, Y: Integer;
yLine, xLine, yLine2, yLine3: PByteArray;
data: PByteArray;
realWidth: Integer;
realHeight: Integer;
begin
realWidth := Round(Texture.Width / Texture.U);
realHeight := Round(Texture.Height / Texture.V);
tex_GetData(Texture, data);

for Y := 1 to realHeight - 2 do
begin
yLine := @data[realWidth * (Y) * 4]; // Current Line
yLine2 := @data[realWidth * (Y - 1) * 4]; // Prior Line
yLine3 := @data[realWidth * (Y + 1) * 4]; // Next Line

xLine := @data[realWidth * Y * 4];

for X := 1 to realWidth - 2 do
begin
xLine^[X * 4] := ((xLine^[X * 4] + xLine^[(X - 1) * 4] + xLine^[(X + 1) * 4] + yLine^[(X - 1) * 4] + yLine^[(X + 1) * 4] + yLine2^[(X - 1) * 4] + yLine2^[(X + 1) * 4] + yLine3^[(X - 1) * 4]
+ yLine3^[(X + 1) * 4]) + (xLine^[(X - 2) * 4] + xLine^[(X + 2) * 4] + yLine^[(X - 2) * 4] + yLine^[(X + 2) * 4] + yLine2^[(X - 2) * 4] + yLine2^[(X + 2) * 4] + yLine3^[(X - 2) * 4]
+ yLine3^[(X + 2) * 4])) div 17;

xLine^[X * 4 + 1] := ((xLine^[X * 4 + 1] + xLine^[(X - 1) * 4 + 1] + xLine^[(X + 1) * 4 + 1] + yLine^[(X - 1) * 4 + 1] + yLine^[(X + 1) * 4 + 1] + yLine2^[(X + 1) * 4 + 1] + yLine2^[(X - 1)
* 4 + 1] + yLine3^[(X + 1) * 4 + 1] + yLine3^[(X - 1) * 4 + 1]) + (xLine^[(X - 2) * 4 + 1] + xLine^[(X + 2) * 4 + 1] + yLine^[(X - 2) * 4 + 1] + yLine^[(X + 2) * 4 + 1] + yLine2^[
(X + 2) * 4 + 1] + yLine2^[(X - 2) * 4 + 1] + yLine3^[(X + 2) * 4 + 1] + yLine3^[(X - 2) * 4 + 1])) div 17;

xLine^[X * 4 + 2] := ((xLine^[X * 4 + 2] + xLine^[(X - 1) * 4 + 2] + xLine^[(X + 1) * 4 + 2] + yLine^[(X - 1) * 4 + 2] + yLine^[(X + 1) * 4 + 2] + yLine2^[(X + 1) * 4 + 2] + yLine2^[(X - 1)
* 4 + 2] + yLine3^[(X + 1) * 4 + 2] + yLine3^[(X - 1) * 4 + 2]) + (xLine^[(X - 2) * 4 + 2] + xLine^[(X + 2) * 4 + 2] + yLine^[(X - 2) * 4 + 2] + yLine^[(X + 2) * 4 + 2] + yLine2^[
(X + 2) * 4 + 2] + yLine2^[(X - 2) * 4 + 2] + yLine3^[(X + 2) * 4 + 2] + yLine3^[(X - 2) * 4 + 2])) div 17;

end;
end;

tex_SetData(Texture, data, 0, 0, realWidth, Texture.Height);
FreeMem(data);
end;

phibermon
02-03-2013, 01:08 PM
ZenGL - the clue is in the name. Why don't you just use mip-map levels + filtering to do the blur in hardware? you can do it in a shader incredibly easily. You're already tied into GL with Zen so not doing it in hardware is folly