OpenCV4.10.0 sdkのjavaソース中に非推奨が指摘される 対策
2025.1.21 2021.3.3Coskx Lab
1 概要
OpenCV sdkのandroidのjavaソースの一部が非推奨と警告が出るようになってきたので,対応します。
すでに非推奨となっているhardware cameraAPIを使わずにcamera2APIを使うプログラミングを対象にしています。
(JavaCameraView.javaを使わずにJavaCamera2View.javaを使っている)
問題になっているのは,次の2つです。
1.JavaCamera2View.java
createCaptureSession()が API level 30 以降で非推奨
2.CameraBridgeViewBase.java
WindowManagerのgetDefaultDisplay()が API level 30 以降で非推奨
それ故,OpenCV4.10.0-sdkのJavaCamera2View.javaとCameraBridgeViewBase.javaを書き換えた対策済の差し替え版を作成します。
修正したJavaCamera2View.javaとCameraBridgeViewBase.javaのダウンロード
2 使用環境
- Windows 11 64-bit
- Android Studio Ladybug Feature Drop | 2024.2.2
Build #AI-242.23726.103.2422.12816248, built on December 18, 2024
Runtime version: 21.0.4+-12508038-b607.1 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Toolkit: sun.awt.windows.WToolkit
- java (JavaVersion.VERSION_11)
- Build Target 35 (24以降で動作検証済)
- OpenCV 4.10.0
3 CameraDevice.createCaptureSessionが非推奨
Android11(API 30)以降を開発ターゲットにすると,OpenCVのJavaCamera2View(Camera2ライブラリ使用クラス)のCameraDevice.createCaptureSessionが非推奨となっており,警告が出ています。
そのままにしていても,当面は大丈夫と思いますが,「Developers」にて置き換えが指示されている別の形のコンストラクタに変更しました。
このJavaCamera2View classは重要なのでいずれOpenCV本家の記述が修正されると思いますが,それまでの間を過ごすための作業です。
3.1 対策前
非推奨警告が出るのはJavaCamera2View.javaのメソッドprivate void createCameraPreviewSession()内のCameraDevice.createCaptureSessionを作っているところです。
OPenCV 4.10.0同梱のJavaCamera2View.java createCameraPreviewSession()
private void createCameraPreviewSession() {
final int w = mPreviewSize.getWidth(), h = mPreviewSize.getHeight();
Log.i(LOGTAG, "createCameraPreviewSession(" + w + "x" + h + ")");
if (w < 0 || h < 0)
return;
try {
if (null == mCameraDevice) {
Log.e(LOGTAG, "createCameraPreviewSession: camera isn't opened");
return;
}
if (null != mCaptureSession) {
Log.e(LOGTAG, "createCameraPreviewSession: mCaptureSession is already started");
return;
}
mImageReader = ImageReader.newInstance(w, h, mPreviewFormat, 2);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image == null)
return;
// sanity checks - 3 planes
Image.Plane[] planes = image.getPlanes();
assert (planes.length == 3);
assert (image.getFormat() == mPreviewFormat);
RotatedCameraFrame tempFrame = new RotatedCameraFrame(new JavaCamera2Frame(image), mFrameRotation);
deliverAndDrawFrame(tempFrame);
tempFrame.mFrame.release();
tempFrame.release();
image.close();
}
}, mBackgroundHandler);
Surface surface = mImageReader.getSurface();
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(mRequestTemplate);
mPreviewRequestBuilder.addTarget(surface);
mCameraDevice.createCaptureSession(Arrays.asList(surface),
allocateSessionStateCallback(), null);
} catch (CameraAccessException e) {
Log.e(LOGTAG, "createCameraPreviewSession", e);
}
}
3.2 対策
https://developer.android.com/reference/android/hardware/camera2/CameraDevice
では
createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
This method was deprecated in API level 30. Please use createCaptureSession(android.hardware.camera2.params.SessionConfiguration) for the full set of configuration options available.
となっています。
そこでSessionConfigurationを使うようにして,次のように置き換えます。
修正後のJavaCamera2View.java createCameraPreviewSession()
private void createCameraPreviewSession() {
final int w = mPreviewSize.getWidth(), h = mPreviewSize.getHeight();
Log.i(LOGTAG, "createCameraPreviewSession(" + w + "x" + h + ")");
if (w < 0 || h < 0)
return;
try {
if (null == mCameraDevice) {
Log.e(LOGTAG, "createCameraPreviewSession: camera isn't opened");
return;
}
if (null != mCaptureSession) {
Log.e(LOGTAG, "createCameraPreviewSession: mCaptureSession is already started");
return;
}
mImageReader = ImageReader.newInstance(w, h, mPreviewFormat, 2);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image == null)
return;
// sanity checks - 3 planes
Image.Plane[] planes = image.getPlanes();
assert (planes.length == 3);
assert (image.getFormat() == mPreviewFormat);
RotatedCameraFrame tempFrame = new RotatedCameraFrame(new JavaCamera2Frame(image), mFrameRotation);
deliverAndDrawFrame(tempFrame);
tempFrame.mFrame.release();
tempFrame.release();
image.close();
}
}, mBackgroundHandler);
Surface surface = mImageReader.getSurface();
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(mRequestTemplate);
mPreviewRequestBuilder.addTarget(surface);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
mCameraDevice.createCaptureSession(
new SessionConfiguration(
SessionConfiguration.SESSION_REGULAR,
Collections.singletonList(new OutputConfiguration(surface)),
Executors.newCachedThreadPool(),
allocateSessionStateCallback()
));
} else { //for old devices (This section would be noted as deprecated.)
mCameraDevice.createCaptureSession(Collections.singletonList(surface),
allocateSessionStateCallback(), null);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
} catch (CameraAccessException e) {
Log.e(LOGTAG, "createCameraPreviewSession", e);
}
}
4 CameraDevice.createCaptureSessionが非推奨
Android11(API 30)以降を開発ターゲットにすると,CameraBridgeViewBase.javaのWindowManagerのgetDefaultDisplay()が API level 30 以降で非推奨が非推奨となっており,警告が出ています。
そのままにしていても,当面は大丈夫と思いますが,修正変更しました。
このCameraBridgeViewBase classは重要なのでいずれOpenCV本家の記述が修正されると思いますが,それまでの間を過ごすための作業です。
4.1 対策前
非推奨警告が出るのはCameraBridgeViewBase.javaのメソッドprotected int getFrameRotation()内のscreenOrientationの値を得ているところです。
OPenCV 4.10.0同梱のCameraBridgeViewBase.java getFrameRotation()
protected int getFrameRotation(boolean cameraFacingFront, int cameraSensorOrientation) {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
int screenOrientation = windowManager.getDefaultDisplay().getRotation();
int screenRotation = 0;
switch (screenOrientation) {
case Surface.ROTATION_0:
screenRotation = 0;
break;
case Surface.ROTATION_90:
screenRotation = 90;
break;
case Surface.ROTATION_180:
screenRotation = 180;
break;
case Surface.ROTATION_270:
screenRotation = 270;
break;
}
int frameRotation;
if (cameraFacingFront) {
frameRotation = (cameraSensorOrientation + screenRotation) % 360;
} else {
frameRotation = (cameraSensorOrientation - screenRotation + 360) % 360;
}
return frameRotation;
}
4.2 対策
getDisplay()を使うようにして,次のように置き換えます。
修正後のCameraBridgeViewBase.java getFrameRotation()
protected int getFrameRotation(boolean cameraFacingFront, int cameraSensorOrientation) {
int screenOrientation;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
screenOrientation = Objects.requireNonNull(((Activity) mContext).getDisplay()).getRotation();
} else { //for old devices (This section would be noted as deprecated.)
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
screenOrientation = windowManager.getDefaultDisplay().getRotation();
}
int screenRotation = 0;
switch (screenOrientation) {
case Surface.ROTATION_0:
screenRotation = 0;
break;
case Surface.ROTATION_90:
screenRotation = 90;
break;
case Surface.ROTATION_180:
screenRotation = 180;
break;
case Surface.ROTATION_270:
screenRotation = 270;
break;
}
int frameRotation;
if (cameraFacingFront) {
frameRotation = (cameraSensorOrientation + screenRotation) % 360;
} else {
frameRotation = (cameraSensorOrientation - screenRotation + 360) % 360;
}
return frameRotation;
}
5 まとめ
OpenCV4.10.0のソースのJavaCamera2View.javaがAndroid11(API 30)以降で非推奨メソッドが使用されているため,
またCameraBridgeViewBase.java getFrameRotation()もAndroid11(API 30)以降で非推奨メソッドが使用されているため,
対応しました。
ただし,両者とも互換対応用記述が残るので,コンパイル時の警告は出ます。
なお次の7つのファイルは使われていないのであれば,無効にすると,コンパイル時のdeprecated警告表示は,かなりなくなります。
Camera2Renderer.java
CameraActivity.java
CameraGLRendererBase.java
CameraGLSurfaceView.java
CameraRenderer.java
JavaCameraView.java
NativeCameraView.java