■RAW画像とは
■撮影の流れ
下記の手順でカメラを制御することで撮影画像を取得することができます。
- カメラをセットアップする
- カメラを開く
- プレビューを表示する
- 撮影する
- 画像を保存する
■カメラをセットアップする
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
※注意※
Android 6.0 (API Level 23)より上記パーミッションのプロテクションレベルが
Dangerousとなります。
そのため、そのまま使用すると実行時にSecurity Exceptionが発生します。
上記の環境でプログラムを実行する際にはContextCompat.checkSelfPermissionを
用いて、ユーザの許可を得る必要があります。
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.raw" />
アプリが起動するとonResume→openCameraと呼ばれ、setUpCameraOutputs
の中でgetCameraCharacteristicsを呼び出すことでカメラデバイスが
有する機能を取得することができます。
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
// We only use a camera that supports RAW in this sample.
if (!contains(characteristics.get(
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES),
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
continue;
}
if (mRawImageReader == null || mRawImageReader.getAndRetain() == null) {
mRawImageReader = new RefCountedAutoCloseable<>(<
ImageReader.newInstance(largestRaw.getWidth(),
largestRaw.getHeight(), ImageFormat.RAW_SENSOR, /*maxImages*/ 5));
}
mRawImageReader.get().setOnImageAvailableListener(
mOnRawImageAvailableListener, mBackgroundHandler);
}
■カメラを開く
private void openCamera() {
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
manager.openCamera(cameraId, mStateCallback, backgroundHandler);
}
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
synchronized (mCameraStateLock) {
// Start the preview session if the TextureView has been set up already.
if (mPreviewSize != null && mTextureView.isAvailable()) {
createCameraPreviewSessionLocked();
}
}
}
■プレビューを表示する
private void createCameraPreviewSessionLocked() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface,
mJpegImageReader.get().getSurface(),
mRawImageReader.get().getSurface()), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
synchronized (mCameraStateLock) {
setup3AControlsLocked(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
cameraCaptureSession.setRepeatingRequest(
mPreviewRequestBuilder.build(),
mPreCaptureCallback, mBackgroundHandler);
mState = STATE_PREVIEW;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
CameraCaptureSessionのcaptureにより撮影を開始します。
private void takePicture() {
// Replace the existing repeating request with one with updated 3A triggers.
mCaptureSession.capture(mPreviewRequestBuilder.build(), mPreCaptureCallback,
mBackgroundHandler);
}
キャプチャするフレームの設定を行います。
最後にもう一度CameraCaptureSessionのcaptureを呼び出すことで
カメラデバイスに対して撮影処理のRequestを発行します。
private void captureStillPictureLocked() {
// Use the same AE and AF modes as the preview.
setup3AControlsLocked(captureBuilder);
// Create an ImageSaverBuilder in which to collect results, and add it to the queue
// of active requests.
ImageSaver.ImageSaverBuilder rawBuilder = new ImageSaver.ImageSaverBuilder(activity)
.setCharacteristics(mCharacteristics);
mRawResultQueue.put((int) request.getTag(), rawBuilder);
mCaptureSession.capture(request, mCaptureCallback, mBackgroundHandler);
}
onCaptureCompletedが呼び出されます。
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
synchronized (mCameraStateLock) {
rawBuilder = mRawResultQueue.get(requestId);
handleCompletionLocked(requestId, rawBuilder, mRawResultQueue);
if (rawBuilder != null) {
rawBuilder.setResult(result);
if (jpegBuilder != null) sb.append(", ");
sb.append("Saving RAW as: ");
sb.append(rawBuilder.getSaveLocation());
}
finishedCaptureLocked();
}
}
バックグラウンドのスレッドとして実行します。
ImageSaverでは、画像の保存処理を行います。
private void handleCompletionLocked(int requestId, ImageSaver.ImageSaverBuilder builder,
TreeMap<Integer, ImageSaver.ImageSaverBuilder> queue) {
ImageSaver saver = builder.buildIfComplete();
if (saver != null) {
queue.remove(requestId);
AsyncTask.THREAD_POOL_EXECUTOR.execute(saver);
}
}
■画像を保存する
DngCreator classを使って取得したデータをDNGファイル形式へ変換します。
※DNGファイルとは米アドビシステムズが開発したファイル形式です。詳細は、リンク先の「Adobe DNG ~ specification」を参照ください
switch (format) {
case ImageFormat.RAW_SENSOR: {
DngCreator dngCreator = new DngCreator(mCharacteristics, mCaptureResult);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
dngCreator.writeImage(output, mImage);
success = true;
} finally {
mImage.close();
closeOutput(output);
}
}
}
最後にMediaScannerConnection classのscanFileを使って、
画像をContentProviderへ登録します。
これにより、撮影した画像をギャラリーへ反映させることができます。
if (success) {
MediaScannerConnection.scanFile(mContext, new String[]{mFile.getPath()},
/*mimeTypes*/null, new MediaScannerConnection.MediaScannerConnectionClient() {
@Override
public void onScanCompleted(String path, Uri uri) {
Log.i(TAG, "Scanned " + path + ":");
Log.i(TAG, "-> uri=" + uri);
}
});
■撮影を終えて
比較すると非常に大きなサイズであることがわかります。
近年、スマホに搭載されるカメラの性能が上がったため、子供の運動会や
結婚式でもスマホで撮影しているシーンをよく見かけます。
大事なシーンの撮影は一眼レフカメラで撮影するイメージが強かったのですが、
スマホがどんどんその性能に近づいてきているんだなと実感しました。





























