Column > 【OpenCVSharp,c#】AndroidをWebカメラ代わりにして画像処理
2016/5/14 【OpenCVSharp,c#】AndroidをWebカメラ代わりにして画像処理

画像処理をしたいときによく使われるライブラリとしてOpenCVというものがあるのですが、
それをc#で使えるような形にしたOpenCVSharpというものがあるそうです。

そのOpenCVSharpとWebカメラを使って何か画像処理をしたいなぁと思ったものの、
Webカメラは持ってないのでどうしようかなという感じだったのですが、
DroidCamというAndroidをWebカメラの代わりとして使うことが出来るソフトを見つけました。

ですので、今回はこの2つを使って簡単な画像処理をやってみました。



使っているPCのスペックの問題でガタガタな動画になってしまっていますが、
Androidで撮っている映像をリアルタイムでPCに送り、エッジ検出などをさせています。

作り方を以下に書いていきます。
開発環境は、windows7Visual Studio Express 2013です!



下準備

1、OpenCVSharpのインストール

まず始めに、OpenCVSharpをインストールしていきます。
OpenCVSharpを開発した方のブログを参考にして入れました。


2、DroidCamのインストール

次に、DroidCamをインストールします。
DroidCamはパソコンとスマホの両方にインストールする必要があるのですが、
パソコンの方は公式サイトから入手できます。

今のところはClient v6.0.0Client v5.0.1の2つのバージョンが出ているみたいです。
こちらのサイトの環境では v5.0.1 しか動かなかったようですが、
自分の環境では逆に v6.0.0 だけが動きました。この辺りは各自で確かめてみて下さい。

スマホの方はGoogle Playで探したら出てきました。
無料版と有料版(500円)があるみたいなので、無料版の方を入れてみました。


3、DroidCamの動作確認

パソコンとスマホの両方にインストールが終わったところでちゃんと動くのかを見てみます。
Wi-Fiで繋いでもUSBケーブルで繋いでも良いみたいなので、今回はWi-Fiで繋いでみます。

スマホをWi-Fiに繋いだ状態でDroidCamを開いて、
下のように繋がっているWi-Fiの情報が出てきたらスマホ側の準備は終了です。



次にパソコン側でDroidCamを起動して、下のような画面が出てくるので
スマホの画面に出ていたWi-FiのIPを入力してstartボタンを押せば
カメラで読み取った映像が出てきます。



下準備はこれで完了です!


2016/12/26 追記


8以降のwindowsに新しく備わった「高速スタートアップ」という機能が有効だと
Webカメラが使えなくなることがあるようです。
思わぬところに落とし穴が……^^;

参考URL:https://answers.microsoft.com/ja-jp/windows/forum/windows_10-hardware/windows-10-%E3%81%A7-web/a6357cee-7bf7-447b-a7f5-00a984837d94



プログラム

ここからはプログラムを組んでいきます。

フォームの見た目は下のような感じで、
送られた映像をそのまま映すモード、ラプラシアンフィルタによるエッジ検出モード、
ネガポジ変換モードの3つを用意して、ボタンで自由に切り替えられるようにしてみます。



LabelとButtonは元からあるコントロールですが、PictureBoxIplというのは
OpenCVSharpで扱うIplImageという画像の型をPictureBoxでも扱えるようにしたコントロールです。
開発者の方のブログを参考に導入しました。

そうして出来たプログラムが下のような感じです。

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 OpenCvSharp;

namespace testCSharp
{
    public partial class Form1 : Form
    {
        BackgroundWorker worker;

        public Form1()
        {
            InitializeComponent();

            worker = new BackgroundWorker();

            // 非同期をキャンセルさせる
            worker.WorkerSupportsCancellation = true;

            // ProgressChangedイベントを発生させるようにする
            worker.WorkerReportsProgress = true;

            // ReportProgressメソッドで呼ばれるProgressChangedのイベントハンドラを追加
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

            // RunWorkerAsyncメソッドで呼ばれるDoWorkに、
            // 別スレッドでUSBカメラの画像を取得し続けるイベントハンドラを追加
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        }

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
        	// カメラからの映像を受け取る
            using (var capture = Cv.CreateCameraCapture(CaptureDevice.Any))
            {
                IplImage frame;
                while (true)
                {
                    frame = Cv.QueryFrame(capture);

                    // 新しい画像を取得したので、
                    // ReportProgressメソッドを使って、ProgressChangedイベントを発生させる
                    worker.ReportProgress(0, frame);
                }
            }
        }

        private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //  frameがe.UserStateプロパティにセットされて渡されてくる
            IplImage image = (IplImage)e.UserState;

            CvSize size = new CvSize(320, 240);
            IplImage reImage = new IplImage(size, image.Depth, image.NChannels);

            Cv.Resize(image, reImage, Interpolation.NearestNeighbor);

            switch (label1.Text)
            {
                case "negaposi":
                    Cv.Not(reImage, reImage);
                    break;
                case "laplace":
                    Cv.Laplace(reImage, reImage);
                    break;
            }

            pictureBoxIpl1.ImageIpl = reImage;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // DoWorkイベントハンドラの実行を開始
            worker.RunWorkerAsync();
        }

        private void defaultButton_Click(object sender, EventArgs e)
        {
            label1.Text = "default";
        }

        private void laplaceButton_Click(object sender, EventArgs e)
        {
            label1.Text = "laplace";
        }

        private void negaposiButton_Click(object sender, EventArgs e)
        {
            label1.Text = "negaposi";
        }
    }
}

				


3つのどれかのボタンが押されるとlabel1のtextの値が変化し、
その値によって画面の処理を変えるというものです。

BackGroundWorkerというクラスは今回始めて使ってみたのですが、
このクラスを使用することで、フォームのボタンの操作と映像を受け取る処理を
別スレッドで行っているようです。
こちらこちらのブログが参考になりました。



2016/12/26 追記


Webカメラで撮った映像を保存したい場合はどうするのか?
という質問を頂いたので、新たにページを作りました。
http://sssignal.web.fc2.com/column/column21.html

この記事の手順通りにOpenCVSharpをインストールされているなら
3行程書くだけで実装できるので、合わせて参考にして頂ければと思います。

2017/1/4 追記


Youtubeの動画の位置を変更しました。
    Please
    Share!
  • feedly
  • facebook
  • twitter
  • hatena bookmark
  • pocket
  • Google plus


inserted by FC2 system