Take’s diary

Macとマイコンに関すること--ワクワクの製作日記

Maker Faire Tokyo 2017 に出ます!!(その2)

iPhone側のソースをビルドして動かせる様になるには、

 かなりつまづくことも多いかと思うので、先週からアプリストア登録作業を行うことにしました。メイカーフェア( Maker Faire Tokyo 2017)に展示するので当然無料配布です。

           f:id:TAKEsan:20170613224819j:plain

 と言っても、iPhone単独では画像が再現できないことと、私はまだ1度も登録作業を行ったことがないので、今のところなんとも言えないのですが.......。同じ様なこと「アプリ単独では、実行が確認できないアプリのアプリストア登録??」を考えている方もいると思うので、申請の過程をメモすることにしました。アプリストア登録完了が、Maker Faire Tokyoに間に合わなかったらすいません。ただその場合は、実機テスト用のインストール説明を書くつもりです。

 まず、本申請の前のテストフライトまでの要点を説明します。OpenFrameWorksを使ったアプリの登録紹介記事がほとんどないので、特に引っかかった点などをまとめてみます。

 今回の基本的な登録の方法は、次のブログを参考にさせていただきました。
痒いところに手が届く素晴らしい記事が満載です。テストフライトもこの記事に沿って実行していくとバッチリ!!

OpenFrameWorks(以降OF)上での問題点

標準UIの問題

 OFでiOSのGUIを使うため、基本的には多摩美の田所先生の記事を参考にさせていただきましたが、iOSがバージョンアップしているので、そのままではすんなり実行できません。以下iOS特有のUI環境構築手段です。

 newfile->iOS->Source->Cocoa touch Class->Next->Class名変更、サブクラスはそのまま、Also creat XLB fileにチェック。3つのファイル(この場合EPSView.h,EPSView.m,EPSView.xlb)は自動で作成されます。そしてxxxx.m の拡張子を .mm に変更。

f:id:TAKEsan:20170613221707p:plain

 一番厄介なのは、iOSのUI環境に関して、OFでも、ビジュアルCを使用しなければない点です。(自動作成されるxxxx.h,xxxx.m2つのファイル)他の言語に慣れている者にとっては何もかも勝手が違うので、この部分を極力少なく記述するのが一番無難な手段だと思われました。今回のアプリは、画像上の位置を取得する必要がありますが、通常のiOSでは、UIのタップイベントに焦点を当てているため、画面の座標取得方法がかなり厄介です。なので、UIを最小限にまとめてディバイスに合わせて縦方向に伸び縮みさせる手段を取っています。

f:id:TAKEsan:20170613205419p:plain

 ボタン等のリンク方法は田所先生の記事

iOSのGUIをopenFrameworksのプロジェクトに追加する | yoppa org

を参考にしてください。ただ、setup()内の初期設定は現状少し変更の必要があります。以下の様にします。EPSViewは固有値です。

    gui = [[EPSView alloc] initWithNibName:@"EPSView" bundle:nil];

    [ofxiOSGetGLParentView() addSubview:gui.view];

標準OSCアドオン応用方法の改善

 過去の記事に書いていますが、iPhoneとWROOM02の通信手段はUDPです。これを使ったOSCという通信プロトコルを使って、画像配信を実現しています。たまたまOFと、WROOM02にライブラリが存在していたので、比較的簡単に双方向通信が実現できました。OSCは、音響機器の通信制御用に開発されたものなので、画像通信にはあまり適していません。今回はプログラムの作成が簡単なOSCの文字列送信を使い、LEPTON1の低解像バイナリデータを余計な変換なしで送っています。通常OSCでバイナリデータを送る場合は一旦文字に変更する必要がありますが、それでは単純にデータ量が4倍近くなるため、WROOM02の処理能力では問題が出て来ます。今回の画像データは、256階調のグレースケールであること(ASCIIコード内で収まる)をうまく利用して、一番問題となるデータ上の、ゼロを1に変更することでなんとかなってます。さらにLEPTONのX方向1行分のデータ164ビットを、String処理の限界に近い5行分送ることで、動画スピードを大幅に改善させました。

位置情報の取得

 これはplistへの追加と、OFの標準関数を使えば簡単にデータを読み取ることができました。実現するまで時間がかかりましたが、最終的にはOFのサンプルソースにヒントがありました。----->CoreLocationExample

plistにLocationを追加して(今回は2つ)

f:id:TAKEsan:20170613211615p:plain

ofApp.h

    ofxiOSCoreLocation * coreLocation; を追加。

ofApp.mm

    coreLocation->getLatitude()

    coreLocation->getLongitude() で緯度経度の値を取り出せます。

動画の保存

 今回は、OF唯一のiOS動画保存addonを使用しています。内部的にはFBOを使って動画保存を実現している様です。ただ、iPhoneのフォトライブラリフォルダに保存しないと使い物にならないので、仕方なくビジュアルCでコードを記述しています。とにかくこれ(ofxiOSVideoWriter)を作った方には感謝しか言葉がありません。

GitHub - julapy/ofxiOSVideoWriter: ofxiOSVideoWriter allows to screen record OF applications on iOS. (still very much a work in progress)

 ただし今回はofVbo(3D画像処理に使用)がうまく表示できないため、main.cppglesVersion をES1に指定する必要がありますが、実行時エラーが出るようです。

    [ error ] ofShader: sorry, it looks like you can't run 'ARB_shader_objects'

    [ error ] ofShader: please check the capabilites of your graphics card:       

    他。

アプリが中断することはないので、無視して良いと思います。また、カメラロールに保存させるために

ofxiOSVideoWriter/src/ofxiOSVideoWriter.mm の中のfinishRecording()関数を以下の様に変更する必要があります。

 

void ofxiOSVideoWriter::finishRecording() {

    if((videoWriter == nil) ||

       [videoWriter isWriting] == NO) {

        return;

    }

    [videoWriter finishRecording];

    killTextureCache();

    //****************************by Takesan ******************************************

    //ローカルフォルダに保存してから、カメラロールにセーブする。

    NSString * docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    NSString * docVideoPath = [docPath stringByAppendingPathComponent:@"/video.mov"];

    UISaveVideoAtPathToSavedPhotosAlbum(docVideoPath,nil,nil,nil);

    //********************************************************************************

}

 

さらにplistに2項目追加する必要がありました。

f:id:TAKEsan:20170622123539p:plain

動画の表示方法

 今までは、画像上で各ピクセルに対応した小さな円を書いて画像を表示していたのですが、あまりにも遅く、非力なWROOM02から送られてくる画像データでも、4倍補間と円の描画に手間取り、iPhone側の処理が間に合いませんでした。今回は、LEPTON1の3D画像を実現させた時に使っている図形描画が非常に早いことに目を付け、高さ方向を0にして2D通常画像を表示させています。円描画に比べると詳細感は出ませんが、スピードを優先させました。ピクセル中に黒を背景に入れると全体が引き締まり、にじみが出にくいのですがが、今回使っているVboでピクセルを小さくするとモアレが出る様です。今回はモアレが発生するギリギリの大きさで、各ディバイスの動画表示を調整しています。ただこれだけでは惜しいので特別にロゴを利用したボタンで詳細感を味わえる様にしています。

          f:id:TAKEsan:20170613214228p:plain

各画素を円にして背景を黒にすると、画像が引き締まり詳細感(にじみが出にくい)が出るが、表示が遅くなる。

テザリング中のiPhoneとWROOM02の電波干渉問題

 今回はテザリングを利用して通信していますが、不思議なことに定期的・時間帯によって画像が乱れました。原因が暫く掴めず、この部分でも10日近く調整を行いましたが、結局はiPhone側のBlueTooth(特にApplewatch使用時)とGPS原因だとわかりました。データ配信量の多いLEPTON3の場合は、これが顕著で決定的に乱れた画像になりますが、今回のLEPTON1ではさほど問題となりません。したがって、より綺麗な画像を求めるなら、両方をiPhone側でOFFにすることをお勧めします。今回は位置情報の同時録画が必要になる場面があると考え、位置情報をONにした場合、位置情報を表示させる様にしています。

アプリ名称の変更

 OFではプロジェクト名がアプリの名称になり、このアプリ名称変更について誰しも悩むところですが、1箇所だけの修正でなんとかなりました。

f:id:TAKEsan:20170613215516p:plain

             Plist のBundle display nameを変更する!!

iOSのソースは

 コメントを含め、内容を整えた上でメーカーフェアー開催までに公開します。

テストフライトエラー対策

アイコン登録でのエラー

 各ディバイスのアイコンが全て存在しないとエラーになります。

f:id:TAKEsan:20170613220548p:plain

 OFではアイコン表示に特殊な処理をしているので、修正方法がなかなか見つけられませんでしたが、基本は至って簡単でした。参考にさせていただいた記事は、

iOSな日々: iOS7:アイコンサイズの追加対応について

1種類のアイコン画像を作って各サイズに変換。それぞれ大きさの違う画像をMedia.xcassetsに貼り付けるだけでした。

f:id:TAKEsan:20170613220606p:plain

 さらにplistのアイコン名称は全て消す必要があります、ですから一般的にWEBで紹介されているアイコンの追加方法ではうまくいきませんでした

オリエンテーションの修正部分

 傾けるとUIが追従する機能ですが、これも正しく設定しないとエラーになります。General-->Deployment info-->Devise Orientation部分を下図のように全てONにするか、

f:id:TAKEsan:20170613220555p:plain

 下図の様にすることが必要。今回のアプリはiPhoneの傾きに追従すると、ドローンの操作中めまぐるしく画面が回転する可能性があるため、下図のようにUI追従を外しました。

f:id:TAKEsan:20170613221311p:plain

          Devise OrientationはPortaitのみON、Status Bar StyleはRepuires full screenのみON

