Thanks to visit codestin.com
Credit goes to github.com

Skip to content

kamyab9k/KamVision

Repository files navigation

KamVision

Medium LinkedIn API

KamVision is an Open-Source library which provides easy access to the complex Camera 2 API (Strategic choice for low-level control in contrast to CameraX) in Jetpack Compose. You can use internal elements like Preview and Frame Capturing as a one-line method call in your projects.

KamVisionLogo


Tech Stack

Category Details
Core Technologies Kotlin, Java, Coroutines, Flow, MVVM (Model-View-ViewModel), Jetpack Compose, Camera 2
Design Patterns Singleton, Builder, Facade
Preview and Image Handling Camera 2 Api, AndroidView for preview start/stop, Bitmap handling for single and multiple frames

Core Logic

The core of this library is provided by Camera2 Api & Jetpack Compose .


Why Camera2 API is chosen over Camera X ?

  • Low-Level Control: Camera2 API provides direct, in-depth control over the camera hardware. You can manipulate almost every aspect of the camera pipeline, including:
  • Manual Exposure Control: Set ISO, shutter speed, and aperture (if supported by hardware) precisely. This is crucial for creative photography and specific lighting conditions.
  • Manual Focus: Achieve precise focus control, including setting specific focus distances.
  • RAW Capture: Access uncompressed RAW sensor data (DNG format), which offers the most flexibility for post-processing.
  • Advanced Capture Request Parameters: Control a vast array of parameters for each capture, such as white balance, color correction, noise reduction, edge enhancement, tone mapping, and more, using CaptureRequest.Builder.
  • Stream Configuration: Define custom output streams and formats for different use cases (e.g., high-resolution still image, real-time preview, video recording, image analysis).
  • Metadata Access: Get detailed metadata for each frame, including sensor timestamps, lens characteristics, and capture settings.
  • Multi-camera Control: For devices with multiple cameras, Camera2 gives you fine-grained control over which camera to use and how to combine their outputs.
  • Flexibility for Complex Use Cases: If you're building something beyond standard photo/video capture, like custom computer vision pipelines, augmented reality applications, or specialized imaging tools, Camera2's granular control is essential

The 👎 of Camera2 api:

  • It is more complex and time-consuming to implement, but I've already done it for you ;)

Main Characteristics

  • Start Camera Preview with only one line function call
  • Stop Camera Preview
  • Switch between front and back Camera lenses
  • Single frame capturing
  • Multiple frame capturing based on a user-defined number
  • Full compatibility with Jetpack Compose
  • Fluent UI
  • Optimized with coroutines

🎯 Download the demonstration of the library usage in a sample Android app KamVision-Showcase.apk


Download

KamVision is available on JitPack.io/KamVision. To integrate it into your Android project, follow these steps:

  1. Add the JitPack repository to your project-level settings.gradle.kts file:
    // settings.gradle.kts
    pluginManagement {
        repositories {
            // ... other repositories
            maven { url = uri("[https://jitpack.io](https://jitpack.io)") }
        }
    }
    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            // ... other repositories
            maven { url = uri("[https://jitpack.io](https://jitpack.io)") }
        }
    }
  1. Add the dependency to your module-level build.gradle.kts (e.g., app/build.gradle.kts):
// app/build.gradle.kts
    dependencies {
        implementation("com.github.kamyab9k:KamVision:LATEST_TAG")
    }

Usage

KamVision makes integrating the Camera2 API into your Jetpack Compose applications simple. Follow these three simple steps to get your camera preview up and running quickly. Note: This is just a simple setup to get started; you can alter or implement the UI and other parameters based on your project or needs!

  1. Request Camera Permissions:
class MainActivity : ComponentActivity() {

    private var cameraPermissionGranted = mutableStateOf(false)
    private val requestCameraPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
            cameraPermissionGranted.value = isGranted
            if (!isGranted) {
                // Optionally, inform the user that permission is needed
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val permissionGranted by remember { cameraPermissionGranted }

            LaunchedEffect(Unit) {
                // Check initial permission status
                cameraPermissionGranted.value = isCameraPermissionGranted()
                if (!cameraPermissionGranted.value) {
                    requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
                }
            }

            if (permissionGranted) {
                CameraPreview()
            } else {
                // Optional: Show a message to the user while waiting for permission
                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                    Text("Camera permission is required to use this app.")
                }
            }
        }
    }

    private fun isCameraPermissionGranted(): Boolean {
        return ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED
    }
}
  1. Integrate KamVision's Camera Preview
