RICHO THETAを最初見たときは,あんまりピンと来なかったのですが使ってみると便利で面白いですね.
そんなTHETAをいじる機会があったので,簡単なAndroid用のプログラムを作ってみました.
SDKは下記のサイトからDLできます.
RICHO THETA Developpers
https://developers.theta360.com/ja/
SDKに付属しているサンプルプログラムは私にとって複雑で,何をしているのかわかりにくいものでした.
そこで,SDKのサンプルとリファレンスを頼りに,以下のようなシャッターを切るだけの簡単なサンプルを作りました.
このサンプルはCONNECT Buttonを押してTHETAに接続し,SHOOT Buttonを押してシャッターを切るというプログラムです.
切断するときはDISCONNECT Buttonを押します.
THETAのステイタスからGUIを動かすサンプルとして,各操作の状況をTHETA statusというtextviewに描画しています.
それではこのプログラムの説明を行います.
まずは,以下のように,インターネットのpermissionを取ります.
この記述は,AndroidManifest.xmlに記述します.
<uses-permission android:name="android.permission.INTERNET"/>
つぎに,GUIのレイアウトを設定します.デフォルトではactivity_main.xmlに記述します.
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="28dp"
android:layout_marginTop="64dp"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="THETA status:" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Status" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CONNECT" />
<Button
android:id="@+id/disconnect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DISCONNECT" />
<Button
android:id="@+id/shoot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SHOOT" />
</LinearLayout>
</LinearLayout>
これまでで,準備が整ったのでMainActivity.javaに処理を記述します.
この処理は基本的に各ボタンのListnerを設定して,そのボタンに合わせて処理を行います.
気を付ける点は以下の2つです.
- THETAとのやりとりはINTERNETを使うので,AsyncTaskなどを使って別スレッドで行う.
- GUIを別スレッドから操作するときは,Handlerを使う.
この点だけ気を付ければ特別難しい処理はないと思います.
各ボタンを押すとConnectTask,DisConnectTask,ShootTaskが実行されます.
ConnectTaskでは,指定したIPアドレスのTHETAに接続を行い,成功したらCONNECTED,失敗したらERRORと表示します.
DisConnectTaskでは,TETAとの接続を断ち,成功したらDISCONNECTED,失敗したらエラーログを表示します.
ShootTaskでは,シャッターを切り,成功したらSHOOT,失敗したら各エラーを表示します.
public class MainActivity extends Activity {
PtpipInitiator camera;
private static final String IP_ADDRESS = "192.168.1.1";
private TextView txt_theta_status;
private Button btn_theta_connect;
private Button btn_theta_disconnect;
private Button btn_theta_shoot;
private Handler handler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt_theta_status = (TextView) findViewById(R.id.status);
btn_theta_connect = (Button) findViewById(R.id.connect);
btn_theta_disconnect = (Button) findViewById(R.id.disconnect);
btn_theta_shoot = (Button) findViewById(R.id.shoot);
btn_theta_connect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new ConnectTask().execute();
}
});
btn_theta_disconnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new DisConnectTask().execute();
}
});
btn_theta_shoot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new ShootTask().execute();
}
});
handler = new Handler();
}
private class ConnectTask extends AsyncTask {
@Override
protected String doInBackground(String... params) {
try {
camera = new PtpipInitiator(IP_ADDRESS);
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("CONNECTED");
}
});
} catch (Throwable e) {
e.printStackTrace();
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("ERROR");
}
});
}
return null;
}
}
private class DisConnectTask extends AsyncTask {
@Override
protected Boolean doInBackground(Void... params) {
try {
PtpipInitiator.close();
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("DISCONNECTED");
}
});
return true;
} catch (Throwable throwable) {
final String errorLog = Log.getStackTraceString(throwable);
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText(errorLog);
}
});
return false;
}
}
}
private static enum ShootResult {
SUCCESS, FAIL_CAMERA_DISCONNECTED, FAIL_STORE_FULL, FAIL_DEVICE_BUSY
}
private class ShootTask extends AsyncTask {
@Override
protected ShootResult doInBackground(Void... params) {
try {
PtpipInitiator camera = new PtpipInitiator(IP_ADDRESS);
camera.initiateCapture();
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("SHOOT");
}
});
return ShootResult.SUCCESS;
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("FAIL_CAMERA_DISCONNECTED");
}
});
return ShootResult.FAIL_CAMERA_DISCONNECTED;
} catch (ThetaException e) {
if (Response.RESPONSE_CODE_STORE_FULL == e.getStatus()) {
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("FAIL_STORE_FULL");
}
});
return ShootResult.FAIL_STORE_FULL;
} else if (Response.RESPONSE_CODE_DEVICE_BUSY == e.getStatus()) {
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("FAIL_DEVICE_BUSY");
}
});
return ShootResult.FAIL_DEVICE_BUSY;
} else {
handler.post(new Runnable() {
@Override
public void run() {
txt_theta_status.setText("FAIL_CAMERA_DISCONNECTED");
}
});
return ShootResult.FAIL_CAMERA_DISCONNECTED;
}
}
}
}
以上で,AndroidアプリからTHETAのシャッターを切る方法の説明を終わります.
コメント
コメントを投稿