Android 如何使用renderscript将Camera2预览帧获取为位图或OpenCV Mat

Android 如何使用renderscript将Camera2预览帧获取为位图或OpenCV Mat,android,opencv,android-camera2,renderscript,yuv,Android,Opencv,Android Camera2,Renderscript,Yuv,我想用OpenCV做实时图像处理,我想用Android Camera2 API。我的问题是将预览帧转换为OpenCV Mat(或者首先转换为位图也会有所帮助) 我知道你可以将图像阅读器连接到相机上,并将所有可用图像转换为位图。问题在于,将ImageReader连接到相机会大幅降低帧速率(不是任何图像转换,而是仅使用ImageReader而无需任何附加代码)。 因此,我的想法是将分配的表面附加到相机,将分配传递给ScriptIntrinsicYuvtorgbRenderScript,并将输出分配复

我想用OpenCV做实时图像处理,我想用Android Camera2 API。我的问题是将预览帧转换为OpenCV Mat(或者首先转换为位图也会有所帮助)

我知道你可以将图像阅读器连接到相机上,并将所有可用图像转换为位图。问题在于,将ImageReader连接到相机会大幅降低帧速率(不是任何图像转换,而是仅使用ImageReader而无需任何附加代码)。 因此,我的想法是将分配的表面附加到相机,将分配传递给ScriptIntrinsicYuvtorgbRenderScript,并将输出分配复制到位图,如中所示。 这就是我迄今为止所尝试的:

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()

对于
yuvtorgbinistic.forEach(rsOutput)
我多次收到相同的消息,可能是针对每个像素:

E/RenderScript: YuvToRGB executed without data, skipping
因此,将数据复制/读取到输入分配中似乎不起作用,但我不知道我做错了什么。它的工作原理应该与上面链接的hdr示例类似

问题在于,将ImageReader连接到相机会大幅降低帧速率(不是任何图像转换,而是仅使用ImageReader而无需任何附加代码)

这不应该发生。您可能没有正确配置相机会话和图像读取器的输出目标。您还需要确保尽快关闭发送到图像阅读器的图像,以便下一个图像可以进入。如果您真的关心性能,您应该使用YUV_420_888作为像素格式,并根据输出目标的大小,使用3-5帧作为图像读取器的缓冲区。以下是一些示例代码,可帮助您从中开始:

val bufferSize=3
val imageReader=imageReader.newInstance(
//从支持的相机输出尺寸拾取宽度和高度
宽度、高度、ImageFormat.YUV_420_888、缓冲区大小)
//从图像读取器检索曲面
val imReaderSurface=imageReader.surface
val目标:MutableList=arrayOf(imReaderSurface).toMutableList()
//使用预定义的目标创建捕获会话
cameraDevice.createCaptureSession(目标,对象:CameraCaptureSession.StateCallback(){
覆盖未配置的乐趣(会话:CameraCaptureSession){
//在此处提交捕获请求
}
//为简洁起见省略。。。
覆盖配置文件(会话:CameraCaptureSession)=单位
},空)
关于RenderScript错误,您提供的详细信息有点难说。如果您还没有这样做,我建议您使用,并在模拟器中测试代码,以排除潜在的驱动程序实现问题

问题在于,将ImageReader连接到相机会大幅降低帧速率(不是任何图像转换,而是仅使用ImageReader而无需任何附加代码)

这不应该发生。您可能没有正确配置相机会话和图像读取器的输出目标。您还需要确保尽快关闭发送到图像阅读器的图像,以便下一个图像可以进入。如果您真的关心性能,您应该使用YUV_420_888作为像素格式,并根据输出目标的大小,使用3-5帧作为图像读取器的缓冲区。以下是一些示例代码,可帮助您从中开始:

val bufferSize=3
val imageReader=imageReader.newInstance(
//从支持的相机输出尺寸拾取宽度和高度
宽度、高度、ImageFormat.YUV_420_888、缓冲区大小)
//从图像读取器检索曲面
val imReaderSurface=imageReader.surface
val目标:MutableList=arrayOf(imReaderSurface).toMutableList()
//使用预定义的目标创建捕获会话
cameraDevice.createCaptureSession(目标,对象:CameraCaptureSession.StateCallback(){
覆盖未配置的乐趣(会话:CameraCaptureSession){
//在此处提交捕获请求
}
//为简洁起见省略。。。
覆盖配置文件(会话:CameraCaptureSession)=单位
},空)
关于RenderScript错误,您提供的详细信息有点难说。如果您还没有这样做,我建议您使用,并在模拟器中测试代码,以排除潜在的驱动程序实现问题

E/RenderScript: YuvToRGB executed without data, skipping
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)