どうもこんばんは
ロ技研会長の15 のもと です。
この記事は rogy Advent Calendar 2019 25日目の記事です。
といってももう12/28日、研究やらで忙しくて記事を書くのが遅れてしまいました。申し訳ない m(_ _)m。
私は高速画像処理の研究をしているのですが、ロボット勢にもっと画像処理をやる人が増えてほしいと思うので、今回は「リアルタイム画像処理入門」と題して記事を書いていきたいと思います。
高速画像処理
画像処理は一般に処理時間が結構かかってしまいます。しかし、動いているものを対象とした画像処理やロボットなどにカメラを乗せて画像処理をしたい場合には遅い速度の画像処理では間に合いません。
例えば3m/sで飛んでいるボールを画像処理で認識してキャッチしたい場合に、画像処理に10fpsかかるとすると処理に100msのインターバルがあるので、画像をとってから認識が終わる間に30cmも移動してしまっています。そのため、物体の移動を予測する必要が出てきます。
しかし、もし超高速に画像処理ができればどうでしょう。ここで私が説明するよりも例えば東大の石川研究室の動画を見れば高速な画像処理の効果が理解できると思います。
リアルタイム画像処理のコツ
では、どうやったら画像処理が高速になるのでしょうか。そのコツを特別に紹介します。
- スレッド分割による並列化
- GPUを用いた並列化
- ピクセルごとに並列計算できるアルゴリズム
- 計算領域削減のためのクリッピング
- 前のフレームの利用
です。今回はこのうち、スレッド分割による並列化を使ってリアルタイム画像処理の入門をしていきたいと思います。
完成系
今日作るアプリケーションはC++, OpenCVをつかったトランプを認識してARっぽいことをするアプリです。
ソースコードはGithubのここにあります。(よかったらスターください)
システム概要
処理は3つのスレッドに分けて行います
-
Capture Thread
カメラの撮像、その画像を取り込みoutputImageに保存する処理、カラー画像の場合グレースケール化してgrayImageに保存する処理、そして二値化をしてbinImageに保存する処理をします。保存した画像はスレッド間で共有するデータで、これをほかのスレッドで画像処理したり出力したりします。
-
Processing Thread
実際に画像処理を行ってトランプを検出するスレッド。
結果画像を表示するる処理は処理が遅いので別のスレッドで行います。
-
Debug Thread
検出した結果を表示するスレッド。
トランプ検出
ではトランプを検出する画像処理を実際に見ていきましょう。
処理自体は特別なことはしていません。OpenCVの機能を使って判定します。
本当はここも超高速化する実家の秘伝があるのですが、今回は入門編なのでやりません。
まずは入力画像を二値化し、二値化画像からエッジを抽出します。
std::vector<std::vector< cv::Point >> contours; cv::findContours(binImage, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
検出したエッジから直線を検知し、四角形の領域を検出します。
// 直線検知 std::vector< cv::Point > approx; cv::approxPolyDP(cv::Mat(*contour), approx, 50.0, true); // 領域検出 double area = cv::contourArea(approx); if (approx.size() == 4 && area > 100.0) { // 四角形かつ領域の面積が 100 pixel以上 }
透視投影変換を行って検出した四角形の領域を長方形に変形します。
この処理によってトランプを抽出することができます。
cv::Mat H = getPerspectiveTransform(aprPoints, dstPoints); warpPerspective(binImage, dst, H, dst.size(), cv::INTER_NEAREST);
抽出したトランプの画像とあらかじめ用意しておいたトランプの二値化画像とを比較して最も近いトランプの番号を決定します。
具体的にはXORを取ります。それによってよりマッチ率が高い場合は黒くなります。
XORをとった時により黒くなったものが正解だと判定します。
bitwise_xor(dst, trump[i], img_xor);
最後によりARっぽくするためにPnP問題を解いてトランプが立体的に見えるように直方体を重ねて描画します。
実行
webカメラを使って実行をしてみました。
検知したトランプの数や、カメラの解像度によりますが、だいたい120fps ~ 300fpsでトランプの検知ができます。
しかし、webカメラは30fpsなので、こんなに速く画像処理をしても無駄になります。
高速カメラ
webカメラは遅かったので、産業用の高速カメラを使ってみます。
高速カメラはBalser、Ximea、FLIRなどのメーカがありますが、今回はBaslerのacA640-750umを使ってみました。
実はこの手の小型高速カメラは6~10万円程度で買えてしまいます。思ったより安いですよね
スペック的には500fps出るのですが、画像処理の処理時間に合わせて120fpsで撮像しました。
ディスプレイのリフレッシュレートが60fps程度なので、出力が完全には見えませんが。
おわりに
いかがでしたか?
リアルタイム画像処理簡単そうですよね。
気が向いたら高速フェイストラッキングや、高速カメラ2台を使ったステレオカメラシステムを組んで高速三次元トラッキングなどの記事も書きます。