注: このページでは、Camera2 パッケージについて説明します。アプリで Camera2 の特定の低レベルの機能を必要とする場合を除き、CameraX を使用することをおすすめします。CameraX と Camera2 は、どちらも Android 5.0(API レベル 21)以降に対応しています。
Android でカメラとカメラ プレビューの向きが常に同じではない できます。
カメラは、デバイスの位置に関係なく、デバイス上の固定された位置にある スマートフォン、タブレット、パソコンのいずれかになります。デバイスの向きが変わると、 カメラの向きが変わります。
そのため、カメラアプリは通常、カメラアプリ デバイスの向きとカメラ プレビューのアスペクト比。特定の スマートフォンが縦向きになっているため、カメラ プレビューは縦長になると考えられる 幅を狭めると長くなりますスマートフォン(とカメラ)を横向きに回転させると、 カメラ プレビューは、横幅が高さよりも幅があることが想定されます。
しかし、折りたたみ式などの新しいフォーム ファクタがこうした前提に反する デバイス、ディスプレイ モード マルチウィンドウ および マルチディスプレイ。 折りたたみ式デバイスでは、ディスプレイ サイズとアスペクト比がそのまま変更される 方向です。マルチ ウィンドウ モードでは、カメラアプリが デバイスの向きにかかわらずカメラ プレビューを拡大縮小できます。 マルチディスプレイ モードでは、セカンダリ ディスプレイを使用できますが、 プライマリ ディスプレイと同じ向きにする必要があります。
カメラの向き
「 Android 互換性定義 は、カメラのイメージ センサーの向きを、 カメラの寸法が画面の長辺と合うようにします。つまり デバイスは横向きで保持されるため、カメラは横向きで画像をキャプチャしなければなりません。 横向きに設定しているとしますこれは、デバイスの自然な状態にかかわらず、 向き:つまり、横向き主体のデバイスと、 自動的に選択されます。
カメラから画面への配置により、カメラの表示領域が最大化される ビューファインダーの画面ですまた、イメージ センサーは通常、 アスペクト比は 4:3 が一般的です
カメラセンサーの自然な向きは横向き。図 1 のセンサーは、 前面カメラの向き(カメラと向きが がスマートフォンに対して 270 度回転している Android 互換性定義。
センサーの回転をアプリに公開するために、
camera2 API には、
SENSOR_ORIENTATION
あります。ほとんどのスマートフォンやタブレットでは、デバイスからセンサーの向きが報告されます。
270 度(前面カメラ)と 90 度(カメラから見た視点)
背面カメラの場合は、デバイスの背面の長辺に合わせて
センサーをデバイスの長辺に接触させることですノートパソコンのカメラは通常、
0 度または 180 度に設定します。
カメラのイメージ センサーは、データ(イメージ バッファ)を
センサーの自然な向き(横向き)では、画像バッファを
カメラ プレビューの角度(SENSOR_ORIENTATION
で指定された角度)
デバイスの自然な向きで縦向きに表示できます。前面カメラの場合は
回転は反時計回りです。背面カメラの場合は時計回りで設定できます
たとえば、図 1 の前面カメラの場合、画像バッファは 次のような画像が表示されます。
画像を反時計回りに 270 度回転させて、プレビューが 向きがデバイスの向きと一致します。
背面カメラでは、同じ向きの画像バッファが生成されます。
上記のバッファと同じですが、SENSOR_ORIENTATION
は 90 度です。その結果
バッファが時計回りに 90 度回転します。
デバイスの回転
デバイスの回転とは、デバイスが自然な状態から回転する度数 方向です。たとえば、横向きのスマートフォンには、 方向に応じて 90 度または 270 度回転できます。
カメラセンサーのイメージ バッファは、カメラセンサーのイメージ バッファを 回転(センサーの向きに加えて)が回転するように カメラ プレビューが上向きに表示されます。
向きの計算
センサーを考慮したカメラ プレビューの適切な向き 画面の向きとデバイスの回転を制御します。
センサー イメージ バッファの全体的な回転は、 式:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
ここで、sign
は前面カメラの場合は 1
、背面カメラの場合は -1
です。
前面カメラの場合、画像バッファは反時計回りに回転します( センサーの自然な向きが調整されます。背面カメラの場合、センサーは 画像バッファが時計回りに回転します。
式 deviceOrientationDegrees * sign + 360
はデバイスの回転を変換し、
背面カメラの場合は、反時計回りから時計回りに変更できます(例:
反時計回り 270 度を時計回り 90 度に変換します)。剰余
演算により、結果が 360 度未満にスケーリングされます(たとえば、540 度に
180 度に変更します。
API によってデバイスの回転の報告方法は異なります。
Display#getRotation()
は、(ユーザーの先端から)デバイスの反時計回りの回転を示します です。この値はそのまま上の式に代入されます。OrientationEventListener#onOrientationChanged()
は、ユーザーの視点から見たデバイスの時計回りの回転を返します。 上記の式で使用する値を否定します。
前面カメラ
図 2 のカメラセンサーによって生成された画像バッファは次のとおりです。
センサーを調整するには、バッファを反時計回りに 270 度回転する必要があります (上記のカメラの向きを参照):
次に、バッファをさらに 90 度回転させて反時計回りに これにより、デバイスの向きが正しく調整され、 カメラ プレビューを図 2 に示します。
ここでは、カメラを右を横向きにしています。
画像バッファは次のとおりです。
センサーを調整するには、バッファを反時計回りに 270 度回転する必要があります 向き:
次に、バッファを反時計回りにさらに 270 度回転させ、 次のように指定します。
背面カメラ
通常、背面カメラのセンサーの向きは 90 度です( 。カメラ プレビューの向きを調整する際、 センサー イメージ バッファは、センサーの回転量だけ時計回りに回転しています (前面カメラのように反時計回りではなく)してから、画像を バッファがデバイスの回転量だけ反時計回りに回転します。
図 4 のカメラセンサーからの画像バッファは次のとおりです。
センサーを調整するには、バッファを時計回りに 90 度回転する必要があります 向き:
次に、デバイスを考慮して、バッファを反時計回りに 270 度回転させます。 ローテーション:
アスペクト比
デバイスの画面の向きが変わるとディスプレイのアスペクト比が変化するだけでなく、 マルチウィンドウでウィンドウのサイズが変更されたときに、折りたたみ式デバイスでの折りたたみと展開 セカンダリ ディスプレイでアプリを開いたときに通知を受け取れます。
カメラセンサーのイメージ バッファの向きとスケーリングは、 ビューファインダー UI 要素の向きとアスペクト比 画面の向きを動的に変える(デバイスの変更の有無にかかわらず) 方向です。
新しいフォーム ファクタ、またはマルチウィンドウまたはマルチディスプレイ環境で、 アプリは、カメラ プレビューの向きがデバイスと同じであると想定する (縦向きまたは横向き)で、プレビューの向きが正しくない、拡大縮小される場合があります 間違っているかもしれません。
図 5 では、デバイスはデバイスを 90° 回転させたと誤って想定されていました。 度(反時計回り)そのため、アプリはプレビューを同じ量だけ回転しました。
図 6 では、アプリは画像バッファのアスペクト比を カメラ プレビュー UI の新しいサイズに合わせて適切に拡大縮小できるようにする 要素です。
向きが固定されているカメラアプリでは、折りたたみ式デバイスで問題が発生することが一般的です。 ノートパソコンなど、その他の大画面デバイス:
図 7 では、カメラアプリの UI が横向きになっています。これは、アプリの向きによって 縦向きのみに制限されます。ビューファインダー画像の向きが正しい カメラセンサーに対して相対的に調整できます。
ポートレート モードをインセット
マルチ ウィンドウ モードをサポートしていないカメラアプリ
(resizeableActivity="false"
)
画面の向きを
(screenOrientation="portrait"
)
または screenOrientation="landscape"
)
大画面のデバイスで縦向きモードをインセットにして配置することで、
カメラ プレビュー。
縦向きの縦向きモードのレターボックス(インセット)の縦向き専用アプリのインセット 画面のアスペクト比が横向きであっても 横向き表示にします 横向き専用のアプリは、横向きになるとレターボックス表示されますが、 ディスプレイのアスペクト比が縦向きです。カメラの画像が回転して配置されます アプリの UI が表示され、カメラ プレビューのアスペクト比に合わせて切り抜かれている 拡大縮小されます。
ポートレート モードのインセットは、カメラ画像のアスペクト比が一定になったときにトリガーされます アプリのプライマリ アクティビティのアスペクト比が一致しません。
図 8 では、縦向き専用のカメラアプリが回転して UI が表示されています。 ノートパソコンのディスプレイに立てて置けます。差異により、アプリがレターボックス表示されます。 縦向きアプリと横向きディスプレイの アスペクト比ですカメラ プレビュー画像は、アプリの UI の回転( ポートレート モードをインセット)を使用しており、画像は 縦向き、画角が狭くなります。
回転、切り抜き、サイズ変更
ディスプレイの縦向き専用のカメラアプリでインセットの縦向きモードが呼び出される 400x250 にします
アプリが縦向きでレターボックス表示されます。
カメラの画像を 90 度回転して、カメラの向きを調整します。 app:
画像はカメラ プレビューのアスペクト比に合わせて切り抜かれた後、次のサイズに拡大されます。 プレビュー全体に表示されます(画角が小さくなります)。
折りたたみ式デバイスでは、カメラセンサーの向きを縦向きにできます。 ディスプレイのアスペクト比は横向きです。
センサーの向きに合わせてカメラ プレビューが回転するため、 ビューファインダーでは画像の向きは適切ですが、縦向き専用アプリでは 使用できます。
縦向きモードのインセットでは、アプリを縦向きにレターボックス表示するだけで済みます アプリとカメラ プレビューの向きを正しく設定します。
API
Android 12(API レベル 31)以降では、インセットの縦向きの明示的な制御も可能
新しい ReplicaSet の
SCALER_ROTATE_AND_CROP
CaptureRequest
のプロパティ
クラスです。
デフォルト値は
SCALER_ROTATE_AND_CROP_AUTO
これにより、システムはインセット縦向きモードを呼び出すことができます。
SCALER_ROTATE_AND_CROP_90
上記のインセット縦表示の動作です。
すべてのデバイスがすべての SCALER_ROTATE_AND_CROP
値をサポートしているわけではありません。リストを取得するには
値、参照先
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES
。
CameraX
Jetpack CameraX ライブラリ センサーの向きに合わせてカメラのビューファインダーを作成し デバイスの回転は簡単です。
PreviewView
レイアウト要素
カメラ プレビューの作成、センサーの向きの自動調整、
デバイスの回転、スケーリングなどがありますPreviewView
は、動画のアスペクト比を維持します。
適用することで、Google の
FILL_CENTER
スケールタイプ: 画像を中央に配置するが、サイズに合わせて画像を切り抜く
(PreviewView
の)。カメラ画像をレターボックス表示するには、スケールタイプを
FIT_CENTER
。
PreviewView
でカメラ プレビューを作成する基本については、以下をご覧ください。
プレビューを実装する。
完全な実装例については、
CameraXBasic
リポジトリをご覧ください。
カメラビューファインダー
プレビューのユースケースと同様に、 CameraViewfinder ライブラリには、カメラ プレビューの作成を簡素化するツールセットが用意されています。 CameraX Core に依存しないため、お使いの Google Cloud 環境にシームレスに統合できます。 既存の Camera2 コードベースを使用します。
代わりに
Surface
直接作成するには、
CameraViewfinder
Camera2 のカメラフィードを表示します。
CameraViewfinder
は内部で TextureView
または SurfaceView
を使用しています
カメラフィードを表示し、それに必要な変換を適用して
ビューファインダーが正しく表示される。
これには、アスペクト比、スケール、回転の修正が含まれます。
CameraViewfinder
オブジェクトからサーフェスをリクエストするには、次のようにします。
ViewfinderSurfaceRequest
を作成します。
このリクエストには、サーフェス解像度とカメラデバイスの要件が含まれています。
CameraCharacteristics
の情報。
requestSurfaceAsync()
を呼び出しています
サーフェス プロバイダ(TextureView
または
SurfaceView
で、ListenableFuture
は Surface
です。
markSurfaceSafeToRelease()
を呼び出しています
サーフェスが不要であることを、サーフェス プロバイダに通知します。
リソースを解放できます
Kotlin
fun startCamera(){ val previewResolution = Size(width, height) val viewfinderSurfaceRequest = ViewfinderSurfaceRequest(previewResolution, characteristics) val surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest) Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> { override fun onSuccess(surface: Surface) { /* create a CaptureSession using this surface as usual */ } override fun onFailure(t: Throwable) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)) }
Java
void startCamera(){ Size previewResolution = new Size(width, height); ViewfinderSurfaceRequest viewfinderSurfaceRequest = new ViewfinderSurfaceRequest(previewResolution, characteristics); ListenableFuture<Surface> surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest); Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() { @Override public void onSuccess(Surface result) { /* create a CaptureSession using this surface as usual */ } @Override public void onFailure(Throwable t) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)); }
SurfaceView
SurfaceView
:
プレビューが表示されない場合に、簡単にカメラ プレビューを作成する方法
処理が必要で、アニメーション化されません。
SurfaceView
は、画像に合わせてカメラセンサーのイメージ バッファを自動的に回転させます。
センサーの向きとデバイスの両方を考慮したディスプレイの向き
作成できます。ただし、画像バッファは SurfaceView
に合わせてスケーリングされます。
アスペクト比は考慮されません。
イメージ バッファのアスペクト比とアスペクト比を一致させる必要があります。
SurfaceView
の比率。これはコンテンツをスケーリングすることで実現できます。
コンポーネントの SurfaceView
onMeasure()
メソッド:
(computeRelativeRotation()
ソースコードは
相対回転については後述します)。
Kotlin
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees) if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ val scaleX = if (relativeRotation % 180 == 0) { width.toFloat() / previewWidth } else { width.toFloat() / previewHeight } /* Scale factor required to scale the preview to its original size on the y-axis. */ val scaleY = if (relativeRotation % 180 == 0) { height.toFloat() / previewHeight } else { height.toFloat() / previewWidth } /* Scale factor required to fit the preview to the SurfaceView size. */ val finalScale = min(scaleX, scaleY) setScaleX(1 / scaleX * finalScale) setScaleY(1 / scaleY * finalScale) } setMeasuredDimension(width, height) }
Java
@Override void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees); if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ float scaleX = (relativeRotation % 180 == 0) ? (float) width / previewWidth : (float) width / previewHeight; /* Scale factor required to scale the preview to its original size on the y-axis. */ float scaleY = (relativeRotation % 180 == 0) ? (float) height / previewHeight : (float) height / previewWidth; /* Scale factor required to fit the preview to the SurfaceView size. */ float finalScale = Math.min(scaleX, scaleY); setScaleX(1 / scaleX * finalScale); setScaleY(1 / scaleY * finalScale); } setMeasuredDimension(width, height); }
SurfaceView
をカメラ プレビューとして実装する方法について詳しくは、以下をご覧ください。
カメラの向き。
TextureView
TextureView
のパフォーマンスが以下を下回っています:
SurfaceView
、作業量が多いが、TextureView
で最大限の
カメラ プレビューのコントロール。
TextureView
は、センサーの向きに基づいてセンサー イメージ バッファを回転しますが、
デバイスの回転やプレビューのスケーリングを処理しません。
スケーリングと回転は、
行列変換。Google Chat で
TextureView
の適切なスケーリングと回転については、以下をご覧ください。
カメラアプリでサイズ変更可能なサーフェスをサポートする
相対回転
カメラセンサーの相対回転は、 カメラセンサーの出力をデバイスの向きに合わせます。
相対回転は SurfaceView
や TextureView
などのコンポーネントで使用されます
プレビュー画像の x と y のスケーリング ファクタを決定します。また、kubectl の「get」コマンドや
センサー イメージ バッファの回転を指定します。
「
CameraCharacteristics
および
Surface
クラスを使用すると、
カメラセンサーの相対回転:
Kotlin
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public fun computeRelativeRotation( characteristics: CameraCharacteristics, surfaceRotationDegrees: Int ): Int { val sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!! // Reverse device orientation for back-facing cameras. val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ) 1 else -1 // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360 }
Java
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public int computeRelativeRotation( CameraCharacteristics characteristics, int surfaceRotationDegrees ){ Integer sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); // Reverse device orientation for back-facing cameras. int sign = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1; // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360; }
ウィンドウ指標
画面サイズからカメラの寸法を判断することはできません ビューファインダー画面の一部で実行されている可能性があります。 モバイル デバイスではマルチウィンドウ モード、ChromeOS ではフリーフリー モードで表示できます。
WindowManager#getCurrentWindowMetrics()
(API レベル 30 で追加)は、
画面のサイズに合わせて調整できます。Jetpack WindowManager ライブラリのメソッド
WindowMetricsCalculator#computeCurrentWindowMetrics()
および
WindowInfoTracker#currentWindowMetrics()
API レベル 14 との下位互換性により、同様のサポートが提供されます。
180 度回転
デバイスを 180 度回転させる(たとえば、自然な向きから
(自然な向きが逆向き)になっていても、
onConfigurationChanged()
呼び出すことができます。その結果、カメラ プレビューが上下逆になることがあります。
180 度の回転を検出するには、
DisplayListener
呼び出してデバイスの回転を確認します。
Display#getRotation()
の
onDisplayChanged()
呼び出すことができます。
限定リソース
Android 10 より前で、マルチウィンドウで一番上に表示されているアクティビティのみ
環境が RESUMED
状態だった。これは ユーザーの混乱を招きました
システムはどの活動が再開されたかを示すものがありませんでした。
Android 10(API レベル 29)では、すべての表示アクティビティがある複数のアプリの再開が導入されました。
RESUMED
状態である。表示中のアクティビティは引き続き PAUSED
に入ることができます
たとえば、透明なアクティビティがそのアクティビティの上に配置されている場合や、
アクティビティがフォーカス可能でない場合(ピクチャー イン ピクチャー モードの場合など)は、
ピクチャー イン ピクチャーのサポート)。
カメラ、マイク、または専用または
API レベル 29 以降のシングルトン リソースは、複数のアプリの再開をサポートする必要があります。対象
たとえば、再開中の 3 つのアクティビティがカメラを使用したい場合、
この専用リソースにアクセスできます各アクティビティでは、
onDisconnected()
より優先度の高いカメラへのプリエンプティブ アクセスを常に認識
できます。
詳細については、次をご覧ください: 複数のアプリの再開。
参考情報
- Camera2 のサンプルについては、Camera2Basic アプリをご覧ください。 ご覧ください。
- CameraX プレビューのユースケースについては、CameraX をご覧ください。 プレビューを実装する。
- CameraX カメラ プレビューの実装例については、以下をご覧ください。 CameraXBasic リポジトリをご覧ください。
- ChromeOS でのカメラ プレビューについて詳しくは、以下をご覧ください。 カメラの向き。
- 折りたたみ式デバイス向けの開発について詳しくは、以下をご覧ください。 詳しくは、折りたたみ式デバイスについての記事をご覧ください。