ディバイス対応方法

 基本的にOFではdraw()内で座標を指定する数値を変更するだけでOKですが、この時、OF標準関数でディバイス名を確認する手段があります。今回はそれを使っています。

            string devtype= ofxiOSGetDeviceRevision();

 今回のアプリは、iPhone6,6s,7  iPhone plus 6,6s,7  iPhone SE   iPad=5th generation以降(mini含む)に対応しています。

 以上の対応で、テストフライトは一応成功しました。共同開発者wiwaoさんに手伝っていただいて、5機種のインストールと表示確認を行い、バグッフィックス終了。いよいよ明日からアプリストア登録作業開始です!!。

WROOM02ソースについて

SPI読み取り部分の改善と単純化

 今回は標準SPIライブラリを使い、少し中途半端なクロック数にしていますが、この設定が最も安定していました。またバイト単位の読み込み関数では、スピードが間に合わないため、LEPTON1データの1行分を全部読み込む処理を行っています。またCS信号のON OFFスピードが決め手となるため、この方のブログ

ESP8266 ( ESP-WROOM-02 ) SPI 通信の高速化に挑戦 | mgo-tec電子工作

を参考にできるだけCS信号の切り替えスピードを速めています。

Yield(),Delay(),などの使い分け

 WROOM02のArduino IDEを使う上で一番厄介な部分です。WIFIやSPIを使う場合これを適度に散りばめないと、yield()やdelay()時間内でWIFI処理を行っている関係上、頻繁にリセットする原因になります。今回は通常考えられないところにyield()やdelay()が入っていますが、各行に入れたり抜いたりして調整した結果がこの位置になっています。今回はLEPTONの上限10FPSが達成し、リセットしないところが最適位置ということになります。色々なブログに対策方法が載っていますが、繰り返し文以外にもどうやらプログラム内容によって確実に必要な場合があり、決定的な決め手がないことにご注意ください。現状での最終的な調整方法は、コンパイルを繰り返し、リセットを起こさない最適値・最適位置を探すだけです。この部分だけでもLEPTON3版開発も含めて、合計1ヶ月間は潰された唯一のアイマイで厄介な所でした。

ダイナミックレンジ変更について。

 LEPTON1には14bit階調のグレースケールデータを出力するモードと、8bit 256階調のカラーデータを出力するモードがあります。カラースケールモードを利用すれば画像を再現する上で最も簡単なのですが、単純にデータ量が3倍になる点とセンサーが感知した温度を計算することが難しいので、今回は不採用。したがって、今回は14bitグレースケール出力を採用しました。ただし、これを採用すると、画像表示上8bitデータに変換する必要があり、確実に階調が落ちます。また、例えば火などが一部に入った画像を確認する時など、温度差がありすぎて背景が消えてしまいます。これらを避けるため測定温度範囲を調整できる様にして256階調表示の欠点を改善しています。 

WROOM側のソース他

 下に提示したソースをWROOM02にインストールし、iPhone側アプリを立ち上げることで、最良のスピードかつ、iPhone側で指定した温度の計測や、先に書いたダイナミックレンジの調整ができる様になります 。今回私たちが作成するボードに頼らなくてもWROOM02市販基盤で実現が可能です。たった300行足らずののソースで、50m以上離れていても動画が鮮明にが再現できて、付加価値情報も取得できる点は、驚くべきところだと思います(WROOM02が...です)。

LEPTON1とWROOM02の接続方法

 以下の配線は、スイッチサイエンス版ESPr Developerを使用した場合です。

   f:id:TAKEsan:20170622112807j:plain

             LEPTON基盤   ESPr Developer

            CS----------> IO15

            MOSI-------> IO13

            MISO-------> IO12

            CLK -------> IO14

            GND-------> GND 

            VIN---------> 3V3

            SDA--------> IO4

            SCL--------> IO5

wiwaoさん設計ボードの場合

 今回の最新試作基盤です(共同開発者wiwaoさん設計)。当然ながらLEPTON基盤にダイレクト接続可能。写真ではLEPTON3を接続しています。

    f:id:TAKEsan:20170622113956j:plain

必要部品は、wiwaoさん設計ボード(キットとしてMaker Faireで販売予定)LEPTON1(シャッター付き)、LEPTONブレイクアウトボード、Lipo電池またはUSB電源、USBシリアルアダプタ、スルーホール用テストワイヤー(マルツパーツ)です。

f:id:TAKEsan:20170624231406j:plain

ピンヘッダを取り付けると邪魔になるので、基盤に直接接続できるスルーホール用テストワイヤーを使います。

f:id:TAKEsan:20170624231425j:plain

配線状況です。Arduinoソースをインストールするときは、この状態でスイッチをONにします。インストール完了後ワイヤーを外せばOK。どこにでも持ち運び自由です。

f:id:TAKEsan:20170624231348j:plain

Arduino IDE について

 ESP8266 Arduino IDEのバージョンは2.2.0を設定してください。最新版の場合Delay()やYield()、SPIの再調整が必要のようです。

     f:id:TAKEsan:20170623095436p:plain

 ESP8266の設定は以下の通りです。Flash FrepuencyとCPU Frepuencyのスピードを上げたいところですがうまくいきませんでした。また、Upload Speed も115200推奨です。これ以上に設定すると、バイナリコードの転送がうまく行かない場合があります。

      f:id:TAKEsan:20170623095443p:plain

WROOM02ソース

 SSID、パスワード、必要ならポート番号を変更(localPortはoutPort+1として下さい。変更した場合は、iPhone側でも変更が必要です)、基板に合わせてLEDのGPIO番号を最初の方で設定してから、ビルド転送して下さい。変更部分は以下の通り4箇所です。

//#######################################################################
//******1.OSCライブラリを以下よりダウンロードして所定の場所にコピーしてください*******
//     https://github.com/sandeepmistry/esp8266-OSC
//========================================================================
//*************** 2.自分の環境に合わせて以下の設定を変更してください **************
//========================================================================
#define SSID_X "XXXX-iPhone" //iPhone
#define PASS_X "99999999999" //iPhone
#define IP_X 172,20,10,1 //iPhone "なし,仕切り。テザリングはこのアドレス固定

//#define SSID_X "YYY-iPad" //iPad
//#define PASS_X "88888888" //iPad
//#define IP_X 172,20,10,1 //iPad "なし,仕切り。テザリングはこのアドレス固定

//#define SSID_X "router ssid" //WiFiを使用する場合
//#define PASS_X "router pass" //WiFi
//#define IP_X 192,168,XX,XX //WiFi "なし,仕切り
//========================================================================
//***************** 3.ポート番号を設定してください ****************************
//========================================================================
const unsigned int outPort = 8090; // 送信は標準で8090 iPhone側は8091
const unsigned int localPort = 8091; // 受信は標準で8091 iPhone側は8090
//========================================================================
//***************** 4.LEDのGPIOピンを設定してください ************************
#define LEDpin 16
//========================================================================

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
#include <OSCData.h>
#include <OSCMatch.h>
#include <OSCMessage.h>
#include <Wire.h>

//iPhoneテザリングLAN設定
char ssid[] = SSID_X; // 無線ランのSSID名称:文字列。
char pass[] = PASS_X; //同上 password
const IPAddress outIp(IP_X); //macの場合

//**************スピード調整******************
//2017/3/14 安定板 スピードは以下に決まり。5行まとめて送信版
#define CLOCK_TAKE 11000000
#define DELAY_READ1 6 //6 1回目の読み取り
//******************************************
OSCErrorCode error;
//************LEPTON コマンド用***************
#define ADDRESS (0x2A)
#define AGC (0x01)
#define SYS (0x02)
#define VID (0x03)
#define OEM (0x08)
#define GET (0x00)
#define SET (0x01)
#define RUN (0x02)
//**************CS信号高速化用*****************
#define PIN_OUT *(volatile uint32_t *)0x60000300
#define PIN_ENABLE *(volatile uint32_t *)0x6000030C
#define PIN_15 *(volatile uint32_t *)0x60000364
//******************************************
WiFiUDP Udp;
char zz[81*5+1]; //5LINE分一挙に送るため Stringの限界450程度
unsigned int min = 65536;
unsigned int max = 0;
float diff;
char ip_ESP[16];
static uint8_t lepton_image1[82*2*60];
int touchX = 39;
int touchY = 29;
//*************OSCアドレス********************
OSCMessage msg1("/minmax");
OSCMessage msg2("/img_8");
float sl_256=0.0f;
//################################# 初期設定 ########################################
void setup()
{
pinMode(LEDpin, OUTPUT);
Wire.begin();
Serial.begin(115200);
pinMode(2, OUTPUT); //使わないピンはOUTPUT

SPI.begin();
SPI.setClockDivider(0); //念のため
delay(1000);
SPI.setFrequency(CLOCK_TAKE); //SPIクロック設定

Serial.println("Wait!! Now SPI set up.........");
PIN_OUT = (1<<15);
PIN_ENABLE = (1<<15);
delay(500);
PIN_15 = 1; //LOW
delay(1000);
Serial.println("setup complete");
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);

while (WiFi.status() != WL_CONNECTED) {
digitalWrite(LEDpin, HIGH);
delay(50);
digitalWrite(LEDpin, LOW);
delay(50);
Serial.print(".");
}

