2013-02-01 25 views
0

我正在學習C#編程和Kinect傳感器編程(我在C#語言和Kinect中都是新手)。我正嘗試使用Microsoft Visual C#2010 Express編寫使用Xtion Pro Live的傳感器控制機器人的應用程序。在我的主要形式中,有2個圖片框對象,2個按鈕對象,3個標籤和3個文本框對象。兩個圖片框對象(pictureBox1)之一是顯示RGB相機。另一個pictureBox2)將模擬2D(x和y座標)圖形中的手位置。兩個按鈕(按鈕1)之一是初始化Xtion Pro Live,並在picturebox1上顯示RGB攝像頭,並在picturebox2上模擬手部位置。另一個(按鈕2)是退出程序。三個標籤label1,label2,label3和三個文本框,textbox1,textbox2,textbox3用於顯示手的3個座標。用Xtion pro模擬手位置

這是我在Form1.cs代碼:

using OpenNI; 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Windows.Forms; 

namespace HandTracking 
{ 
    public partial class Form1 : Form 
    { 
     public const string path = @"C:/Vu/Kinect/Data/SamplesConfig.xml"; 
     public bool run; 
     public Thread thread; 
     public Bitmap bitmap; 
     public Context context; 
     public ScriptNode node; 
     public ImageGenerator image; 
     public DepthGenerator depth; 
     public GestureGenerator gesture; 
     public HandsGenerator hand; 
     public Queue<Point3D> handpoint = new Queue<Point3D>(); 
     public const int maxpoint = 30; 
     enum GestureStatus 
     { 
      Unrecognized, Progress, Recognized 
     } 
     private GestureStatus gesstatus = GestureStatus.Unrecognized; 
     enum HandsStatus 
     { 
      Untracked, Create, Update 
     } 
     private HandsStatus handstatus = HandsStatus.Untracked; 
     public Pen pen = new Pen(Color.Red, 5); 
     public Brush brush = new SolidBrush(Color.Magenta); 
     public Font font = new Font("Times New Roman", 20); 
     public PointF point = new PointF(0, 0); 

     public Form1() 
     { 
      InitializeComponent(); 
      this.pictureBox1.BackColor = Color.Black; 
      this.pictureBox2.BackColor = Color.White; 
      this.button1.Enabled = true; 
     } 

     public void button1_Click(object sender, EventArgs e) 
     { 
      this.button1.Enabled = false; 
      try 
      { 
       context = Context.CreateFromXmlFile(path, out node); 
       image = context.FindExistingNode(NodeType.Image) as ImageGenerator; 
       if (image == null) 
        throw new Exception(context.GlobalErrorState); 
       depth = context.FindExistingNode(NodeType.Depth) as DepthGenerator; 
       if (depth == null) 
        throw new Exception(context.GlobalErrorState); 
       depth.AlternativeViewpointCapability.SetViewpoint(image); 
        gesture = context.FindExistingNode(NodeType.Gesture) as  GestureGenerator; 
       if (gesture == null) 
        throw new Exception(context.GlobalErrorState); 
       gesture.AddGesture("RaiseHand"); 
       gesture.GestureRecognized += new  EventHandler<GestureRecognizedEventArgs>(GestureRecognized); 
       gesture.GestureProgress += new EventHandler<GestureProgressEventArgs> (GestureProgress); 
       hand = context.FindExistingNode(NodeType.Hands) as HandsGenerator; 
       if (hand == null) 
        throw new Exception(context.GlobalErrorState); 
       hand.HandCreate += new EventHandler<HandCreateEventArgs>(HandCreate); 
       hand.HandUpdate += new EventHandler<HandUpdateEventArgs>(HandUpdate); 
       context.StartGeneratingAll(); 
       MapOutputMode map = image.MapOutputMode; 
       bitmap = new Bitmap((int)map.XRes, (int)map.YRes,  System.Drawing.Imaging.PixelFormat.Format24bppRgb); 
       run = true; 
       thread = new Thread(CallThread); 
       thread.Start(); 
      } 
      catch (Exception error) 
      { 
       MessageBox.Show(error.Message); 
      } 
     } 

     public void GestureRecognized(object sender, GestureRecognizedEventArgs e) 
     { 
      gesstatus = GestureStatus.Recognized; 
      hand.StartTracking(e.EndPosition); 
     } 

     public void GestureProgress(object sender, GestureProgressEventArgs e) 
     { 
      gesstatus = GestureStatus.Progress; 
     } 

     public void HandCreate(object sender, HandCreateEventArgs e) 
     { 
      handstatus = HandsStatus.Create; 
     } 

     public void HandUpdate(object sender, HandUpdateEventArgs e) 
     { 
      handstatus = HandsStatus.Update; 
      handpoint.Enqueue(e.Position); 
     } 
     public void button2_Click(object sender, EventArgs e) 
     { 
      DialogResult result = MessageBox.Show("Do you want to quit?", "Confirm",  MessageBoxButtons.OKCancel, MessageBoxIcon.Question); 
      if (result == DialogResult.OK) 
      { 
       try 
       { 
        run = false; 
        if (thread != null) 
         thread.Join(); 
        this.Close(); 
       } 
       catch (Exception error) 
       { 
        MessageBox.Show(error.Message); 
       } 
      } 
     } 

