Other Posts in Image Editing

  1. Perlin Noise
  2. Fault Formation
  3. Cellular Textures
  4. Resizing an Image in C#
  5. Box Blur and Gaussian Blur... Sort of...
  6. Thermal Erosion
  7. Using Mid Point Displacement to Create Cracks
  8. Fluvial Erosion
  9. Creating Marble Like Textures Procedurally
  10. Procedural Textures and Dilation
  11. Converting Image to Black and White in C#
  12. Getting an HTML Based Color Palette from an Image in C#
  13. Adding Noise/Jitter to an Image in C#
  14. Creating Pixelated Images in C#
  15. Edge detection in C#
  16. Using Sin to Get What You Want... In C#...
  17. Noise Reduction of an Image in C# using Median Filters
  18. Image Dilation in C#
  19. Sepia Tone in C#
  20. Kuwahara Filter in C#
  21. Matrix Convolution Filters in C#
  22. Symmetric Nearest Neighbor in C#
  23. Bump Map Creation Using C#
  24. Normal Map Creation Using C#
  25. Creating Negative Images using C#
  26. Red, Blue, and Green Filters in C#
  27. Converting an Image to ASCII Art in C#
  28. Adjusting Brightness of an Image in C#
  29. Adding Noise to an Image in C#
  30. Adjusting the Gamma of an Image Using C#
  31. Adjusting Contrast of an Image in C#
  32. Drawing a Box With Rounded Corners in C#
  33. Anding Two Images Together Using C#
  34. Motion Detection in C#
  35. Creating Thermometer Chart in C#
  36. Colorizing a Black and White Image in C#
  37. Extracting an Icon From a File
  38. Setting the Pixel Format and Image Format of an Image in .Net
  39. Using Unsafe Code for Faster Image Manipulation
  40. Sobel Edge Detection and Laplace Edge Detection in C#

Motion Detection in C#

5/29/2009

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:

   1: /*
   2: Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System.Drawing;
  24: using System.Drawing.Imaging;
  25: #endregion
  26:  
  27: namespace Utilities.Media.Image
  28: {
  29:     /// <summary>
  30:     /// Used for motion detection
  31:     /// </summary>
  32:     public static class MotionDetection
  33:     {
  34:         #region Public Static Functions
  35:  
  36:         /// <summary>
  37:         /// Runs the motion detection algorithm
  38:         /// </summary>
  39:         /// <param name="NewImage">The "new" frame</param>
  40:         /// <param name="OldImage">The "old" frame</param>
  41:         /// <param name="Threshold">The threshold used to detect changes in the image</param>
  42:         /// <param name="DetectionColor">Color to display changes in the images as</param>
  43:         /// <returns>A bitmap indicating where changes between frames have occurred overlayed on top of the new image.</returns>
  44:         public static Bitmap Process(Bitmap NewImage, Bitmap OldImage, int Threshold, Color DetectionColor)
  45:         {
  46:             using (Bitmap NewImage1 = Utilities.Media.Image.Image.ConvertBlackAndWhite(NewImage))
  47:             {
  48:                 using (Bitmap OldImage1 = Utilities.Media.Image.Image.ConvertBlackAndWhite(OldImage))
  49:                 {
  50:                     using (Bitmap NewImage2 = Utilities.Media.Image.Image.SNNBlur(NewImage1, 5))
  51:                     {
  52:                         using (Bitmap OldImage2 = Utilities.Media.Image.Image.SNNBlur(OldImage1, 5))
  53:                         {
  54:                             using (Bitmap OutputImage = new Bitmap(NewImage2, NewImage2.Width, NewImage2.Height))
  55:                             {
  56:                                 using (Bitmap Overlay = new Bitmap(NewImage, NewImage.Width, NewImage.Height))
  57:                                 {
  58:                                     BitmapData NewImage2Data = Image.LockImage(NewImage2);
  59:                                     int NewImage2PixelSize = Image.GetPixelSize(NewImage2Data);
  60:                                     BitmapData OldImage2Data = Image.LockImage(OldImage2);
  61:                                     int OldImage2PixelSize = Image.GetPixelSize(OldImage2Data);
  62:                                     BitmapData OverlayData = Image.LockImage(Overlay);
  63:                                     int OverlayPixelSize = Image.GetPixelSize(OverlayData);
  64:                                     for (int x = 0; x < OutputImage.Width; ++x)
  65:                                     {
  66:                                         for (int y = 0; y < OutputImage.Height; ++y)
  67:                                         {
  68:                                             Color NewPixel = Image.GetPixel(NewImage2Data, x, y, NewImage2PixelSize);
  69:                                             Color OldPixel = Image.GetPixel(OldImage2Data, x, y, OldImage2PixelSize);
  70:                                             if (System.Math.Pow((double)(NewPixel.R - OldPixel.R), 2.0) > Threshold)
  71:                                             {
  72:                                                 Image.SetPixel(OverlayData, x, y, Color.FromArgb(100, 0, 100), OverlayPixelSize);
  73:                                             }
  74:                                             else
  75:                                             {
  76:                                                 Image.SetPixel(OverlayData, x, y, Color.FromArgb(200, 0, 200), OverlayPixelSize);
  77:                                             }
  78:                                         }
  79:                                     }
  80:                                     Image.UnlockImage(Overlay, OverlayData);
  81:                                     Image.UnlockImage(NewImage2, NewImage2Data);
  82:                                     Image.UnlockImage(OldImage2, OldImage2Data);
  83:                                     using (Bitmap Overlay2 = Utilities.Media.Image.Image.EdgeDetection(Overlay, 25, DetectionColor))
  84:                                     {
  85:                                         BitmapData Overlay2Data = Image.LockImage(Overlay2);
  86:                                         int Overlay2PixelSize = Image.GetPixelSize(Overlay2Data);
  87:                                         for (int x = 0; x < OutputImage.Width; ++x)
  88:                                         {
  89:                                             for (int y = 0; y < OutputImage.Height; ++y)
  90:                                             {
  91:                                                 Color Pixel1 = Image.GetPixel(Overlay2Data, x, y, Overlay2PixelSize);
  92:                                                 if (Pixel1.R != DetectionColor.R || Pixel1.G != DetectionColor.G || Pixel1.B != DetectionColor.B)
  93:                                                 {
  94:                                                     Image.SetPixel(Overlay2Data, x, y, Color.FromArgb(200, 0, 200), Overlay2PixelSize);
  95:                                                 }
  96:                                             }
  97:                                         }
  98:                                         Image.UnlockImage(Overlay2, Overlay2Data);
  99:                                         return Utilities.Media.Image.Image.Watermark(OutputImage, Overlay2, 1.0f, 0, 0, Color.FromArgb(200, 0, 200));
 100:                                     }
 101:                                 }
 102:                             }
 103:                         }
 104:                     }
 105:                 }
 106:             }
 107:         }
 108:  
 109:         #endregion
 110:     }
 111: }

It uses a number of functions, classes, etc. from my utility library and 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.



Comments