diff --git a/CameraXAdvanced/build.gradle b/CameraXAdvanced/build.gradle index 78f510b9..25369742 100644 --- a/CameraXAdvanced/build.gradle +++ b/CameraXAdvanced/build.gradle @@ -1,64 +1,6 @@ -/* - * Copyright 2020 Google LLC - * - * 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 - * - * https://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. - */ - -buildscript { - - ext { - // Top-level variables used for versioning - ext.kotlin_version = '1.5.21' - ext.java_version = JavaVersion.VERSION_1_8 - } - - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.diffplug.spotless:spotless-plugin-gradle:5.11.1' - } -} - -allprojects { - repositories { - google() - mavenCentral() - maven { // repo for TFLite snapshot - name 'ossrh-snapshot' - url 'https://s01.oss.sonatype.org/content/repositories/snapshots' - } - } -} - -subprojects { - apply plugin: 'com.diffplug.spotless' - spotless { - java { - target "**/*.java" - trimTrailingWhitespace() - removeUnusedImports() - googleJavaFormat() - endWithNewline() - } - kotlin { - target "**/*.kt" - trimTrailingWhitespace() - endWithNewline() - } - } -} +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.3.1' apply false + id 'com.android.library' version '7.3.1' apply false + id 'org.jetbrains.kotlin.android' version '1.7.20' apply false +} \ No newline at end of file diff --git a/CameraXAdvanced/gradle.properties b/CameraXAdvanced/gradle.properties index 23339e0d..3c5031eb 100644 --- a/CameraXAdvanced/gradle.properties +++ b/CameraXAdvanced/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects @@ -15,7 +15,9 @@ org.gradle.jvmargs=-Xmx1536m # Android operating system, and which are packaged with your app's APK # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/CameraXAdvanced/gradle/wrapper/gradle-wrapper.jar b/CameraXAdvanced/gradle/wrapper/gradle-wrapper.jar index f6b961fd..e708b1c0 100644 Binary files a/CameraXAdvanced/gradle/wrapper/gradle-wrapper.jar and b/CameraXAdvanced/gradle/wrapper/gradle-wrapper.jar differ diff --git a/CameraXAdvanced/gradle/wrapper/gradle-wrapper.properties b/CameraXAdvanced/gradle/wrapper/gradle-wrapper.properties index 2be8ad4d..c36c1f55 100644 --- a/CameraXAdvanced/gradle/wrapper/gradle-wrapper.properties +++ b/CameraXAdvanced/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Dec 16 12:00:46 WET 2020 +#Mon Jan 09 15:18:03 BRT 2023 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/CameraXAdvanced/gradlew b/CameraXAdvanced/gradlew index cccdd3d5..4f906e0c 100755 --- a/CameraXAdvanced/gradlew +++ b/CameraXAdvanced/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/CameraXAdvanced/gradlew.bat b/CameraXAdvanced/gradlew.bat index f9553162..107acd32 100644 --- a/CameraXAdvanced/gradlew.bat +++ b/CameraXAdvanced/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/CameraXAdvanced/settings.gradle b/CameraXAdvanced/settings.gradle index 844db508..4f3f5038 100644 --- a/CameraXAdvanced/settings.gradle +++ b/CameraXAdvanced/settings.gradle @@ -1 +1,20 @@ -include 'tflite' +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + maven { // repo for TFLite snapshot + name 'ossrh-snapshot' + url 'https://s01.oss.sonatype.org/content/repositories/snapshots' + } + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Camera Object Detector" +include ':tflite' diff --git a/CameraXAdvanced/tflite/build.gradle b/CameraXAdvanced/tflite/build.gradle index b221bf77..87064ce4 100644 --- a/CameraXAdvanced/tflite/build.gradle +++ b/CameraXAdvanced/tflite/build.gradle @@ -1,74 +1,71 @@ -/* - * Copyright 2020 Google LLC - * - * 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 - * - * https://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. - */ - -apply plugin: "com.android.application" -apply plugin: "kotlin-android" +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} android { - compileSdkVersion 31 - ndkVersion "21.3.6528147" + namespace 'com.android.example.camerax.tflite' + compileSdk 33 defaultConfig { - applicationId 'com.android.example.camerax.tflite' - minSdkVersion 21 - targetSdkVersion 30 + applicationId "com.android.example.camerax.tflite" + minSdk 21 + targetSdk 33 versionCode 1 versionName "0.0.1" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } } compileOptions { - sourceCompatibility rootProject.ext.java_version - targetCompatibility rootProject.ext.java_version + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = rootProject.ext.java_version + jvmTarget = '1.8' } - buildFeatures { viewBinding true } - androidResources { - noCompress 'lite' + + aaptOptions { + noCompress "tflite" } } dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' // App compat and UI things - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.core:core-ktx:1.9.0' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.7.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' // CameraX - def camerax_version = "1.1.0-beta01" + def camerax_version = "1.2.0" implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" implementation "androidx.camera:camera-lifecycle:${camerax_version}" implementation "androidx.camera:camera-view:${camerax_version}" implementation "androidx.camera:camera-video:${camerax_version}" - // Tensorflow lite dependencies - implementation 'org.tensorflow:tensorflow-lite:2.9.0' + implementation 'org.tensorflow:tensorflow-lite:2.10.0' implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0' - implementation 'org.tensorflow:tensorflow-lite-support:0.4.2' + implementation 'org.tensorflow:tensorflow-lite-support:0.4.3' + - testImplementation 'org.robolectric:robolectric:4.4' testImplementation 'junit:junit:4.13.2' -} + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} \ No newline at end of file diff --git a/CameraXAdvanced/tflite/proguard-rules.pro b/CameraXAdvanced/tflite/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/CameraXAdvanced/tflite/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/androidTest/java/com/android/example/camerax/tflite/ExampleInstrumentedTest.kt b/CameraXAdvanced/tflite/src/androidTest/java/com/android/example/camerax/tflite/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..1da99c89 --- /dev/null +++ b/CameraXAdvanced/tflite/src/androidTest/java/com/android/example/camerax/tflite/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.android.example.camerax.tflite + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.android.example.camerax.tflite", appContext.packageName) + } +} \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/AndroidManifest.xml b/CameraXAdvanced/tflite/src/main/AndroidManifest.xml index 965fd839..0e986f50 100644 --- a/CameraXAdvanced/tflite/src/main/AndroidManifest.xml +++ b/CameraXAdvanced/tflite/src/main/AndroidManifest.xml @@ -26,23 +26,30 @@ + android:theme="@style/Theme.CameraObjectDetector" + tools:ignore="AllowBackup,GoogleAppIndexingWarning" + tools:targetApi="31"> + android:name=".CameraActivity" + android:exported="true" + android:rotationAnimation="seamless"> - - + + + - + + - + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/java/com/example/android/camerax/tflite/CameraActivity.kt b/CameraXAdvanced/tflite/src/main/java/com/android/example/camerax/tflite/CameraActivity.kt similarity index 93% rename from CameraXAdvanced/tflite/src/main/java/com/example/android/camerax/tflite/CameraActivity.kt rename to CameraXAdvanced/tflite/src/main/java/com/android/example/camerax/tflite/CameraActivity.kt index 4f94dc84..12cc2cd2 100644 --- a/CameraXAdvanced/tflite/src/main/java/com/example/android/camerax/tflite/CameraActivity.kt +++ b/CameraXAdvanced/tflite/src/main/java/com/android/example/camerax/tflite/CameraActivity.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.example.android.camerax.tflite +package com.android.example.camerax.tflite import android.Manifest import android.annotation.SuppressLint @@ -53,8 +53,6 @@ import java.util.concurrent.TimeUnit import kotlin.math.min import kotlin.random.Random - -/** Activity that displays the camera and performs object detection on the incoming frames */ class CameraActivity : AppCompatActivity() { private lateinit var activityCameraBinding: ActivityCameraBinding @@ -76,21 +74,25 @@ class CameraActivity : AppCompatActivity() { val cropSize = minOf(bitmapBuffer.width, bitmapBuffer.height) ImageProcessor.Builder() .add(ResizeWithCropOrPadOp(cropSize, cropSize)) - .add(ResizeOp( - tfInputSize.height, tfInputSize.width, ResizeOp.ResizeMethod.NEAREST_NEIGHBOR)) + .add( + ResizeOp( + tfInputSize.height, tfInputSize.width, ResizeOp.ResizeMethod.NEAREST_NEIGHBOR + ) + ) .add(Rot90Op(-imageRotationDegrees / 90)) .add(NormalizeOp(0f, 1f)) .build() } - private val nnApiDelegate by lazy { + private val nnApiDelegate by lazy { NnApiDelegate() } private val tflite by lazy { Interpreter( FileUtil.loadMappedFile(this, MODEL_PATH), - Interpreter.Options().addDelegate(nnApiDelegate)) + Interpreter.Options().addDelegate(nnApiDelegate) + ) } private val detector by lazy { ObjectDetectionHelper( @@ -128,7 +130,8 @@ class CameraActivity : AppCompatActivity() { if (isFrontFacing) postScale(-1f, 1f) } val uprightImage = Bitmap.createBitmap( - bitmapBuffer, 0, 0, bitmapBuffer.width, bitmapBuffer.height, matrix, true) + bitmapBuffer, 0, 0, bitmapBuffer.width, bitmapBuffer.height, matrix, true + ) activityCameraBinding.imagePredicted.setImageBitmap(uprightImage) activityCameraBinding.imagePredicted.visibility = View.VISIBLE } @@ -158,7 +161,7 @@ class CameraActivity : AppCompatActivity() { private fun bindCameraUseCases() = activityCameraBinding.viewFinder.post { val cameraProviderFuture = ProcessCameraProvider.getInstance(this) - cameraProviderFuture.addListener ({ + cameraProviderFuture.addListener({ // Camera provider is now guaranteed to be available val cameraProvider = cameraProviderFuture.get() @@ -186,7 +189,8 @@ class CameraActivity : AppCompatActivity() { // the analyzer has started running imageRotationDegrees = image.imageInfo.rotationDegrees bitmapBuffer = Bitmap.createBitmap( - image.width, image.height, Bitmap.Config.ARGB_8888) + image.width, image.height, Bitmap.Config.ARGB_8888 + ) } // Early exit: image analysis is in paused state @@ -196,10 +200,10 @@ class CameraActivity : AppCompatActivity() { } // Copy out RGB bits to our shared buffer - image.use { bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) } + image.use { bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) } // Process the image in Tensorflow - val tfImage = tfImageProcessor.process(tfImageBuffer.apply { load(bitmapBuffer) }) + val tfImage = tfImageProcessor.process(tfImageBuffer.apply { load(bitmapBuffer) }) // Perform the object detection for the current frame val predictions = detector.predict(tfImage) @@ -225,7 +229,8 @@ class CameraActivity : AppCompatActivity() { // Apply declared configs to CameraX using the same lifecycle owner cameraProvider.unbindAll() cameraProvider.bindToLifecycle( - this as LifecycleOwner, cameraSelector, preview, imageAnalysis) + this as LifecycleOwner, cameraSelector, preview, imageAnalysis + ) // Use the camera object to link our preview use case with the view preview.setSurfaceProvider(activityCameraBinding.viewFinder.surfaceProvider) @@ -233,9 +238,8 @@ class CameraActivity : AppCompatActivity() { }, ContextCompat.getMainExecutor(this)) } - private fun reportPrediction( - prediction: ObjectDetectionHelper.ObjectPrediction? - ) = activityCameraBinding.viewFinder.post { + + private fun reportPrediction(prediction: ObjectDetectionHelper.ObjectPrediction?) = activityCameraBinding.viewFinder.post { // Early exit: if prediction is not good enough, don't report it if (prediction == null || prediction.score < ACCURACY_THRESHOLD) { @@ -248,7 +252,7 @@ class CameraActivity : AppCompatActivity() { val location = mapOutputCoordinates(prediction.location) // Update the text and UI - activityCameraBinding.textPrediction.text = "${"%.2f".format(prediction.score)} ${prediction.label}" + activityCameraBinding.textPrediction.text = "${prediction.score} ${prediction.label}" (activityCameraBinding.boxPrediction.layoutParams as ViewGroup.MarginLayoutParams).apply { topMargin = location.top.toInt() leftMargin = location.left.toInt() @@ -282,7 +286,8 @@ class CameraActivity : AppCompatActivity() { activityCameraBinding.viewFinder.width - previewLocation.right, previewLocation.top, activityCameraBinding.viewFinder.width - previewLocation.left, - previewLocation.bottom) + previewLocation.bottom + ) } else { previewLocation } @@ -314,8 +319,7 @@ class CameraActivity : AppCompatActivity() { // Request permissions each time the app resumes, since they can be revoked at any time if (!hasPermissions(this)) { - ActivityCompat.requestPermissions( - this, permissions.toTypedArray(), permissionsRequestCode) + ActivityCompat.requestPermissions(this, permissions.toTypedArray(), permissionsRequestCode) } else { bindCameraUseCases() } @@ -346,4 +350,4 @@ class CameraActivity : AppCompatActivity() { private const val MODEL_PATH = "coco_ssd_mobilenet_v1_1.0_quant.tflite" private const val LABELS_PATH = "coco_ssd_mobilenet_v1_1.0_labels.txt" } -} +} \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/java/com/example/android/camerax/tflite/ObjectDetectionHelper.kt b/CameraXAdvanced/tflite/src/main/java/com/android/example/camerax/tflite/ObjectDetectionHelper.kt similarity index 62% rename from CameraXAdvanced/tflite/src/main/java/com/example/android/camerax/tflite/ObjectDetectionHelper.kt rename to CameraXAdvanced/tflite/src/main/java/com/android/example/camerax/tflite/ObjectDetectionHelper.kt index a22025d8..3a65637a 100644 --- a/CameraXAdvanced/tflite/src/main/java/com/example/android/camerax/tflite/ObjectDetectionHelper.kt +++ b/CameraXAdvanced/tflite/src/main/java/com/android/example/camerax/tflite/ObjectDetectionHelper.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.example.android.camerax.tflite +package com.android.example.camerax.tflite import android.graphics.RectF import org.tensorflow.lite.Interpreter @@ -29,8 +29,8 @@ class ObjectDetectionHelper(private val tflite: Interpreter, private val labels: data class ObjectPrediction(val location: RectF, val label: String, val score: Float) private val locations = arrayOf(Array(OBJECT_COUNT) { FloatArray(4) }) - private val labelIndices = arrayOf(FloatArray(OBJECT_COUNT)) - private val scores = arrayOf(FloatArray(OBJECT_COUNT)) + private val labelIndices = arrayOf(FloatArray(OBJECT_COUNT)) + private val scores = arrayOf(FloatArray(OBJECT_COUNT)) private val outputBuffer = mapOf( 0 to locations, @@ -39,23 +39,24 @@ class ObjectDetectionHelper(private val tflite: Interpreter, private val labels: 3 to FloatArray(1) ) - val predictions get() = (0 until OBJECT_COUNT).map { - ObjectPrediction( + val predictions + get() = (0 until OBJECT_COUNT).map { + ObjectPrediction( - // The locations are an array of [0, 1] floats for [top, left, bottom, right] - location = locations[0][it].let { - RectF(it[1], it[0], it[3], it[2]) - }, + // The locations are an array of [0, 1] floats for [top, left, bottom, right] + location = locations[0][it].let { + RectF(it[1], it[0], it[3], it[2]) + }, - // SSD Mobilenet V1 Model assumes class 0 is background class - // in label file and class labels start from 1 to number_of_classes + 1, - // while outputClasses correspond to class index from 0 to number_of_classes - label = labels[1 + labelIndices[0][it].toInt()], + // SSD Mobilenet V1 Model assumes class 0 is background class + // in label file and class labels start from 1 to number_of_classes + 1, + // while outputClasses correspond to class index from 0 to number_of_classes + label = labels[1 + labelIndices[0][it].toInt()], - // Score is a single value of [0, 1] - score = scores[0][it] - ) - } + // Score is a single value of [0, 1] + score = scores[0][it] + ) + } fun predict(image: TensorImage): List { tflite.runForMultipleInputsOutputs(arrayOf(image.buffer), outputBuffer) diff --git a/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_launcher_background.xml b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_launcher_background.xml new file mode 100644 index 00000000..38c55e63 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_launcher_background.xml @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter.xml b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter.xml new file mode 100644 index 00000000..0c4fed56 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_focused.xml b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_focused.xml new file mode 100644 index 00000000..5f9051a8 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_focused.xml @@ -0,0 +1,33 @@ + + + + + diff --git a/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_normal.xml b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_normal.xml new file mode 100644 index 00000000..47d87c87 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_normal.xml @@ -0,0 +1,33 @@ + + + + + diff --git a/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_pressed.xml b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_pressed.xml new file mode 100644 index 00000000..5f9051a8 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/drawable-v24/ic_shutter_pressed.xml @@ -0,0 +1,33 @@ + + + + + diff --git a/CameraXAdvanced/tflite/src/main/res/values/styles.xml b/CameraXAdvanced/tflite/src/main/res/drawable-v24/shape_rectangle.xml similarity index 57% rename from CameraXAdvanced/tflite/src/main/res/values/styles.xml rename to CameraXAdvanced/tflite/src/main/res/drawable-v24/shape_rectangle.xml index 8bfac621..8e292f6b 100644 --- a/CameraXAdvanced/tflite/src/main/res/values/styles.xml +++ b/CameraXAdvanced/tflite/src/main/res/drawable-v24/shape_rectangle.xml @@ -1,5 +1,4 @@ - - - - - - - - + + + + + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/layout/activity_camera.xml b/CameraXAdvanced/tflite/src/main/res/layout/activity_camera.xml index c094f944..7e6d627a 100644 --- a/CameraXAdvanced/tflite/src/main/res/layout/activity_camera.xml +++ b/CameraXAdvanced/tflite/src/main/res/layout/activity_camera.xml @@ -1,5 +1,4 @@ - - - + android:layout_height="match_parent" + android:background="@android:color/black"> + android:layout_height="match_parent" + tools:background="@tools:sample/backgrounds/scenic" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/box_prediction" /> + app:layout_constraintEnd_toEndOf="@+id/view_finder" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> @@ -62,11 +62,11 @@ android:layout_width="@dimen/round_button_large" android:layout_height="@dimen/round_button_large" android:layout_marginBottom="@dimen/shutter_button_margin" - android:scaleType="fitCenter" android:background="@drawable/ic_shutter" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent" + android:contentDescription="@string/capture_button_alt" + android:scaleType="fitCenter" app:layout_constraintBottom_toBottomOf="parent" - android:contentDescription="@string/capture_button_alt" /> + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" /> \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/values-night/themes.xml b/CameraXAdvanced/tflite/src/main/res/values-night/themes.xml new file mode 100644 index 00000000..7d10bb62 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/values-night/themes.xml @@ -0,0 +1,36 @@ + + + + + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/values/colors.xml b/CameraXAdvanced/tflite/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8c6127d --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/values/strings.xml b/CameraXAdvanced/tflite/src/main/res/values/strings.xml index dbfb4c04..3dbdf02b 100644 --- a/CameraXAdvanced/tflite/src/main/res/values/strings.xml +++ b/CameraXAdvanced/tflite/src/main/res/values/strings.xml @@ -1,21 +1,5 @@ - - Camera Object Detector Capture UNKNOWN - + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/values/themes.xml b/CameraXAdvanced/tflite/src/main/res/values/themes.xml new file mode 100644 index 00000000..e61be376 --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/values/themes.xml @@ -0,0 +1,36 @@ + + + + + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/xml/backup_rules.xml b/CameraXAdvanced/tflite/src/main/res/xml/backup_rules.xml new file mode 100644 index 00000000..fa0f996d --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/main/res/xml/data_extraction_rules.xml b/CameraXAdvanced/tflite/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 00000000..9ee9997b --- /dev/null +++ b/CameraXAdvanced/tflite/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/CameraXAdvanced/tflite/src/test/java/com/android/example/camerax/tflite/ExampleUnitTest.kt b/CameraXAdvanced/tflite/src/test/java/com/android/example/camerax/tflite/ExampleUnitTest.kt new file mode 100644 index 00000000..e81f3c13 --- /dev/null +++ b/CameraXAdvanced/tflite/src/test/java/com/android/example/camerax/tflite/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.android.example.camerax.tflite + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file