12,549,492 members (42,488 online)
alternative version

688K views
280 bookmarked
Posted

# Image Processing for Dummies with C# and GDI+ Part 5 - Displacement filters, including swirl

, 25 Dec 2002
 Rate this:
In the fifth installment, we build a framework for generating filters that work by changing a pixel's location, rather than colour.

## Introduction

Welcome again to my series on image processing. This time around I want to talk about displacement filters. Most of the information you'll find about image processing is similar to the previous articles, talking about changing an image by changing the colour values of pixels. Instead the filters we are looking at today change an image by changing each pixels location. I got a lot of email for my last article, asking why I bothered writing code to resize images. The answer was that the last article explains bilinear filtering, a way of moving pixels so they are drawn to a theoretical location between physical pixels. We will use that ability in this article, but I will not explain it, instead I recommend that you review the prior article[^] if you are not familiar with bilinear filtering.

## The framework

Once again we will start by implementing a frame work which we can use to create filters. Our basic approach will be to create a two dimensional array of points. The array will be the size of the image, and each point will store the new location for the pixel at that index. We will do this two ways, one that stores a relative location, and one that stores an absolute location. Finally, we will create our own point struct, which contains two `double`s instead of `int`s, which we will use to write the implementation to performs the bilinear filtering.

## Arrays in C#

I must admit I had not done anything with 2D arrays in C# before this, and they are very cool. The code looks like this:

`Point [,] pt = new Point[nWidth, nHeight];`

This creates a 2D array dynamically, and we can access the pixels using notation like `pt[2, 3]`, instead of the C++ `pt[2][3]`. Not only is this much neater than C++, but a `Point[,]` is a valid parameter to pass into a function, making it a snap to pass around arrays of size unknown at compile time.

## Offset Filter

The first helper function we will write will take a relative location, so for example if we want to move pixel 2, 4 to location 5, 2, then `pt[2, 4]` will equal 3, -2. We could use `Set/GetPixel` to do this, but we will continue to use direct access, which is probably faster. As we must now span an arbitrary number of rows to access pixels from anywhere in the image, we will do so by using the `Stride` member of the `BitmapData`, which we can multiply by our Y value to get the number of rows down. Then our X value is multiplied by 3, because we are using 3 bytes per pixel ( 24 bit ) as our format. The code looks like this:

```public static bool OffsetFilter(Bitmap b, Point[,] offset )
{
Bitmap bSrc = (Bitmap)b.Clone();

// GDI+ still lies to us - the return format is BGR, NOT RGB.
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0,
bSrc.Width, bSrc.Height),

int scanline = bmData.Stride;

System.IntPtr Scan0 = bmData.Scan0;
System.IntPtr SrcScan0 = bmSrc.Scan0;

unsafe
{
byte * p = (byte *)(void *)Scan0;
byte * pSrc = (byte *)(void *)SrcScan0;

int nOffset = bmData.Stride - b.Width*3;
int nWidth = b.Width;
int nHeight = b.Height;

int xOffset, yOffset;

for(int y=0;y < nHeight;++y)
{
for(int x=0; x < nWidth; ++x )
{
xOffset = offset[x,y].X;
yOffset = offset[x,y].Y;

p[0] = pSrc[((y+yOffset) * scanline) + ((x+xOffset) * 3)];
p[1] = pSrc[((y+yOffset) * scanline) + ((x+xOffset) * 3) + 1];
p[2] = pSrc[((y+yOffset) * scanline) + ((x+xOffset) * 3) + 2];

p += 3;
}
p += nOffset;
}
}

b.UnlockBits(bmData);
bSrc.UnlockBits(bmSrc);

return true;
}```

You'll notice that the framework is there for a boolean success code, but it's not really used. The OffsetFilterAbs does pretty much the same thing, except that if we want to move any pixel to location 3, 2, the point stored for that location will be 3, 2 and not an offset. OffsetFilterAntiAlias is much more complex because it implements a bilinear filter, if you don't understand that code, refer to the previous [^]article.

## Now, the filters

The basic format then for all the filters is to create an array, populate it with values ( either offset or absolute ) and then pass the bitmap and the array to the appropriate function. There is a lot of trigonometry going on in quite a few of these, which I am not going to discuss in any great detail, instead focusing on what the filter does, and it's parameters.

## Flip

I guess the most obvious thing to do if we're going to move pixels around is flip the image. I'll show the code for this one as it is a simple example, which will highlight the underlying process more so than later examples such as swirl. The end result is obvious, so I won't slow your bandwidth with an example.

```public static bool Flip(Bitmap b, bool bHorz, bool bVert)
{
Point [,] ptFlip = new Point[b.Width,b.Height];

int nWidth = b.Width;
int nHeight = b.Height;

for (int x = 0; x < nWidth; ++x)
for (int y = 0; y < nHeight; ++y)
{
ptFlip[x, y].X = (bHorz) ? nWidth - (x+1) : x;
ptFlip[x,y].Y = (bVert) ? nHeight - (y + 1) : y;
}

OffsetFilterAbs(b, ptFlip);

return true;
}```

