7月から、Olympus AIR A01 CAMERA KIT SDK付属のサンプルアプリImageCaptureSampleにいろいろと手を加えて遊んでいるわけだが、今回はライブビュー表示のことなど。
ライブビュー表示のことなど
ミラーレスカメラでは背面の液晶やEVF内に、イメージセンサーが捉えた画像(ライブビュー画像)が常に表示されている。AIR A01では、ライブビュー画像がwifiという細い線を通ってスマホの画面に表示されているわけである。
ライブビュー画像の表示品質や表示更新のタイミングは、OM-Dなどのカメラではとても気になること。AIR A01ではスマホの画面で見る限り、さほど気になるものでもないのだけれど、実際はどんなもんかなのかな、と思ってライブビュー画像、撮影後の確認画像、カメラの撮影結果をjpegにして比べてみることにした。モデルには、いつもの金魚ちゃんを使った。
カメラの撮影画像をスマホに保存
最初に、カメラが撮影したjpeg画像。撮影時には i-Finishで階調オートとし、1600×1200のSuper Fineで保存した。これでいいでしょう、という品質と思う。
撮影時のピクチャーモードや階調等の設定は、OLYCameraクラスのsetCameraProperty()というAPIを使う。たいていの設定はこのメソッドの呼び出しで済む。
なお、カメラが撮影した画像は、カメラ内のSDカードだけではなくwifiを経由してスマホ側に保存することもできるので、今回はそのようにした。スマホ側に保存するときには、
1 2 3 4 |
try { SettingFragment.setCameraPropertyValue2(camera, "RAW", "OFF"); SettingFragment.setCameraPropertyValue2(camera, "DESTINATION_FILE", "DESTINATION_FILE_WIFI"); } catch (OLYCameraKitException e) { } |
として、RAWファイルの保存を禁止してから書き込み先をWIFIに向ける必要がある。RAW保存を許可したままでは、「このプロパティは変更禁止ですよ」といった内容がLogcatに出てくる。
SettingFragment.setCameraPropertyValue2()というメソッドは、APIのsetCameraPropertyValue()を呼び出すために作ったもので、
1 2 3 4 5 6 7 8 9 10 |
static public void setCameraPropertyValue2(final OLYCamera camera,final String key, final String value) throws OLYCameraKitException { String v = "<" + key + "/" + value + ">"; try { camera.setCameraPropertyValue(key, v); } catch (OLYCameraKitException e) { e.printStackTrace(); Log.w("setCameraProperty2() ", key + ", " + v + " failed."); throw e; } } |
というだけのもの。
カメラが撮影を終えると、撮影結果の転送が始まり、その完了時に OLYCameraRecordingSupportsListener のonReceiveCapturedImage() が呼ばれる。このメソッドに渡される byte[] dataの中身はJPEGデータそのものなので、実装の中で dataをそのままファイルに書いて拡張子 “.jpg”を与えている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@Override public void onReceiveCapturedImage(OLYCamera camera, final byte[] data, Map<String, Object> metadata) { String name = "air_" + DateFormat.format("yyyyMMddkkmmss", Calendar.getInstance()) + ".jpg"; File file = new File(getPrivateStorageDir(), name); BufferedOutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(file)); out.write(data); out.flush(); out.close(); out = null; Log.w(TAG, "onReceiveCapturedImage() " + file.getAbsolutePath() + " is written."); String[] paths = { file.getAbsolutePath() }; String[] types = {"*/*"}; MediaScannerConnection.scanFile(getActivity(), paths, types, null); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) try { out.close(); } catch(IOException ee) {} } } |
この中にある、getPrivateStorageDir()というメソッドは、Environment.getExternalStorageDirectory()でもって作ったプライベートな格納先を得るためのもの。また、MediaScannerConnection.scanFile()をいちいち呼ぶことで、スマホの内部にできるjpegファイルをUSB接続中のPCから見ることができるようになる(たまにWindows Explorerの表示が更新されないことがあるが)。
ライブビュー表示画像の保存
スマホにライブビュー表示される画像データは、OLYCameraLiveViewListenerのonUpdateLiveView() の実装において更新都度ごとに得ることができる。ImageCaptureSampleアプリの実装では、カメラから得たビットマップデータを、ライブビュー表示用のビュー(CameraLiveImageViewのインスタンス、imageViewと表記)に渡す。imageViewは、BitmapFactory.decodeByteArray()でもって Bitmapオブジェクトを生成し画面を描画する。
今回ライブビュー画像を保存するため、imageViewが作ったBitmapオブジェクトを取り出し、jpegに変換してファイルに書かせることにした。書込みのタイミングは、シャッターボタンがクリックされて、実際の撮影動作(takePicture()の呼び出し)に入る直前とした。
ライブビュー画像(1024×768)をAndroidのAPIでjpeg化したもの。jpeg化時の品質は100%とした。カメラが撮影した画像と比べると、ピクセルが間引かれているように見えて低品位である。センサーからの読出しを端折っているんじゃないのかな。
当初は、ライブビュー画像を1秒に1回程度蓄積していき、シャッターを切ることなくパラパラ動画でも作れないものかなと思っていたのだが、jpegを作ってみると思いの外品質が低いのでやめた。
ライブビュー画像であるため、ライブビューを拡大表示した場合にもそのまま保存される。スマホの画面では目玉にピントがあってるように思ったのだが、こうしてみるとそうでもない。
Bitmapオブジェクト(bitmap)をjpegとして保存するときには、先ほどの撮影画像の保存時とほとんど同じコードを使う。out.write(data); の代わりに、bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); とするくらい。
ライブビューの大きさは、最大1280×960まで指定できるのだが品質は変わらない。1280×960としたときの転送されるデータサイズは130KBytes程度である。
※撮影画像や確認画像と同様に、通知時のdata[]にはjpegイメージそのものが入っているので、コピーを作って書き出せばjpegファイルを得ることもできる。後で気が付いた。やってみたが、品質が上がるわけでもない。
撮影確認画像
撮影確認画像というのは、カメラでの撮影直後にスマホに転送されてくる確認表示用(プレビュー用)の画像である。これもファイルに落としてみた。
カメラの撮影結果と同様のインターフェースであるOLYCameraRecordingSupportsListenerの、onReceiveCapturedImagePreview()を実装してファイルに書かせる。ImageCaptureSampleでは、撮影確認画像を表示するためのビューを起こしているが、そのかわりに圧縮済のビットマップ(実はjpeg)をもつdata[]をそのまま拡張子”.jpg”のファイルに書かせている。
撮影確認画像の大きさは、ライブビュー表示サイズによらず常に1024×768に決まっているようである。品質は高く、カメラの撮影画像と遜色ない。
ただ、撮影結果の画像もwifiで得ているわけなので、確認画像をあえて何かに使うことはないだろう。撮影確認を許可していない場合、最短の撮影可能間隔は実測で3秒なのだが、撮影確認画像の転送が入ると4秒になってしまう。
パラパラ動画を作るなら、1920×1080のSuper Fineなjpegを適当なタイミングでインターバル撮影してスマホに落としておき、後で別のアプリで順に読みだしながらエンコードといった流れになると思う。AndroidのMediaCodecの勉強をしないとならないのだが、これがややこしくて。