Sadly I've come to the point where I will not be able to add more functionality to the Image class within my utility library. To be honest, I've run out of simple processing techniques (that I can think of anyway, although I'm sure that I've missed some). So I'm going to show how you can use those functions to do actual work (well that and how to use procedural content to do some cool image effects in the future). In this case I'm going to show you how to do basic motion detection.
Motion is really (as far as we're concerned) just a change in the environment assuming of course you consider the moving object a part of the environment. Therefore detecting motion is simply detecting a change within the environment. We really don't need to worry about object recognition, etc. Instead we simply need to determine that a group of pixels within our image has changed. This is done by taking two frames/images. The first image being the current frame and the second being whatever our baseline is. We take these two images and simply compare them pixel by pixel, seeing if there is a noticeable difference. If it is we mark that pixel as changed. And if we have enough of these pixels, we have motion. So how about some code:
/// <summary>
/// Used for motion detection
/// </summary>
public static class MotionDetection
{
/// <summary>
/// Runs the motion detection algorithm
/// </summary>
/// <param name="NewImage">The "new" frame</param>
/// <param name="OldImage">The "old" frame</param>
/// <param name="Threshold">The threshold used to detect changes in the image</param>
/// <param name="DetectionColor">Color to display changes in the images as</param>
/// <returns>A bitmap indicating where changes between frames have occurred overlayed on top of the new image.</returns>
public static Bitmap Process(Bitmap NewImage, Bitmap OldImage, int Threshold,Color DetectionColor)
{
Bitmap NewImage1 = Utilities.Media.Image.Image.ConvertBlackAndWhite(NewImage);
Bitmap OldImage1 = Utilities.Media.Image.Image.ConvertBlackAndWhite(OldImage);
Bitmap NewImage2 = Utilities.Media.Image.Image.SNNBlur(NewImage1, 5);
NewImage1.Dispose();
Bitmap OldImage2 = Utilities.Media.Image.Image.SNNBlur(OldImage1, 5);
OldImage1.Dispose();
Bitmap OutputImage = new Bitmap(NewImage, NewImage.Width, NewImage.Height);
Bitmap Overlay = new Bitmap(NewImage, NewImage.Width, NewImage.Height);
for (int x = 0; x < OutputImage.Width; ++x)
{
for (int y = 0; y < OutputImage.Height; ++y)
{
Color NewPixel = NewImage2.GetPixel(x, y);
Color OldPixel = OldImage2.GetPixel(x, y);
OutputImage.SetPixel(x, y, NewPixel);
if (System.Math.Pow((double)(NewPixel.R - OldPixel.R), 2.0) > Threshold)
{
Overlay.SetPixel(x, y, Color.FromArgb(100,0,100));
}
else
{
Overlay.SetPixel(x, y, Color.FromArgb(200, 0, 200));
}
}
}
OldImage2.Dispose();
NewImage2.Dispose();
Bitmap Overlay2 = Utilities.Media.Image.Image.EdgeDetection(Overlay, 25, DetectionColor);
for (int x = 0; x < OutputImage.Width; ++x)
{
for (int y = 0; y < OutputImage.Height; ++y)
{
Color Pixel1 = Overlay2.GetPixel(x, y);
if (Pixel1.R != DetectionColor.R || Pixel1.G != DetectionColor.G || Pixel1.B != DetectionColor.B)
{
Overlay2.SetPixel(x, y, Color.FromArgb(200, 0, 200));
}
}
}
Overlay.Dispose();
Bitmap ReturnImage = Utilities.Media.Image.Image.Watermark(OutputImage, Overlay2, 1.0f, 0, 0, Color.FromArgb(200, 0, 200));
Overlay2.Dispose();
OutputImage.Dispose();
return ReturnImage;
}
}
It's a bit slow and can definitely be optimized but it gets the job done. Anyway originally it goes in and converts the images to black and white, next an SNN blur is applied to them, and finally we compare the pixels. We could stop here but I've gone a step further and added some edge detection afterwords to outline what has changed which is then overlayed onto the original image... It's actually fairly simple and works fairly well. There are plenty of ways to improve the algorithm but this is definitely a good start. So give it a try, leave feedback, and happy coding.
e37b0d32-3b23-43e1-a770-32ec3da94908|2|3.0