## RandomJitter

This filter takes a number and moves each pixel by a random amount that is within the bounds of that number. This is surprisingly effective, doing it multiple times ends up with quite an effective oil painting effect.

## Swirl

This filter was my personal holy grail, and the impetus for my coming up with this stuff. Basically it starts in the middle, and moves around in a circle, increasing the radius as it also increases the degree of rotation. As a result of using trig, it benefits greatly from the bilinear filter which is an option. I will show both the normal, then the bilinear filtered example for this image, then all others that offer the filter, I will show with the filter on. The parameter that is passed in is a very small number, for the example it is .05.

## Sphere

The sphere filter is one example of a filter created through playing around. I was trying for the effect of the image being wrapped around a ball. I don't think it works that well, but it is interesting and a starting point for such an idea.

## Time Warp

Another interesting filter, this one causes the image the warp as it disappears in the distance. The example uses a factor of 15.

## Moire

While playing with the swirl idea, I discovered that if I increased the rate at which the radius moved out, I could either get a wide swirl, or with the right parameters, a moire effect was produced. The example uses a factor of 3.

## Water

A more useful filter is one that makes things appear to be underwater. This could be improved by the addition of extra artifacts, such as rings and ripples. In effect this filter passes a sin wave through the water in both x and y directions.

## Pixellate

This is an example of a filter which can be done generically but would be better done with specific code. Pixellation is a way of referring to the fact that when an image is enlarged, curves become blocky. This filter provides a mosaic effect by creating blocks that are the same colour as their top left corner, and can also draw lines to mark the individual tiles. A better implementation would use the average colour present within the block in question, as opposed to the top left corner, but this still works quite well.

## Conclusion

The filters provided are designed to show some of the things you can do with a displacement framework, and to provide a variety of samples from which you can derive your own filters. I hope you find the examples useful, and the framework a good starting point for your own explorations of the underlying concept. I hope next to demonstrate writing of a specific one-off filter, and to discuss how this is always the most flexible approach, although transformation matrices and displacement techniques are an excellent way of establishing rough ideas and implementing general concepts.

Version 1.01 : Added some bounds checking code in the three main filters so that the filters do not crash if any values passed in are out of bounds. Some filters generate some out of bounds values on the edges, and checking this way causes more values to be processed than creating a border around all images.

A list of licenses authors might use can be found here

## Share

 Software Developer (Senior) Australia
