Jump to content
  • Advertisement
Sign in to follow this  
kloffy

Image filters using Tao.Sdl and SDL.NET

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was wondering how to use the convolution filters from sdl-gfx in SDL.NET. Here's what I've got:
Surface source = new Surface(new Size(100, 100));

// Blit stuff here

short[] kernel =  { 0, 1, 0, 1, 1, 1, 0, 1, 0 };

byte[] src = ???;
byte[] dst = new byte[src.Length];

SdlGfx.SDL_imageFilterConvolveKernel3x3Divide(src, dst, 3, 3, kernel, 1);

Surface result = new Surface(dst);
So, right now I'm having two questions here: First, how do I get the byte[] from the Surface? (Maybe there is a way of getting it using "source.Pixels"...) Second, am I using SDL_imageFilterConvolveKernel correctly? (To be honest I couldn't make much sense out of the information on the SDL_gfx Library page...)

Share this post


Link to post
Share on other sites
Advertisement
I just realized that the SDL_imageFilterConvolveKernel functions need MMX, so I wrote my own convolution filter. However, it is not optimized and ergo pretty slow. I do not recommend using it.

Edit: Updated code. Still horribly slow...

private static float Weight(short[,] kernel)
{
float weight = 0;

for (int ki = 0; ki < kernel.GetLength(0); ki++)
{
for (int kj = 0; kj < kernel.GetLength(1); kj++)
{
weight += kernel[ki, kj];
}
}

return 1/(float)Math.Max(1, Math.Abs(weight));
}

public static Color GetColor(Surface s, int x, int y)
{
//IntPtr ptr = new IntPtr(s.Pixels.ToInt32() + y * s.Pitch + x * s.BytesPerPixel);

//return s.GetColor(Marshal.ReadInt32(ptr));

return s.GetPixel(new Point(x, y));
}

public static void SetColor(Surface s, int x, int y, Color c)
{
//IntPtr ptr = new IntPtr(s.Pixels.ToInt32() + y * s.Pitch + x * s.BytesPerPixel);

//Marshal.WriteInt32(ptr, s.GetColorValue(c));

s.Draw(new Point(x, y), c);
}

public static Surface Convolve(Surface src, short[,] kernel)
{
return Convolve(src, kernel, Weight(kernel));
}

public static Surface Convolve(Surface src, short[,] kernel, float weight)
{
Surface dst = new Surface(src);

int kw = kernel.GetLength(1);
int kh = kernel.GetLength(0);

int ox = kw / 2, ux = (kw + 1) / 2;
int oy = kh / 2, uy = (kh + 1) / 2;

for (int y = oy; y < src.Height - uy; y++)
{
for (int x = ox; x < src.Width - ux; x++)
{
int r = 0, g = 0, b = 0, a = 0;

for (int kj = 0; kj < kh; kj++)
{
for (int ki = 0; ki < kw; ki++)
{
Color c = GetColor(src, x + ki - ox, y + kj - oy);

int w = kernel[kj, ki];

r += w * c.R;
g += w * c.G;
b += w * c.B;
a += w * c.A;
}
}

r = Bound((int)(r * weight), 0, 255);
g = Bound((int)(g * weight), 0, 255);
b = Bound((int)(b * weight), 0, 255);
a = Bound((int)(a * weight), 0, 255);

SetColor(dst, x, y, Color.FromArgb(a, r, g, b));
}
}

return dst;
}


[Edited by - kloffy on January 1, 2008 9:33:45 AM]

Share this post


Link to post
Share on other sites
Apparently the bottleneck was the polling of the PixelFormat for every GetPixel/SetPixel. For some reason SdlDotNet doesn't buffer the Surface PixelFormat information, so everytime information about the PixelFormat is needed it goes throug the following methods:

        internal Sdl.SDL_Surface SurfaceStruct
{
get
{
if (this.disposed)
{
throw (new ObjectDisposedException(this.ToString()));
}
GC.KeepAlive(this);
return (Sdl.SDL_Surface)Marshal.PtrToStructure(this.Handle,
typeof(Sdl.SDL_Surface));
}
}

internal Sdl.SDL_PixelFormat PixelFormat
{
get
{
if (this.disposed)
{
throw (new ObjectDisposedException(this.ToString()));
}
GC.KeepAlive(this);
return (Sdl.SDL_PixelFormat)Marshal.PtrToStructure(this.SurfaceStruct.format,
typeof(Sdl.SDL_PixelFormat));
}
}


By polling the necessary PixelFormat information only once for the entire filtering process I managed to get down to about 1/7 of the original time it took to run the filter.

        private struct Format
{
public short pitch;
public byte bpp;

public int ashift;
public int rshift;
public int gshift;
public int bshift;

public Format(Surface surface)
{
this.pitch = surface.Pitch;
this.bpp = surface.BytesPerPixel;

this.ashift = surface.AlphaShift;
this.rshift = surface.RedShift;
this.gshift = surface.GreenShift;
this.bshift = surface.BlueShift;
}
}

private static float Weight(short[,] kernel)
{
float weight = 0;

for (int ki = 0; ki < kernel.GetLength(0); ki++)
{
for (int kj = 0; kj < kernel.GetLength(1); kj++)
{
weight += kernel[ki, kj];
}
}

return 1/(float)Math.Max(1, Math.Abs(weight));
}

private static Color GetColor(Surface s, Format format, int x, int y)
{
IntPtr ptr = new IntPtr(s.Pixels.ToInt32() + y * format.pitch + x * format.bpp);

int col = Marshal.ReadInt32(ptr);

int a = (col >> format.ashift) & 0xFF;
int r = (col >> format.rshift) & 0xFF;
int g = (col >> format.gshift) & 0xFF;
int b = (col >> format.bshift) & 0xFF;

return Color.FromArgb(a, r, g, b);
}

private static void SetColor(Surface s, Format format, int x, int y, Color c)
{
IntPtr ptr = new IntPtr(s.Pixels.ToInt32() + y * format.pitch + x * format.bpp);

int col =
c.A << format.ashift |
c.R << format.rshift |
c.G << format.gshift |
c.B << format.bshift;

Marshal.WriteInt32(ptr, col);
}

public static Surface Convolve(Surface src, short[,] kernel)
{
return Convolve(src, kernel, Weight(kernel));
}

public static Surface Convolve(Surface src, short[,] kernel, float weight)
{
Surface dst = new Surface(src);

Format srcFormat = new Format(src);
Format dstFormat = new Format(dst);

int kw = kernel.GetLength(1);
int kh = kernel.GetLength(0);

int ox = kw / 2, ux = (kw + 1) / 2;
int oy = kh / 2, uy = (kh + 1) / 2;

for (int y = oy; y < src.Height - uy; y++)
{
for (int x = ox; x < src.Width - ux; x++)
{
int r = 0, g = 0, b = 0, a = 0;

for (int kj = 0; kj < kh; kj++)
{
for (int ki = 0; ki < kw; ki++)
{
Color c = GetColor(src, srcFormat, x + ki - ox, y + kj - oy);

int w = kernel[kj, ki];

r += w * c.R;
g += w * c.G;
b += w * c.B;
a += w * c.A;
}
}

r = Bound((int)(r * weight), 0, 255);
g = Bound((int)(g * weight), 0, 255);
b = Bound((int)(b * weight), 0, 255);
a = Bound((int)(a * weight), 0, 255);

SetColor(dst, dstFormat, x, y, Color.FromArgb(a, r, g, b));
}
}

return dst;
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!