digitalWrite(LEDpin, HIGH);
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
//ローカルipを文字列に変換moziretunihennkann
sprintf(ip_ESP, "%d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
Serial.println(ip_ESP);
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(Udp.localPort());
Serial.println("LEPTON START!!");
}
//################################# SPI データ 読み取りコマンド ########################################
void read_lepton_frame(void)
{
int i;
uint16_t data = 0x0f;
delay(DELAY_READ1); //********************************<-----肝心!! 6固定
while ((data & 0x0f) == 0x0f)
{
PIN_15 = 1; //LOW
SPI.transferBytes(0x0000,lepton_image1,164);
PIN_15 = 0; //High
data = (lepton_image1[0]<<8 | lepton_image1[1]);
}
for (int frame_number = 1; frame_number < 60; frame_number++){
PIN_15 = 1; //LOW
SPI.transferBytes(0x0000,&lepton_image1[frame_number*164],164);
PIN_15 = 0; //High
}
}
//#################################メーカーSDK i2C 操作コマンド########################################
void lepton_command(unsigned int moduleID, unsigned int commandID, unsigned int command)
{
byte error;
Wire.beginTransmission(ADDRESS);

// Command Register is a 16-bit register located at Register Address 0x0004
Wire.write(0x00);
Wire.write(0x04);

if (moduleID == 0x08) //OEM module ID
{
Wire.write(0x48);
}
else
{
Wire.write(moduleID & 0x0f);
}
Wire.write( ((commandID << 2 ) & 0xfc) | (command & 0x3));

error = Wire.endTransmission(); // stop transmitting
if (error != 0)
{
Serial.print("error=");
Serial.println(error);
}
}
//######################LEPTON SDK i2C 操作コマンド#############################
void set_reg(unsigned int reg)
{
byte error;
Wire.beginTransmission(ADDRESS); // transmit to device #4
Wire.write(reg >> 8 & 0xff);
Wire.write(reg & 0xff); // sends one byte

error = Wire.endTransmission(); // stop transmitting
if (error != 0)
{
Serial.print("error=");
Serial.println(error);
}
}
//######################LEPTON SDK i2C 操作コマンド#############################
int read_reg(unsigned int reg)
{
int reading = 0;
set_reg(reg);
Wire.requestFrom(ADDRESS, 2);
reading = Wire.read(); // receive high byte (overwrites previous reading)
reading = reading << 8; // shift high byte to be high 8 bits
reading |= Wire.read(); // receive low byte as lower 8 bits
return reading;
}
//######################LEPTON SDK i2C 操作コマンド#############################
int read_data()
{
int i;
int data;
int payload_length;

while (read_reg(0x2) & 0x01)
{
Serial.println("busy");
}
payload_length = read_reg(0x6);
Wire.requestFrom(ADDRESS, payload_length);
//set_reg(0x08);
for (i = 0; i < (payload_length / 2); i++)
{
data = Wire.read() << 8;
data |= Wire.read();
}
return data;
}
//############################# iPhone Touch XY #############################
void touch(OSCMessage &msg) {
float sli=sl_256;
touchX = msg.getInt(0);
touchY = msg.getInt(1);
sl_256 = msg.getFloat(2);
if (sl_256 > 0.95 || sl_256 < -0.95) sl_256=sli;
}
//########################### メインルーチン ###################################
void loop()
{
int p,tempXY1;
int reading = 0;
String debugString;
int col;
float value_min,value_max,tempXY;
//**********Osc Receive**********
OSCBundle bundle;
int size = Udp.parsePacket();
if (size > 0) {
while (size--) {
bundle.fill(Udp.read());
}
if (!bundle.hasError()) {
bundle.dispatch("/tmpXY",touch);
} else Serial.print("error!!");
}
//********** 温度計算 **********
min = 65536;
max = 0;
read_lepton_frame();
yield();
for (int frame_number = 0; frame_number < 60; frame_number++){
for (int i = 2; i < 82; i++)
{
p=(lepton_image1[frame_number*164+2*i] <<8 | lepton_image1[frame_number*164+2*i+1]);
if(frame_number==touchY && i-2==touchX) tempXY1=p; //iPhoneをタッチしたアドレスの温度データ
if(p < min) min = p;
if(p > max) max = p;
}
}
int rrr=(int)(max - min)*(1.0f-abs(sl_256)); //高温側を256等分 iPhoneスライダーに連動 標準は0。最高で0.9
diff = rrr/ 256.0f;
rrr=(float)(max - min)*sl_256; //開始低温度側温度
lepton_command(SYS, 0x14 >> 2 , GET); //ondo : 0x14 = chip 0x10 = aux
float aux=read_data() ;
ESP.wdtFeed(); //大事!!

if(sl_256>0) min=(float)min+rrr; //最低温度表示も開始温度に連動させる
if(sl_256<0) {max=(float)max+rrr;} //最高温度表示も開始温度に連動させる minはそのまま

float fpatemp_f =- 472.22999f + (aux/ 100.0f) * 1.8f - 459.67f;
value_min = (((0.05872 * (float)min + fpatemp_f)) - 32.0f) / 1.8f;
value_max = (((0.05872 * (float)max + fpatemp_f)) - 32.0f) / 1.8f;
tempXY = (((0.05872 * (float)tempXY1 + fpatemp_f)) - 32.0f) / 1.8f;
//*****************Send osc data*****************
msg1.add(value_min).add(value_max).add(tempXY).add(ip_ESP);
if(Udp.beginPacket(outIp, outPort)==1)
{
msg1.send(Udp);
Udp.endPacket();
msg1.empty();
}
yield();
//***********************************************
for (int frame_number = 0; frame_number < 60; frame_number+=5){
for (int ii = 0; ii< 5 ; ii++)
{
for (int i = 2; i < 82; i++)
{
int ax=(frame_number+ii)*164+2*i;
col = (int)((lepton_image1[ax]<<8 | lepton_image1[ax+1]) - min)/ diff; //(int)を入れないと符号無し演算になる!!1; //=0
if(col <= 0) col = 1; //=0
if(col > 255) col = 255;
zz[ii*81+i-1]=col;
yield(); //これがデータ安定の決め手
}
zz[ii*81]=frame_number+ii;
if(frame_number==0) zz[0]=0x3c; //=0 nara 0x3c tosuru.
}
zz[81*5+1]='\0'; //String の最終処理
//*****************Send osc data************
msg2.add(zz );
if( Udp.beginPacket(outIp, outPort)==1)
{
msg2.send(Udp);
Udp.endPacket();
msg2.empty();
}
//******************************************
yield(); //絶対必要!!
}
}

                                                      では、また。 

 

 

メイカーフェア東京2017に出ます!!

あー長かった。Maker Faire Tokyo 2017 の承認通知が来ました。

f:id:TAKEsan:20170603223845j:plain

  このブログをきっかけに知り合ったwiwaoさんと2人で、今年のメイカーフェア東京に参加申請することになった経緯は前回書きました。トイドローンに取り付けたLEPTONサーモカメラ画像をiPhoneで確認。LEPTON1動画の大幅なスピードアップだけではなく、その4倍素数の多いLEPTON3でもWROOM02で画像配信を実現させようというプロジェクトです。WROOM02専用ボードとトイドローンへの実装はwiwaoさん。ソフト全般が私です。Jetson TX2はあくまでもディープラーニング応用例に使うだけで、基本はLEPTON+WROOM02+iPhoneがあればテザリングで画像が再現されます

f:id:TAKEsan:20170604131934p:plain

        【今回使うモノ】

  

       【組み合わせると~~~~~~~。】

       実際にLEPTON1+EROOM02をトイドローンに取り付け、今回作ったiPhone側ソフトで

       実際に録画した画像!! 

f:id:TAKEsan:20170604134903p:plain         【iPhoneではこんなことが.....】

      LEPTON1の画素 80X60を317X237(約4倍)に補間。とてもなめらか!!

 

f:id:TAKEsan:20170603214339p:plain       カラーを白黒に変えると、より立体的にリアルに表示される!!f:id:TAKEsan:20170603214333p:plain           3D表示画面。温度差が立体的に表示される!!

         【これが低解像度画像なんだろうか.....】

 去年の2月.....

 もともと赤外線センサーに惹かれるものがあって、OMRON D6TとかMLX90621を使って自分の好きなものを作っていたのですが、LEPTON1を手にした時、確かに衝撃的なセンサーではありました。画素数が6X6とか16X4というレベルではなく、一挙に80x60。この道のプロにとっては、こんなに荒い画像で、何ができるんだ的なものがあるとは思いますが。なにせ当方「4X4を目一杯の補間でなんとか実用的に使おう!!」から始まってるわけですから、それもPiで制御できるなんてワクワクワクでした。ただ熱も治ってから、TX1という魅力的な機器に遭遇。デープラーニングにうつつを抜かしている時、wiwaoさんから過去記事についての問い合わせがあったことで、再度WROOM02とLEPTON1赤外線センサーに目覚めてしまいました。wiwaoさんの提案はトイドローンにこのセットをつけたら面白いんじゃないか?。消費電力も低いし.....。的な。

 wiwaoさんからの情報や私自身の経験から使ってみてわかったのですが、このセンサータフっ。完全防水。振動にもビクともしない。挙げ句の果てボードごと+−を間違っても煙を上げません(こんなこと絶対しないように!!)。これにPIより明らか非力なWROOM02で、Pi並みの動画スピードを達成するってことに二人ともこだわり抜いて、作り直し始めたのが今年の2月ごろでした。MFT2017の出展締め切りまでに、サンプル基板とトイドローンへの実装成功。動画も満足なスピードに達成したので応募することにしました。

 思えばあの頃は....

 まだまだ、画面が乱れたり、画像が遅かったりしていました。

                    

             去年まではこんなに動画スピードが遅かった!!。画像は

             当初Macで再現していました。 

 ここ数ヶ月、WEB上でトイドローンにつけたLETONサーモセンサーからの画像配信プロジェクト記事をたくさん見ました。LEPTON側が小さくても受信側に大袈裟な機器が必要とか、動画スピードが異常に早く明らかに合成画像とか、ドローンに接続できても画像配信は搭載されたCPU任せで、画像受信ができないとか。

 トイドローンに載せるには、Piじゃ無理なんです。あまりにも電池容量が少なすぎる。WROOM02じゃなきゃ!!。低消費電力と軽量化により結果的にあらゆる用途で、赤外線カメラの使用が可能になることになりました。

 3ヶ月間格闘の日々。

 LEPTON1センサーのデータ垂れ流しの使いにくさ、WROOMの遅さ、WiFiの限界、WROOMを改良してもiPhone側の画像処理がこれに間に合わない(なんつったって4倍画像補間してる上に双方向通信してるんですから)、深刻なドローンとWROOM02の電波干渉問題、SPIのノイズ対策。これらを乗り越えてできたのが冒頭の動画です。おそらくWROOM02+LEPTON1では世界最速、多機能!!       

       実際録画機能を利用して作った画像。一瞬で3Dに切り替わったり、カラーを変えたり、

       ダイナミックレンジを調整したりできます。LEPTON1の動画配信スピードは、10FPS

       ですからLEPTON1の最大スピードが出ています。

 屋外でも50m以上このスピードで安定して画像再現します。未だかつてない(っと思っている)サーモカメラの誕生と相成りました。

iPhone側の画像処理は 

 OpenFrameWorksを使ってるんで、Mac、Windows、ANDROID、linux、全てのメジャーOSでWROOM02からのWiFi接続で画像データの応用が可能です。

  夜間監視カメラだろうが、漆黒の闇の中をドローンで操縦しようが、暗闇の対戦型ゲームだろうが、雪山の中の人命救助だろうが、恒温動物の認識だろうが.......。この世の中のありとあらゆるものに応用が可能なんです。80x60の画素の小ささは、大きな改革を実現させる要素を秘めていました。

  赤外線センサーカメラとディスプレイが一体化しているものなら、中央部のみの温度検出で良いかと思いますが、カメラが可動式で、定点観測もあり得るので、トーゼン画面の任意対象物に対する温度計測がiPhone側から確認できます。

 センサーデータは、256階調表示で画面ごとにその温度範囲が変化するため、例えばタバコの火を画面に入れると、突然背景が真っ暗になります。その逆でも同じ。市販のサーモカメラは、自動調整できるのですが、WROOM02では浮動小数点演算を使うと、極端にスピードが落ちます。さらに双方向通信が成り立たないとこの種の調整はできません。今回これも実現できました。f:id:TAKEsan:20170603235730p:plain

      タバコの火が入ると、周囲と温度差がありすぎるため一瞬で背景のコントラストが無くなる。

f:id:TAKEsan:20170603235735p:plain

右端のスライダーでコントラストを調整すると、背景がはっきりと表示されるようになる。カーソルの移動で、その部分の温度が確認できる。186!!

 画像録画機能も付いてます。3Dでも2DでもiPhoneと同じ品質で録画できて、メールで即配信できるんです。

今回は、

 今話題のJetson TX2で、持ち前のディープラーニング環境を最大限利用した人体検出も参考展示します。これはOFとTX1でTensor RTを実現した経験をもとに作成しました。 ディープラーニングですから、少しの工夫で赤外線画像であっても、標準学習済みデータで人体を認識できます。TX2はGPIOを使えるのはご存知の通りですが、SPIを使うにはカーネルの再コンパイルが必要。リスクを伴います。それに比べればOFを利用したOSC通信で画像再現ができるので、比較的簡単に実現できました。       

         WROOM02からWIFIで送られて来たデータを、TX2で再現。ついでに人体認識

          している様子。会場では何人くらい同時に認識できるでしょうか?

 そして.............LEPTON3。

 次なるとても難しい課題。そう、知る人ぞ知るLEPTON3を使った動画配信実現。160x120 の画像処理です。これが実際にできるんでしょうかWROOM02で???。

f:id:TAKEsan:20170604001835j:plain

                                                   超難関だったLEPTON3 

  PI3の1/10のメモリ。Pi Zeroと比較しても10倍以上スピードの劣るWROOM02で安定した動画配信と呼べる処理が可能?。何よりもシングルタスクだし....。今回は、これにも挑戦しています。ホントはほとんどできてるんですけど現在は最終調整段階なので、進行状況は次回の記事をお楽しみに。

なんか全体的にハデハデで、表現がイジョウで少し反省してる.....。TAKEsanより。

                                では、また。

 

 

 

 

 

 

 

 

Jetson TX2 ってどうなんだろ?

随分休んでしまいました。

 このブログをきっかけにwiwaoさんと知り合いになって、今年のメイカーフェアに参加申請することになりました。トイドローンに取り付けたLEPTONサーモカメラ画像をiPhoneで確認しようというものです。LEPTON1動画の大幅なスピードアップだけではなく、その4倍画素数の多いLEPTON3でもWROOM02で画像配信が実現できました。休んでいたのはこのため。審査が通ったらwiwaoさんと相談しながら随時このブログに紹介していきたいと思っています。とても面白いものになりましたので、乞うご期待!!。
              

                 TX2でサーモカメラを使った人体認識も展示予定

 

TX1の記事をたくさん書いてきたので、

 メーカーが2倍早くなったというTX2がどうなったのか、アメリカからすぐに取り寄せて試してみたかったのですが、日本国内発売を待つまでは、技適に通ってるかどうか判断できないので、ガマンしてました。

 正式に国内で販売開始されていたので、間髪入れず手配。すぐに自宅に届きました。現在は再入荷待ちのようです。

f:id:TAKEsan:20170508122623j:plain

 電源を入れればlinuxが起動されますが、このままでは何も入ってません。Jetpacをフルスペックで再インストーする必要ありです。再インストール方法は、去年の私の記事を参考にすればとりたてて問題ありませんでした。 

 技適は?....。

外箱に明記されてました。

f:id:TAKEsan:20170508122615j:plain

TX2の目玉は

 2スレッドのCPUが追加されて、2種類のCPUが合計6スレッドとして動くという、日本人が食いつきそうなフォルクスワーゲンTSIツインターボみたいなシステム!!。その他では内部SSDSRAMの拡張などが目玉です。

f:id:TAKEsan:20170508123413p:plain

          システムモニターを確認すると、CPUが6つもある!!

 でも、使って見てOSがまだ不安定気味。外付けSSDにはOSをインストールしないで(途方も無いインストールの時間的リスクが伴うので)単純にOSが安定するまで持っているSSDを外部記憶装置として使うことにしました。内部SSDが拡張されたことで、ある程度のライブラリをインストールしても、特に容量的な問題が起きません。頻繁に読み書きする必要のある開発環境等は外付けSSDで作業すれば、当面内部SSDの基本寿命にはほとんど影響がないと思います。

 ディープラーニングにおいてGPUのメモリはかなり重要な要素で、TX1では実行できない場面が数多くあったのですが、今回の基本メモリ8Gは大きな進歩です。(TX1、TX2とも基本メモリをCPUと共用しているのでこれが倍になったということは、よほど大きな画像やデータを使わない限りTX2で消化できる様になることを意味します)GTX1080でもGPUメモリは8Gなんですから。ただしGPUに関してはメモリ以外ハードにスペック上の進化がないので、基本性能の差は感じません。Pascal世代の最適化されたライブラリがまだ存在しないようです。これはメーカーの動向待ちです。

 今までTX1やUbuntuメインマシンで、様々なディープラーニングフレームワーク上っ面だけ試して見ましたが、それぞれ応用するには、かなりの学習時間が必要だと自分的には結論づけました。

 TX2でアマチュアがデープラーニングを応用するには、TensorRTと開発環境の一つであるOF(Openframeworks)が実現できて、メインマシンで学習環境(DIGITS)が実行可能なら、現時点ではほとんど問題ない様に思えます。OFでTensorRTが動けば、画像描画ソフトを作る上で、スピードの遅いPyCaffeをわざわざ使う場面が思い当たりません。

私が必要なTX2の環境構築は今までの作業経験から以下に絞られます。

  • OpenFrameWorksのインストー
  • TenterRT(jetson-infarens)のインストー
  • ZED ステレオカメラSDKのインストー
  • 念のため標準Caffeのインストー
  • OpenCVは新たにインストールしない。(プレインストールされるOpenCVTegra利用)

 これが実現できて、TX1より実行スピードが少しでも上がれば、現段階では必要十分なのですが、全て実現できました。

 CPUのスピードアップを実感するためには、TX1と同じようにhomeからsudo ./Jetson_clocks.shを実行します。

6個全てのCPUクロックが2.38GHzになりGPUクロックも最大になります。簡単なPythonのCPUテストを行うと。

      Intel Joule  12秒

      TX1     11.5秒(JETSON_CLOCKS実行)   

      TX2     8.3秒  (        〃     )

      iMac    4.7秒  (Intel Core  i7    3.4Mhz )

f:id:TAKEsan:20170508122614p:plain

上記の簡単なPYthonプログラムを使ってスピードテスト。あくまでも簡易的なテストですが、経験上1コアでのCPUスピードの目安がわかります。

となりました。TX1よりクロックスピードの差分くらいは確実に早いようですが、まだまだホストマシンからは差があるようです。ただしOFをインストールしてサンプルを実行するとホストマシンとほぼ遜色なくなります。これはGPUを含めたトータル性能で、iMacクラスと肩を並べるレベルになっていると見て良いかとは思います。ただメーカーの言っているTX1の2倍早くなったとは、どこを指してスピードが2倍なのかとてもでした。でも早くなったのでウレシイ....。メモリー関連なら2倍なのは理解できるんですが。

TensorRTライブラリサンプルは、

 JETPAC 3.0ではTensorRTはV1.0のままなので Jetson-inferenceサンプルをを実行させても、USB WEB Cameraを使う限り、各アプリのフレームレイトの改善はほとんど(1フレームくらいは上がる)ありません。ということはCPUのスピード向上分も改善されてません。メーカーは何を考えてるんでしょうね?売り込みの目玉部分のアピールができてませんでした。

 外付けWebCAMERAのビデオ番号が、

 またまた使いにくいvideo1になってしまいました。拡張ボードに付属するカメラがVideo0です。今までOpenCV等を利用してvideo0で動いていたソースはそのままだと画面が真っ暗になります。したがってプログラムソース上の設定を全て変更する必要があります。Linuxの上級者で、Video0と1をOS上で変更できる方は別ですが、リスクを伴うので、ソース側を変更するのが一番無難。ちなみにOFでは setup() の中に 

   vidGrabber.setDeviceID(1); を追加するだけです。

  (vidGrabbeはofVideoGrabberで変数宣言がしてあるものとする)

 拡張ボード付属のビデオカメラについては、大きな基盤の片隅に付いていて、移動が困難なので、実用性はゼロに近いと思ってるのは私だけでしょうか?あくまでもテスト用です。TX2のフォーラムでもこのカメラに固執する方がいますが、意味のないことだと思います。

 ZEDステレオカメラに関しては、

 TX2に対応できる様になってました。今まで外付けGPUのついたWINDOWSでしか実現しなかったZEDfuが現実的なスピードで動作できます。GPUクロックアップされたハードを使い切っているZEDのソフト開発者がすばらしいんでしょうね。この辺りにもメーカー側と真面目なサードパーティの温度差を感じます。ただ、TX2版のZEDfuはリアルタイムテクスチャー貼り付けは出来ていない様です。

f:id:TAKEsan:20170508122611p:plain

  ZEDはZEDfu(3Dモデル作成アプリ)が実行可能になった!!。上記写真はそれを実行させているところ。CPUは6コア全てを使用している。

 OpenFrameWorksのインストールは、

 Openframeworksは、前回インストールが成功したTX1版を利用してgruw3の再コンパイルだけで動いちゃいました。ソースをつけます。TX2でビルドしたアプリの安定感とスピードは、さすがにCPUのスピードが上がっただけのことはあり、文句のつけようがありません。

 前回の記事通りにインストールできます。一応TX1で動作確認済みのOFとTX2用にコンパイル済みglfwフォルダをダウンロード可能にしておきました。

of_v0.9.8.zip ------->TX1用のOpenframeworks

glfw.zip         ------->of_v0.9.8/libs の中のglfwを解凍したフォルダで入れ替え

(5/11  glfw.zipの中に余計なファイルが入ってました。glfw.zzzzフォルダは消してから入れ替えてください)

詳しいインストール方法は、以下のページの下の方を確認してください。

takesan.hatenablog.com

インストールできない場合は、コメントに書き込んでください。

TensorRTの応用は、

 jetson-infarensはここからダウンロードしてインストールします。

GitHub - dusty-nv/jetson-inference: Guide to deploying deep-learning inference networks and deep vision primitives with TensorRT and Jetson TX1/TX2.

問題なく動きました。説明も機能もかなり拡張された様です。

 jetson-infarensはTensorRT(16ビット浮動小数点に特化したJetsonに関するディープラーニング用のライブラリ)が実行できるNVIDIAが公開のデープラーニングの唯一の例題とライブラリ群です。これをOFで動かすことで手軽にディープラーニングが実現できます。以前TX1用に書いたOF上でTenter RTが動くソースが全て実行できましたので、興味のある方は以前の記事を確認してください。スピードは最大で30%程度上がっていました。これは単純にCPUスピードの差だけだと思われます。依然としてメーカー側で提示しているサンプルアプリと同じ動作ソースを実行すると、私の作ったものの方が表示スピード性能が良い様です。

f:id:TAKEsan:20170508122608p:plain

OFで以前作ったObject Detectを使って人体認識するソースを動かしているところ。TX2では11.2FPS出ている。(TX1では7.8FPSくらい)

 標準Caffeのインストールは

 JETSON-HACKSのスクリプトが一番簡単です。たった3行のコマンドとrun testだけで済んでしまいます。

www.jetsonhacks.com

内部的にTegraOpenCVを使っているので、事前にOpenCVのインストールが必要ありません。その他この記事の中に書いてありますが、

  • sudo nvpmodel -m 1 (Max-Q)
  • sudo nvpmodel -m 2 (Max-P)
  • sudo nvpmodel -m 0 (Max-N)

で、3種類のCPUクロックと消費電力が指定できるようで、 -m 0が最大になるようですが、このコマンドだけではjetson_clock.shとは異なりファンが回らないので、CPUの温度上昇には注意する必要があります。

 最後に、

 JetPac3.0は、去年の今頃のTX1の時の様にあまり安定していません。今後のバージョンアップで確実に良くなると思います。ただ、CPUを最高スペックに設定した後のUbuntuの使い勝手は前にも増してスルスルでした。TX1で完結するアプリを作る場合は、わざわざクロスコンパイル環境の構築は必要ない様です。

 

 

                      ということで今回はおしまい。

 

 

 

 

ESP32 + LEPTONサーモカメラで'3Dサーモグラフィー'を作る!!

なんでこんなことを思いついたんでしょう。

 最近、ZEDステレオカメラのソフトをかじっていて、画像の遠近をポイントクラウドで表現する参考プログラムを見ていたからなんです。

f:id:TAKEsan:20170221134238p:plain

ZEDステレオカメラのサンプルアプリ。右側がポイントクラウド。カメラからの距離が3Dで確認できる。

 温度分布をポイントクラウドで表現すれば、平面的な色で表現するよりぐっと認識しやすくなります。つまり一目で温度差が確認できるんじゃないか。ムフフフ。方針さえ決まれば、ワクワクの時間です。ZEDステレオカメラは、あくまでも詳細な距離測定が目玉ですから、コンピュータが表現しなくとも人間は物体の遠近を認識できるので、3Dにする意味をあまり感じませんが、これがLEPTONサーモカメラで測定した温度となるとどうか。

                                

こうなります。Z軸方向が測定した温度に対応しています。一応キーボード入力で、カラーマップの選択、ワイヤーフレームの有無、ポイント自体の大きさ変更が可能。サーモカメラで取り込んだデータの動きはどうでしょうか?。ポイントクラウドの操作はサクサクです。

f:id:TAKEsan:20170221143007j:plain

今回はESP32をLEPTONサーモカメラ(画像上部赤い袴をはいたPIカメラみたいなやつ)データ送信専用として使い、後ろのiMacでデータを受信。OpenFrameworksで加工して表示させました。

f:id:TAKEsan:20170221135555p:plain f:id:TAKEsan:20170221135610p:plain

       メガネ部分は温度が低くなるので。目の部分がえぐれてます。キモチ悪り〜

f:id:TAKEsan:20170221135608p:plain f:id:TAKEsan:20170221135604p:plain

 数年前Kinectで再現していたポイントクラウドとは別の意味で結構衝撃なのですが。私だけかな。

f:id:TAKEsan:20170221135601p:plain

当然ながら温度の高いところは山が高くなるわけで。うちのワンコを写してみたら目が飛び出てしまいました。それを見た本人(本犬)がキャンキャン騒ぐので掲載中止。

 この画像を見て、ESP32が鍵を握ってるなんて信じられます?。(複雑な処理は全てiMacですけど。)取得した画像の温度差がそのまま高低差で表現されます。

 実行させるには動画のフレームレートと解像度をできるだけ上げることが必須。

 元々は、WROOM02に表示機器をダイレクトに取り付けても、画像表示は実用レベルじゃないんじゃないか?という仮定のもと、LEPTONで読み取ったサーモグラフィー画像をWIFIとOSCを組み合わせて、iMaciPhoneに表示させてしまおうという発想でした。色々な条件が一致して、なんとかサーモグラフィーになりましたが、画像の荒さはしょうがないとして、スピードがいまいち。WROOM02の能力以外にも、私のソフト作成能力にも問題があるような....。

 そこで、今回は巷で噂の WROOM02の2倍は早いんじゃないかというESP32を使って、とりあえず今の私の実力でどんだけ早く画像が再現できるかも追求。

大まかな処理の流れは、

  1. LEPTON赤外線カメラから、SPIの垂れ流し信号をESP32で読み取る。
  2. 80x60の14bitグレースケール画像を256色すなわち8bitグレースケールに変更。ついでにセンサー温度、最高最低温度を摂氏に変換。
  3. 80個のグレースケールデータを1行ずつStringにして60回に分けてOSC送信
  4. ついでに読み取った温度もOSC送信。ここまではESP32で実行。
  5. MAC側OSCでデータを受け取り、グレースケールデータ60x80から317x237 に補間-->カラー化-->VBOで3D変換。
  6. VBO表示は自由に拡大縮小、回転できるが触ってるうちに場所がわからなくなるので、念のため読み取り画像の小さな表示もつけて....。

って感じです。今回はiPhoneでの画像再現ではなく、作成の簡単なiMacで動かしてみます。テストなのでOSC通信は、一方通行ESP32-->iMac だけにしました。

ESP32側

 以前WROOM02を使ったLEPTONの赤外線画像送信を試みました。今回は以前のカクカクスピードを改善する目的でESP32を採用。WROOM02のOSC送信プログラムがそのまま使えれば苦労しないのですが、そんな訳ありませんよね。

LEPTON+ESP32でのOSC通信を実現するには、以下の過程が必要です。

ESP32の入手

www.ebay.com

技適付き。ESP8266環境向上委員会 辻直弘さん情報 送料込み3,000円前後。7日で届きました。

色々情報がありますが、iMac上で以下のコマンドを入力するだけ。

mkdir -p ~/Documents/Arduino/hardware/espressif && \
cd ~/Documents/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32/tools/ && \
python get.py

 参考:MacでESP32のLチカ(Arduino IDE版) - Qiita

  • ESP8266 OSC 通信ライブラリダウンロード及び修正

OSCライブラリは以下から、お礼を言いながらダウンロード。ARDUINOのliblalyフォルダに入れる。ESP32の場合、このままではエラーになるので、以下の2点を修正。(やはりすんなり実行できない)

 https://github.com/CNMAT/OSC

  • OSCData.h 94行目以下のようにコメントを入れる。 
 #endif
  //OSCData (int32_t);
  #ifndef ESP8266
OSCData (int);
  oscData.c 
  • OSCData.c 30行付近 6行についてコメントを入れるか、消す。
  /*

  OSCData::OSCData(int32_t i){
  error = OSC_OK;
  type = 'i';
  bytes = 4;
  data.i = i;
  }

  */

 

  • SPI他

 SPIは 以前のWROOM02専用の特殊ライブラリではなく、ESP32 ARDUINO IDEの標準ライブラリを使用。以前とコマンド内容が違うので、やはりLEPTONから出力される信号の同期を取るのが、最大の難関でしたが、いつもの様にトライアンドゴー。コンパイルを100回以上繰り返してやっと繋げることができました。結果は、WIFIで信号を流している割には速度が良好。スピード的に理想に近いRaspberry PI環境でのLEPTON再生動画と、あまり変わらないものになりました。LEPTONの画像データはせいぜい9FPS程度とのこと(トランジスタ技術12月号)前回WROOM02+iPhoneでは2FPSくらいなので、大幅にスピードアップしました。これはソース上で、各所に存在していたdelay待ち時間を最小にしても動いたことが大きな理由です。

 LEPTONサーモカメラは、温度計算やチップ制御を実行するために、さらにi2Cの接続が必要というめんどくさいセンサーなのですが、こちらの方は問題なく接続できました。

  • ピンの接続
             LEPTON           ESP32