Programming computers ( self taught ) since about 1984 when I bought my first Apple ][. Was working on a GUI library to interface Win32 to Python, and writing graphics filters in my spare time, and then building n-tiered apps using asp, atl and asp.net in my job at Dytech. After 4 years there, I've started working from home, at first for Code Project and now for a vet telemedicine company. I owned part of a company that sells client education software in the vet market, but we sold that and I worked for the owners for five years before leaving to get away from the travel, and spend more time with my family. I now work for a company here in Hobart, doing all sorts of Microsoft based stuff in C++ and C#, with a lot of T-SQL in the mix.

## You may also be interested in...

 Pro Pro

 First PrevNext
 My vote of 5 DrABELL30-Aug-15 9:31 DrABELL 30-Aug-15 9:31
 My vote of 5 manoj kumar choubey20-Feb-12 19:44 manoj kumar choubey 20-Feb-12 19:44
 couldn't find web image processing in your blog chandru201115-Apr-11 0:33 chandru2011 15-Apr-11 0:33
 Compiler Errors in Visual Studio 2010 vaxvax20-Mar-11 10:59 vaxvax 20-Mar-11 10:59
 Re: Compiler Errors in Visual Studio 2010 gluip2-Feb-12 3:59 gluip 2-Feb-12 3:59
 Cartoonist like filter Glauber Torres18-Nov-10 4:41 Glauber Torres 18-Nov-10 4:41
 ECG wave extraction biaali10-Aug-10 22:49 biaali 10-Aug-10 22:49
 Re: ECG wave extraction Christian Graus24-Aug-10 23:43 Christian Graus 24-Aug-10 23:43
 Re: web cam image processing Christian Graus24-Aug-10 23:42 Christian Graus 24-Aug-10 23:42
 Image Pattern recognition using C# Dan_danAUS25-May-09 21:42 Dan_danAUS 25-May-09 21:42
 Christian can you help me understand how to make the Image Manipulation work in asp.net. Rob Gaudet28-Jan-09 17:18 Rob Gaudet 28-Jan-09 17:18
 Thank you futurejo4-Jan-09 0:48 futurejo 4-Jan-09 0:48
 Detect Straight Lines and Show Co-ordinates of the line on the tiff image(PixelFormat.Format1bppIndexed) using VB.net GDI jeetu_197826-Dec-08 23:08 jeetu_1978 26-Dec-08 23:08
 About Sphere! Md. Arifuzzaman Roman3-Dec-08 20:40 Md. Arifuzzaman Roman 3-Dec-08 20:40
 sort the images based on matching objects in them patil.yogini.0513-Nov-08 20:22 patil.yogini.05 13-Nov-08 20:22
 Converting a Bitmap To TIFF ehsan_op28-Sep-08 0:35 ehsan_op 28-Sep-08 0:35
 Re: Converting a Bitmap To TIFF ckcool26-May-09 18:38 ckcool 26-May-09 18:38
 Auto correction (brightness and contrast) drkalucard13-May-08 17:41 drkalucard 13-May-08 17:41
 Invert Sphere Filter? Scutter133717-Jan-08 15:02 Scutter1337 17-Jan-08 15:02
 Re: Invert Sphere Filter? ersin386-Dec-08 6:44 ersin38 6-Dec-08 6:44
 Alpha woes Unprofessional9113-Oct-07 6:54 Unprofessional911 3-Oct-07 6:54
 Re: Alpha woes Christian Graus3-Oct-07 11:11 Christian Graus 3-Oct-07 11:11
 Correcting red eyes r_tebar6-Apr-07 13:11 r_tebar 6-Apr-07 13:11
 Re: Correcting red eyes Christian Graus3-Oct-07 11:19 Christian Graus 3-Oct-07 11:19
 Re: Correcting red eyes r_tebar3-Oct-07 12:00 r_tebar 3-Oct-07 12:00
 Wonderful set of Classes and functionality!. Re-use? GSL310-Mar-07 8:59 GSL3 10-Mar-07 8:59
 Re: Wonderful set of Classes and functionality!. Re-use? Christian Graus3-Oct-07 11:10 Christian Graus 3-Oct-07 11:10
 Hough Transform shdelpiero21-Feb-07 5:56 shdelpiero 21-Feb-07 5:56
 Loop in capturing image and Generic error occured in GDI+ labby19-Dec-06 21:02 labby 19-Dec-06 21:02
 Re: Loop in capturing image and Generic error occured in GDI+ Christian Graus20-Dec-06 9:20 Christian Graus 20-Dec-06 9:20
 Re: Loop in capturing image and Generic error occured in GDI+ Norshuhada Samudin20-Dec-06 15:37 Norshuhada Samudin 20-Dec-06 15:37
 Re: Loop in capturing image and Generic error occured in GDI+ Norshuhada Samudin20-Dec-06 15:54 Norshuhada Samudin 20-Dec-06 15:54
 Re: Loop in capturing image and Generic error occured in GDI+ Christian Graus20-Dec-06 17:21 Christian Graus 20-Dec-06 17:21
 Re: Loop in capturing image and Generic error occured in GDI+ Christian Graus20-Dec-06 18:20 Christian Graus 20-Dec-06 18:20
 basic question about image processing labby25-Aug-06 0:28 labby 25-Aug-06 0:28
 Re: basic question about image processing Christian Graus5-Oct-06 12:50 Christian Graus 5-Oct-06 12:50
 How to use in vb.NET? fomruuzun17-Jul-06 14:14 fomruuzun 17-Jul-06 14:14
 Re: How to use in vb.NET? Christian Graus25-Aug-06 0:33 Christian Graus 25-Aug-06 0:33
 transforming image from polar to rectangular coordinates catalin11111-Jul-06 1:22 catalin111 11-Jul-06 1:22
 Re: transforming image from polar to rectangular coordinates Christian Graus11-Jul-06 1:25 Christian Graus 11-Jul-06 1:25
 Despeckle kwaltman5-Jun-06 11:57 kwaltman 5-Jun-06 11:57
 is it posible in web also dev guru28-May-06 9:49 dev guru 28-May-06 9:49
 Re: is it posible in web also Christian Graus28-May-06 10:51 Christian Graus 28-May-06 10:51
 Color filter 24 bits RGB ñoqui4-Apr-06 14:28 ñoqui 4-Apr-06 14:28
 Re: Color filter 24 bits RGB Christian Graus4-Apr-06 14:31 Christian Graus 4-Apr-06 14:31
 Is there a filter to apply a blurred/faded edge to an image? rickengle5-Feb-06 8:13 rickengle 5-Feb-06 8:13
 Re: Is there a filter to apply a blurred/faded edge to an image? Christian Graus5-Feb-06 9:11 Christian Graus 5-Feb-06 9:11
 Error in convolution formula stebond28-Sep-05 21:29 stebond 28-Sep-05 21:29
 Re: Error in convolution formula Christian Graus29-Sep-05 19:34 Christian Graus 29-Sep-05 19:34
 Last Visit: 31-Dec-99 18:00     Last Update: 22-Oct-16 18:29 Refresh 12345 Next »