ラベル OpenCvSharp の投稿を表示しています。 すべての投稿を表示
ラベル OpenCvSharp の投稿を表示しています。 すべての投稿を表示

2016年7月14日木曜日

OpenCvSharpでWebカメラをキャプチャしてFormに表示

マイコンに飽きてきたというか、ハードを考えるのに飽きてきたのでまたPCに戻ってきた。
とりあえずOpenCvSharpで遊んでる。で、タイトルの件。

特に難しいことはない

Thread t;
readonly int CameraIndex;

public Form1()
{
    InitializeComponent();

    CameraIndex = 0;

    t = new Thread(new ThreadStart(ImageLoad));
    t.IsBackground = true;
    t.Start();
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    t.Abort();
}

private void ImageLoad()
{
    using (CvCapture cap = Cv.CreateCameraCapture(CameraIndex))
    {
        while (true)
        {
            using (IplImage img = cap.QueryFrame())
            {
                Bitmap bmp = BitmapConverter.ToBitmap(img);

                if (pictureBox1.Image != null)
                {
                    pictureBox1.Image.Dispose();
                }

                pictureBox1.Image = bmp;
            }
        }
    }
}

ロード時にバックグラウンドスレッドを作ってFormClosedの時に止める。バックグラウンドスレッドの中ではキャプチャを作って無限ループで読み込みと表示を行う。
OpenCvのWindowを使うときにはCv.WaitKeyが必要だが、Formに表示するなら不要。QueryFrameで適切にウエイトが入る。というかカメラが1コマ撮影しないとスレッドに処理が返らない。カメラの性能に左右されるが、数fps-数十fpsくらいで安定する。これはカメラや帯域以外にも、光量にも依存する。つまり周りが暗いとカメラはシャッタースピードを遅くする必要があるから、FPSが稼げなくなる。

ただしCaptureがカメラではなく動画ファイルとかで、リアルタイムに表示する必要があるならcap.Fpsを使って適切なディレイを設定すること。ただThreadのSleepとかはあまり正確ではないので、例えば1時間の動画ファイルをちょうど1時間で表示しなければいけない場合などは工夫が必要。

OpenCvSharpの動作確認とかで途中の画像を出力したい場合もBitmapConverter.ToBitmapでC#が扱える画像に変換してPictureBoxに渡してやればOK。

2016年3月11日金曜日

物体追跡

OpenCvで物体を追跡するヤツを作っています。最終的な目的はWebカメラ(or UVCなキャプチャデバイス)からリアルタイムに動画を読み込んで電動雲台で追尾することですが、とりあえず今は動画ファイルを読み込んで追尾しています(OpenCvは動画とカメラをほぼ同じように扱えるので便利)。

とりあえず最低限の動作は実装できたので、試しにロケットの動画を読み込ませてみました。手持ちにロケットの映像が無かったのでyoutubeから。


そして結果がこちら。




打ち上げ直後は綺麗に追尾できていますが、上空に上がって煙が太陽に照らされると煙自体を追尾するようになってしまいました。二値化の閾値をギリギリにするとうまく追尾できますが、値に余裕が無いので現地でリアルタイムに設定するのは結構大変だと思います。
解像度256x256でダイナミックレンジ広くて12bitくらいで輝度情報だけ出てくるUSBカメラがあれば良いんだけど。インダストリアルでそんなの無いかな。

画像自体は256x256にリサイズした後に処理しているので、FHDに比べれば情報量は多くありませんが、それでもCore i5 3.2GHzのマシンで18fps前後が限界です。Core i5 2.3GHzのノートでは10fpsも出ませんでした。早いCPUを積んだデスクトップならリアルタイムでトラッキングできると思いますが、射場にそんなの持ち込むわけにもいかないので、どうにか高速化する必要があると思います。
GeForce搭載のハイエンドノートとかもありますから、お金があるチームはそれを使うのが手かも。値段もTOUGHBOOKより安いですしw。

他には、例えばAIM-9X 画像誘導ミサイルの解像度は128x128ピクセルで、これでも10km程度先の戦闘機をLockできるはずですから、解像度自体はその程度でも十分なのかもしれません。ただし望遠レンズで視野が狭いですから、追尾用のカメラは小型軽量なモノを独立した高速なジンバルに載せてやる必要があります。


いろいろ課題は有りますが、少しずつ進めていこうと思っています。

2016年3月9日水曜日

OpenCvでコントラスト調整

OpenCvSharpでコントラストを調整したいのでググったが、どうやらできないみたい。

ゴリラになる知識: コントラスト調整

ということでCv.Scaleを使って調整してみた。
まず256の範囲で獲得したヒストグラムをbins[]に突っ込んでおく。そしてminに一番暗い輝度を、maxに一番明るい輝度を設定する。今回はminを0に、maxを255に近づけるような処理を行う。

int min = 0, max = bins.Length - 1;

for (int i = 0; i < bins.Length; i++)
{ if (bins[i] > 0) { min = i; break; } }

for (int i = bins.Length - 1; i >= 0; i--)
{ if (bins[i] > 0) { max = i; break; } }

float scale = 256f / (max - min);
float shift = -min * scale;

Cv.Scale(img2, img2, scale, shift);

Cv.ScaleではSrc, Dst, Scale, Shiftを引数に渡す。処理としてはまずScaleでn倍に拡張し、その後でShiftを加算している。コントラストを調整したい場合はminとmaxの差が256になるようにScaleで拡張する。その後にShiftでminを0に近づけたいわけだが、minもScaleでn倍にされているので、引数に渡すShiftもscaleでn倍にして渡す。

