如何在一秒钟内捕获多张图像并将其保存?

时间:2019-07-09 14:40:27

标签: android kotlin android-camera2

我试图在一秒钟内捕获多张图像,即使10 fps也应该可以。我正在使用华为Mate20Pro。我尝试了处理程序方法,但实现了1fps,并减少了延迟,从而进一步导致相机挂起。代码在这里:

button.setOnClickListener {
            prepareUIForCapture()
            if(isRunning){
                handler.removeCallbacksAndMessages(null)
                restartActivity()
            }else{
                button.text = "Stop"
                handler.postDelayed(object : Runnable {
                    override fun run(){
                        twoLens.reset()
                        twoLens.isTwoLensShot = true
                        MainActivity.cameraParams.get(dualCamLogicalId).let {
                            if (it?.isOpen == true) {
                                Logd("In onClick. Taking Dual Cam Photo on logical camera: " + dualCamLogicalId)
                                takePicture(this@MainActivity, it)
                                Toast.makeText(applicationContext, "Captured", Toast.LENGTH_LONG).show()
                            }
                        }
                        handler.postDelayed(this, 1000)
                    }
                }, 2000)
            }
            isRunning = !isRunning
        }

此处第一枪是2秒后,并且每1秒捕获一次。工作正常。我希望增加这个比率。我正在尝试突发捕获。 这是我到目前为止所做的。 在takePicture()方法中:

val captureList = ArrayList<CaptureRequest>()
for (i in 0 until 10){
    captureList.add(params.previewBuilder?.build()!!)
}
params.captureSession?.captureBurst(captureList, StillCaptureSessionCallback(activity, params), params.backgroundHandler)
            params.captureBuilder?.removeTarget(normalParams?.imageReader?.surface!!)
          params.captureBuilder?.removeTarget(wideParams?.imageReader?.surface!!)

我认为这是可行的,因为没有错误或异常。但是,我看不到保存的图像。这是我如何保存它们。

Toast.makeText(activity, "Burst Captured", Toast.LENGTH_LONG).show()
var tempBitmap: Bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
//We need both shots to be done and both images in order to proceed
if (!twoLens.normalShotDone || !twoLens.wideShotDone || (null == twoLens.normalImage)
        || (null == twoLens.wideImage))
        return tempBitmap //Return empty bitmap

    Logd("Normal image timestamp: " + twoLens.normalImage?.timestamp)
    Logd("Wide image timestamp: " + twoLens.wideImage?.timestamp)

    val wideBuffer: ByteBuffer? = twoLens.wideImage!!.planes[0].buffer
    val wideBytes = ByteArray(wideBuffer!!.remaining())
    wideBuffer.get(wideBytes)

    val normalBuffer: ByteBuffer? = twoLens.normalImage!!.planes[0].buffer
    val normalBytes = ByteArray(normalBuffer!!.remaining())
    normalBuffer.get(normalBytes)
    val tempWideBitmap = BitmapFactory.decodeByteArray(wideBytes, 0, wideBytes.size, null)
    val tempNormalBitmap = BitmapFactory.decodeByteArray(normalBytes, 0, normalBytes.size, null)
    //Utils.bitmapToMat(tempNormalBitmap, normalMat)
    save(tempWideBitmap, "NormalShot")
    save(tempNormalBitmap, "WideShot")

保存方法在这里:

fun save(bytes: Bitmap, tempName: String) {
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    val dataDir = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "TwoCameraImagesNew")
    if (!dataDir.exists()) {
        dataDir.mkdir()
    }
    val fileName = tempName + "_IMG_$timeStamp.jpg"
    val fileDir = File(dataDir.path + File.separator + fileName)
    try {
        val fileOutputStream = FileOutputStream(fileDir)
        bytes.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)
        //fileOutputStream.write(bytes)
        fileOutputStream.close()
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

但是,我看不到已保存的图片(它正常工作而不会破裂)。有单独的方法保存连拍图像吗? 这是我的onImageAvailableListener:

imageReader = ImageReader.newInstance(960, 720, ImageFormat.JPEG, 20)
imageReader?.setOnImageAvailableListener(imageAvailableListener, backgroundHandler)

ImageAvailableListener类获取下一张图像(这对于连拍是否正确?),然后调用该方法以获取图像并保存它们(如上所示)。完整的ImageAvailableListener类在此处给出:

class ImageAvailableListener(private val activity: MainActivity, internal var params: CameraParams) : ImageReader.OnImageAvailableListener {
    override fun onImageAvailable(reader: ImageReader) {
        Log.d(MainActivity.LOG_TAG, "ImageReader. Image is available, about to post.")
        val image: Image = reader.acquireNextImage()
        if (MainActivity.twoLens.isTwoLensShot) {

            if (MainActivity.wideAngleId == params.id) {
                twoLens.wideImage = image

            } else if (MainActivity.normalLensId == params.id) {
                twoLens.normalImage = image
            }

            if (twoLens.wideShotDone && twoLens.normalShotDone
                && null != twoLens.wideImage
                && null != twoLens.normalImage) {

                val finalBitmap: Bitmap = DoBokeh(activity, twoLens)
                setCapturedPhoto(activity, params.capturedPhoto, finalBitmap)

                twoLens.normalImage?.close()
                twoLens.wideImage?.close()
            }

        }
        Log.d(MainActivity.LOG_TAG, "ImageReader. Post has been set.")
    }
}

这是捕获照片时至少达到10fps的正确方法吗?如果没有,应该如何进行?如何保存连拍的图像?

1 个答案:

答案 0 :(得分:0)

不幸的是,拍照不是正确的方法,因为相机的回收时间取决于多种因素,包括硬件。 我建议您拍摄视频,然后检索帧。 您可以使用MediaRecorder拍摄和保存视频,然后可以使用MediaMetadataRetriever提取帧。 也许最后一堂课可能会给您带来一些问题。如果可以,我认为可以使用FFmpegMediaMetadataRetriever更好。 要拍摄框架,可以使用以下方法:

retriever.getFrameAtTime(time, MediaMetadataRetriever.OPTION_CLOSEST);

请注意,时间以微秒为单位,而不是毫秒。