Motion Detection in C#

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.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/29/2009 at 1:53 PM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Anding Two Images Together Using C#

So first I'm stuck working on SharePoint site management (which I'm going to be doing for a little while) and then I become sick with something that seems to be taking out everyone around here. However I'm now back doing some coding (in my spare time anyway). And since my update to the ORM isn't ready yet, I'm going to hand out some more image manipulation code.

Today I'm going to show you how to and two images together. And, Or, Xor, etc. are logical operations that, as programmers, you've seen about 10,000 times. They can also be used in image processing, causing various effects. All of them are extremely simple, so let's look at the basic code:

        public static Bitmap And(Bitmap Image1, Bitmap Image2)
        {
            System.Drawing.Bitmap TempBitmap = Image1;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            for (int x = 0; x < NewBitmap.Width; ++x)
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    Color Pixel1 = Image1.GetPixel(x, y);
                    Color Pixel2 = Image2.GetPixel(x, y);
                    NewBitmap.SetPixel(x, y, Color.FromArgb(Pixel1.R & Pixel2.R, Pixel1.G & Pixel2.G, Pixel1.B & Pixel2.B));
                }
            }
            return NewBitmap;
        }

As you can see, all that it takes in is two images (and it makes the assumption that they're the same size). It then just does a logical and of the red, green, and blue values for the two pixels. You can easily substitute a ^ or a | instead of the &. That's all there is to it really. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/27/2009 at 8:38 AM
Tags: , , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Fix Access Denied Errors in SharePoint Search

As of late, I haven't been doing much in the way of programming. Instead I've been working with our SharePoint install at work (setting up InfoPath, Excel Services, etc.). One of the issues that I had to tackle was the fact that the crawler stopped working. The account it was using had the proper rights, the service itself was set up correctly, etc. In fact it was working at one point and there hadn't been any changes to the settings. So why the sudden issue?

Well we have one server that acts as the search service and the site itself. As such the search service is basically doing a crawl on the local host (and we're using a fully qualified domain name). This apparently doesn't work due to a loop back check that windows does in order to protect itself from reflection attacks (you can read about it here). In otherwords, it's by design and shouldn't be messed with on public facing servers. However in my case, this server is completely behind the firewall. So how do we disable the loopback check and get our search working? Simple, follow these steps (which are described in the link above):

  1. Click Start, then Run (or if you're on 2008, just click on the search box), and type regedit, and then click OK.
  2. In Registry Editor, locate and click the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
  3. Right-click Lsa->New->DWORD Value.
  4. Change the name of the new key to DisableLoopbackCheck.
  5. Right-click DisableLoopbackCheck, and click Modify.
  6. In the Value data box, type 1, and click OK.
  7. Quit Registry Editor and restart your computer.
That's it. Once the computer restarts you should be able to start the crawl and have it work. Hopefully this helps you out. So try it out, leave feedback, and happy coding.
kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 5/20/2009 at 8:53 AM
Tags: , , ,
Categories: General
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed