首页 > 解决方案 > Android:从图像捕获中获取旧图像数据

问题描述

我有一个 android 应用程序,用于拍摄图像并通过 (W)Lan 将它们发送到远程 PC。

为此,我有两个功能来拍摄图像:

RAW 图像的一项功能:

fun takePhotoRAW(cmdDispatcher: CommandDispatcher) {   
    val rawImageList = ArrayList<Image>()

    rawImageReader.setOnImageAvailableListener({ reader ->
        rawImageList.add(reader.acquireLatestImage())
    }, null)


    val captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply {
        addTarget(rawImageReader.surface)
    }

    setSingleCaptureRequestSettings(captureRequest)

    session.captureSingleRequest(captureRequest.build(), cameraExecutor, object : CameraCaptureSession.CaptureCallback() {
        override fun onCaptureStarted(session: CameraCaptureSession, request: CaptureRequest, timestamp: Long, frameNumber: Long) {
            super.onCaptureStarted(session, request, timestamp, frameNumber)
            CoroutineScope(Dispatchers.Main).launch {
                logger.log("Capturing RAW image...")
            }
        }

        override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
            super.onCaptureCompleted(session, request, result)

            var cnt = 0
            while (rawImageList.size < 1) {
                runBlocking {
                    delay(10)
                }
                if (cnt++ > 100) break
            }

            if (rawImageList.size > 0) {
                val dngCreator = DngCreator(characteristics, result)
                val stream = ByteArrayOutputStream()

                dngCreator.writeImage(stream, rawImageList.first())
                rawImageList.first().close()
                rawImageList.clear()
                logger.log("RAW Image Captured. Sending to client...")
                CoroutineScope(Dispatchers.IO).launch {
                    cmdDispatcher.sendImageToClient(stream.toByteArray(), NetworkCommandTypeEnum.IMAGERAW)
                }
            } else {
                logger.log("RAW Image Capture failed...")
                CoroutineScope(Dispatchers.IO).launch {
                    cmdDispatcher.sendFailedCommand()
                }
            }
        }
    })
}

一个用于 JPEG 图像:

fun takePhotoJPEG(cmdDispatcher: CommandDispatcher) {
    val jpegImageList = ArrayList<Image>()

    jpegImageReader.setOnImageAvailableListener({ reader ->
        jpegImageList.add(reader.acquireLatestImage())
    }, null)


    val captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply {
        addTarget(jpegImageReader.surface)
    }

    setSingleCaptureRequestSettings(captureRequest)

    session.captureSingleRequest(captureRequest.build(), cameraExecutor, object : CameraCaptureSession.CaptureCallback() {
        override fun onCaptureStarted(session: CameraCaptureSession, request: CaptureRequest, timestamp: Long, frameNumber: Long) {
            super.onCaptureStarted(session, request, timestamp, frameNumber)
            logger.log("Capturing JPEG image...")
        }

        override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
            super.onCaptureCompleted(session, request, result)

            var cnt = 0
            while (jpegImageList.size < 1) {
                runBlocking {
                    delay(10)
                }
                if (cnt++ > 100) break
            }

            if (jpegImageList.size > 0) {
                val jpegbuffer = jpegImageList.first().planes[0].buffer
                val bytes = ByteArray(jpegbuffer.remaining())

                jpegbuffer.get(bytes, 0, jpegbuffer.remaining())
                jpegImageList.first().close()
                jpegImageList.clear()
                logger.log("JPEG Image Captured. Sending to client...")
                CoroutineScope(Dispatchers.IO).launch {
                    cmdDispatcher.sendImageToClient(bytes, NetworkCommandTypeEnum.IMAGEJPEG)
                }
            } else {
                logger.log("JPEG Image Capture failed...")
                CoroutineScope(Dispatchers.IO).launch {
                    cmdDispatcher.sendFailedCommand()
                }
            }
        }
    })
}

这些功能中的每一个都可以单独工作,但是由于某种原因,如果我按以下顺序拍摄图像:

  1. 生的
  2. JPEG
  3. 生的

第二张 RAW 图像包含与第一张相同的图像数据。此时我必须重新启动应用程序,以便能够再次拍摄不同的 RAW 图像。JPEG 图像仍然可以正常工作。

但是,如果我按此顺序拍摄图像:

  1. 生的
  2. 生的
  3. 生的

正如预期的那样,我得到了三个不同的 RAW 图像。不知何故,拍摄 JPEG 图像会扰乱原始图像的捕获......

编辑:(试图回答评论问题):

这两个函数的调用方法如下:

private fun takePhoto(type: String) {
    when (type) {
        "RAW" -> cameraManager.takePhotoRAW(this)
        "JPEG" -> cameraManager.takePhotoJPEG(this)
        else -> return
    }
}

图像之间的最短时间基本上是图像通过网络发送到客户端所需的时间:客户端机器请求图像,一旦它收到图像,它就会请求下一个图像。但是,我也可以手动触发请求,调用这两个函数之间的时间似乎没有影响(测试从立即到 10+ 秒)。

标签: androidkotlinandroid-camera2

解决方案


推荐阅读