CS -------------->D5
MOSI------------->D23
MISO------------->D19
CLK ------------->D18
GND ------------->GND
VIN ------------->3V3
SDA ------------->D21
SCL ------------->D22 
  • 今回のESP32側ソースは以下からダウンロードしてください。

                           id:TAKEsan の LEPTON-WROOM32TEST.ino

 たまにシステムダウンすることがありますが、このままの設定で1時間以上動くので許容範囲としました。頻繁にESP32がダウンする場合は、read_lepton_flame の最初の方に入れているdeleyの数値を調節する必要があります。

Mac 側Openframeworks

 前回までは画面のチラツキがあり、かなり不満でした。原因はESP32から送られる画像データが1行ずつなので、1行送られるたびに画像表示していたから。今回は60行分送られた時点で画像表示するよう改良したので、チラツキが全くなくなりました。

 チラツキさえなくなれば、VBOを使って画像を3D化(ポイントクラウド)できます。ただし、以前は2倍に補間して画像を比較的滑らかに表示してましたが、3D化する場合は画素数が不足します。今回は4倍に補間したデータを使いました。実験なので単純な平均値です。ofxCVを利用してバイキュービック補間すればベターですが、そこまでしなくても結果は見ての通りGoodでした。

今回作ったOpenFrameworksソースは以下からダウンロードしてください。 

 oscReceive-LEPTON.zip

VBOについてはOFの大御所。多摩美術大学「田所先生」の例題を応用させていただきました。

openFrameworks 3Dグラフィクス、OpenGL | yoppa org

当然ながら

 OFをインストールしたTX1でも動くわけで、ZEDステレオカメラと組み合わせたら距離と対象物の温度が同時に...。デープラーニングなんか使わなくとも人間と動物くらい簡単に認識できちゃうかも。 

f:id:TAKEsan:20170221132555p:plain

Jetson TX1で以前作ったZEDアプリと今回の3Dサーモグラフィーアプリを同時に実行しているところ。多分OFで組み合わせた場合マルチスレッド化可能。両者のフォーカスを合わせればどんなことができるんでしょうか?ワクワクしてきました。

                               では また。

NVIDIA TX1+OpenFremeworks+DIGITS でTensorRT をさらに加速させる。

メーカー側のお題みたいですが、

 今回はDIGITSで学習させたDetectNET学習済みデータが、TX1で応用可能かどうか確認してみることにしました。さらに、OpnFrameworks(以降OF)のofThreadでマルチスレッド化。ディープラーニング技術が現実的にTX1で簡単に実現可能かどうかもテストしてみました。

f:id:TAKEsan:20170203172051p:plain

実際に母艦環境でKITTIを学習させ(早い話、車の認識)、このデータを利用してTX1に接続したWebカメラで、iMac上の動画を読み取らせて、車を認識させた上にBox2Dでバウンディングパーティクルを車の中心から吹き出させています。60fps!!滑らか〜〜。

         

Movieで再現するとこんな感じ。Box2Dの吹き出すパーティクルについては、多摩美術大学の田所先生のソースを応用させていただきました。

まずDIGITSで学習させたDetectNETデータが、TX1で実行可能か?

 以前使用した学習済みデータは、Jetson-inferense をビルド時に自動的にダウンロードされたデータを使っていました。

github.com

が、現実的に母艦環境のDIGITで学習させたデータが利用できるんでしょうか?。以前も書いたように、「この人なんか怪しい」。GitHub上の質疑応答を見てもなんだかなーです。実際、作者本人以外ネット上で公開している方が存在していないみたいです。で、やってみました。もともとテストデータは人物の認識でした。今回はカメラで取り込んだ動画で、「車」の認識を実現させて見ます。

 まず、当然ですが学習させることから始めます。日本語環境ではこの方のブログがベスト。

soralab.space-ichikawa.com

 私の母艦環境はGTX1080+i7 6700Kなので、縮小データでなく実データで学習させて見ました。3.5時間程度必要。3.5時間といっても30エポックなので、GTX1080はそれなりにかなり早い(現実的なスピード)と思われます。そして車を認識しているかどうか確認してから、作成されたファイルをTX1にコピーします。必要なデータは3つで以下の通り。

f:id:TAKEsan:20170203141858p:plain

わかりにくいのですがデータの保存先がDIGIT上に表示されています(矢印部分) 。ソララボさんが主張している通りグラフが変です。

f:id:TAKEsan:20170203141937p:plain

必要なデータはdeploy.protitxtと、各エポックで作成されるスナップショットデータの一番最後と、

f:id:TAKEsan:20170203141934p:plain

           KITTI変換データのmean.binaryprotoファイルです。

さらに、deploy.prototxt の一番最後を消します。(どうやらPythonクラスはTensorRTでは実行できない模様)

f:id:TAKEsan:20170203141931p:plain

この3つを「car」とか名称をつけたフォルダにまとめて、この前のTX1上のOFプロジェクトのbinにコピー。

takesan.hatenablog.com

さらにプロジェクト中のsrc/ofApp.cppの最初の方2箇所を修正追加(赤部分)

#include "ofApp.h"

#include <include/cudaMappedMemory.h>

#include <include/cudaNormalize.h>

#include <include/detectNet.h>

#include <include/cudaRGB.h>

#include <include/cudaNormalize.h>

 

//標準では、PEDNET,PEDNET_MULTI,FACENETの指定可能。それぞれped-100multiped-500face-120に対応 binフォルダの中にリンクフォルダを入れておく

//リンクファイルは、jetson-inference/build/aarch64/bin に入ってる。

detectNet::NetworkType networkType = detectNet::PEDNET;

//他の学習済みデータを使う場合はCreateを次の用に変更

detectNet* net = detectNet::Create("car/deploy.prototxt.bak", "car/snapshot_iter_19140.caffemodel", "car/mean.binaryproto");

//Create("multiped-500/deploy.prototxt", "multiped-500/snapshot_iter_178000.caffemodel", "multiped-500/mean.binaryproto" );

//この場合はmultiped-500。必要なのは3つのファイル jetson-inference/detectNet.cpp 参照。後の2つの引数がデータ種類によって違うので注意。

//detectNet* net = detectNet::Create(networkType);

....................

 

 最初は時間がかかります(変換作業により3〜4分)が、2回目以降は簡単に実行できるようになります。自分で作成したデータの学習結果がTX1+OFで自由自在に応用できるようになります。が.........、カクカク画面が気に入らない。このままでは、本来のOF上画像処理を始めTX1のGPIOに接続した外部機器までもがカクカクになってしまう...。ってことで次の段階。

f:id:TAKEsan:20170203141927p:plain

TX1側のOFのプロジェクトの中身です。初回でmake -j4 make run すると、〇〇〇.caffemodel.tensorcasdheが作成されるため実行までに3〜4分必要。ターミナルにエラーが表示されていなければ正常に動いてます。ハングしたんじゃないかと心配になりますが...。一度作成されれば次回からはスーイスイ。

               

          

      全体のスピードは、TX1のクロックスピードを最大にしても8ps程度のカクカク動画。

で、マルチスレッド化!!

 どんなことかって言うと、2台のTX1があって、1方はカメラ画像のみ、もう1方は人物や車の認識をしているとして、これを1つのTX1で実行してしまうのと同じことを実現させるのと同じ。マルチスレッドと言うんだそうです。前回までは1スレッドのみの実行だったので、物体認識に時間を取られ、単純な画像表示までカクカクになってました。が、マルチスレッド化すると画像表示が本来のスピードに戻ります。有り余った時間(CPUはIntel Jouleより多少遅いですが、なんつったってTX1は本格的なGPUと、CPUを4つ持ってるんですからこれを最大限使ってやります)でOF本来の画像処理が可能。一方、物体認識用のスレッドは本来のスピードで認識し続けます。やっと認識した結果を、早い方のスレッドに渡してやります。ただし認識処理部分が極端に遅いとイマイチなんですが、今回はまーまーなんで、知らない人はおおおおーっと思うことでしょうね。こんなことは昔から「C」をかじってきた人なら、すぐ思い付くでしょうが、できると分かっていても敷居が高くてなかなか踏み込めません。立て続けにTX1がらみのソフトをかじってきて、できたらいいなーってことをやってみました。TensorRT側はGPUを使っているので、うまくマルチススレッド化できるのかどうか疑問が残りましたが、OFのアドオンofThreadを使ったら、割とあっけなく動いてしまいました。結果は次の動画。

                

今回のカメラデータは1280x720です。そこそこ大きな画面ですが、60fps出てるのが確認できます。肝心の車の認識ですが、どうでしょうか。ほぼリアルタイムなのがわかると思います。この例では高速道路上の車の認識なんですが、街中に入ると若干遅れぎみになります(相対スピードの問題)。

 開発環境がOpenFrameworksなんで、朝飯前なんです。こんなところにフレームワークに乗っかってプログラムを作る意味が出てきます。マルチスレッド化についてはWEB上で画像での比較が見つかりません(私の場合はですが)。2つの動画の比較で、感覚だけでも理解できると思います。認識はほとんどリアルタイムって感じでしょ。画像表示部分に関しては、単純にカメラ画像と認識した部分の図形を表示しているだけですから、まだまだ沢山の画像処理などを実行させても力が有り余ってます。今回のOFプロジェクトはここからダウンロードできます。

take-detct-thread_X.zip 直

 

コンパイル済み実行ファイルと、学習済みデータも入れときましたので、Jetson-inferenseがビルドできていれば動くはずなんですけど、どうでしょうか?。今回はDetectNet上で2クラス以上の物体についても認識可能(色分け可能)にしました。

 ちょっと話が違いますが、今回取り上げたJetson-inferense。TX1のGPUクロックを最大にしても、認識スピードに変化がありません(作者がjetson_clocks.shを実行しなさいと書いているにもかかわらず)。前に試したZEDライブラリは倍近く早くなったのに、不思議。GPUメモリに画像を転送しないと動かないということは、確実に認識エンジンとしてGPUを使ってるはず。っということはまだ改良の余地があるカモです。この辺りも非常にアヤシイ!!。もうしばらくバージョンアップの動向を追っていく必要がありそうです。

