OpenCV for Androidでキャプチャしたカメラ画像にフレームを合成

卒業研究も無事に終わり、中途半端に終わってしまったソースコードの手直しとかしてました。

卒業研究周りはこの辺がもう少し落ち着いたらまた手を付けて行きたいなぁと。

その時に解決できた事柄を1個メモ。

 

OpenCV for Android 2.4.6のサンプル OpenCV Tutorial 1 -Camera Previewを使って枠付きの写真を撮影する作ってみます。

 

自分がメモしたいと思ったところのみに絞るのでプロジェクトの追加方法は割愛します(閲覧している方は0に近いと思いますが、もし気になる方いらっしゃればご一報を。追記します)

 

Tutorial1Activity.javaの中にOnCameraFrameメソッドがあります。

この中に記述を追記することで、表示するカメラの映像に編集を加えます。

 

   public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

 

        return inputFrame.rgba();

    }

 

 元々これだけの記述しかありませんが、これを色々変えていじります。

 

かぶせる枠はresフォルダ-drawableフォルダの中へ。

 

f:id:eight-seven:20140225053601p:plain

 

こんな具合です。sunset.pngが枠の画像です。

以下のコードを記述することでsunset.pngの画像ファイル(PNG)をビットマップとして取り込むことができます。(要import android.graphics.BitmapFactory;記述)

 

      Resources r = getResources(); 

      Bitmap bmp_frame = BitmapFactory.decodeResource(r, R.drawable.sunset);

 

 

例えば、今回のsunset.pngというファイル名であれば、

R.drawable.sunset

という名前のidの変数をdecodeResource関数のid部分に記述します。

 

後で画像を合成する際に、サイズを合わせる必要があるため

Bitmap型の時点でサイズの変換を行います。今回取り込むカメラ画像は640x480なのでそれに合わせます。 

 

     bmp_frame = Bitmap.createScaledBitmap(bmp_frame, 640, 480, false);

 

これでPNGの画像はBitmap型になります。 

しかしBitmap型のままでは合成ができないので、bitmapToMat関数を使ってMat型に変換します。(要import org.opencv.android.Util;記述?<筆者はimport.org.opencv.android.*;で対処>)

 

 

     Mat mat = new Mat(3,3,CvType.CV_32F);

     Utils.bitmapToMat(bmp_frame, mat);

 

 

変換した後の置き場として変数matを作りました。

ちなみにブランクのMatを作ろうとしてずっとnullでやってエラー吐いてました...

ちゃんとコンストラクタで定義しましょう。(恥ずかしい)

 

 

     Mat mat2 = new Mat(3,3,CvType.CV_32F); 

     mat2 = inputFrame.rgba();

 

 

カメラ画像用のMatも用意しておきます。このサンプルコードだと、

 

   inputFrame.rgba();

 

でカメラ画像のMatを取得することができます。

 

そして、Coreクラスのaddメソッドで2つのMatを合成します。

 

  Core.add(mat2, mat, mat);

 

ここまでの流れをざっと示すと以下のソースコードになるはずです。

 

   public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

    

     Resources r = getResources(); 

     Bitmap bmp_frame = BitmapFactory.decodeResource(r, R.drawable.sunset);

     bmp_frame = Bitmap.createScaledBitmap(bmp_frame, 640, 480, false);

 

     Mat mat = new Mat(3,3,CvType.CV_32F);

     Utils.bitmapToMat(bmp_frame, mat);

 

     Mat mat2 = new Mat(3,3,CvType.CV_32F); 

     mat2 = inputFrame.rgba();

     

   Core.add(mat2, mat, mat);

                  

        return mat;

    }

 

これを記述して起動するとこんな感じになります。枠の画像は某フォロワさん作。

 

f:id:eight-seven:20140225060341p:plain

 

んー、このコードだと半透明になってしまうのが...元の画像にアルファ値含まれているんだろうか。

アルファ値削除か、マスク画像使う手法を試していないので後でやってみます。 

 

 

