Mobilenet из моделей Tensorflow < /p>
mobilenet > Приложение работает следующим образом: < /p>
Я захватываю изображение, используя камеру и сохраняю его в качестве временного файла. < /Li>
Затем изображение изменяется до 224x224 пикселей и нормализуется в соответствии с этапами предварительной обработки Mobilenet (вычитание 127,5 и разделение на 127,5). < /Li>
к модели для вывода. < /li>
< /ol>
, в то время как модель работает без каких -либо исключений, возвращаемые вероятности всегда одинаковы для всех классов, независимо от входного изображения. Например, вероятность каждого класса неизменно близок к нулю или равномерной, как если бы модель не отвечает на вход. /p>
mainactivity.kt
Код: Выделить всё
package com.example.myapplication
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.FrameLayout
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import java.io.File
import java.io.InputStream
import java.nio.ByteBuffer
import java.text.SimpleDateFormat
import java.util.*
class MainActivity : ComponentActivity() {
private lateinit var photoUri: Uri
private lateinit var mobileNetClassifier: MobileNetClassifier
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mobileNetClassifier = MobileNetClassifier(this)
// Layout programmatically
val layout = FrameLayout(this).apply {
id = FrameLayout.generateViewId()
}
setContentView(layout)
val button = Button(this).apply {
text = "Take a Photo"
setOnClickListener { checkPermissionsAndOpenCamera() }
}
layout.addView(button)
// Align button in the center
val params = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {
gravity = android.view.Gravity.CENTER
}
button.layoutParams = params
}
private fun analyzePhoto(photoUri: Uri) {
val inputStream: InputStream? = contentResolver.openInputStream(photoUri)
val bitmap = BitmapFactory.decodeStream(inputStream)
inputStream?.close()
// Convert the image to ByteBuffer
val byteBuffer = convertBitmapToByteBuffer(bitmap)
// Get the prediction
val result = mobileNetClassifier.classifyImage(byteBuffer)
// Display the result
Toast.makeText(this, "Result: $result", Toast.LENGTH_LONG).show()
}
private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {
val IMAGE_MEAN = 127.5f
val IMAGE_STD = 127.5f
val IMAGE_SIZE_X = 224
val IMAGE_SIZE_Y = 224
val DIM_PIXEL_SIZE = 3
val NUM_BYTES_PER_CHANNEL = 4 // Float size
// Resize bitmap to match model input size
val resizedBitmap = Bitmap.createScaledBitmap(bitmap, IMAGE_SIZE_X, IMAGE_SIZE_Y, false)
val intValues = IntArray(IMAGE_SIZE_X * IMAGE_SIZE_Y)
resizedBitmap.getPixels(intValues, 0, resizedBitmap.width, 0, 0, resizedBitmap.width, resizedBitmap.height)
val byteBuffer = ByteBuffer.allocateDirect(
IMAGE_SIZE_X * IMAGE_SIZE_Y * DIM_PIXEL_SIZE * NUM_BYTES_PER_CHANNEL
)
byteBuffer.order(ByteOrder.nativeOrder())
byteBuffer.rewind()
// Normalize pixel values
for (pixel in intValues) {
byteBuffer.putFloat(((pixel shr 16 and 0xFF) - IMAGE_MEAN) / IMAGE_STD) // Red
byteBuffer.putFloat(((pixel shr 8 and 0xFF) - IMAGE_MEAN) / IMAGE_STD) // Green
byteBuffer.putFloat(((pixel and 0xFF) - IMAGE_MEAN) / IMAGE_STD) // Blue
}
return byteBuffer
}
private fun checkPermissionsAndOpenCamera() {
when {
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
else -> {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
}
}
private val takePictureLauncher = registerForActivityResult(
ActivityResultContracts.TakePicture()
) { isSaved: Boolean ->
if (isSaved) {
analyzePhoto(photoUri)
}
}
private fun openCamera() {
val photoFile = createImageFile()
photoUri = FileProvider.getUriForFile(
this,
"${packageName}.provider",
photoFile
)
takePictureLauncher.launch(photoUri)
}
private fun createImageFile(): File {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val storageDir = getExternalFilesDir(null)
return File.createTempFile(
"JPEG_${timestamp}_",
".jpg",
storageDir
)
}
}
Код: Выделить всё
package com.example.myapplication
import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.support.common.FileUtil
import java.io.InputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder
class MobileNetClassifier(context: Context) {
private val interpreter: Interpreter
private val labels: List
init {
interpreter = loadModel(context, "mobilenet_v2_1.4_224.tflite")
labels = loadLabels(context)
Log.d("MobileNetClassifier", "Model and labels successfully loaded")
}
private fun loadModel(context: Context, modelFileName: String): Interpreter {
return try {
val model = FileUtil.loadMappedFile(context, modelFileName)
Interpreter(model)
} catch (e: Exception) {
Log.e("MobileNetClassifier", "Error loading model file: $modelFileName", e)
throw RuntimeException("Failed to load model", e)
}
}
private fun loadLabels(context: Context): List {
val labelsList = mutableListOf()
try {
val inputStream: InputStream = context.assets.open("labels.txt")
inputStream.bufferedReader().useLines { lines ->
lines.forEach { line ->
if (line.isNotBlank()) labelsList.add(line.trim())
}
}
} catch (e: Exception) {
Log.e("MobileNetClassifier", "Error loading labels", e)
throw RuntimeException("Failed to load labels", e)
}
return labelsList
}
fun classifyImage(byteBuffer: ByteBuffer): String {
val output = Array(1) { FloatArray(1001) }
interpreter.run(byteBuffer, output)
val probabilities = output[0]
val maxIndex = probabilities.indices.maxByOrNull { probabilities[it] }
return labels.getOrNull(maxIndex ?: -1) ?: "Unknown"
}
}
Несмотря на то, что следуют рекомендуемой предварительной обработке и использованию действительной модели .tflite, выходные вероятности идентичны для всех входов. Может ли это быть проблемой с предварительной обработкой или самого файла модели?
Что я попробовал? Несколько изображений:
Я сделал разные фотографии с различным содержанием (например, объекты, ландшафты и т. Д.), Но вероятности классификации остаются одинаковыми каждый раз. Процесс:
Я обеспечил, чтобы модель Mobilenet_v2_1.4_224.tflite была правильно загружена с использованием метода Tensorflow Lite's FileUtil.LoadMapedFile. Функция, чтобы подтвердить, что нормализация пикселей (среднее вычитание и деление по стандартному отклонению) была реализована правильно. отправлено в модель, чтобы убедиться, что они меняются между изображениями. Журналы показывают, что входной буфер действительно отличается для каждого изображения. То же самое, независимо от входного изображения.
чего я ожидал? Содержание изображения. Поскольку Mobilenet является предварительно обученной моделью классификации изображений, она должна создавать различные выходы для различных входов, особенно для таких разных фотографий.
Подробнее здесь: https://stackoverflow.com/questions/792 ... bilenet-v2