优化
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package com.sw.inbound.activity
|
||||
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.text.SpannableStringBuilder
|
||||
@@ -62,7 +61,7 @@ abstract class GoodsListActivity : ComponentActivity() {
|
||||
public const val IS_NEW_RECEIPT = "isNewReceipt"
|
||||
|
||||
const val PAGE_SIZE = 10
|
||||
private const val DELAY_TIME = 10 * 1000
|
||||
private const val DELAY_TIME = 5 * 1000
|
||||
}
|
||||
|
||||
var isReceiptPage: Boolean = false
|
||||
@@ -127,11 +126,7 @@ abstract class GoodsListActivity : ComponentActivity() {
|
||||
dropdownPopup?.showAsDropDown(v)
|
||||
}
|
||||
binding.tvPurchaseNo.setOnClickListener {
|
||||
handleGoodsResult(
|
||||
goodsList = mutableListOf(),
|
||||
file = null,
|
||||
name = null
|
||||
)
|
||||
handleGoodsResult()
|
||||
}
|
||||
binding.tvUserName.text = GlobalData.deviceId
|
||||
binding.tvUserName.gone()
|
||||
@@ -202,6 +197,9 @@ abstract class GoodsListActivity : ComponentActivity() {
|
||||
|
||||
fun recognizeFood() {
|
||||
if (isShowRecognizeDialog.not()) {
|
||||
if(goodsRecognizeDialog == null) {
|
||||
isShowRecognizeDialog = true
|
||||
}
|
||||
return
|
||||
}
|
||||
Timber.tag(TAG).d("recognizeFood,takePhoto")
|
||||
@@ -213,6 +211,7 @@ abstract class GoodsListActivity : ComponentActivity() {
|
||||
} catch (e: Exception) {
|
||||
Timber.tag(TAG).d("recognizeFood,takePhoto异常:${e.message}")
|
||||
e.printStackTrace()
|
||||
handleGoodsResult()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,21 +240,21 @@ abstract class GoodsListActivity : ComponentActivity() {
|
||||
"IMG_CROP_${System.currentTimeMillis()}.jpg"
|
||||
)
|
||||
Timber.d("${this.javaClass.simpleName}-searchFood-裁剪bitmap保存文件路径:${file?.absolutePath}")
|
||||
val foodNameList = FoodModule.queryFood(newBmp)
|
||||
//val foodList = FoodModule.queryFood(newBmp)
|
||||
val foodList = FoodModule.getFoodScoreList(newBmp)
|
||||
runOnUiThread {
|
||||
if (foodNameList.isEmpty()) {
|
||||
handleGoodsResult(
|
||||
goodsList = mutableListOf(),
|
||||
file = file,
|
||||
name = null
|
||||
)
|
||||
if (foodList.isEmpty()) {
|
||||
handleGoodsResult()
|
||||
return@runOnUiThread
|
||||
}
|
||||
viewModel.recognizeGoodsList(foodNameList) { goodsList ->
|
||||
viewModel.recognizeGoodsList(
|
||||
//nameList = foodList,
|
||||
scoreList = foodList,
|
||||
) { goodsList ->
|
||||
handleGoodsResult(
|
||||
goodsList = if (goodsList.size == foodNameList.size) goodsList else mutableListOf(),
|
||||
goodsList = if (goodsList.size == foodList.size) goodsList else mutableListOf(),
|
||||
file = file,
|
||||
name = foodNameList.joinToString(",")
|
||||
name = foodList.joinToString(",")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -269,9 +268,9 @@ abstract class GoodsListActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun handleGoodsResult(
|
||||
goodsList: List<SearchGoodsInfo.Record>,
|
||||
file: File?,
|
||||
name: String?
|
||||
goodsList: List<SearchGoodsInfo.Record> = mutableListOf(),
|
||||
file: File?=null,
|
||||
name: String?=null,
|
||||
) {
|
||||
runOnUiThread {
|
||||
if (goodsRecognizeDialog?.isShowing == true) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import coil.load
|
||||
import com.chad.library.adapter4.BaseQuickAdapter
|
||||
import com.chad.library.adapter4.viewholder.QuickViewHolder
|
||||
import com.sw.inbound.databinding.ListItemRecognizeBinding
|
||||
import com.sw.inbound.ext.toFormattedString
|
||||
import com.sw.inbound.model.response.SearchGoodsInfo
|
||||
import com.sw.inbound.utils.ext.dp
|
||||
import com.sw.inbound.utils.ext.setShapeDrawable
|
||||
@@ -26,7 +27,7 @@ class RecognizeAdapter(var list: MutableList<SearchGoodsInfo.Record>) :
|
||||
override fun onBindViewHolder(holder: VH, position: Int, item: SearchGoodsInfo.Record?) {
|
||||
holder.binding.let {
|
||||
it.tvRecName.run {
|
||||
text = item?.goodsName
|
||||
text = if (item!!.score == 0) item.goodsName else "${item.goodsName}\n${((item.score)/100.0).toFormattedString(2)}%"
|
||||
setShapeDrawable2(
|
||||
solidColor = "#DEF5F5F5",
|
||||
bottomRightRadius = 12.dp,
|
||||
|
||||
@@ -16,7 +16,7 @@ import com.sw.inbound.utils.ext.hideKeyboard
|
||||
abstract class BaseDialog(
|
||||
context: Context,
|
||||
var defWidth: Int = 1500.dp,
|
||||
var defHeight: Int = 900.dp
|
||||
var defHeight: Int = 800.dp
|
||||
) : Dialog(context, R.style.DialogTheme) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@@ -102,12 +102,4 @@ class GoodsRecognizeDialog(
|
||||
recognizeAdapter.stateView = it
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
super.dismiss()
|
||||
activity?.run {
|
||||
isShowRecognizeDialog = true
|
||||
goodsRecognizeDialog = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,8 @@ data class SearchGoodsInfo(
|
||||
val unitVoList: List<UnitVo>? = listOf(),
|
||||
@SerializedName("zjmCode")
|
||||
val zjmCode: String? = "",
|
||||
var isSelected: Boolean = false
|
||||
var isSelected: Boolean = false,
|
||||
var score: Int = 0
|
||||
) : Parcelable {
|
||||
val goodsNameStr: String
|
||||
get() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.sw.inbound.objbox
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.util.SparseLongArray
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.sw.inbound.MyApp
|
||||
@@ -60,7 +61,11 @@ object FoodModule {
|
||||
NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB
|
||||
)
|
||||
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
|
||||
return outputTensor.dataAsFloatArray
|
||||
val floatArray = outputTensor.dataAsFloatArray
|
||||
if (bitmap.isRecycled.not()) {
|
||||
bitmap.recycle()
|
||||
}
|
||||
return floatArray
|
||||
}
|
||||
|
||||
fun queryFood(uri: Uri, queryCount: Int = 15): List<String>? {
|
||||
@@ -69,40 +74,63 @@ object FoodModule {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回识别物品名称列表
|
||||
*/
|
||||
fun queryFood(bitmap: Bitmap, queryCount: Int = 15): List<String> {
|
||||
val inputTensor =
|
||||
TensorImageUtils.bitmapToFloat32Tensor(
|
||||
bitmap,
|
||||
NO_MEAN_RGB, // [0.485, 0.456, 0.406] TORCHVISION_NORM_MEAN_RGB
|
||||
NO_STD_RGB // [0.229, 0.224, 0.225] TORCHVISION_NORM_STD_RGB
|
||||
)
|
||||
val outputTensor = module_mobile.forward(IValue.from(inputTensor)).toTensor()
|
||||
val floatArray = outputTensor.dataAsFloatArray
|
||||
if (bitmap.isRecycled.not()) {
|
||||
bitmap.recycle()
|
||||
}
|
||||
val floatArray = bitmap2FloatArray(bitmap)
|
||||
return queryFood(floatArray, queryCount)
|
||||
}
|
||||
|
||||
fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> {
|
||||
/**
|
||||
* 返回识别物品IdNameScore对象列表
|
||||
*/
|
||||
fun queryFoodNameScore(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
|
||||
val floatArray = bitmap2FloatArray(bitmap)
|
||||
return queryFoodNameScore(floatArray, queryCount)
|
||||
}
|
||||
|
||||
fun queryFoodNameScore(floatArray: FloatArray, queryCount: Int = 15): List<IdNameScore> {
|
||||
val query: Query<Food> =
|
||||
box.query(Food_.foodVector.nearestNeighbors(floatArray, queryCount)).build()
|
||||
//查询比较分数
|
||||
// val tempList = query.findWithScores().sortedBy { it.score }.map { "${it.get().name}|${it.get().foodIdx}|${it.score}" }
|
||||
val map = mutableMapOf<String, Int>()
|
||||
val idScoreList = query.findIdsWithScores()
|
||||
val nameScoreList = mutableListOf<IdNameScore>()
|
||||
idScoreList.forEach {
|
||||
nameScoreList.add(IdNameScore(id = it.id, name = box.get(it.id).name?:"", score = it.score))
|
||||
}
|
||||
Timber.tag("FoodModule").d("queryFood数据:${nameScoreList.toJsonString()}")
|
||||
idScoreList.filter { it.score < 0.05 }.forEach {
|
||||
val food = box.get(it.id)
|
||||
//FoodQueryResult(id = it.id, name = food.name, foodIdx = food.foodIdx, score = it.score)
|
||||
food.name?.let { key ->
|
||||
val count = map[key] ?: 0
|
||||
map[key] = count + 1
|
||||
}
|
||||
|
||||
return nameScoreList
|
||||
}
|
||||
fun getFoodScoreList(bitmap: Bitmap, queryCount: Int = 15): List<IdNameScore> {
|
||||
val floatArray = bitmap2FloatArray(bitmap)
|
||||
val nameScoreList = queryFoodNameScore(floatArray, queryCount)
|
||||
val maxScoreList = nameScoreList.groupBy { it.name }.map { (_, value) -> value.maxByOrNull { it.score }!! }.toMutableList()
|
||||
val map = mutableMapOf<String, Int>()
|
||||
nameScoreList.forEach {
|
||||
val key = it.name
|
||||
val count = map[key] ?: 0
|
||||
map[key] = count + 1
|
||||
}
|
||||
val orderList = map.entries.sortedByDescending { it.value }.map { it.key }.toMutableList()
|
||||
val firstFood = nameScoreList[0].name
|
||||
orderList.remove(firstFood)
|
||||
orderList.add(0, firstFood)
|
||||
|
||||
val sortedScoreList = maxScoreList.sortedWith(compareBy {
|
||||
orderList.indexOf(it.name)
|
||||
})
|
||||
Timber.tag("FoodModule").d("getFoodScoreList数据:${sortedScoreList.toJsonString()}")
|
||||
return sortedScoreList
|
||||
}
|
||||
fun queryFood(floatArray: FloatArray, queryCount: Int = 15): List<String> {
|
||||
val map = mutableMapOf<String, Int>()
|
||||
val nameScoreList = queryFoodNameScore(floatArray, queryCount)
|
||||
nameScoreList.filter { it.score < 0.05 }.forEach {
|
||||
val count = map[it.name] ?: 0
|
||||
map[it.name] = count + 1
|
||||
}
|
||||
val list = map.entries.sortedByDescending { it.value }.map { it.key }
|
||||
return list
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.sw.inbound.model.response.EquipmentInfo
|
||||
import com.sw.inbound.model.response.GoodsInfo
|
||||
import com.sw.inbound.model.response.SearchGoodsInfo
|
||||
import com.sw.inbound.network.LoadingState
|
||||
import com.sw.inbound.objbox.FoodModule
|
||||
import com.sw.inbound.repository.RemoteRepository
|
||||
import com.sw.inbound.utils.ToastUtils
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -197,12 +198,18 @@ abstract class BaseViewModel(
|
||||
}
|
||||
|
||||
fun recognizeGoodsList(
|
||||
nameList: List<String>,
|
||||
nameList: List<String>?=null,
|
||||
scoreList: List<FoodModule.IdNameScore>?=null,
|
||||
callback: (List<SearchGoodsInfo.Record>) -> Unit
|
||||
) {
|
||||
launch {
|
||||
val response = repository.recognizeGoodsList(nameList)
|
||||
if (nameList.isNullOrEmpty() && scoreList.isNullOrEmpty()) return@launch
|
||||
val paramList = if (nameList.isNullOrEmpty()) scoreList!!.map { it.name } else nameList
|
||||
val response = repository.recognizeGoodsList(paramList)
|
||||
val list = if (parseResponse(response)) response.data?:listOf() else listOf()
|
||||
scoreList?.forEachIndexed { index, item ->
|
||||
list[index].score = ((1 - item.score) * 10000).toInt()
|
||||
}
|
||||
callback(list)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
<TextView
|
||||
android:id="@+id/tvRecName"
|
||||
android:layout_width="340dp"
|
||||
android:layout_height="85dp"
|
||||
android:layout_height="86dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="#DEF5F5F5"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="30sp"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
tools:text="大白菜"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user