============================

 【ここから反省会】

Matを合成する部分?でエラーを吐いていたのですがその原因が分からず滞っていました。

こんなの。

02-22 04:02:22.634: E/cv::error()(18106): OpenCV Error: Assertion failed (src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols) in void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean), file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp, line 97

02-22 04:02:22.634: E/org.opencv.android.Utils(18106): nMatToBitmap catched cv::Exception: /home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp:97: error: (-215) src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols in function void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean)

02-22 04:02:22.634: E/CameraBridge(18106): Mat type: Mat [ 825*675*CV_8UC4, isCont=true, isSubmat=false, nativeObj=0xab5160, dataAddr=0x5d916010 ]

02-22 04:02:22.634: E/CameraBridge(18106): Bitmap type: 640*480

02-22 04:02:22.634: E/CameraBridge(18106): Utils.matToBitmap() throws an exception: /home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp:97: error: (-215) src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols in function void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean)

 

これが、2つのMatファイルのサイズの相違を示していたなんて...

 

02-22 04:02:22.634: E/CameraBridge(18106): Mat type: Mat [ 825*675*CV_8UC4, isCont=true, isSubmat=false, nativeObj=0xab5160, dataAddr=0x5d916010 ]

 これが枠の画像(825*675)で

 

02-22 04:02:22.634: E/CameraBridge(18106): Bitmap type: 640*480

こっちが取り込んだカメラ画像(640*480)と。
 
今回は

 

     bmp_frame = Bitmap.createScaledBitmap(bmp_frame, 640, 480, false);

 
の記述を追加して、枠の画像をカメラ画像に合わせて対処しました。
もっとOpenCVしっかり勉強しないとなぁ。
 

MacでLaTeX

MacBookにはTeXShopっていう名前のエディタがあるようで、

これを使うとTeXファイルの編集、pdfファイルへの出力ができます。

 

ただ、なんかウチの大学のMacBookLaTeX環境設定の部分でポカったらしいので対処法とか載せときます。

 

 

今のところ確認しているのは2つ。

 

1. LaTeXのコマンドファイルのパスの形式がおかしい(多分みんなこれ)

2.X11をインストールしたため、必要なライブラリファイルが移動されていた(一部の人?GIMP入れた人も相当?)

 
まー、これだけ直せばなんとかなると思います。
いかんともしがたい物ではないので、レッツトライ。
 
1. LaTeXのコマンドファイルのパスの形式がおかしい
 

f:id:eight-seven:20131020002613p:plain

多分こんなのになってると思うんですけど、
学籍番号/Library/TeXShop/bin/platex2pdf-utf8
ありません。
 
このまんま動かそうとするとこんなエラーが出ます。
 

f:id:eight-seven:20131020002857p:plain

 

 

このエラーが仰るとおりパスが正しく設定されてません

...というか元のファイルの名前が間違っています。

 

なので、元のファイルの名前を書き替えてしまいます。

 

学籍番号/Library(もしくはライブラリ)/TeXShop/bin/
のディレクトリの中に、こんなコマンド

ファイルがあるはずです。

 
 
f:id:eight-seven:20131020003339p:plain
 

その名も、「pltex2pdf-utf8」です。
aが抜け落ちてますね。
 
ということでこの名前を書き替えます。
 
「pltex2pdf-utf8」→「platex2pdf-utf8」
コンソールからやってもよし、Finderから変えちゃってもよし。
 
多分これで動く人は結構いるのでは。
それでも止まるようであれば、使われているepsファイル(TeXで扱われる画像ファイル。TeXファイルと同じディレクトリにあります。)を日本語から英文字にするとなんとかなるみたいです。
その場合はファイル名だけでなく、TeXファイルの中の名前も変えてください。
 
 
2.X11をインストールしていたため、必要なライブラリファイルが移動されていた
 
で、困ったことに1をやっても別の問題が現れるケースがあるんですね。
 
それは「画像(epsファイル)付きのTeXファイルをpdfに出力しようとした時」に起きます。
 
