FLIR Oneを使ったアプリを考える前に, FLIR Oneについてもう少し理解を深めてみよう.
まずは, FLIR Oneのドキュメント[1]やサンプルコード[2]をベースに, 基本的な機能(サーマル画像表示, 温度測 - 定など)を実装し, FLIR Oneの基本的な動きを確認してみる.
1. サーマル画像表示
基本的な処理の流れは以下の通り.
[手順]
1) onCreateメソッド
- 画像タイプを指定して, FrameProcessorのインスタンスを取得する.
2) onResumeメソッド
- Device#startDiscoveryメソッドで, FLIR Oneとの接続を開始する.
注) 例外処理(try-catch)をすること.
3) onStopメソッド
- Device#stopDiscoveryメソッドで, FLIR Oneからのリスニングを中止し接続を停止する.
注) stopDescoveryメソッド内で, closeメソッドも実行される.
4) onDeviceConnectedメソッド
- デバイス情報を保持する.
- Device#startFrameStreamメソッドで,On ストリーミングを開始する.
5) onDeviceDisconnectedメソッド
- チューニング状態をUnknownにする.
- Device#stopFrameStreamメソッドで, ストローミングを停止する.
6) onFrameReceivedメソッド
- チューニング状態がInProgressでない場合に, FrameProcessor#processFrameメソッドで, フレームデータを処理する.
7) onFrameProcessedメソッド
- RenderImage#getBitmapメソッドで, ビットマップ画像を取得する.
- ImageView#setImageBitmapメソッドで, ビットマップ画像をビューにセットし, 画像を表示させる.
注) UI表示はrunOnUiThread内で行うこと.
[コード]
package com.moonlight_aska.android.vision.flironedemo;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;
import com.flir.flironesdk.Device;
import com.flir.flironesdk.Frame;
import com.flir.flironesdk.FrameProcessor;
import com.flir.flironesdk.RenderedImage;
import java.util.EnumSet;
public class PreviewActivity extends AppCompatActivity
implements Device.Delegate, Device.StreamDelegate, FrameProcessor.Delegate {
private static final String LOG_TAG = PreviewActivity.class.getSimpleName();
private ImageView mThermalView = null; // 表示用View
private volatile Device mDevice = null; // Flir Oneデバイス
private FrameProcessor mFrmProcessor = null; // フレーム処理プロセッサ
private Device.TuningState mTuningState = Device.TuningState.Unknown; // チューニング状態
private Bitmap mThermalBitmap = null; // 描画用ビットマップ画像
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preview);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mThermalView = (ImageView)findViewById(R.id.thermal_view_id);
mThermalView.setRotation(180.0f); // 表示上下反転
RenderedImage.ImageType defImageType = RenderedImage.ImageType.BlendedMSXRGBA8888Image; // Thermal + Visual画像
mFrmProcessor = new FrameProcessor(this, this, EnumSet.of(defImageType));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_preview, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
try {
Log.i(LOG_TAG, "onPesume, starting discovery!");
Device.startDiscovery(this, this);
} catch(IllegalStateException e) {
Log.e(LOG_TAG, "onPesume, startDiscovery() error!");
e.printStackTrace();
}
}
@Override
protected void onStop() {
Log.i(LOG_TAG, "onStop, stopping discovery!");
Device.stopDiscovery();
super.onStop();
}
@Override
public void onTuningStateChanged(Device.TuningState tuningState) {
}
@Override
public void onAutomaticTuningChanged(boolean b) {
}
@Override
public void onDeviceConnected(Device device) {
Log.i(LOG_TAG, "Device connected!");
mDevice = device;
mDevice.startFrameStream(this); // ストリーミング開始
// Debug
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Device connected.", Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onDeviceDisconnected(Device device) {
Log.i(LOG_TAG, "Device disconnected!");
mTuningState = Device.TuningState.Unknown;
if (mDevice != null) {
mDevice.stopFrameStream();
mDevice = null;
// Debug
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Device disconnected.", Toast.LENGTH_LONG).show();
}
});
}
}
@Override
public void onFrameReceived(Frame frame) {
Log.i(LOG_TAG, "Frame received!");
if (mFrmProcessor != null) {
if (mTuningState != Device.TuningState.InProgress) { // チューン中でない
mFrmProcessor.processFrame(frame);
}
}
}
@Override
public void onFrameProcessed(RenderedImage renderedImage) {
Log.i(LOG_TAG, "Frame processing!");
if (renderedImage.imageType() == RenderedImage.ImageType.BlendedMSXRGBA8888Image) {
mThermalBitmap = renderedImage.getBitmap();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mThermalView != null) {
mThermalView.setImageBitmap(mThermalBitmap); // 画像表示
}
}
});
}
}
}
[実行結果]
- Nexus 7(2013) / Android 4.4.4
一応, サーマル画像を表示できるようになった.
次は, 温度表示を行ってみようと思う.
----
参照URL:
[1] FLIR One SDK Documentation
[2] FLIR One Software Development Kit