調子に乗って

 別スレッドで実行している「クルマ」の認識結果を利用して、ofxBox2Dを使ってパーティクルを動かして見たのが冒頭の画像です。Box2Dで制御されたCircleの動きが自然であることが確認できると思います。一見複雑そうな処理も簡単に実現できました。

 これで「母艦環境でのDIGITSを使った学習-->TX1を使った現場での応用」の基本環境と流れができちゃいました。夢見ていたディープラーニング応用がとても簡単に!!。どうでしょうか?夢中になっちゃいますよね。

f:id:TAKEsan:20170203141542j:plain

                               では また。

 

 

 

Jetson TX1 + OF + TensorRT でディープラーニング segmentation編

ヤッチマッター

 と言っても私のせいではありません。この記事の下書きを書いていたら突然飛んでしまいました。この頃OSX良くないですね。私のiMacでは、Bluetoothとか外部HDとかサファリとかが周期的に調子が悪くなります。使ってる側からすれば、ここまで来ればOSの進化なんかどうでもいいんです。「安定だけ!!」こんなことはどうでもいいでしょうから本題へ。

今回はこんなのです。

f:id:TAKEsan:20170122140304j:plain

         

認識中の動画です。Py Fastere RCNN 並みにカクカク画面ですが、認識中している物体の輪郭が、大雑把ながらも具体的に表示されます。今回は特に認識する対象物を確認しやすくするため、キーボードから選択可能とし、バッテン印で表示させるようにしました。この画像では対象が「車」です。後の方で対象物を変えてます。周りの景色で認識確率の度合いが変わってくるようです。

前回の続きで、

 今度はSegmentationです。前回のDetectnetはせいぜい認識する物体の対象が1つか2つでしたが、今回は20項目程度の認識が可能となります。過去に取り上げたPy Faster RCNNと方向性は似ていますが、それとは少しコンセプトが違い、認識した画像の輪郭を抽出しようという代物です。前回まで見逃してたのですが、jetson-inferrencehttps://github.com/dusty-nv/jetson-inferenceに入っていました。なぜ見逃したのか?-->解説に載っていなかっただけです。作者(多分NVIDIA社員)は動作が鈍いので自信がなかったのでしょうか?2ヶ月ぐらい前に追加されていたのですが、多分取説を書くのがめんどくさかったからだけなんででしょうね。

 jetson-inferrenceのビルド時に、自動的にダウンロードされる学習済みファイルは、道路上で主に見かける20種類のクラスを認識できます。車載カメラからの物体認識を想定しているのでしょう。クラスに対応したラベル(認識物体の名称)は以下の通りです。

        class 00  label 'void'

        class 01  label 'dynamic'

        class 02  label 'ground'

        class 03  label 'road'

        class 04  label 'sidewalk'

        class 05  label 'parking'

        class 06  label 'building'

        class 07  label 'wall'

        class 08  label 'fence'

        class 09  label 'guard rail'

        class 10  label 'bridge tunnel'

        class 11  label 'pole'

        class 12  label 'traffic light'

        class 13  label 'traffic sign'

        class 14  label 'vegetation'

        class 15  label 'terrain'

        class 16  label 'sky'

        class 17  label 'person'

        class 18  label 'car'

        class 19  label 'truck'

        class 20  label 'cycle'

クラスの中には当然人物も存在するので、試しにjetson-inferrenceに入っている写真で確認すると、

f:id:TAKEsan:20170122140449p:plain

標準で入っているsegnet-consoleアプリで人体を含む写真を認識させると、認識した部分が赤で表示されます。他のクラスは違う色で輪郭を囲んでいるのがわかると思います。ただ、これを実行するにはわざわざ作者が添付しているsegNet.batを実行しただけでは動かない。segNet.cppを確認する必要がありました。結局 ./segNet-console peds-006.png test.png fcn-alexnet-cityscapes-hd で動かした結果です。(最終はtest.png画像)

 こんな感じ。添付されている1980x1080ピクセル画像で、認識処理に0.6秒程度必要でした。赤で人物を認識してます。認識範囲がギザギザ=荒いですねー。TX1ではここら辺が限界なんでしょう。セグメンテーションモデルのサンプルアプリはこれだけ。写真しか認識できません。認識する対象物数が多いことから、動画にしたところで1fps強しかスピードがでないとは思いましたが、写真よりマシということで、OFで作ってみました。

前回で味をしめたので、

 簡単にできるんじゃないかって思ってましたが、やはり初心者がCUDAなんてとんでもないことだとつくづく思い知らされました。おかげで頭も体もガクガク。記憶が頻繁に飛んでしまうので、作成中に限界を感じてしまい挫折しそうでしたが、頑張ってみました。完璧に初老の症状です。が、できたものは、OpenFrameworks(以降OF)から見る限りとても簡素なソースになりました。動作はカクカクですが、TX1にインストールしたOFで動くので、ofTheadアドオンでマルチスレッド化すれば、認識画面の結果を待つ間、結果を元にモーターを動かすとか、i2Cに繋いだセンサー値を読み取るとか面白そうなことが、できそうです。

 作成中理解できたsegNet認識エンジンの構造は下図の通り。OFから操作できるのは、クラス番号配列だけにしました。単独クラスだけの認識も可能ですが、全体スピードにさほど違いがありません。なのでこれがベターかと勝手に判断。下図の最終段階で、「各々の確率で最大のクラス番号を出力」とありますが、この部分を修正すると認識率がもっと改善されるはずです(segnet.cpp中身。最大とは言え、90%以上とは限られないのですから、そのあたりのチェック方法が運命の分かれ道)。今回はライブラリソースsegnet.cppの中も修正したので、jetson-inferrenceの再コンパイルが必要です。

f:id:TAKEsan:20170122140630p:plain

セグメンテーションモデルとはどんなものか?

 は、この方のブログを確認してみて下さい。Py Faster RCNN との比較も載っています。

soralab.space-ichikawa.com

今回作ったソースは、

 下図のようなことができます。

f:id:TAKEsan:20170122140336j:plain

カメラから取り込んだ動画でも、写真から認識したものと同じような認識結果でした(iMacに表示した写真画像をカメラで取り込んでいる)。ただ、色分けだけでは認識している対象がなんだかわからないので、明確に判断できるようにしました。(画像ではperson=人々。認識しているところはバッテン印)

f:id:TAKEsan:20170122140414j:plain

 ここでは車を対象としています。(青のバッテン印。車は確実に認識するが、誤認識している部分あり)

 デープラーニングエンジン部分の処理が重く、取り込んだ画素数を上げてもさほどスピードに影響が出ないことから、カメラの画素数を1920x1080として認識精度を上げています。(せいぜい1.6〜1.8fpsのカクカク動画)

実行条件

  • JetPack2.3.0以降の64bit版がインストールしてあること。
  • Jetson-inferrenceをダウンロードしてビルドしてあること。/home/ubuntu に入れないとOFコンパイル時、リンクエラーが出るので注意
  • TX1にOpenframeworksがインストールしてあること。

    TX1には通常Openframeworksはインストールできません。インストールするには手順が必要です。最短で実行したい場合は以下の記事を参考に!!

    takesan.hatenablog.com

実行手順

  1. USBにWebCameraをつなぐ(Logicool製品が一番安心。できればC920以上)。
  2. プロジェクトsegNET.zipを解凍して中にあるtake-segをフォルダごとOF/apps/myAppsへ突っ込む。
  3. さらにsegnet.hsegnet.cppJetson-inferrenceの最上層に突っ込む(重ね書き)。
  4. Jetson-inferrence/build/aarch64/bin  の中の FCN-Alexnet-Cityscapes-HDFCN-Alexnet-SYNTHIA-Summer-HDフォルダへのリンクファイルをOF/apps/myapps/take-seg/binへ入れる。(既に解凍したファイルには同名のフォルダが入ってるので消してから)
  5. Jetson-inferrence/build/aarch64/include フォルダへのリンクファイルをOF/apps/myapps/take-seg/srcに入れる(既に解凍したファイルには同名のフォルダが入ってるので消してから)
  6. すでにビルドしているJetson-inferrence/buildに入り make clean --> cmake ..  --> make -j4  を実行。-->Jetson-inferrenceを再コンパイル
  7. includeリンクファイルの中で、修正が必要なファイルあり-->cudaUtility.h。最初の方の赤文字部分を追加。

    cudaUtility.h

    /*

     * http://github.com/dusty-nv/jetson-inference

     */

     

    #ifndef __CUDA_UTILITY_H_

    #define __CUDA_UTILITY_H_

     

     

    #include </usr/local/cuda-8.0/targets/aarch64-linux/include/cuda_runtime.h>

    #include </usr/local/cuda-8.0/targets/aarch64-linux/include/cuda.h>

    #include <stdio.h>

    #include <string.h>

  8. ZED SDKやOpenCV2.4.13をインストールしていない方は、segNET/config.make の中身の修正が必要です。一番最後に追記した「すいません」以降を確認してください。

  9. OF/apps/myapps/take-seg に移動して いつものようにmake -j4  make run で実行。

ソース内容

 はてなブログでは文字化けしちゃうんで、ダウンロードしてみてください。segNET.zip CUDAライブラリ使用部分は、前回より複雑な処理なのに逆に簡素になりました。(私の能力がアップしたか?! ん なわけねーよな。)

※2017/1/23 ダウンロードファイルが違っていました。Detect-RT.zipからsegNET.zipに修正しました。

※すいません!!解凍したフォルダ「segNET」の中にあるconfig.makeの中身はZED SDKへのリンクも入ってました。このままだとZEDを所有していない方は、リンクエラーになるのでDetect-RT/config.make の80行目 PROJECT_LDFLAGS= 部分を以下に変更してください。