...と思ってあの時を再現しようと思ったら無理あったので手順だけ説明します。
 

f:id:eight-seven:20131020005721p:plain

finderで検索欄に「libpng12.0.dylib」を入れて検索をします。
画像だと2つファイル出てますけど、実際は1つしか出ません。
これをコピーして、
Macintosh HD/opt/local/lib(finderから辿ってください!)に張り付けます。
こんだけで動くはずです。 多分。
 
 
というような感じです。
づがれだ。
 
このごろ欲しいCDが多過ぎてオサイフ大ダメージ受けてます。
Sonic CoasterPopとかYMCKの新譜とか前期capsuleとか相対性理論の新譜とかとかとか。

 寝よ

Mac OSX SnowLeopardXcode 3.2.6 C++でのLeap Motionの環境構築

 

自分のための忘備録。

そもそもがSnowLeopardが推奨環境じゃないので、多分参考になるのはごくわずかな人

なんだろうなぁとか考えてますが、まあ忘れないようにと書いておきます。

 

Xcodeの設定画面がver 4.〜とver.3〜では全く違っていたので、

そこだけです。実際のところ。

 

さて、順番を一通り書いていきます。

f:id:eight-seven:20130913233858p:plain

プロジェクトの作成はコマンドラインツールで。

名前は今回は「leapDemo」とします。

 

f:id:eight-seven:20130913234003p:plain

 

プロジェクトを作成できたら、/LeapSDK/libにある、「libLeap.dylib」を

Xcodeの「グループとファイル」の欄にドラッグ&ドロップします。

 

で、このdylibのパスを環境変数として書き込まなければならないんですが、

 その場所がイマイチ分かりづらくて...

 

f:id:eight-seven:20130913234401p:plain

 実行可能ファイルの中身を右クリックして「情報を見る」にあるんですね。

これで1時間近くも迷ってました... ははは

 

f:id:eight-seven:20130929194640p:plain

ここは、下の欄の「環境に設定される変数」に

名前を「DYLD_LIBRARY_PATH」として、値は先ほど入れたlibLeap.dylibのあるディレクトリのパスを入れればよいです。

 (注!9/29追記・変更)

変更するまでは、libLeap.dylibのパスを指定してました。 つまり /Users/k10105kk/Documents/LeapSDK/lib/libLeap.dylib です。

正しくは/Users/k10105kk/Documents/LeapSDK/lib です。

あのままだとビルド時に下記のエラーが出ます。

dyld: Library not loaded: @loader_path/libLeap.dylib

  Referenced from: /Users/k10105kk/Documents/workspace/kenshouLeap/build/Debug/kenshouLeap

  Reason: no suitable image found.  Did find:

/Users/k10105kk/Documents/LeapSDK/lib/libLeap.dylib/libLeap.dylib: stat() failed with errno=20

 

フォーラム見てみると困ってらっしゃる方とかいらしてたみたいなので、念のため。

このエラーが出てたら一度DYLD_LIBRARY_PATHの値をチェックすると良いかもしれません。

 

f:id:eight-seven:20130913234625p:plain

あとは/LeapSDK/include/leap.hを入れて、

 

 

f:id:eight-seven:20130913234719p:plain

 

プロジェクトの情報を開いて、

 

 

f:id:eight-seven:20130913234751p:plain

 

ユーザー定義の設定をします。

これがまた分かりにくいかったね。

 

f:id:eight-seven:20130913234858p:plain

 

んで、設定(名前)をLEAPSDK_PATHとして、値にはLeapSDKのパスを指定。

f:id:eight-seven:20130913235038p:plain

そして、ヘッダ検索パスには、$(LEADSDK_PATH)/include を、

 

f:id:eight-seven:20130913235129p:plain

 

ライブラリ検索パスには $(LEADSDK_PATH)/lib を入力して準備バッチリ。

 

 

あとはmain.cppにソースコードを書き込んで実行すれば動きます。

LeapSDK/samples/Sample.cpp  をコピペするなりすれば大丈夫かと。

 

 

