Skip to content

Commit

Permalink
Fix luminance calculation for Android in lanscape mode
Browse files Browse the repository at this point in the history
  • Loading branch information
icc-guerrero committed Nov 9, 2023
1 parent e5c5f8f commit feacc38
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 30 deletions.
7 changes: 4 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ android {
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
buildToolsVersion getExtOrDefault('buildToolsVersion')
defaultConfig {
minSdkVersion 19
minSdkVersion 21
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
versionCode 131
versionName "1.3.1"
versionCode 132
versionName "1.3.2"

}

Expand Down Expand Up @@ -135,5 +135,6 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.camera:camera-core:1.1.0-alpha06"
implementation "com.facebook.react:react-native:+" // From node_modules
implementation 'com.quickbirdstudios:opencv:4.5.3.0'
api project(":react-native-vision-camera")
}
1 change: 1 addition & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ':opencv'
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class VisionCameraFaceDetectorPlugin: FrameProcessorPlugin("faceDetector") {

var f = Rect(face.boundingBox.left, face.boundingBox.top, face.boundingBox.right, face.boundingBox.bottom)

val luminanceStats:LuminanceStats = imageService.getLuminanceStats(f, image.width, rotationDegrees)
val luminanceStats:LuminanceStats = imageService.getLuminanceStats(f, image.width)

val imageWidth = if (rotated) image.height else image.width
val imageHeight = if (rotated) image.width else image.height
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ package com.visioncamerafacedetector.services
import android.graphics.Rect
import android.util.Log
import androidx.camera.core.ImageProxy
import org.opencv.core.Core
import org.opencv.core.CvType
import org.opencv.core.Mat
import org.opencv.core.Point
import org.opencv.core.Size
import org.opencv.imgproc.Imgproc
import java.nio.ByteBuffer
import kotlin.math.abs

Expand All @@ -12,33 +18,38 @@ data class LuminanceStats(val scene: Double, val splitLightingDifference:Double)

class ImageQualityService(buffer: ImageProxy) {

val imageBuffer: ImageProxy = buffer
// Since format in ImageAnalysis is YUV, image.planes[0] contains the Y (luminance) plane
val luminanceByteArray: ByteArray = imageProxyToByteArray(buffer)
val rotationDegrees: Int = buffer.imageInfo.rotationDegrees

private fun ByteBuffer.toByteArray(): ByteArray {
rewind()
val data = ByteArray(remaining())
get(data)
return data
private fun imageProxyToByteArray(imageProxy: ImageProxy): ByteArray {
val yBuffer = imageProxy.planes[0].buffer
val ySize = yBuffer.remaining()
val yByteArray = ByteArray(ySize)
yBuffer.get(yByteArray)
val matYuv = Mat(imageProxy.height, imageProxy.width, CvType.CV_8UC1)
matYuv.put(0, 0, yByteArray)
if (imageProxy.imageInfo.rotationDegrees==90) {
val matYuv = Mat(imageProxy.height, imageProxy.width, CvType.CV_8UC1)
matYuv.put(0, 0, yByteArray)
val rotatedMat = Mat(matYuv.width(), matYuv.height(),CvType.CV_8UC1)
Core.rotate(matYuv,rotatedMat, Core.ROTATE_90_COUNTERCLOCKWISE)
val yRotatedByteArray = ByteArray(ySize)
rotatedMat.get(0, 0, yRotatedByteArray)
return yRotatedByteArray
}
return yByteArray
}

fun getLuminance(): Double {
// Since format in ImageAnalysis is YUV, image.planes[0] contains the Y (luminance) plane
val buffer = imageBuffer.planes[0].buffer
// Extract image data from callback object
val data = buffer.toByteArray()
// Convert the data into an array of pixel values
val pixels = data.map { it.toInt() and 0xFF }
val pixels = luminanceByteArray.map { it.toInt() and 0xFF }
// Compute average luminance for the image

return pixels.average() / 255
}

fun getLuminanceStats(faceBounds:Rect, imageWidth:Int, rotationDegrees: Int): LuminanceStats {
fun getLuminanceStats(faceBounds:Rect, imageWidth:Int): LuminanceStats {

// Since format in ImageAnalysis is YUV, image.planes[0] contains the Y (luminance) plane
val buffer = imageBuffer.planes[0].buffer
// Extract image data from callback object
val data = buffer.toByteArray()
// Compute average luminance for the image

val midHorizontal = (faceBounds.right - faceBounds.left) / 2 + faceBounds.left
Expand All @@ -50,7 +61,7 @@ class ImageQualityService(buffer: ImageProxy) {
var scene = 0
var left = 0
var right = 0
data.forEachIndexed { index, byte ->
luminanceByteArray.forEachIndexed { index, byte ->
val y = index % imageWidth
val x = index / imageWidth

Expand All @@ -60,17 +71,11 @@ class ImageQualityService(buffer: ImageProxy) {
} else if (midHorizontal <= x && x < faceBounds.right && faceBounds.top <= y && y < faceBounds.bottom) {
luminanceR += (byte.toInt() and 0xFF).toDouble() / 255.0
right += 1
} else if (midVertical >= y && rotationDegrees == 90){
// Monitor only top of the scene
luminanceScene += (byte.toInt() and 0xFF).toDouble() / 255.0
scene += 1
} else if (midVertical < y && rotationDegrees == 270){
// Monitor only top of the scene
} else {
luminanceScene += (byte.toInt() and 0xFF).toDouble() / 255.0
scene += 1
}
}

return LuminanceStats(luminanceScene/scene, abs((luminanceR / right) - (luminanceL / left)))
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vision-camera-facedetector",
"version": "1.3.1",
"version": "1.3.2",
"description": "VisionCamera Frame Processor Plugin that uses MLKit Face Recognition API to recognize faces",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down

0 comments on commit feacc38

Please sign in to comment.