I am using teachable machine to do generate a tensorflow-lite
model and using that model in my android app. The result from tensor flow lite
model shows display name as empty. Below is a screenshot of my teachable-machine
process. I have added Cats and Dogs as name though other values like index, label, score are displayed properly. Here is a sample of the output after detection
<Category "1" (displayName= score=0.99609375 index=1)>
Here is my code snippet
class ImageClassifierHelper(
var threshold: Float = 0.5f,
var numThreads: Int = 2,
var maxResults: Int = 2,
var currentDelegate: Int = 0,
var currentModel: Int = 0,
val context: Context,
val imageClassifierListener: ClassifierListener?
) {
private var imageClassifier: ImageClassifier? = null
init {
setupImageClassifier()
}
fun clearImageClassifier() {
imageClassifier = null
}
private fun setupImageClassifier() {
val optionsBuilder = ImageClassifier.ImageClassifierOptions.builder()
.setScoreThreshold(threshold)
.setMaxResults(maxResults)
val baseOptionsBuilder = BaseOptions.builder().setNumThreads(numThreads)
when (currentDelegate) {
DELEGATE_CPU -> {
// Default
}
DELEGATE_GPU -> {
if (CompatibilityList().isDelegateSupportedOnThisDevice) {
baseOptionsBuilder.useGpu()
} else {
imageClassifierListener?.onError("GPU is not supported on this device")
}
}
DELEGATE_NNAPI -> {
baseOptionsBuilder.useNnapi()
}
}
optionsBuilder.setBaseOptions(baseOptionsBuilder.build())
val modelName =
when (currentModel) {
MODEL_MOBILENETV1 -> "model.tflite"
MODEL_EFFICIENTNETV0 -> "model.tflite"
MODEL_EFFICIENTNETV1 -> "model.tflite"
MODEL_EFFICIENTNETV2 -> "model.tflite"
else -> "model.tflite"
}
try {
imageClassifier =
ImageClassifier.createFromFileAndOptions(context, modelName, optionsBuilder.build())
} catch (e: IllegalStateException) {
imageClassifierListener?.onError(
"Image classifier failed to initialize. See error logs for details"
)
Log.e(TAG, "TFLite failed to load model with error: " + e.message)
}
}
fun classify(image: Bitmap, rotation: Int) {
if (imageClassifier == null) {
setupImageClassifier()
}
// Inference time is the difference between the system time at the start and finish of the
// process
var inferenceTime = SystemClock.uptimeMillis()
// Create preprocessor for the image.
// See https://www.tensorflow.org/lite/inference_with_metadata/
// lite_support#imageprocessor_architecture
val imageProcessor =
ImageProcessor.Builder()
.build()
// Preprocess the image and convert it into a TensorImage for classification.
val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))
val imageProcessingOptions = ImageProcessingOptions.builder()
.setOrientation(getOrientationFromRotation(rotation))
.build()
val results = imageClassifier?.classify(tensorImage, imageProcessingOptions)
inferenceTime = SystemClock.uptimeMillis() - inferenceTime
imageClassifierListener?.onResults(
results,
inferenceTime
)
}
// Receive the device rotation (Surface.x values range from 0->3) and return EXIF orientation
// http://jpegclub.org/exif_orientation.html
private fun getOrientationFromRotation(rotation: Int) : ImageProcessingOptions.Orientation {
return when (rotation) {
Surface.ROTATION_270 ->
ImageProcessingOptions.Orientation.BOTTOM_RIGHT
Surface.ROTATION_180 ->
ImageProcessingOptions.Orientation.RIGHT_BOTTOM
Surface.ROTATION_90 ->
ImageProcessingOptions.Orientation.TOP_LEFT
else ->
ImageProcessingOptions.Orientation.RIGHT_TOP
}
}
interface ClassifierListener {
fun onError(error: String)
fun onResults(
results: List<Classifications>?,
inferenceTime: Long
)
}
companion object {
const val DELEGATE_CPU = 0
const val DELEGATE_GPU = 1
const val DELEGATE_NNAPI = 2
const val MODEL_MOBILENETV1 = 0
const val MODEL_EFFICIENTNETV0 = 1
const val MODEL_EFFICIENTNETV1 = 2
const val MODEL_EFFICIENTNETV2 = 3
private const val TAG = "ImageClassifierHelper"
}
}
I don't think issue is with my android app code but with the model generated from teachable machine.
The model only outputs as numbers, each of the unique number representing a category.
In the above example, you need to create a map that assigns a Category to display name: {'0': 'Cat', '1': 'dog'}
.