android - 如何使用 CameraX 在 Android 中提高相机速度
问题描述
嗨,我是 Android 编程新手。
如标题,如何提高使用 CameraX 或 Camera2 或 OpenCV 拍照的速度?我的项目目标是尽可能快地使用 Android 和 OpenCV 进行图像处理(4k 图像)。
如果您有任何意见,请告诉我。
void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
Preview preview = new Preview.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
executor = Executors.newSingleThreadExecutor();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
ImageCapture imageCapture = new ImageCapture.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
.build();
camera_capture_button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Log.v("Info", "Button Click");
imageCapture.takePicture(executor , new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(@NonNull ImageProxy image) {
super.onCaptureSuccess(image);
Log.v("Info", "Capture Success = W:" + image.getWidth() + "/" + "H:" + image.getHeight());
Bitmap bitmap = toBitmap(image);
Log.v("Info", "Bitmat cvt = W:" + bitmap.getWidth() + "/" + "H:" + bitmap.getHeight());
Mat matOriginal = new Mat();
Mat matResult = new Mat();
Utils.bitmapToMat(bitmap, matOriginal);
Log.v("Info", "Mat cvt = W:" + matOriginal.width() + "/" + "H:" + matOriginal.height());
Imgproc.cvtColor(matOriginal, matResult, Imgproc.COLOR_BGR2HSV);
image.close();
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Log.v("Info", "Capture Error");
exception.printStackTrace();
}
});
}
});
这是用于测量时间的 Logcat 消息
2021-05-12 16:20:40.427 V/Info: 按钮点击
2021-05-12 16:20:40.976 V/信息:捕获成功 = W:3840/H:2160
2021-05-12 16:20:41.092 V/信息:位图 cvt = W:3840/H:2160
2021-05-12 16:20:41.106 V/信息:Mat cvt = W:3840/H:2160
作为结果
549msec - takePicture(我觉得太慢了)
116 毫秒 - 位图转换
014msec - 垫转换
解决方案
您可以尝试将图像转换为 Mat 而无需先转换为位图,使用此扩展功能:
fun Image.yuvToRgba(): Mat {
val rgbaMat = Mat()
if (format == ImageFormat.YUV_420_888
&& planes.size == 3) {
val chromaPixelStride = planes[1].pixelStride
if (chromaPixelStride == 2) { // Chroma channels are interleaved
assert(planes[0].pixelStride == 1)
assert(planes[2].pixelStride == 2)
val yPlane = planes[0].buffer
val uvPlane1 = planes[1].buffer
val uvPlane2 = planes[2].buffer
val yMat = Mat(height, width, CvType.CV_8UC1, yPlane)
val uvMat1 = Mat(height / 2, width / 2, CvType.CV_8UC2, uvPlane1)
val uvMat2 = Mat(height / 2, width / 2, CvType.CV_8UC2, uvPlane2)
val addrDiff = uvMat2.dataAddr() - uvMat1.dataAddr()
if (addrDiff > 0) {
assert(addrDiff == 1L)
Imgproc.cvtColorTwoPlane(yMat, uvMat1, rgbaMat, Imgproc.COLOR_YUV2BGR_NV12)
} else {
assert(addrDiff == -1L)
Imgproc.cvtColorTwoPlane(yMat, uvMat2, rgbaMat, Imgproc.COLOR_YUV2BGR_NV21)
}
} else { // Chroma channels are not interleaved
val yuvBytes = ByteArray(width * (height + height / 2))
val yPlane = planes[0].buffer
val uPlane = planes[1].buffer
val vPlane = planes[2].buffer
yPlane.get(yuvBytes, 0, width * height)
val chromaRowStride = planes[1].rowStride
val chromaRowPadding = chromaRowStride - width / 2
var offset = width * height
if (chromaRowPadding == 0) {
// When the row stride of the chroma channels equals their width, we can copy
// the entire channels in one go
uPlane.get(yuvBytes, offset, width * height / 4)
offset += width * height / 4
vPlane.get(yuvBytes, offset, width * height / 4)
} else {
// When not equal, we need to copy the channels row by row
for (i in 0 until height / 2) {
uPlane.get(yuvBytes, offset, width / 2)
offset += width / 2
if (i < height / 2 - 1) {
uPlane.position(uPlane.position() + chromaRowPadding)
}
}
for (i in 0 until height / 2) {
vPlane.get(yuvBytes, offset, width / 2)
offset += width / 2
if (i < height / 2 - 1) {
vPlane.position(vPlane.position() + chromaRowPadding)
}
}
}
val yuvMat = Mat(height + height / 2, width, CvType.CV_8UC1)
yuvMat.put(0, 0, yuvBytes)
Imgproc.cvtColor(yuvMat, rgbaMat, Imgproc.COLOR_YUV2BGR_I420, 4)
}
}
return rgbaMat
}
并这样称呼它:
image.image?.let {
if (it.format == ImageFormat.YUV_420_888
&& it.planes.size == 3
) {
val rgbaMat = it.yuvToRgba()
}
}
推荐阅读
- python - Keras:如何将两个层而不是 Elementwise 组合成更大的形状
- c# - 鼠标轴基于位置,而不是移动
- javascript - 如何修复图像不显示在 php 中?
- spring-boot - 推土机映射器字段不存在
- java - 是创建一个仅用于 Optional.ifPresentOrElse 的类变量是要避免的做法吗?
- java - Android Studio 错误:致命信号 6 (SIGABRT),代码 -1
- opencv - Azure Kinect 录制颜色格式
- c - C 编译:重定位被截断以适合 R_X86_64_PC32 对符号
- html - 在引导程序中居中文本
- java - Binary Heap downheap 方法无法正常工作