     public void CallThread() 
     { 
      try 
      { 
       while (run) 
       { 
        Data(); 
        pictureBox1.Invalidate(); 
        pictureBox2.Invalidate(); 

       } 
      } 
      catch (Exception error) 
      { 
       MessageBox.Show(error.Message); 
      } 
     } 

     public unsafe void Data() 
     { 
      context.WaitAndUpdateAll(); 
      ImageMetaData imd = image.GetMetaData(); 
      lock (this) 
      { 
       Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); 
       BitmapData data = bitmap.LockBits(rect, ImageLockMode.WriteOnly,  System.Drawing.Imaging.PixelFormat.Format24bppRgb); 
       byte* dstp = (byte*)data.Scan0.ToPointer(); 
       byte* imstp = (byte*)image.ImageMapPtr.ToPointer(); 
       for (int i = 0; i < imd.DataSize; i += 3, dstp += 3, imstp += 3) 
       { 
        dstp[0] = imstp[2]; 
        dstp[1] = imstp[1]; 
        dstp[2] = imstp[0]; 
       } 
       bitmap.UnlockBits(data); 
       if (handpoint.Count != 0) 
       { 
        Point3D start =  depth.ConvertRealWorldToProjective(handpoint.Peek()); 
        foreach (Point3D hpoint in handpoint) 
        { 
         Point3D pt = depth.ConvertRealWorldToProjective(hpoint); 
         HandPosition(start); 
         start = pt; 
        } 
       } 
       string mess = "Gesture: RaiseHand" + " ,Status:" + gesstatus.ToString()  + "\n" + "Hand: " + handstatus.ToString(); 
       PicDraw(bitmap, mess); 
      } 
     } 

     public void HandPosition(Point3D pt) 
     { 
      try 
      { 
       float a,b,c; 
       string handx, handy, handz; 
       a=pt.X; 
       b=pt.Y; 
       c=pt.Z; 
       handx = a.ToString(); 
       handy = b.ToString(); 
       handz = c.ToString(); 
       Graphics g = pictureBox2.CreateGraphics(); 
       g.FillEllipse(brush, a - 5, b - 5, 20, 20); 
       textBox1.Text = handx; 
       textBox2.Text = handy; 
       textBox3.Text = handz; 
       g.Dispose(); 
      } 
      catch (Exception error) 
      { 
       MessageBox.Show(error.Message); 
      } 
     } 

     public void PicDraw(Bitmap bmap, string me) 
     { 
      try 
      { 
       Graphics g; 
       pictureBox1.Image = bmap; 
       g = Graphics.FromImage(pictureBox1.Image); 
       g.DrawString(me, font, brush, point); 
       g.Dispose(); 
      } 
      catch (Exception error) 
      { 
       MessageBox.Show(error.Message); 
      } 
     } 
    } 
} 

這是我在Program.cs中的代碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Forms; 

namespace HandTracking 
{ 
    static class Program 
    { 
     ........ 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Form1 f1 = new Form1(); 
      f1.Text = "Hand Tracking"; 
      f1.StartPosition = FormStartPosition.CenterScreen; 
      Application.Run(f1); 
     } 
    } 
} 

當我編譯程序很多次,每一次不同的錯誤拋出:InvalidOperationException未處理;跨線程操作無效:從其創建線程以外的線程訪問的控件'textBox1';對象目前正在其他地方使用。 我不知道我傳遞參數的方式:HandPosition(start)和PicDraw(bitmap,mess)是否正確。如果我使用HandPosition(start)來控制機器人,會出現任何問題。任何人都可以告訴我我的錯誤,並幫助我糾正這個計劃嗎?

回答

0

問題是您正嘗試訪問除UI線程以外的線程上的WinForms控件。正在使用Thread.Start創建的線程完成。

Windows Forms的一個更好的技術是使用BackgroundWorker方法(如果使用.NET 4,Task Parallel Library非常好)。使用BackgroundWorker,您可以將線程發送給一些工作,並且它會提供UI線程更新,並將您所選擇的任何對象發送回去。由於您對C#更新,因此BackgroundWorker是正確的選擇,因爲它易於使用,並且如果卡住了,它上面會有大量文檔。

在UI線程上,您只需執行這些更新,然後從UI線程更新您的WinForms控件。問題已修復。

要了解更多關於BackgroundWorker的,谷歌,或者你可以從這裏開始:

http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners

+0

闡述了一下,你會從你按一下按鈕處理程序中實例化一個BackgroundWorker,給它一個方法,它執行並定義一些其他在後臺工作完成時調用的方法,以及何時有進度報告。然後,在您的CallThread,Data,HandPosition,PicDraw和其他在該線程上運行的方法中,只需將進度更新發送到BackgroundWorker,然後在您定義的回調方法中處理它。確保從新線程上運行的方法中獲取對WinForms控件的所有引用。 –

+0

onemancat,非常感謝您的幫助。我將更多地瞭解BackgroundWorker。 –

+0

不客氣。你能否以我的解答作爲答案的好意?這是讓人們想盡全力回答問題的一件事。 –