Skip to content

Why does my OpenCV Camera does not show up for the first time when I grant the camera permission #27446

Open
@BraveEvidence

Description

@BraveEvidence

System Information

Kotlin user OpenCV android version: 4.11.0 Operating System / Platform: Android 12

Detailed description

I am trying to display JavaCameraView in my Android app with OpenCV but when I install the app for the very first time and grant camera permission it does not show up the camera but when I reopen the app then it works, here is the code

package com.codingwithnobody.myandroidprojectcameracv

import android.content.ContentValues
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.opencv.android.CameraActivity
import org.opencv.android.CameraBridgeViewBase
import org.opencv.android.JavaCameraView
import org.opencv.android.OpenCVLoader
import org.opencv.core.Mat
import org.opencv.core.MatOfByte
import org.opencv.core.Point
import org.opencv.core.Scalar
import org.opencv.imgcodecs.Imgcodecs
import org.opencv.imgproc.Imgproc
import java.io.ByteArrayInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.Collections
import androidx.core.app.ActivityCompat

class MainActivity : CameraActivity(), CameraBridgeViewBase.CvCameraViewListener2 {

    private lateinit var cameraView: JavaCameraView
    private lateinit var button: Button

    private var shouldCapture = false

    private val REQUEST_CODE_PERMISSIONS = 10
    private val REQUIRED_PERMISSIONS = mutableListOf(android.Manifest.permission.CAMERA).apply {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
            add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
    }.toTypedArray()

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(
            baseContext, it) == PackageManager.PERMISSION_GRANTED
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {

                    Toast.makeText(this, "Permissions granted by the user.", Toast.LENGTH_LONG).show()
                    cameraView.visibility = View.VISIBLE
                    cameraView.enableView()
                    cameraView.setCvCameraViewListener(this@MainActivity)


            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }

        cameraView = findViewById(R.id.cameraView)
        button = findViewById(R.id.capture)
        if(OpenCVLoader.initLocal()){
            ActivityCompat.requestPermissions(
                this,
                REQUIRED_PERMISSIONS,
                REQUEST_CODE_PERMISSIONS
            )
        }




        button.setOnClickListener {
            shouldCapture = true
        }

    }

    override fun getCameraViewList(): MutableList<out CameraBridgeViewBase> {
        return Collections.singletonList(cameraView)
    }

    override fun onPause() {
        super.onPause()
        cameraView.disableView()
    }

    override fun onResume() {
        super.onResume()
        cameraView.enableView()
    }

    override fun onCameraViewStarted(width: Int, height: Int) {
        cameraView.setMaxFrameSize(width, height)
    }

    override fun onCameraViewStopped() {

    }

    private fun matToByteArray(mat: Mat, ext: String = ".png"): ByteArray {
        val converted = Mat()
        Imgproc.cvtColor(mat, converted, Imgproc.COLOR_RGBA2BGR)

        val buf = MatOfByte()
        Imgcodecs.imencode(ext, converted, buf)

        return buf.toArray()
    }


    override fun onCameraFrame(inputFrame: CameraBridgeViewBase.CvCameraViewFrame?): Mat {
        val rgba = inputFrame!!.rgba()
        val center = Point(rgba.cols() / 2.0, rgba.rows() / 2.0)
        Imgproc.circle(rgba, center, 100, Scalar(255.0, 0.0, 0.0, 255.0), 5)

        if (shouldCapture) {
            shouldCapture = false
            val frame = rgba.clone()

            CoroutineScope(Dispatchers.Main).launch {
                val bytes = matToByteArray(frame, ".png")
                try {
                    val uri = saveImageToExternalStorage(
                        bytes = bytes,
                        fileName = "opencv_${System.currentTimeMillis()}",
                        extension = "png",
                        mimeType = "image/png"
                    )
                    Toast.makeText(this@MainActivity, "Saved to: $uri", Toast.LENGTH_SHORT).show()
                } catch (e: IOException) {
                    e.printStackTrace()
                    Toast.makeText(this@MainActivity, "Failed to save image", Toast.LENGTH_SHORT).show()
                }
            }
        }

        return rgba
    }

    private suspend fun saveImageToExternalStorage(
        bytes: ByteArray,
        fileName: String,
        extension: String,
        mimeType: String
    ): Uri = withContext(Dispatchers.IO) {
        val cv = ContentValues().apply {
            put(MediaStore.Video.Media.DISPLAY_NAME, "$fileName.$extension")
            put(MediaStore.Video.Media.MIME_TYPE, mimeType)
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
            }
        }

        val resolver = contentResolver
        val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
        } else {
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI
        }
        val uriSavedVideo = resolver.insert(collection, cv)

        uriSavedVideo?.let { uri ->
            resolver.openFileDescriptor(uri, "w")?.use { pfd ->
                FileOutputStream(pfd.fileDescriptor).use { out ->
                    ByteArrayInputStream(bytes).use { inputStream ->
                        val buffer = ByteArray(8192)
                        var length: Int
                        while (inputStream.read(buffer).also { length = it } > 0) {
                            out.write(buffer, 0, length)
                        }
                    }
                }
                // Update the content values to mark the video as not pending
                cv.clear()
                resolver.update(uri, cv, null, null)
            }
        }

        uriSavedVideo ?: throw IOException("Failed to create new MediaStore record.")
    }
}


Here is the output video

Screen_recording_20250614_215336.mp4

Steps to reproduce

Clone this repo and open it in Android Studio

Issue submission checklist

  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found any solution
  • I updated to the latest OpenCV version and the issue is still there
  • There is reproducer code and related data files (videos, images, onnx, etc)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy