Skip to content

Commit

Permalink
[tensorfloe-lite-examples-common][DEV]: update to Devbricks X 1.1.0;
Browse files Browse the repository at this point in the history
[tensorfloe-lite-examples-common][DEV]: update settings implementation;
[example-image-classification][DEV]: adapt to latest example framework;
  • Loading branch information
dailystudio committed Aug 11, 2020
1 parent 9bf5be5 commit f136f10
Show file tree
Hide file tree
Showing 27 changed files with 258 additions and 79 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ext {
VERSION_NAME = version()
VERSION_CODE = versionCode().toInteger()

DEVBRICKS_X_VERSION = '1.0.7'
DEVBRICKS_X_VERSION = '1.1.0'
ROOM_VERSION = '2.2.5'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.dailystudio.devbricksx.development.Logger
import com.dailystudio.devbricksx.settings.AbsSettingsDialogFragment
import com.dailystudio.tflite.example.common.AbsExampleActivity
import com.dailystudio.tflite.example.common.InferenceInfo
import com.dailystudio.tflite.example.text.bertqa.fragment.ArticleQAFragment
Expand Down Expand Up @@ -122,10 +123,6 @@ class ArticleQAActivity : AbsExampleActivity<InferenceInfo, List<QaAnswer>>() {
return null
}

override fun createSettingsView(): View? {
return null
}

override fun onResultsUpdated(results: List<QaAnswer>) {
}

Expand Down Expand Up @@ -180,4 +177,8 @@ class ArticleQAActivity : AbsExampleActivity<InferenceInfo, List<QaAnswer>>() {
}
}
}