@Composable
fun CameraPreview() {
    val coroutineScope =
        rememberCoroutineScope()
    var cameraService: CameraService? by remember { mutableStateOf(null) }
    var textureView: TextureView? by remember { mutableStateOf(null) }

    Box(modifier = Modifier.fillMaxSize()) {
        AndroidView(
            factory = { ctx ->
                TextureView(ctx).also {
                    textureView = it
                }
            },
            modifier = Modifier.fillMaxSize(),
            update = { tv ->
                if (cameraService == null) {
                    cameraService = CameraService.Builder(
                        context = tv.context,
                        textureView = tv,
                        scope = coroutineScope
                    )
                        .setFrontCamera(false)
                        .setAutoBrightnessMode(true)
                        .setAutoFocusMode(true)
                        .setFlashMode(2)
                        .build()
                    cameraService?.startPreview()
                }
                cameraService?.captureFrame(50)
                cameraService?.getCapturedFrames { frames: List<Bitmap> ->
                    println("Hi  $frames")
                }
            }
        )
        Button(
            onClick = {
                coroutineScope.launch {
                    cameraService?.switchCamera()
                }
            },
            modifier = Modifier.align(Alignment.BottomCenter)
        ) {
            Text("Switch Camera")
        }
    }

    DisposableEffect(Unit) {
        onDispose {
            cameraService?.stopCameraPreview()
        }
    }
}
  1. Leverage KamVision Functions:
...
           update = { tv ->
                if (cameraService == null) {
                    cameraService = CameraService.Builder(
                        context = tv.context,
                        textureView = tv,
                        scope = coroutineScope
                   )
            .setFrontCamera(false)       // KamVision parameter: 'true' for front camera, 'false' for back camera
            .setAutoBrightnessMode(true) // KamVision parameter: 'true' to enable auto brightness adjustment, 'false' otherwise
            .setAutoFocusMode(true)      // KamVision parameter: 'true' to enable auto focus, 'false' otherwise
            .setFlashMode(2)             // KamVision parameter: Sets the flash mode (0: OFF, 1: Single Flash, 2: Torch)
            .build()                     // Builds the CameraService instance with the specified configurations
        cameraService?.startPreview()    // KamVision function: Starts the camera preview
    }
    cameraService?.captureFrame(50)      // KamVision function: Captures the specified number of frames (e.g., 50 frames)
    cameraService?.getCapturedFrames { frames: List<Bitmap> -> // KamVision function: Retrieves the list of captured frames
        println("Hi  $frames")
    }
            }
        )
        Button(
            onClick = {
                coroutineScope.launch {
            cameraService?.switchCamera() // KamVision function: Asynchronously switches between front and back cameras
                }
            },
            modifier = Modifier.align(Alignment.BottomCenter)
        ) {
            Text("Switch Camera")
        }
    }

    DisposableEffect(Unit) {
        onDispose {
            cameraService?.stopCameraPreview()
        }
    }
}

Library functions

There are several functions you can call with KamVision.


Function Example Usage
• startPreview() cameraService?.startPreview()
Starts the camera preview.
• stopPreview() cameraService?.stopPreview()
Stops the camera preview.
• captureFrame(Frames: Int) cameraService?.captureFrame(15)
Capture frames and the number is given in parameter .
• getCapturedFrames(frames: List) cameraService?.getCapturedFrames { frames: List ->}
Returns the list of captured frames in Bitmap format.

Input KamVision Configurations

In addition to the builder functions, KamVision receives some configurations. For example:

// shows a Preview in Jetpack Compose AndroidView
    Box(modifier = Modifier.fillMaxSize()) {
        AndroidView(
            factory = { ctx ->
                // Create the TextureView
                TextureView(ctx).also {
                    textureView = it
                }
            },
            modifier = Modifier.fillMaxSize(),
            update = { textureView ->
                if (cameraService == null) {
                    cameraService = CameraService.Builder(
                        context = textureView.context,
                        textureView = textureView,
                        scope = coroutineScope
                    ).build()

Read more about these three important topics to better understand the functionality of this Library:


In Development⚡️

  • Video capturing & more
  • Adding more parameters

License

Copyright 2024 Mohammad Khosravi

Licensed under the Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.