Как я могу сделать несколько снимков за одну секунду и сохранить их? - PullRequest
0 голосов
/ 09 июля 2019

Я пытаюсь сделать несколько снимков за одну секунду, даже 10 кадров в секунду должно быть хорошо.Я использую Huawei Mate20Pro.Я попробовал метод обработчика, но с этим достигается 1 кадр / с, и уменьшение задержки приводит к зависанию камеры.Код здесь:

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.")
    }
}

Это правильный способ получить по крайней мере 10 кадров в секунду при захвате фотографий?Если нет, то как следует поступить?Как я могу сохранить серию снимков?

1 Ответ

0 голосов
/ 09 июля 2019

К сожалению, фотографирование - это неправильный подход, потому что у камеры есть время перезарядки, которое зависит от нескольких факторов, включая аппаратное обеспечение. Я предлагаю вам снять видео, а затем получить кадры. Вы можете использовать MediaRecorder , чтобы взять и сохранить видео, затем вы можете извлечь кадры, используя MediaMetadataRetriever . Может быть, этот последний класс может дать вам некоторые проблемы Если это так, вы можете использовать FFmpegMediaMetadataRetriever , что, на мой взгляд, намного лучше. Чтобы взять кадр, вы можете использовать метод:

retriever.getFrameAtTime(time, MediaMetadataRetriever.OPTION_CLOSEST);

Будьте осторожны, время в микросекундах, а не в миллисекундах.

...