title: Manipulating an image and updating the pictureBox has some issues
body: <p>I could not fit exactly what I wanted to say in the title, it would be too long.  Okay this is a multi-threaded app.  What my app does is looks at a picture, find the edges of the picture, and finds the shape of that object from the edges.  While it finds the shape, it constantly updates the image so we can get some sort of visual representation.  I have created a very short (40 seconds) video demonstrating the issue:  <a href="http://phstudios.com/projects/Programming/MultiThreadIssue/" rel="nofollow">http://phstudios.com/projects/Programming/MultiThreadIssue/</a></p>
  
  <p>As you can see, everything is working fine until the minute I move the window.  This is always the case.  I ran the program several times without moving the window and it ran fine.  However, the minute I move the window, it will come up with that error.  As you see, I am locking the specific image I would like to work with.  Is the forms OnPaint overriding that somehow?  Is there any way I can fix that?</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Linq;
  using System.Text;
  using System.Windows.Forms;
  using System.Threading;
  using System.Drawing.Imaging;
  
  namespace LineRecognition
  {
      public enum Shape
      {
          Unknown,
          Quadrilateral,
          Circle,
          Triangle
      }
      public partial class Form1 : Form
      {
          Bitmap image, original, shapes;
  
          List&lt;Point&gt; outlines;
  
          Shape shape;
  
          ShapeDetection detector;
          public Form1()
          {
              InitializeComponent();
              edgeDetection.WorkerReportsProgress = true;
              shapeDetection.WorkerReportsProgress = true;
              shape = Shape.Unknown;
          }
  
          private void Form1_Load(object sender, EventArgs e)
          {
              original = new Bitmap("photo1.png");
              image = new Bitmap("photo1.png");
              shapes = new Bitmap(image.Width, image.Height);
              pictureBox1.Image = (Image)original;
          }
  
          private void findLines_Click(object sender, EventArgs e)
          {
              if (edgeDetection.IsBusy != true)
              {
                  lblStatus.Text = "Finding Edges";
                  edgeDetection.RunWorkerAsync();
              }
          }
  
          private void justTheOutlines(Bitmap image, List&lt;Point&gt; pixels, BackgroundWorker worker)
          {
              lock (image)
              {
                  for (int i = 0; i &lt; pixels.Count; i++)
                  {
                      image.SetPixel(pixels[i].X, pixels[i].Y, Color.Red);
                      worker.ReportProgress((int)((float)i * 100 / (float)pixels.Count));
                  }
              }
          }
  
          private List&lt;Point&gt; outlineLines(Bitmap image, BackgroundWorker worker)
          {
              int w = image.Width;
              int h = image.Height;
  
              int alpha = 800000;
  
              List&lt;Point&gt; changes = new List&lt;Point&gt;();
  
              lock (image)
              {
  
                  for (int i = 0; i &lt; w; i++)
                  {
                      for (int j = 0; j &lt; h; j++)
                      {
                          Color selected = image.GetPixel(i, j);
                          Color nextRight = selected;
                          Color nextDown = selected;
  
                          if (i &lt; w - 1)
                              nextRight = image.GetPixel(i + 1, j);
  
                          if (j &lt; h - 1)
                              nextDown = image.GetPixel(i, j + 1);
  
                          int iSelected = selected.ToArgb();
                          int iNextRight = nextRight.ToArgb();
                          int iNextDown = nextDown.ToArgb();
  
                          if (Math.Abs(iSelected - iNextRight) &gt; alpha)
                          {
                              if (iSelected &lt; iNextRight)
                              {
                                  Point p = new Point(i, j);
                                  if(!ContainsPoint(changes, p)) changes.Add(p);
                              }
                              else
                              {
                                  Point p = new Point(i + 1, j);
                                  if (!ContainsPoint(changes, p)) changes.Add(p);
                              }
                          }
  
                          if (Math.Abs(iSelected - iNextDown) &gt; alpha)
                          {
                              if (iSelected &lt; iNextDown)
                              {
                                  Point p = new Point(i, j);
                                  if (!ContainsPoint(changes, p)) changes.Add(p);
                              }
                              else
                              {
                                  Point p = new Point(i, j + 1);
                                  if (!ContainsPoint(changes, p)) changes.Add(p);
                              }
                          }
  
                          image.SetPixel(i, j, Color.White);
                      }
                      worker.ReportProgress((int)(((float)i / (float)w) * 100));
                  }
              }
  
              return changes;
          }
  
          private bool ContainsPoint(List&lt;Point&gt; changes, Point p)
          {
              foreach (Point n in changes)
              {
                  if (n.Equals(p)) return true;
              }
              return false;
          }
  
          private void edgeDetection_DoWork(object sender, DoWorkEventArgs e)
          {
              BackgroundWorker worker = sender as BackgroundWorker;
              outlines = outlineLines(image, worker);
              justTheOutlines(image, outlines, worker);
              pictureBox2.Image = (Image)image;
              Thread.Sleep(100);
              image.Save("photo-lines.jpg");
          }
  
          private void edgeDetection_ProgressChanged(object sender, ProgressChangedEventArgs e)
          {
              algorithmProgress.Value = e.ProgressPercentage;
          }
  
          private void edgeDetection_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
          {
              algorithmProgress.Value = 0;
              findLines.Enabled = false;
              determineShape.Enabled = true;
              lblStatus.Text = "";
          }
  
          private void determineShape_Click(object sender, EventArgs e)
          {
              if (shapeDetection.IsBusy != true)
              {
                  pictureBox1.Image = (Image)image;
                  lblStatus.Text = "Running Shape Detection:  Circle -&gt; Quadrilateral";
                  shapeDetection.RunWorkerAsync();
              }
          }
  
          private void ShapeDetection_DoWork(object sender, DoWorkEventArgs e)
          {
              BackgroundWorker worker = sender as BackgroundWorker;
              detector = new ShapeDetection(outlines, 40, 10);
              detector.Worker = worker;
              detector.circleChange += new ShapeDetection.CircleChangeEventHandler(circleChange);
              if (detector.IsCircle())
              {
                  MessageBox.Show("Object is a circle");
                  shape = Shape.Circle;
              }
              else if (detector.IsQuadrilateral())
              {
                  MessageBox.Show("Object is a quadrilateral", "Number of edges:  " + detector.Summits);
                  shape = Shape.Quadrilateral;
              }
              else
              {
                  int sides = detector.Summits.Count;
                  if (sides == 3)
                  { 
                      MessageBox.Show("Object is a triangle");
                      shape = Shape.Triangle;
                  }
                  else
                  {
                      MessageBox.Show("Number of edges:  " + detector.Summits.Count, "Unknown");
                  }
              }
  
              BitmapDrawing.DrawLines(detector.Summits, shapes);
              BitmapDrawing.DrawSummits(detector.Summits, shapes);
              pictureBox2.Image = (Image)shapes;
              Thread.Sleep(100);
          }
  
          private void ShapeDetection_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
          {
              if (detector != null)
              {
                  lblSummits.Text += detector.Summits.Count;
                  lblType.Text += shape.ToString();
                  determineShape.Enabled = false;
                  lblStatus.Text = "";
              }
          }
  
          void circleChange(object sender, CircleChangeEventArgs e)
          {
              lock (shapes)
              {
                  Point p = detector.visited[detector.visited.Count - 1];
                  shapes.SetPixel(p.X, p.Y, Color.Blue);
                  pictureBox2.Image = (Image)shapes;
                  Thread.Sleep(10);
                  detector.Worker.ReportProgress((int)(e.percent * 100));
              }
          }
  
          private void shapeDetection_ProgressChanged(object sender, ProgressChangedEventArgs e)
          {
              algorithmProgress.Value = e.ProgressPercentage;
          }
      }
  }
  </code></pre>
  
  <p><strong>Update</strong></p>
  
  <p>What Nick said before worked fine.  I added that to my CircleChange event and it works.  Can somebody explain why the invoke makes it work instead of setting the picturebox2.Image to the shapes image?  I mean I call it after I call setpixel, so I should be done modifying the image right?</p>
  
  <pre><code>void circleChange(object sender, CircleChangeEventArgs e)
  {
      Point p = detector.visited[detector.visited.Count - 1];
      shapes.SetPixel(p.X, p.Y, Color.Blue);
      Image copyForPictureBox = shapes.Clone() as Image;
      BeginInvoke(new Action(() =&gt; pictureBox2.Image = copyForPictureBox));
      Thread.Sleep(15);
      detector.Worker.ReportProgress((int)(e.percent * 100));
  }
  </code></pre>