override fun createSettingsFragment(): AbsSettingsDialogFragment? {
TODO("Not yet implemented")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.dailystudio.devbricksx.development.Logger
import com.dailystudio.devbricksx.settings.AbsSettingsDialogFragment
import com.dailystudio.devbricksx.utils.ImageUtils
import com.dailystudio.tflite.example.common.AbsExampleActivity
import com.dailystudio.tflite.example.common.image.ImageInferenceInfo
Expand Down Expand Up @@ -33,10 +34,6 @@ class ExampleActivity : AbsExampleActivity<ImageInferenceInfo, RecognizedDigit>(
return view
}

override fun createSettingsView(): View? {
return null
}

override fun onResultsUpdated(results: RecognizedDigit) {
Logger.debug("result: $results")

Expand All @@ -61,4 +58,8 @@ class ExampleActivity : AbsExampleActivity<ImageInferenceInfo, RecognizedDigit>(
}
}

override fun createSettingsFragment(): AbsSettingsDialogFragment? {
return null
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.dailystudio.devbricksx.development.Logger
import com.dailystudio.devbricksx.fragment.AbsRecyclerViewFragment
import com.dailystudio.devbricksx.settings.AbsSettingsDialogFragment
import com.dailystudio.devbricksx.utils.StringUtils
import com.dailystudio.tflite.example.common.AbsExampleActivity
import com.dailystudio.tflite.example.common.InferenceInfo
Expand Down Expand Up @@ -58,10 +59,6 @@ class ExampleActivity : AbsExampleActivity<InferenceInfo, List<Classifier.Recogn
return stubView
}

override fun createSettingsView(): View? {
return null
}

override fun onResultsUpdated(results: List<Classifier.Recognition>) {
val selectedGesture = if (results.isNotEmpty()) {
results[0]
Expand Down Expand Up @@ -101,4 +98,8 @@ class ExampleActivity : AbsExampleActivity<InferenceInfo, List<Classifier.Recogn
}
}

override fun createSettingsFragment(): AbsSettingsDialogFragment? {
TODO("Not yet implemented")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.dailystudio.devbricksx.fragment.AbsAboutFragment
import com.dailystudio.devbricksx.settings.AbsSettingsDialogFragment
import com.dailystudio.tflite.example.common.AbsExampleActivity
import com.dailystudio.tflite.example.common.InferenceInfo
import com.dailystudio.tflite.example.common.ui.BaseSettingsFragment
import com.dailystudio.tflite.example.image.classification.fragment.ImageClassificationCameraFragment
import com.dailystudio.tflite.example.image.classification.fragment.ImageClassificationSettingsFragment
import org.tensorflow.lite.examples.classification.tflite.Classifier
import kotlin.math.min

Expand Down Expand Up @@ -60,7 +61,19 @@ class ExampleActivity : AbsExampleActivity<InferenceInfo, List<Classifier.Recogn
}

override fun createSettingsFragment(): AbsSettingsDialogFragment? {
return BaseSettingsFragment()
return ImageClassificationSettingsFragment()
}

override fun getExampleIconResource(): Int {
return R.drawable.about_icon
}

override fun getExampleName(): CharSequence {
return getString(R.string.app_name)
}

override fun getExampleDesc(): CharSequence? {
return getString(R.string.app_desc)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.dailystudio.tflite.example.image.classification

import com.dailystudio.devbricksx.annotations.PreferenceValue
import com.dailystudio.devbricksx.annotations.SharedPreference
import com.dailystudio.tflite.example.common.ui.InferenceSettings
import org.tensorflow.lite.support.model.Model

@SharedPreference
class ImageClassificationSettings(@PreferenceValue
val tfLiteModel: String? = null,
device: String = Model.Device.CPU.toString(),
numOfThread: Int = 1)
: InferenceSettings(device, numOfThread)
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ package com.dailystudio.tflite.example.image.classification.fragment
import android.graphics.Bitmap
import com.dailystudio.devbricksx.GlobalContextWrapper
import com.dailystudio.devbricksx.development.Logger
import com.dailystudio.devbricksx.preference.AbsPrefs
import com.dailystudio.devbricksx.utils.ImageUtils
import com.dailystudio.devbricksx.utils.MatrixUtils
import com.dailystudio.tflite.example.common.InferenceSettings
import com.dailystudio.tflite.example.common.image.AbsImageAnalyzer
import com.dailystudio.tflite.example.common.image.AbsExampleCameraFragment
import com.dailystudio.tflite.example.common.image.ImageInferenceInfo
import com.dailystudio.tflite.example.common.ui.InferenceSettingsPrefs
import com.dailystudio.tflite.example.image.classification.ImageClassificationSettingsPrefs
import org.tensorflow.lite.examples.classification.tflite.Classifier
import org.tensorflow.lite.examples.classification.tflite.Classifier.Recognition
import org.tensorflow.lite.support.model.Model
import java.lang.Exception

private class ImageClassificationAnalyzer(rotation: Int, lensFacing: Int)
: AbsImageAnalyzer<ImageInferenceInfo, List<Recognition>>(rotation, lensFacing) {
Expand All @@ -24,12 +28,36 @@ private class ImageClassificationAnalyzer(rotation: Int, lensFacing: Int)
if (classifier == null) {
val context = GlobalContextWrapper.context
context?.let {
val modelStr = ImageClassificationSettingsPrefs.instance.tfLiteModel
val deviceStr = ImageClassificationSettingsPrefs.instance.device

val model = modelStr?.let {str ->
try {
Classifier.Model.valueOf(str)
} catch (e: Exception) {
Logger.warn("cannot parse model from [$str]: $e")

Classifier.Model.QUANTIZED_MOBILENET
}
} ?: Classifier.Model.QUANTIZED_MOBILENET

val device = try {
Model.Device.valueOf(deviceStr)
} catch (e: Exception) {
Logger.warn("cannot parse device from [$deviceStr]: $e")

Model.Device.CPU
}

val threads = ImageClassificationSettingsPrefs.instance.numberOfThreads
Logger.debug("[CLF UPDATE]: classifier creating: model = $model, device = $device, threads = $threads")


classifier = Classifier.create(it,
Classifier.Model.QUANTIZED_EFFICIENTNET,
inferenceSettings.device,
inferenceSettings.numOfThreads)
model, device, threads)
}

Logger.debug("[CLF UPDATE]: classifier created = $classifier")
Logger.debug("classifier created: $classifier")
}

Expand All @@ -48,16 +76,22 @@ private class ImageClassificationAnalyzer(rotation: Int, lensFacing: Int)
return ImageInferenceInfo()
}

override fun onInferenceSettingsChange(settings: InferenceSettings) {
super.onInferenceSettingsChange(settings)
override fun onInferenceSettingsChange(changePrefName: String) {
super.onInferenceSettingsChange(changePrefName)
Logger.debug("[CLF UPDATE]: new settings: $changePrefName")

invalidateClassifier()
when (changePrefName) {
ImageClassificationSettingsPrefs.PREF_TF_LITE_MODEL,
InferenceSettingsPrefs.PREF_DEVICE,
InferenceSettingsPrefs.PREF_NUMBER_OF_THREADS -> invalidateClassifier()
}
}

@Synchronized
private fun invalidateClassifier() {
classifier?.close()
classifier = null
Logger.debug("[CLF UPDATE]: classifier is invalidated to null")
}

override fun preProcessImage(frameBitmap: Bitmap?,
Expand All @@ -81,4 +115,8 @@ class ImageClassificationCameraFragment : AbsExampleCameraFragment<ImageInferenc
return ImageClassificationAnalyzer(rotation, lensFacing)
}

override fun getSettingsPreference(): AbsPrefs {
return ImageClassificationSettingsPrefs.instance
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.dailystudio.tflite.example.image.classification.fragment

import android.content.Context
import com.dailystudio.devbricksx.settings.AbsSetting
import com.dailystudio.devbricksx.settings.RadioSetting
import com.dailystudio.devbricksx.settings.SimpleRadioSettingItem
import com.dailystudio.tflite.example.common.ui.InferenceSettingsFragment
import com.dailystudio.tflite.example.common.ui.InferenceSettingsPrefs
import com.dailystudio.tflite.example.image.classification.ImageClassificationSettingsPrefs
import com.dailystudio.tflite.example.image.classification.R
import org.tensorflow.lite.examples.classification.tflite.Classifier

class ImageClassificationSettingsFragment : InferenceSettingsFragment() {

override fun createSettings(context: Context): Array<AbsSetting> {
val settings: MutableList<AbsSetting> =
super.createSettings(context).toMutableList()

val settingsPrefs = getInferenceSettingsPrefs()
if (settingsPrefs !is ImageClassificationSettingsPrefs) {
return settings.toTypedArray()
}

val models = arrayOf(
SimpleRadioSettingItem(context,
Classifier.Model.QUANTIZED_MOBILENET.toString(),
R.string.model_quantized_mobile_net),
SimpleRadioSettingItem(context,
Classifier.Model.FLOAT_MOBILENET.toString(),
R.string.model_float_mobile_net),
SimpleRadioSettingItem(context,
Classifier.Model.QUANTIZED_EFFICIENTNET.toString(),
R.string.model_quantized_efficient_net),
SimpleRadioSettingItem(context,
Classifier.Model.FLOAT_EFFICIENTNET.toString(),
R.string.model_float_efficient_net)
)

val modelSetting = object: RadioSetting<SimpleRadioSettingItem>(
context,
ImageClassificationSettingsPrefs.PREF_TF_LITE_MODEL,
R.drawable.ic_setting_models,
R.string.setting_model,
models) {
override val selectedId: String?
get() = settingsPrefs.tfLiteModel

override fun setSelected(selectedId: String?) {
settingsPrefs.tfLiteModel = selectedId
}
}

settings.add(modelSetting)

return settings.toTypedArray()
}

override fun getInferenceSettingsPrefs(): InferenceSettingsPrefs {
return ImageClassificationSettingsPrefs.instance
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FF9900"
android:alpha="0.8">
<group android:scaleX="0.71428573"
android:scaleY="0.71428573"
android:translateX="3.4285715"
android:translateY="3.4285715">
<path
android:fillColor="@android:color/white"
android:pathData="M22,11V3h-7v3H9V3H2v8h7V8h2v10h4v3h7v-8h-7v3h-2V8h2v3z"/>
</group>
</vector>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions example-image-classification/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
<resources>
<string name="app_name">Image Classification</string>
<string name="app_desc">Test an image classification solution with a pre-trained model that can recognize 1000 different types of items from input frames on a mobile camera.</string>

<string name="setting_model">TensorFlow Lite models</string>

<string name="model_float_mobile_net">MobileNet (Float32)</string>
<string name="model_quantized_mobile_net">MobileNet (Quantized)</string>
<string name="model_float_efficient_net">Efficient (Float32)</string>
<string name="model_quantized_efficient_net">Efficient (Quantized)</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.dailystudio.devbricksx.settings.AbsSettingsDialogFragment
import com.dailystudio.tflite.example.common.AbsExampleActivity
import com.dailystudio.tflite.example.common.image.AdvanceInferenceInfo
import com.dailystudio.tflite.example.common.ui.ItemLabel
Expand Down Expand Up @@ -50,10 +51,6 @@ class ExampleActivity : AbsExampleActivity<AdvanceInferenceInfo, SegmentationRes
return stubView
}

override fun createSettingsView(): View? {
return null
}

override fun onResultsUpdated(results: SegmentationResult) {
val overlay: MaskOverlay = findViewById(R.id.mask_overlay)
overlay?.setMask(results.maskBitmap)
Expand Down Expand Up @@ -83,4 +80,8 @@ class ExampleActivity : AbsExampleActivity<AdvanceInferenceInfo, SegmentationRes
}
}

override fun createSettingsFragment(): AbsSettingsDialogFragment? {
TODO("Not yet implemented")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.dailystudio.tflite.example.image.detection
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import com.dailystudio.devbricksx.settings.AbsSettingsDialogFragment
import com.dailystudio.tflite.example.common.AbsExampleActivity
import com.dailystudio.tflite.example.common.image.ImageInferenceInfo
import com.dailystudio.tflite.example.image.detection.fragment.ObjectDetectionCameraFragment
Expand Down Expand Up @@ -38,10 +39,6 @@ class ExampleActivity : AbsExampleActivity<ImageInferenceInfo, List<Classifier.R
return null
}

override fun createSettingsView(): View? {
return null
}

override fun onResultsUpdated(results: List<Classifier.Recognition>) {
tracker.trackResults(results, System.currentTimeMillis())
trackingOverlay?.postInvalidate()
Expand All @@ -55,4 +52,8 @@ class ExampleActivity : AbsExampleActivity<ImageInferenceInfo, List<Classifier.R
info.imageRotation)
}

override fun createSettingsFragment(): AbsSettingsDialogFragment? {
TODO("Not yet implemented")
}

}
Loading

0 comments on commit f136f10

Please sign in to comment.