1

こんにちは、私のスレッドを読んでくれてありがとう!多くの検索を行った後、この特定の問題を解決するものが見つからなかったため、コードについてアドバイスを求めたいと思います。私はグーグルでstackoverflowを検索しましたが、すべてのソリューションが何らかの形で機能しませんでした(または実装方法がわかりませんでした)。これが私のコードです:

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 AForge.Video;
using AForge.Video.DirectShow;
using System.Threading ;

    namespace Motion_Detection
    {
         public partial class Form1 : Form
        {
            private FilterInfoCollection VideoCaptureDevices;
            private VideoCaptureDevice FinalVideo;

        private void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            Bitmap video = (Bitmap)eventArgs.Frame.Clone();
            pictureBox1.Image = video;
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
            {
                devicesList.Items.Add(VideoCaptureDevice.Name);
                devicesList.SelectedIndex = 0;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[devicesList.SelectedIndex].MonikerString);
            FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);

            FinalVideo.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            pictureBox1.Image = null;
            FinalVideo.Stop();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            worker.RunWorkerAsync();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            worker.CancelAsync();
        }

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (!worker.CancellationPending)
            {
                Bitmap map = new Bitmap(pictureBox1.Image); // this line throws the error

                for (int x = 0; x < pictureBox1.Width; x++)
                {
                    for (int y = 0; y < pictureBox1.Height; y++)
                    {
                        Color pixel = map.GetPixel(x, y);

                        if (pixel.R == 255 && pixel.G == 0 && pixel.B == 0)
                        {
                            // detected red pixel
                        }
                    }
                }

                Thread.Sleep(100); // check every 100ms or any other given interval
            }
        }
    }
}

Aforge ビデオ DLL を使用して Web カメラにアクセスしています。この部分は機能し、そこからストリームにアクセスして読み取ることができます。それをpicturebox1にダンプすると、遅延がまったくなく、完全に表示されます。

今、モーション検出をいじっています。最初に、カメラの前に現れる特定の色のピクセルを検出できるかどうかを確認したかったのです。すべてのピクセルをループする必要があるため、これを別のスレッドに配置する必要がありました。そうしないと、GUI がフリーズし続け、表示が遅れ始めました。

問題は、私がこれを行ったためです。タイトルからエラーをトリガーせずに、バックグラウンド ワーカーから picturebox.image コンテンツに適切にアクセスする方法がわかりません。インターネット上の何人かは lock() の使用を提案しましたが、私はこれを実行したことがなく、ここで何を lock() すべきかを知りません。最終的にアクセス違反を処理できなかったという理由だけで、以前はマルチスレッドを使用したことがありませんでした..

この問題を解決するために、try ブロック内でも同じ例外が発生しましたが、try finally ブロックなどを試しました。私が言及したことを実行するためのよりクリーンな方法があると思いますが、それがどれであるかについて頭を悩ませることはできません。

ここでのフォーラムへの最初の投稿が、できるだけ明確で理解しやすいものであったことを願っています。

よろしくお願いします〜イルハン

4

1 に答える 1

0

UIスレッドでない限り、pictureBox1にアクセスすることはできません/すべきではありません。

次のようなことをする必要があると思います:

private void GetImage(out Bitmap img)
{
    img = new Bitmap(pictureBox1.Image);
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    Bitmap img = null;
    Invoke(new Action(() => GetImage(out img)));
    // Do what you want with the bitmap
}

UI スレッド上にない場合、winform 上のコントロールにアクセスすると例外がスローされます。正しいスレッドにいるかどうかは、pictureBox1.InvokeRequired で確認できます。Invoke を呼び出すと、渡されたデリゲートを実行するように UI スレッドにメッセージが送信され、渡されたデリゲートが完了するまで待機します。BeginInvoke を呼び出すと、メッセージは送信されますが、待機しません。

于 2013-05-14T16:31:41.097 に答える