/// <summary>
        /// Converts an image to ASCII art
        /// </summary>
        /// <param name="Input">The image you wish to convert</param>
        /// <returns>A string containing the art</returns>
        public static string ToASCIIArt(this Bitmap Input)
        {
            if (Input == null)
                throw new ArgumentNullException("Input");
            bool ShowLine = true;
            using (Bitmap TempImage = Input.BlackAndWhite())
            {
                BitmapData OldData = TempImage.LockImage();
                int OldPixelSize = OldData.GetPixelSize();
                StringBuilder Builder = new StringBuilder();
                for (int x = 0; x < TempImage.Height; ++x)
                {
                    for (int y = 0; y < TempImage.Width; ++y)
                    {
                        if (ShowLine)
                        {
                            Color CurrentPixel = OldData.GetPixel(y, x, OldPixelSize);
                            Builder.Append(_ASCIICharacters[((CurrentPixel.R * _ASCIICharacters.Length) / 255)]);
                        }

                    }
                    if (ShowLine)
                    {
                        Builder.Append(System.Environment.NewLine);
                        ShowLine = false;
                    }
                    else
                    {
                        ShowLine = true;
                    }
                }
                TempImage.UnlockImage(OldData);
                return Builder.ToString();
            }
        }
 /// <summary>
 /// Sobel edge detection function
 /// </summary>
 /// <param name="Input">Image to manipulate</param>
 /// <param name="FileName">File to save to</param>
 /// <returns>A bitmap image</returns>
 public static Bitmap SobelEdgeDetection(this Bitmap Input, string FileName = "")
 {
     Input.ThrowIfNull("Input");
     ImageFormat FormatUsing = FileName.GetImageFormat();
     using (Bitmap TempImage = Input.BlackAndWhite())
     {
         Filter TempFilter = new Filter(3, 3);
         TempFilter.MyFilter[0, 0] = -1;
         TempFilter.MyFilter[0, 1] = 0;
         TempFilter.MyFilter[0, 2] = 1;
         TempFilter.MyFilter[1, 0] = -2;
         TempFilter.MyFilter[1, 1] = 0;
         TempFilter.MyFilter[1, 2] = 2;
         TempFilter.MyFilter[2, 0] = -1;
         TempFilter.MyFilter[2, 1] = 0;
         TempFilter.MyFilter[2, 2] = 1;
         TempFilter.Absolute = true;
         using (Bitmap TempImageX = TempFilter.ApplyFilter(TempImage))
         {
             TempFilter = new Filter(3, 3);
             TempFilter.MyFilter[0, 0] = 1;
             TempFilter.MyFilter[0, 1] = 2;
             TempFilter.MyFilter[0, 2] = 1;
             TempFilter.MyFilter[1, 0] = 0;
             TempFilter.MyFilter[1, 1] = 0;
             TempFilter.MyFilter[1, 2] = 0;
             TempFilter.MyFilter[2, 0] = -1;
             TempFilter.MyFilter[2, 1] = -2;
             TempFilter.MyFilter[2, 2] = -1;
             TempFilter.Absolute = true;
             using (Bitmap TempImageY = TempFilter.ApplyFilter(TempImage))
             {
                 using (Bitmap NewBitmap = new Bitmap(TempImage.Width, TempImage.Height))
                 {
                     BitmapData NewData = NewBitmap.LockImage();
                     BitmapData OldData1 = TempImageX.LockImage();
                     BitmapData OldData2 = TempImageY.LockImage();
                     int NewPixelSize = NewData.GetPixelSize();
                     int OldPixelSize1 = OldData1.GetPixelSize();
                     int OldPixelSize2 = OldData2.GetPixelSize();
                     int Width = NewBitmap.Width;
                     int Height = NewBitmap.Height;
                     Parallel.For(0, Width, x =>
                     {
                         for (int y = 0; y < Height; ++y)
                         {
                             Color Pixel1 = OldData1.GetPixel(x, y, OldPixelSize1);
                             Color Pixel2 = OldData2.GetPixel(x, y, OldPixelSize2);
                             NewData.SetPixel(x, y,
                                 Color.FromArgb((Pixel1.R + Pixel2.R).Clamp(255, 0),
                                     (Pixel1.G + Pixel2.G).Clamp(255, 0),
                                     (Pixel1.B + Pixel2.B).Clamp(255, 0)),
                                 NewPixelSize);
                         }
                     });
                     NewBitmap.UnlockImage(NewData);
                     TempImageX.UnlockImage(OldData1);
                     TempImageY.UnlockImage(OldData2);
                     Bitmap NewBitmap2 = NewBitmap.Negative();
                     if (!string.IsNullOrEmpty(FileName))
                         NewBitmap2.Save(FileName, FormatUsing);
                     return NewBitmap2;
                 }
             }
         }
     }
 }
 /// <summary>
 /// Runs a simplistic 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 MotionDetection(this Bitmap NewImage, Bitmap OldImage, int Threshold, Color DetectionColor)
 {
     NewImage.ThrowIfNull("NewImage");
     OldImage.ThrowIfNull("OldImage");
     DetectionColor.ThrowIfNull("DetectionColor");
     using (Bitmap NewImage1 = NewImage.BlackAndWhite())
     {
         using (Bitmap OldImage1 = OldImage.BlackAndWhite())
         {
             using (Bitmap NewImage2 = NewImage1.SNNBlur(5))
             {
                 using (Bitmap OldImage2 = OldImage1.SNNBlur(5))
                 {
                     using (Bitmap OutputImage = new Bitmap(NewImage2, NewImage2.Width, NewImage2.Height))
                     {
                         using (Bitmap Overlay = new Bitmap(NewImage, NewImage.Width, NewImage.Height))
                         {
                             BitmapData NewImage2Data = NewImage2.LockImage();
                             int NewImage2PixelSize = NewImage2Data.GetPixelSize();
                             BitmapData OldImage2Data = OldImage2.LockImage();
                             int OldImage2PixelSize = OldImage2Data.GetPixelSize();
                             BitmapData OverlayData = Overlay.LockImage();
                             int OverlayPixelSize = OverlayData.GetPixelSize();
                             int Width = OutputImage.Width;
                             int Height = OutputImage.Height;
                             Parallel.For(0, Width, x =>
                             {
                                 for (int y = 0; y < Height; ++y)
                                 {
                                     Color NewPixel = NewImage2Data.GetPixel(x, y, NewImage2PixelSize);
                                     Color OldPixel = OldImage2Data.GetPixel(x, y, OldImage2PixelSize);
                                     if (System.Math.Pow((double)(NewPixel.R - OldPixel.R), 2.0) > Threshold)
                                     {
                                         OverlayData.SetPixel(x, y, Color.FromArgb(100, 0, 100), OverlayPixelSize);
                                     }
                                     else
                                     {
                                         OverlayData.SetPixel(x, y, Color.FromArgb(200, 0, 200), OverlayPixelSize);
                                     }
                                 }
                             });
                             Overlay.UnlockImage(OverlayData);
                             NewImage2.UnlockImage(NewImage2Data);
                             OldImage2.UnlockImage(OldImage2Data);
                             using (Bitmap Overlay2 = Overlay.EdgeDetection(25, DetectionColor))
                             {
                                 BitmapData Overlay2Data = Overlay2.LockImage();
                                 int Overlay2PixelSize = Overlay2Data.GetPixelSize();
                                 Width = OutputImage.Width;
                                 Height = OutputImage.Height;
                                 Parallel.For(0, Width, x =>
                                 {
                                     for (int y = 0; y < Height; ++y)
                                     {
                                         Color Pixel1 = Overlay2Data.GetPixel(x, y, Overlay2PixelSize);
                                         if (Pixel1.R != DetectionColor.R || Pixel1.G != DetectionColor.G || Pixel1.B != DetectionColor.B)
                                         {
                                             Overlay2Data.SetPixel(x, y, Color.FromArgb(200, 0, 200), Overlay2PixelSize);
                                         }
                                     }
                                 });
                                 Overlay2.UnlockImage(Overlay2Data);
                                 return OutputImage.Watermark(Overlay2, 1.0f, 0, 0, Color.FromArgb(200, 0, 200));
                             }
                         }
                     }
                 }
             }
         }
     }
 }
 /// <summary>
 /// Laplace edge detection function
 /// </summary>
 /// <param name="Image">Image to manipulate</param>
 /// <param name="FileName">File to save to</param>
 /// <returns>A bitmap object</returns>
 public static Bitmap LaplaceEdgeDetection(this Bitmap Image, string FileName = "")
 {
     Image.ThrowIfNull("Image");
     ImageFormat FormatUsing = FileName.GetImageFormat();
     using (Bitmap TempImage = Image.BlackAndWhite())
     {
         Filter TempFilter = new Filter(5, 5);
         TempFilter.MyFilter[0, 0] = -1;
         TempFilter.MyFilter[0, 1] = -1;
         TempFilter.MyFilter[0, 2] = -1;
         TempFilter.MyFilter[0, 3] = -1;
         TempFilter.MyFilter[0, 4] = -1;
         TempFilter.MyFilter[1, 0] = -1;
         TempFilter.MyFilter[1, 1] = -1;
         TempFilter.MyFilter[1, 2] = -1;
         TempFilter.MyFilter[1, 3] = -1;
         TempFilter.MyFilter[1, 4] = -1;
         TempFilter.MyFilter[2, 0] = -1;
         TempFilter.MyFilter[2, 1] = -1;
         TempFilter.MyFilter[2, 2] = 24;
         TempFilter.MyFilter[2, 3] = -1;
         TempFilter.MyFilter[2, 4] = -1;
         TempFilter.MyFilter[3, 0] = -1;
         TempFilter.MyFilter[3, 1] = -1;
         TempFilter.MyFilter[3, 2] = -1;
         TempFilter.MyFilter[3, 3] = -1;
         TempFilter.MyFilter[3, 4] = -1;
         TempFilter.MyFilter[4, 0] = -1;
         TempFilter.MyFilter[4, 1] = -1;
         TempFilter.MyFilter[4, 2] = -1;
         TempFilter.MyFilter[4, 3] = -1;
         TempFilter.MyFilter[4, 4] = -1;
         using (Bitmap NewImage = TempFilter.ApplyFilter(TempImage))
         {
             Bitmap NewBitmap = NewImage.Negative();
             if (!string.IsNullOrEmpty(FileName))
                 NewBitmap.Save(FileName, FormatUsing);
             return NewBitmap;
         }
     }
 }
 /// <summary>
 /// Laplace edge detection function
 /// </summary>
 /// <param name="Image">Image to manipulate</param>
 /// <returns>A SwiftBitmap object</returns>
 public static SwiftBitmap LaplaceEdgeDetection(this SwiftBitmap Image)
 {
     Contract.Requires<ArgumentNullException>(Image != null, "Image");
     return Image.BlackAndWhite().ApplyConvolutionFilter(new int[][]{
                     new int[] {-1, -1, -1, -1, -1},
                     new int[] {-1, -1, -1, -1, -1},
                     new int[] {-1, -1, 24, -1, -1},
                     new int[] {-1, -1, -1, -1, -1},
                     new int[] {-1, -1, -1, -1, -1},
                 });
 }
 /// <summary>
 /// Sobel edge detection function
 /// </summary>
 /// <param name="Input">Image to manipulate</param>
 /// <returns>A SwiftBitmap image</returns>
 public static SwiftBitmap SobelEdgeDetection(this SwiftBitmap Input)
 {
     Contract.Requires<ArgumentNullException>(Input != null, "Input");
     Input.BlackAndWhite();
     using (SwiftBitmap TempImageX = ((SwiftBitmap)Input.Clone()).ApplyConvolutionFilter(new int[][]{
                     new int[] {-1, 0, 1},
                     new int[] {-2, 0, 2},
                     new int[] {-1, 0, 1}
                 }, true))
     {
         using (SwiftBitmap TempImageY = ((SwiftBitmap)Input.Clone()).ApplyConvolutionFilter(new int[][]{
                     new int[] {1, 2, 1},
                     new int[] {0, 0, 0},
                     new int[] {-1, -2, -1}
                 }, true))
         {
             using (SwiftBitmap NewBitmap = new SwiftBitmap(Input.Width, Input.Height))
             {
                 NewBitmap.Lock();
                 TempImageX.Lock();
                 TempImageY.Lock();
                 int Width = NewBitmap.Width;
                 int Height = NewBitmap.Height;
                 Parallel.For(0, Width, x =>
                 {
                     for (int y = 0; y < Height; ++y)
                     {
                         Color Pixel1 = TempImageX.GetPixel(x, y);
                         Color Pixel2 = TempImageY.GetPixel(x, y);
                         NewBitmap.SetPixel(x, y,
                             Color.FromArgb((Pixel1.R + Pixel2.R).Clamp(255, 0),
                                 (Pixel1.G + Pixel2.G).Clamp(255, 0),
                                 (Pixel1.B + Pixel2.B).Clamp(255, 0)));
                     }
                 });
                 NewBitmap.Unlock();
                 TempImageY.Unlock();
                 TempImageX.Unlock();
                 return Input.Copy(NewBitmap).Negative();
             }
         }
     }
 }