0

C#ブール配列に変換されている画像があるフォームを作成しました。画像が1秒間に4回変換されるタイマー付きのスレッドを生成しようとしています。

私がそれをデバッグするとき、それは機能します、私はタイマーからティックを追跡することができます。しかし、フォームが実行されているとき、アプリケーションはバグを与えることなく終了します。

これは初期化スクリプトです:

form = new LoadForm();
form.Show();
form.BringToFront();

timer = new System.Threading.Timer(new TimerCallback(camTick), null, 0, 250);

これは機能するダニです:

private void camTick(Object myObject) 
{
    if (form.isRunning) 
    {
        bool[,] ar = form.getBoolBitmap(100);
    }
}

これは、ビットマップをロードおよび保存する関数です。form1.csで

public bool[,] getBoolBitmap(uint threshold) {
        unsafe {
            Bitmap b = getBitmap();

            BitmapData originalData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            bool[,] ar = new bool[b.Width, b.Height];

            for (int y = 0; y < b.Height; y++) {
                byte* Row = (byte*)originalData.Scan0 + (y * originalData.Stride);

                for (int x = 0; x < b.Width; x++) {
                    if ((byte)Row[x * 3] < threshold) {
                        ar[x, y] = false;
                    } else {
                        ar[x, y] = true;
                    }
                }
            }

            b.Dispose();

            return ar;
        }
    }

public Bitmap getBitmap() {
        if (!panelVideoPreview.IsDisposed) {
            Bitmap b = new Bitmap(panelVideoPreview.Width, panelVideoPreview.Height, PixelFormat.Format24bppRgb);
            using (Graphics g = Graphics.FromImage(b)) {
                Rectangle rectanglePanelVideoPreview = panelVideoPreview.Bounds;
                Point sourcePoints = panelVideoPreview.PointToScreen(new Point(panelVideoPreview.ClientRectangle.X, panelVideoPreview.ClientRectangle.Y));
                g.CopyFromScreen(sourcePoints, Point.Empty, rectanglePanelVideoPreview.Size);
            }

            return b;
        } else {
            Bitmap b = new Bitmap(panelVideoPreview.Width, panelVideoPreview.Height);
            return b;
        }
    }
4

3 に答える 3

2

この画像はPictureBoxのようなコントロールに保存されていますか?その場合は、コントロールのスレッドでのみアクセスしていることを確認してください。Control.Invoke()を確認してください。

于 2012-05-03T16:31:53.507 に答える
1

からのコールバックはスレッドでSystem.Threading.Timer実行されます。ThreadPoolそのコールバックでは、Formインスタンスにアクセスしています。あなたは単にこれを行うことはできません。できますが、正しく機能しません。それは予測不可能で、時には見事に失敗します。

System.Windows.Forms.Timer代わりに使用してください。4秒ごとにチェックしてもらいます。Tickイベントでは、フォームから必要なデータを取得し、それ別のスレッドに渡してさらに処理します。

次のコードでは、UIスレッドBitmapを呼び出してオブジェクトを取得します。次に、バックグラウンドでに変換できる場所にオフをDrawToBitmap渡します。必要に応じて、からそれを返し、必要に応じて呼び出してUIスレッドに戻すことができます(ただし、おそらくそうする必要はないようです)。BitmapTaskbool[]bool[]TaskContinueWith

private void YourWindowsFormsTimer_Tick(object sender, EventArgs args)
{
  // Get the bitmap object while still on the UI thread.
  var bm = new Bitmap(panelVideoPreview.ClientSize.Width, panelVideoPreview.ClientSize.Height, PixelFormat.Format24bppRgb);
  panelVideoPreview.DrawToBitmap(bm, panelVideoPreview.ClientRectangle);

  Task.Factory
    .StartNew(() =>
    {
      // It is not safe to access the UI here.

      bool[,] ar = ConvertBitmapToByteArray(bm);

      DoSomethingWithTheArrayHereIfNecessary(ar);

      // Optionally return the byte array if you need to transfer it to the UI thread.
      return ar;
    })
    .ContinueWith((task) =>
    {
      // It is safe to access the UI here.

      // Get the returned byte array.
      bool[,] ar = task.Result;

      UpdateSomeControlIfNecessaryHere(ar);

    }, TaskScheduler.FromCurrentSynchronizationContext());
}

そしてConvertBitmapToByteArray今はこんな感じになります。

public unsafe bool[,] ConvertBitmapToBoolArray(Bitmap b, uint threshold) 
{
  BitmapData originalData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

  bool[,] ar = new bool[b.Width, b.Height];

  for (int y = 0; y < b.Height; y++) 
  {
    byte* Row = (byte*)originalData.Scan0 + (y * originalData.Stride);
    for (int x = 0; x < b.Width; x++) 
    {
      if ((byte)Row[x * 3] < treshold) 
      {
        ar[x, y] = false;
      } else 
      {
        ar[x, y] = true;
      }
    }
  }
  b.Dispose();
  return ar;
}
于 2012-05-03T19:19:42.273 に答える
0

インターネットで検索した後、これを見つけました。これを返すために別の関数を作成する必要がありましたbool[,]。これが私が思いついたものです。

public bool[,] invokeBitmap(uint treshold) {
        if (this.InvokeRequired) {
            return (bool[,])this.Invoke((Func<bool[,]>)delegate {
                return getBoolBitmap(treshold);
            });
        } else {
            return getBoolBitmap(treshold);
        }
    }
于 2012-05-04T14:32:56.437 に答える