多分またわかんなくなったりしたら書き直すと思います。多分。

さて、モチベも戻ったので進捗の資料作りに戻らねば...

横置きLeapMotion

なんとかいけました!

どうやらLeapmotionは、USB接続したその時に、

自動的に位置の初期設定を行っているようで、

f:id:eight-seven:20130723235131j:plain

 

こういう状態にしたままUSB接続にするとうまくいくようです。

 

シュミレータだとXYZ軸が実際と異なるためか、

方向が違って見えますが、まあそうでしょう。

その都度座標データに合わせればいいか。

Leap Motionを手話認識として使う為には。

現在卒業研究で手話認識の研究を進めています。

たまたま紹介でこの機器を紹介してもらったのですが、

生憎時期が合わず、研究費では買わず、個人的に扱うことにしました。

 

まあ趣味で楽しもうかなぁ...って思ったんですが、これが意外と精度がよかったんですね。

 

f:id:eight-seven:20130723004332j:plain

 

ちゃんと指先まで捉えてくれます。

さらに手の裏表や、指の動き(スワイプ)も認識してくれるので、これはもしかしたら本当に研究材料として使えるかもしれない!

 

と思ったんですが、それがどうもうまくいかないわけでして。

結局趣味の範囲でやってることで、研究室の進捗報告でも発表できなく、お流れになってしまう可能性大なのでざざっとこっちで書いてしまおうか。

 

 

f:id:eight-seven:20130723232721j:plain

 

 

下から撮っているという特性上、LEAP Motionはこういう手の形はしっかりとくれます。

LEAP Motion機器と平行にあるような向きの形です。

 

f:id:eight-seven:20130723233337p:plain

セッティングのビジュアライザを使うとこんな感じ。  指先までクッキリです。

 

この手の形を縦にしてみましょう。

 

f:id:eight-seven:20130723232728j:plain

 

こんな感じ。 今度はモニターに平行になる形です。

 

すると...

 

f:id:eight-seven:20130723233410p:plain

んー、なかなかいい精度は出てこないようです...

手の裏表は正確に捉えているようですが...。

 

実は手話はこの手の向きの形の単語が多いです。

つまり、LEAP Motion機器と垂直の位置にある形です。

もちろん、前者のように、平行になる形の手の形もあるのですが... むしろどちらも捉えられなければ。

 

また、手話の一種である、指のポーズで文字1文字を表す、指文字も、多くがこの形です。

しかし、自分が調べた中では、指文字はほとんどがLEAP Motion機器に垂直の位置の手の形がほとんどです。

手話のようにオールマイティである必要性は少ないので、もしかしたら有用性はあるのかも...?

動きが必要である「の」や「ん」も捉えられるので、うまくいけばかなり精度がいいものが作れるのかもしれません。問題は指文字をどうつかうのーってところなんですが。

 

んー、しかしLEAP Motionを置く位置を変えたとして、

キャリブレーションの設定はいかにすればいいのか。

 

f:id:eight-seven:20130723235131j:plain

こうなればいいのかな...

 

はてさて。どうすればいいのやら。

 

もしかしたら自分の動作環境(Mac OS X Snow Lepard<推奨環境対象外>)なのが悪いのかもしれませんが、

記憶が正しければ、研究室のPC(Windows 7Core i7<推奨環境対象>)

でも同じだったような感じだったと思います。

 

 

んー、どうしましょ。

Leapmotionが家にやってきた!

やって参りました。

ドライバもインストールできるようになったので、いろいろと試しています。

Leap Motion

結局研究の対象にしようか迷ったまんま、注文だけはしてそのままにしてたけど

そろそろ出荷スタートらしい。

 

 

amazon で買うと13800円かぁ。

公式で買うと送料込で99ドルくらいだったかなぁと思って計算してみたけど、

そんなに違うんだ...

 

個人的にやってみようと思ってSDKもあらかじめダウンロードしてみました。

ちょっとだけ楽しみ。