PROJECT_LDFLAGS=-L/usr/lib/aarch64-linux-gnu/tegra -L/usr/local/cuda-8.0/lib64 -L/usr/local/lib -L/home/ubuntu/jetson-inference/build/aarch64/lib -rdynamic /home/ubuntu/jetson-inference/build/aarch64/lib/libjetson-inference.so -lX11 -lpthread -lGLEW -lGLU -lGL -ldl -lrt -lnvcaffe_parser -lnvinfer /usr/local/cuda-8.0/lib64/libcudart.so /usr/local/cuda-8.0/lib64/libnppc.so /usr/local/cuda-8.0/lib64/libnppi.so /usr/local/cuda-8.0/lib64/libnpps.so /usr/local/cuda-8.0/lib64/libcublas.so /usr/local/cuda-8.0/lib64/libcufft.so -ldl -lm -lpthread -lrt -Wl,-rpath,/usr/lib/aarch64-linux-gnu/tegra:/usr/local/lib:/usr/local/cuda-8.0/lib64:/home/ubuntu/jetson-inference/build/aarch64/lib

 

 

                                                    では、また。

 

Jetson TX1 + OF + TensorRT でディープラーニング

今回のお題の内容は、

 TX1にインストールしたOpenframeworks(以後OF)で、以前チラッと紹介したTensorRTを実現させようという試みです。やっとディープラーニングに戻りました。

         

今回の最終画像。TX1+OF+TensorRTで認識した人物をリアルタイムで表示している。前回のOpenCV+HOGと比べて認識率と反応が全く違う。すごい。さすが最新ディープラーニング技術!!

f:id:TAKEsan:20170117201633j:plain

左がTX1+OF+TensorRTで認識させたディスプレイ画面(緑の四角で認識した人物を特定してる)。iMacの人物画像と奥のテレビに映った「さんまさん」も認識してる。

 TensorRTはここに紹介されています。

github.com

 未だにTensorRTって分かってませんが、インストール中にCaffeライブラリをダウンロードしてるんで、多分Caffeの16bit版(例のrun test がうまくいかないやつ)を使ってるだけじゃないか?なんて、今思ってます。結果が良好なんで、使う側にとってはどうでも良いことですけど。

 この中で、Object Detection の学習済みデータを使い、TX1に接続したカメラ画像で、リアルタイムにいろいろ認識させてみるというアプリをOFで実現させてしまいした

 Object Detectionについては、この記事を見ると大体理解できると思います。

soralab.space-ichikawa.com

この方のブログに注目してるんですが、応援方法がわからない....。

 Object Detectionの学習は、非常に時間のかかることが分かると思いますが、今回は、Object Detectionの学習済みデータを利用して、実用的に使うみたいなコンセプト。TX1は、GPUに関して最新のものと比較すると完全に見劣りしますが、本体が非常に小さく、ほどほどのスピードなので、現場で使うには非常に実用的。メーカーが本来考えていたことが実現できたことになります。

Jetson-inferrenceのOF化について

 Jetson-inferrenceをインストールすると、数種類のアプリが実行できますが、この中でも実用的かつ一番面白いと思われるdetectnet-cameraOF化してみました。

このアプリの欠点と思われる部分は、

  • カメラ部分と表示部分にCUDAがらみの処理が多く、私ではちんぷんかんぷん。
  • 表示画像が逆なのに直す「すべ」が分からない(カメラとOpenGL部分の座標の違いか?)。こんな感じ!!。

        f:id:TAKEsan:20170117201706j:plain

    カメラは普通に設置してるのに、画像が逆さま。青い四角で人物を確実に認識してるが......。

  • このソース利用しようとしても、入出力が特殊なので応用が非常に難しい

 OFに移植なんて無理かなと思ってたのですが、ディープラーニングのエンジン部分がとても単純であることが判明。で、やっとできたので記事にしたいと思ったわけです。いつも書いてますがOF化によって、応用範囲がぐんと広がることが約束されます。この画面のMjpeg配信なんか簡単にできちゃいます。

 できたものは、本家アプリの場合6.1fpsに対して、同条件で今回は7.8fpsになりました。早くなったんです!!。早くなったのはなぜ? 感覚的に本家の方は、変換作業が多すぎるような気配があるのですが、この辺りかもしれません。でも私の作ったものの方が早いなんて、とっても嬉しくなります。ソースが短い(こんなにすごいことを実行しているのに....。)のでaddonにする必要もないと思いましたので、ofApp.cppに全部入れちゃいました。ただ、config.makeが特殊(リンクオプションをたくさん追加しているため)なので、ソースダウンロード可能にしときます。--->Detect-RT.zip

 今後このフォルダをコピーすれば、どんどん面白そうなものが作れそうです。感心するのは、全体のスピードは8ps前後で多少カクついていますが、カメラから画像を取り込んでから遅延がほとんどないこと。前回のOpenCV Hogは確実に1秒以上「間」を置いてからの表示なので、リアルタイムではありませんでした。また、今回1080x720と、そこそこ大きい画素数ですが、遅延がほとんどないんです(前回は640x390 HD720にすると6fpsくらいで遅延が3秒!!)これは実用的!!。

 注意点は、以前ビルドしたOpenCV2.4.13の関数を使うと実行エラーが出て動かなくなること。当初の狙いは、前回作ったZEDの深度測定と組み合わせようと思ったのですが、これは不可能のようです。どうやらコンパイラオプションのGLライブラリが競合するようです。検証をしていませんが、OFに標準で入ってるアドオン「ofxOpencv」は、リンクするライブラリが違うので競合しない可能性があります。

 実際の認識性能がどうか?なのですが、この前のOpenCV HOG 認識器の動画と比べれば、違いに気づくと思います。とにかく認識が安定してますし、一度に認識する数も比較になりません。断然良い!!。さすがディープラーニングの最新技術ですよね。ただし、結構誤認識してしまう欠点があります。問題は学習の仕方でしょうか?

 今回のソースを最後に付けます。Jetson-inferrenceをインストールすると、学習済みデータが自動ダウンロードされます。3種類存在するので、これを利用できます。顔認識、人物認識、人物とバッグの認識です。以前は、このフォルダの中のどのデータを利用するのかわからなかったのですが、今回はっきりしたので、最後に付けたソース中に、その辺りもコメントを入れてます。次は母艦のDIGITSでデータを作って、TX1で結果を実行させたいと思っています。尚、今回のモデルはmultiped-500です。昨年の暮れには夢だったことが実現できて幸せ!!。これからは、個人でディープラーニングを活用した実用レベルのソフトが作れそうです。

実行条件

  • JetPack2.3.0以降の64bit版がインストールしてあること。
  • Jetson-inferrenceをダウンロードしてビルドしてあること。/home/ubuntu に入れないとOFコンパイル時、リンクエラーが出るので注意
  • TX1にOpenframeworksがインストールしてあること。

TX1には通常Openframeworksはインストールできません。インストールするには手順が必要です。最短で実行したい場合は以下の記事を参考に!!

takesan.hatenablog.com

実行手順

  1. USBにWebCameraをつなぐ(Logicool製品が一番安心。できればC920以上)。
  2. プロジェクトDetect-RT.zipを解凍したらフォルダごとOF/apps/myAppsへ突っ込む。
  3. Jetson-inferrence/build/aarch64/bin  の中の facenet-120、multiped-500、ped-100フォルダへのリンクファイルをDetect-RT/binへ入れる。(既に解凍したファイルには同名のフォルダが入ってるので消してから)
  4. Jetson-inferrence/build/aarch64/include フォルダへのリンクファイルをDetect-RT/srcに入れる(既に解凍したファイルには同名のフォルダが入ってるので消してから)
  5. ZED SDKやOpenCV2.4.13をインストールしていない方は、Detect-RT/config.make の中身の修正が必要です。一番最後に追記した「すいません」以降を確認してください。
  6. includeリンクファイルの中で、修正が必要なファイルあり-->cudaUtility.h。最初の方の赤文字部分を追加。

    cudaUtility.h

    /*

     * http://github.com/dusty-nv/jetson-inference

     */

     

    #ifndef __CUDA_UTILITY_H_

    #define __CUDA_UTILITY_H_

     

     

    #include </usr/local/cuda-8.0/targets/aarch64-linux/include/cuda_runtime.h>

    #include </usr/local/cuda-8.0/targets/aarch64-linux/include/cuda.h>

    #include <stdio.h>

    #include <string.h>

  7. Detect-RT に移動して いつものようにmake -j4  make run で実行。

ソース内容

 はてなブログでは文字化けしちゃうんで、ダウンロードしてみてください。Detect-RT.zip (複数のクラスがあった場合、認識した部分を表す四角形の色分けをしてません)

※すいません!!解凍したフォルダ「Detect-RT」の中にあるconfig.makeの中身はZED SDKへのリンクも入ってました。このままだとZEDを所有していない方は、リンクエラーになるのでDetect-RT/config.make80行目 PROJECT_LDFLAGS= 部分を以下に変更してください。)

PROJECT_LDFLAGS=-L/usr/lib/aarch64-linux-gnu/tegra -L/usr/local/cuda-8.0/lib64 -L/usr/local/lib -L/home/ubuntu/jetson-inference/build/aarch64/lib -rdynamic /home/ubuntu/jetson-inference/build/aarch64/lib/libjetson-inference.so -lX11 -lpthread -lGLEW -lGLU -lGL -ldl -lrt -lnvcaffe_parser -lnvinfer /usr/local/cuda-8.0/lib64/libcudart.so /usr/local/cuda-8.0/lib64/libnppc.so /usr/local/cuda-8.0/lib64/libnppi.so /usr/local/cuda-8.0/lib64/libnpps.so /usr/local/cuda-8.0/lib64/libcublas.so /usr/local/cuda-8.0/lib64/libcufft.so -ldl -lm -lpthread -lrt -Wl,-rpath,/usr/lib/aarch64-linux-gnu/tegra:/usr/local/lib:/usr/local/cuda-8.0/lib64:/home/ubuntu/jetson-inference/build/aarch64/lib

 

                                           では、また。