2013/10/20

C#で画像処理-WEBカメラの使用-

Lv_ZEROです。

前回予告したように今回はUSB接続のWEBカメラから画像を読み込む方法を紹介していきたいと思います。
windows環境でUSB接続のWEBカメラを使用するには2通りの方法があります。1つは"DirectShow"を使う方法で、もう一つは"VFW(video for windows)"を使う方法です。"AForge.NET"では前者の"DirectShow"を使ってWEBカメラから画像を読み込む方法が実装されています。

それではプログラムの説明をしていきます。

ライブラリを使用するために「プロジェクト(P)」→「参照の追加(R)」から
AForge.Video.dll
AForge.Video.DirectShow.dll
をプロジェクトに追加しておいてください。さらに、
using AForge.Video;
using AForge.Video.DirectShow;
もプログラムに追加しておいてください。

WEBカメラを使用する時のプログラムの流れは以下のようになります。
①接続されている全てのビデオデバイスの取得
//ビデオ入力デバイスのみ取得
FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
②使用するビデオデバイスのオブジェクト生成
//VideoDevices中のデバイス1つを選択し、そのオブジェクトを生成
int Index;
VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[Index].MonikerString);
//最初に見つかったビデオデバイスを使用する場合、以下のようにIndex = 0とすればよい
VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
③フレームサイズなど、ビデオデバイスの設定
//ビデオデバイスの提供する機能一覧を配列に格納
VideoCapabilities[] videoCapabilities = videoSource.VideoCapabilities;
//提供されているフレームサイズをコンボボックスのアイテムに追加
foreach ( VideoCapabilities capabilty in videoCapabilities )
{
    comboBox.Items.Add( string.Format( "{0} x {1}", capabilty.FrameSize.Width, capabilty.FrameSize.Height ) );
}
comboBox.SelectedIndex = 0;
//コンボボックスで選択されているのフレームサイズに設定
videoSource.VideoResolution = videoCapabilities[comboBox.SelectedIndex];
//このプログラムのままだと"SelectedIndex"が常に0となってしまうので、別のメソッドで設定するするように
④新しいフレームが来たら発生するイベントの登録
//新しいフレームが来たら"video_NewFrame"という名のメソッドが呼ばれる
//"=="でなく"+="になっている点に注意
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
⑤ビデオデバイスの起動
//ビデオデバイスの起動
videoSource.Start();
⑥新しいフレームが来たら処理(繰り返し)
//新しいフレームが来たら実行されるメソッド
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    //新しいフレーム"eventArgs.Frame"のコピーを"Bitmap"に格納して扱う
    Bitmap img = (Bitmap)eventArgs.Frame.Clone();
    //ここで画像処理などを行う
    pictureBox.Image = img;//画像を"pictureBox.Image"に表示
}
⑦ビデオデバイスの停止
//ビデオデバイスの停止
videoSource.SignalToStop();
//完全に停止するまで待つ
videoSource.WaitForStop();
//これ以上使用しないならオブジェクトを空にする
videoSource = null;

細かいメソッドの役割は以上です。これを組み合わせてプログラムを作ります。
まだ紹介していないメソッドなどもありますが、基本的にこれだけ分かっていれば、自分で調べて実装することもできるでしょう。

最後に、実際にwindowsフォームで作ったプログラムを公開しておきます。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
//名前空間の省略
using AForge.Video;
using AForge.Video.DirectShow;

namespace CSharpで画像処理
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //接続されている全てのビデオデバイス情報を格納する変数
        private FilterInfoCollection videoDevices;
        //使用するビデオデバイス
        private VideoCaptureDevice videoDevice;
        //ビデオデバイスの機能を格納する配列
        private VideoCapabilities[] videoCapabilities;

        //ウィンドウが生成された時
        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox2.Enabled = false;
            button1.Enabled = false;
            button2.Enabled = false;
        }

        //"デバイス取得"ボタンが押された時
        private void button3_Click(object sender, EventArgs e)
        {
            videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            if (videoDevices.Count != 0)
            {
                comboBox1.Items.Clear();
                foreach (FilterInfo device in videoDevices)
                {
                    comboBox1.Items.Add(device.Name);
                }
                comboBox1.SelectedIndex = 0;
                comboBox2.Enabled = true;
                button1.Enabled = true;
            }
            else
            {
                comboBox1.Items.Clear();
                comboBox1.Items.Add("デバイスが見つかりません");
                comboBox1.SelectedIndex = 0;
            }
            
        }

        //デバイスが変更された時
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            videoDevice = new VideoCaptureDevice(videoDevices[comboBox1.SelectedIndex].MonikerString);
            videoCapabilities = videoDevice.VideoCapabilities;
            comboBox2.Items.Clear();
            foreach (VideoCapabilities capabilty in videoCapabilities)
            {
                comboBox2.Items.Add(string.Format("{0} x {1}", capabilty.FrameSize.Width, capabilty.FrameSize.Height));
            }
            comboBox2.SelectedIndex = 0;
            videoCapabilities = videoDevice.VideoCapabilities;
            comboBox2.Items.Clear();
            foreach (VideoCapabilities capabilty in videoCapabilities)
            {
                comboBox2.Items.Add(string.Format("{0} x {1}", capabilty.FrameSize.Width, capabilty.FrameSize.Height));
            }
            comboBox2.SelectedIndex = 0;
        }

        //フレームサイズが変更された時
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            videoDevice.VideoResolution = videoCapabilities[comboBox2.SelectedIndex];
        }

        //"起動"ボタンが押された時
        private void button1_Click(object sender, EventArgs e)
        {
            videoDevice.NewFrame += new NewFrameEventHandler(videoDevice_NewFrame);
            videoDevice.Start();
            button1.Enabled = false;
            button2.Enabled = true;
            button3.Enabled = false;
            comboBox1.Enabled = false;
            comboBox2.Enabled = false;
        }

        //新しいフレームが来た時
        void videoDevice_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            Bitmap img = (Bitmap)eventArgs.Frame.Clone();
            //ここで画像処理
            pictureBox1.Image = img;
        }

        //"停止"ボタンが押された時
        private void button2_Click(object sender, EventArgs e)
        {
            if (videoDevice.IsRunning)
            {
                videoDevice.SignalToStop();
                videoDevice.WaitForStop();
            }
            pictureBox1.Image = null;
            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = true;
            comboBox1.Enabled = true;
            comboBox2.Enabled = true;
        }

        //ウィンドウを閉じる時
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (videoDevice.IsRunning)
            {
                videoDevice.SignalToStop();
                videoDevice.WaitForStop();
                videoDevice = null;
            }
        }

        

        
    }
}

本来ならtry-catch構文でエラー回避するべきですが、コードが見ずらくなると思ったので実装していません。

これでUSB接続のWEBカメラから画像を読み込むことができましたので動画像処理も可能となりました。
次からは"AForge.NET"での画像処理を試していきたいと思います。

2 件のコメント:

  1. レスキューロボットに興味がありす。が、NHKの学生ロボコンや川崎ロボット大会には出場されないのですか?ロボットファクトリーでは、どのくらいのロボット製作が可能ですか?今後のご活躍に期待しています。

    返信削除
  2. レスキューロボットに興味がありす。が、NHKの学生ロボコンや川崎ロボット大会には出場されないのですか?ロボットファクトリーでは、どのくらいのロボット製作が可能ですか?今後のご活躍に期待しています。

    返信削除