結果


上が入力画像、下がコントラスト調整後の画像。左がカラー、右がグレースケールの画像となる。グレースケールはカラーをグレースケールに変換した後にコントラストを調整している。調整の係数はグレースケールのヒストグラムをカラーにも使用した。


ということでコントラストの調整は結構簡単にできるっぽい。ただ自動でコントラストを拡張したい場合は予めヒストグラムを獲得しておく必要がある。OpenCvのヒストグラム獲得は結構面倒なので、そのあたりが面倒。

カラーのコントラストを単純に調整すると色味に違和感が出る気がする。まぁこれは見る人の問題なのでそこら辺は好きにいじるように。

2016年2月3日水曜日

OpenCvSharpでレンズ補正っぽいことをする

OpenCvでレンズ補正を行うプログラムをC#に移植してみた。といってもほとんど全く同じコードで動くわけだが。OpenCvSharpすぎょい。(ただし本気でSharpにするならいろいろ最適化できるが)

カメラはiBUFFALO マイク内蔵320万画素WEBカメラ F2.2ガラスレンズ搭載モデル ブ ラック BSW32KM03BKを使用した。

修正したサンプル 上が補正済み、下が未補正。


元画像がほとんど歪みのない画像なのであまり違いがわからない。Webカメラすぎょい。

チェッカーボードは本来印刷したりして使うんだろうが、プリンタが無いのでとりあえず画面に表示して代用した。



この画像は24インチの1920x1080液晶で表示することで1マスが25.0mmのROW9,COL18なチェッカーボードとして使用することができる。ROWとCOLはコマの数ではなく、交差しているところの数であることに注意。

補正情報を拾うための画像は適当にいろいろな角度や距離から撮影しておく。距離や向きに多様性がある方がいいと思うが、チェッカーボードが一部でも隠れていると解析に失敗してしまうので、すべての領域が撮影されている必要がある。

情報はXMLで書きだされ、今回はこんな感じになった。

<?xml version="1.0"?>
<opencv_storage>
<intrinsic type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    1.04094995e+003 0. 6.19313538e+002 0. 1.15699170e+003
    3.98739349e+002 0. 0. 1.</data></intrinsic>
<rotation type_id="opencv-matrix">
  <rows>1</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    -2.04190898e+000 -2.19732761e+000 2.56176054e-001</data></rotation>
<translation type_id="opencv-matrix">
  <rows>1</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    -1.47931931e+002 -1.17953056e+002 6.39266296e+002</data></translation>
<distortion type_id="opencv-matrix">
  <rows>1</rows>
  <cols>4</cols>
  <dt>f</dt>
  <data>
    8.36658627e-002 -6.74404874e-002 -1.06694188e-003 -7.54280773e-005</data></distortion>
</opencv_storage>


さて、とりあえずオプティカルフローでカメラの動きを検出することができるようになった。それからレンズ歪みも補正できるようになった。あとはオプティカルフローでシェイクリダクションをできるようになれば、ウェアラブルカメラの補正とかができて楽しいかな。


2016年2月2日火曜日

OpenCv(Sharp)でオプティカルフロー



OpenCvSharpでオプティカルフローを行ってみた。ソースコードは"実践OpenCV 2.4―映像処理&解析"のオプティカルフロー、178ページのC++のコードをほぼそのまま使用している。
サンプルには検出しやすそうなキーボードを使ってみた。キーボードのバックライトで表示された文字もちゃんと文字として認識できるのが面白い。
それとオリジナルの処理として画像の下側に移動の長さの量を表示している。上の画像は平行移動しているので鋭いスペクトルが出ている。ということで出現回数が多い移動を平均すれば移動方向が把握できる。と思ったのだけど、流石にそんな簡単じゃない。



上の画像は平行移動ではなく、カメラを回転させたサンプル。回転中心が移動量最小で、中心から離れる程に移動量が多くなる。なので鋭いスペクトルは出ず、様々な長さの移動が検出される。
とりあえずシェイクリダクションでもやってみようかと思っていたけど、かなり大変のようだ。とりあえずオプティカルフローで遊ぶという目的は達成したけど、もうちょっといろいろ調べてみよう。

2015年9月3日木曜日

OpenCvSharpでWebカメラを表示する

Webカメラというか、USBビデオクラス(UVC)を使用するUSBカメラを表示するためのサンプル。USBカメラを表示したかったが録画する機能とかもいらないしサクッと作ってみた。

OpenCvSharpで読み込んでC#のフォームに表示してもいいが、今回は手っ取り早くOCvで表示まで行った。

ソースコードはオブジェクト指向とは思えないような感じになってる。がまぁ動作してるので。。。

文字列入力を読み込みたかったので、スレッドでQueue<string>にConsole.ReadLineを読み込んでいる。一般的には「CvのWindowで何かキーを押せば終了」だと思うが、このコードはConsoleにquitを入力することで終了する。Console.ReadLineは同期読み込みだから、途中で読み込みを止めたいと思っても止められない(はず)。ということで最後にユーザーがEnterを入力してやる必要がある。Inのストリームを引っ張ってきて自前で処理すればいいかもしれないが、今回は面倒だったのでやってない。

解像度は「適切な(縦横比の)解像度で縦横を連続して設定すると適用される」みたいな動作になってるのでハードコードしてやった。

リアルタイムで映像を表示するだけの機能しかないが、画角の確認だとかフォーカスの確認くらいなら可能。