我想使用OpenCV进行实时图像处理,并且想使用Android Camera2 API。我的问题是将预览帧转换为OpenCV Mat(或者首先转换为位图也会有所帮助)。
我知道您可以将ImageReader附加到相机并将每个可用的图像转换为位图。问题在于将ImageReader附加到相机会大大降低帧速率(不是任何图像转换,而只是使用ImageReader而没有任何其他代码)。 所以我的想法是将Allocation的表面附加到相机上,将该Allocation传递给ScriptIntrinsicYuvToRGB-Renderscript并将输出的Allocation复制到位图,就像在android-hdf-viewfinder example中一样。 那就是我到目前为止所尝试的:
private fun setupRenderscript(){
rs = RenderScript.create(context)
val tb1 = Type.Builder(rs, Element.YUV(rs)).setX(size.width).setY(size.height)
rsInput = Allocation.createTyped(rs, tb1.create(), Allocation.USAGE_IO_INPUT or Allocation.USAGE_SCRIPT)
bmOut = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888)
val tb2 = Type.Builder(rs, Element.RGBA_8888(rs)).setX(size.width).setY(size.height)
rsOutput = Allocation.createTyped(rs, tb2.create(), Allocation.USAGE_SCRIPT)
yuvToRgbIntrinistic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))
yuvToRgbIntrinistic.setInput(rsInput)
}
private fun createCameraPreviewSession() {
setupRenderscript()
val texture = cameraTextureView.surfaceTexture //Normal camera preview surface
texture.setDefaultBufferSize(size.width, size.height)
val surface = Surface(texture)
captureRequestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder?.addTarget(surface)
captureRequestBuilder?.addTarget(rsInput.surface) //Attach Allocation Surface to CaptureRequest
cameraDevice?.createCaptureSession(Arrays.asList(surface, rsInput.surface), cameraCaptureSession, backgroundHandler)
private val surfaceTextureListener = object : SurfaceTextureListener {
override fun onSurfaceTextureAvailable(texture: SurfaceTexture?, width: Int, height: Int) {
openCamera(width, height)
}
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture?, width: Int, heigth: Int) {
configureTransform(width, heigth)
}
override fun onSurfaceTextureUpdated(texture: SurfaceTexture?){
if (::rsOutput.isInitialized){
log("Image")
rsInput.ioReceive()
yuvToRgbIntrinistic.forEach(rsOutput)
rsOutput.copyTo(bmOut)
}
}
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture?) = true
}
相机预览工作正常,现在引发致命错误,但我没有将预览作为位图。我收到以下日志消息:
对于rsInput.ioReceive()
:
E/NdkImageReader: acquireImageLocked: Output buffer format: 0x22, ImageReader configured format: 0x1
E/RenderScript: lockNextBuffer: acquire image from reader 0x7427c7d8a0 failed! ret: -10000, img 0x0
E/RenderScript_jni: non fatal RS error, Error receiving IO input buffer.
对于yuvToRgbIntrinistic.forEach(rsOutput)
,我可能会针对每个像素多次收到相同的消息:
E/RenderScript: YuvToRGB executed without data, skipping
因此,似乎无法将数据复制/读取到输入分配中,但是我不知道自己在做什么错。它的工作方式应类似于上面链接的hdr示例。
答案 0 :(得分:0)
问题在于,将ImageReader附加到相机会大大降低帧率(不是任何图像转换,而只是使用ImageReader而没有任何其他代码)
这不应该发生。您可能没有正确配置相机会话和图像读取器的输出目标。您还需要确保尽快关闭发送到图像阅读器的图像,以便下一幅图像可以进入。如果您真的很在意性能,则应该使用YUV_420_888作为像素格式,具体取决于输出目标的大小,3-5帧作为图像读取器的缓冲区。以下是一些示例代码,可帮助您开始适应this blog post:
val bufferSize = 3
val imageReader = ImageReader.newInstance(
// Pick width and height from supported camera output sizes
width, height, ImageFormat.YUV_420_888, bufferSize)
// Retrieve surface from image reader
val imReaderSurface = imageReader.surface
val targets: MutableList<Surface> = arrayOf(imReaderSurface).toMutableList()
// Create a capture session using the predefined targets
cameraDevice.createCaptureSession(targets, object: CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
// Submit capture requests here
}
// Omitting for brevity...
override fun onConfigureFailed(session: CameraCaptureSession) = Unit
}, null)
关于RenderScript错误,很难判断您提供的详细信息是怎么回事。如果您尚未这样做,我建议您使用RenderScript support library,并在模拟器中测试代码以排除潜在的驱动程序实现问题。