替换菜品识别模型,暂时取消相似的判断,查询全部数据测试新模型效果,暂时取消查询前后数据量不一致的判断避免查不出数据

This commit is contained in:
mazengfei
2026-02-11 18:05:40 +08:00
parent 655e9cd56e
commit f562abc12f
9 changed files with 274 additions and 125 deletions
@@ -607,6 +607,7 @@ class FoodCollectionActivity : ComponentActivity() {
tip
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show()
mDialogWaiting!!.setCanceledOnTouchOutside(true)
mDialogWaiting!!.setCancelable(true)
}
}
@@ -628,6 +629,7 @@ class FoodCollectionActivity : ComponentActivity() {
val view = View.inflate(this, R.layout.dialog_waiting, null)
mDialogWaiting = CustomDialog(this, view, R.style.MyDialog)
mDialogWaiting!!.show()
mDialogWaiting!!.setCanceledOnTouchOutside(true)
mDialogWaiting!!.setCancelable(true)
}
val contentView = mDialogWaiting?.findViewById<ViewGroup>(android.R.id.content)
@@ -377,7 +377,8 @@ abstract class GoodsListActivity : ComponentActivity() {
if (newBmp.isRecycled.not()) {
newBmp.recycle()
}
val count = foodList.count { it.score < 0.15 }
// val count = foodList.count { it.score < 0.15 }
val count = foodList.size
if (count == 0) {
//未识别到满足相似度>=0.85的,显示识别率最高的
var tempList = foodList.filter { it.name.contains("黑袋子").not() }
@@ -429,7 +430,9 @@ abstract class GoodsListActivity : ComponentActivity() {
return@runOnUiThread
}
handleGoodsResult(
goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(),
// TODO: 暂时取消不一致判断,显示查询到的菜品
// goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(),
goodsList = goodsList,
// file = null,
// name = foodList.joinToString(",")
)
@@ -16,9 +16,9 @@ class RequestInterceptor : Interceptor {
val requestBuilder = originalRequest.newBuilder()
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("deviceId", GlobalData.deviceId)
.header("X-DEVICE-CODE", GlobalData.deviceId)
// .header("X-DEVICE-CODE", "bcf396ed-78f6-3864-9837-7c37c5b2ec41")
.header("deviceId", if (GlobalData.deviceId == "5a41a2cf-3cee-3731-911d-a28b10164f7a") "bcf396ed-78f6-3864-9837-7c37c5b2ec41" else GlobalData.deviceId)
// .header("X-DEVICE-CODE", GlobalData.deviceId)
.header("X-DEVICE-CODE", if (GlobalData.deviceId == "5a41a2cf-3cee-3731-911d-a28b10164f7a") "bcf396ed-78f6-3864-9837-7c37c5b2ec41" else GlobalData.deviceId)
.header("x-access-token", GlobalData.appToken)
.header("authorization", "57ee87183f2a4fa59683ec9ef41c8f5d")
// .header("Authorization", "Bearer ${getToken()}")
@@ -4,10 +4,12 @@ import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.renderscript.Element.DataType
import android.util.Log
import androidx.core.graphics.scale
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.sw.inbound.MyApp
import com.sw.inbound.objbox.ObjectBox.boxStore
import com.sw.inbound.utils.AssetsTool
import com.sw.inbound.utils.ImageUtil
import com.sw.inbound.utils.ext.toJsonString
@@ -16,6 +18,7 @@ import io.objectbox.kotlin.boxFor
import io.objectbox.query.IdWithScore
import io.objectbox.query.Query
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import okhttp3.internal.closeQuietly
import org.pytorch.IValue
@@ -31,12 +34,14 @@ import java.io.InputStream
object FoodModule {
private lateinit var module_mobile: Module
// private lateinit var box: Box<Food>
// private lateinit var box: Box<Food>
private lateinit var embeddingsList: List<List<Float>>
private lateinit var labelsList: IntArray
private lateinit var classInfo: FoodClassInfo
private val NO_MEAN_RGB = floatArrayOf(0.0f, 0.0f, 0.0f)
private val NO_STD_RGB = floatArrayOf(1.0f, 1.0f, 1.0f)
// 1. 定义你的模型固定输入尺寸 (根据你的tflite模型修改,比如224x224)
private const val MODEL_INPUT_WIDTH = 300
private const val MODEL_INPUT_HEIGHT = 300
@@ -47,12 +52,7 @@ object FoodModule {
suspend fun init(context: Context) {
withContext(Dispatchers.IO) {
module_mobile = Module.load(copyAssetToCache(context, "best_embedding_model_mobile.pt"))
ObjectBox.safeDbOp {
val box = ObjectBox.getBox<Food>()
if (box?.all?.isEmpty() == true) {
initDefFoodData(context)
}
}
initDefFoodData(context)
}
}
@@ -65,13 +65,13 @@ object FoodModule {
// }
fun bitmap2FloatArray(originBitmap: Bitmap, isRecycle: Boolean): FloatArray? {
var rgb565Bitmap: Bitmap?=null
var rgb565Bitmap: Bitmap? = null
try {
val scaledBitmap = originBitmap.scale(MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT)
if (isRecycle) {
originBitmap.recycle()
}
rgb565Bitmap = scaledBitmap.copy(Bitmap.Config.RGB_565, false)
rgb565Bitmap = scaledBitmap.copy(Bitmap.Config.RGB_565, false)
scaledBitmap.recycle()
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
rgb565Bitmap,
@@ -114,7 +114,10 @@ object FoodModule {
// return queryFoodNameScore(floatArray, queryCount)
// }
suspend fun queryFoodNameScore(floatArray: FloatArray?, queryCount: Int = 15): List<IdNameScore> {
suspend fun queryFoodNameScore(
floatArray: FloatArray?,
queryCount: Int = 15
): List<IdNameScore> {
if (floatArray == null) return emptyList()
// val query: Query<Food> = box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build()
// //查询比较分数
@@ -126,15 +129,18 @@ object FoodModule {
// // 先关闭Query,释放Cursor
// query.close()
// }
Timber.tag("FoodModule").d("queryFood向量:${floatArray.slice(0 until 50).toJsonString()}")
val idScoreList = ObjectBox.query(floatArray, queryCount)
val nameScoreList = mutableListOf<IdNameScore>()
idScoreList.forEach {
val name = ObjectBox.get(it.id)?.name?:""
val name = ObjectBox.get(it.id)?.name ?: ""
nameScoreList.add(IdNameScore(id = it.id, name = name, score = it.score))
}
Timber.tag("FoodModule").d("queryFood数据:${nameScoreList.toJsonString()}")
return nameScoreList
}
suspend fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
val floatArray = bitmap2FloatArray(bitmap, false) ?: return emptyList()
Timber.tag("FoodModule").d("向量:${floatArray.toJsonString()}")
@@ -165,6 +171,7 @@ object FoodModule {
Timber.tag("FoodModule").d("getFoodScoreList数据:${sortedScoreList.toJsonString()}")
return sortedScoreList
}
suspend fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> {
val map = mutableMapOf<String, Int>()
val nameScoreList = queryFoodNameScore(floatArray, queryCount)
@@ -177,39 +184,51 @@ object FoodModule {
}
data class IdNameScore(
val id:Long,
var name:String,
val id: Long,
var name: String,
val score: Double
)
suspend fun initDefFoodData(context: Context, action:()-> Unit={}) {
val count = ObjectBox.getBox<Food>()?.all?.count { it.foodIdx == DEFAULT_FOOD_INDEX }?:0
if (count > 0) {
return
}
val embeddingsJson = AssetsTool.readAssetsFile(context, "data/embeddings.json")
val labelsJson = AssetsTool.readAssetsFile(context, "data/labels.json")
val classInfoJson = AssetsTool.readAssetsFile(context, "data/class_info.json")
suspend fun initDefFoodData(context: Context, action: () -> Unit = {}) {
try {
val count =
ObjectBox.getBox<Food>()?.all?.count { it.foodIdx == DEFAULT_FOOD_INDEX } ?: 0
if (count > 0) {
return
}
val embeddingsJson = AssetsTool.readAssetsFile(context, "data/embeddings.json")
val labelsJson = AssetsTool.readAssetsFile(context, "data/labels.json")
val classInfoJson = AssetsTool.readAssetsFile(context, "data/class_info.json")
embeddingsList =
Gson().fromJson(embeddingsJson, object : TypeToken<List<List<Float>>>() {}.type)
labelsList = Gson().fromJson(labelsJson, IntArray::class.java)
classInfo =
Gson().fromJson(classInfoJson, FoodClassInfo::class.java)
embeddingsList =
Gson().fromJson(embeddingsJson, object : TypeToken<List<List<Float>>>() {}.type)
labelsList = Gson().fromJson(labelsJson, IntArray::class.java)
classInfo =
Gson().fromJson(classInfoJson, FoodClassInfo::class.java)
val foodMap = classInfo.idx_to_class
val list = mutableListOf<Food>()
embeddingsList.forEachIndexed { index, floatList ->
val classIdx = labelsList[index]
val foodName = foodMap["$classIdx"]
val array = floatList.toFloatArray()
// ObjectBox.boxStore.runInTx {
// box.put(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX))
// }
list.add(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX))
val foodMap = classInfo.idx_to_class
val list = mutableListOf<Food>()
val size = embeddingsList.size
val size2 = labelsList.size
val size3 = foodMap.size
Log.d("TAG", "initDefFoodData: $size,$size2,$size3")
embeddingsList.forEachIndexed { index, floatList ->
val classIdx = labelsList[index]
val foodName = foodMap["$classIdx"]
val array = floatList.toFloatArray()
// ObjectBox.boxStore.runInTx {
// box.put(Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX))
// }
val food = Food(name = foodName, foodVector = array, foodIdx = DEFAULT_FOOD_INDEX)
list.add(food)
}
// val tempList = list.chunked(10)
ObjectBox.putAll(list)
action()
} catch (e: Exception) {
e.printStackTrace()
Log.d("TAG", "initDefFoodData: ---${e.message}--")
}
ObjectBox.putAll(list)
action()
}
@@ -140,6 +140,7 @@ object ObjectBox {
dbMutex.withLock { operation() }
} catch (e: FileCorruptException) {
// 操作中触发损坏,尝试重建数据库
e.printStackTrace()
//val context = boxStore.context
//deleteDbFiles(context)
init(MyApp.instance!!)
@@ -173,19 +174,20 @@ object ObjectBox {
}
suspend fun putAll(entities: List<Food>) = safeDbOp {
getBox<Food>()?.put(entities)
val box = getBox<Food>()
box?.put(entities)
}
suspend fun filter(name:String?) = safeDbOp {
suspend fun filter(name: String?) = safeDbOp {
val list = getBox<Food>()?.all?.distinctBy { it.name }
if (name.isNullOrBlank().not()) {
list?.filter { it.name?.contains(name) == true }
} else {
list
}?:emptyList()
} ?: emptyList()
}
suspend fun remove(name:String) = safeDbOp {
suspend fun remove(name: String) = safeDbOp {
getBox<Food>()?.run {
val filterIdList = all.filter { it.name == name }.map { it.id }
removeByIds(filterIdList)