采集向量优化调试

This commit is contained in:
2026-01-08 15:02:44 +08:00
parent 378e6088e7
commit 2a55ddb617
35 changed files with 663 additions and 1112 deletions
@@ -25,8 +25,10 @@ import androidx.recyclerview.widget.GridLayoutManager
import com.google.common.util.concurrent.ListenableFuture
import com.sw.dualscreen.GlobalData
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.activity.fragment.CollectFragment
import com.sw.dualscreen.adapter.SearchFoodAdapter
import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.dialog.RemindDialog
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.load
@@ -36,12 +38,16 @@ import com.sw.dualscreen.model.response.ClickBackEvent
import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.FoodOrder
import com.sw.dualscreen.model.response.PaySuccessEvent
import com.sw.dualscreen.model.response.ResetBoxEvent
import com.sw.dualscreen.model.response.UserFaceModel
import com.sw.dualscreen.objbox.Food
import com.sw.dualscreen.objbox.FoodModule
import com.sw.dualscreen.objbox.FoodModule.IdNameScore
import com.sw.dualscreen.objbox.ObjectBox
import com.sw.dualscreen.presentation.MainScreenPresentation
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.socket.TcpClient
import com.sw.dualscreen.utils.ActivityManager
import com.sw.dualscreen.utils.BitmapSaver
import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.GsonUtils
@@ -58,7 +64,12 @@ import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.facedb.FaceDatabase
import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.Job
import kotlinx.coroutines.runBlocking
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject
@@ -69,6 +80,7 @@ import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale
import java.util.concurrent.Executors
import kotlin.collections.get
import kotlin.math.roundToInt
/**
@@ -135,6 +147,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun initialize() {
super.initialize()
box = ObjectBox.boxStore.boxFor(Food::class)
isPageVisible = true
addBackEventListener()
//FoodModule.init(this)
@@ -262,7 +275,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.previewView.visibility = View.VISIBLE
binding.ivImg.visibility = View.GONE
resumeAnalysis()
viewModel.cleanIdentifiedFoodInfoList()
// viewModel.cleanIdentifiedFoodInfoList()
return
}
pauseAnalysis()
@@ -318,6 +331,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
SensorScaleUtils.addWeightListener { weight ->
Timber.d("registerDataChange weight = $weight")
if (isPageVisible.not() || isStartRecognize.not()) {
if (ActivityManager.currentActivity() is MainActivity) {
isPageVisible = true
}
return@addWeightListener
}
val isWeightChange = weight - lastWeight > 0.05
@@ -328,8 +344,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun recognizeByWeight(weight: Double, isWeightChange: Boolean, block: () -> Unit = {}) {
presentation?.updateWeight(weight)
if (weight <= 0.005) {//余量取餐,检测到秤上没有东西,重新启动识别菜品 && presentation?.mealPickupMode == 1
if (weight <= 0.005) {
////余量取餐,检测到秤上没有东西,重新启动识别菜品 && presentation?.mealPickupMode == 1
isRecognitionFood = true
return
}
if (isWeightChange && isRecognitionFood) { // 大于50g
@@ -368,7 +386,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
failCount++
hideWaitingDialog()
// ToastUtils.showToast("拍照异常,请手动放置后重新识别")
shutdownCamera()
setupCamera()
@@ -389,39 +406,42 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
val queryData = GsonUtils.toJson(list)
val recData = GsonUtils.toJson(scoreList)
Timber.d("registerDataChange识别后查询接口数据:$queryData,识别数据:$recData")
if (list.isEmpty()) {
binding.tvToSearch.let {
it.text = "未查询到,手动搜索"
it.visible()
}
return
}
list.forEach { foodInfo ->
val scoreItem = scoreList.firstOrNull { it.name == foodInfo.foodName }
val score = scoreItem?.score ?: 0.0
foodInfo.score = ((1 - score) * 10000).roundToInt()
}
val list2 = try {
val orderList = scoreList.map { it.name.trim() }
list.sortedBy { orderList.indexOf(it.foodName) }
} catch (e: Exception) {
e.printStackTrace()
list
}
//接口已处理排序
// val list2 = try {
// val orderList = scoreList.map { it.name.trim() }
// list.sortedBy { orderList.indexOf(it.foodName) }
// } catch (e: Exception) {
// e.printStackTrace()
// list
// }
searchFoodList.clear()
searchFoodList.addAll(list2)
searchFoodList.addAll(list)
adapter.notifyDataSetChanged()
//adapter.updateData(list)
if (list2.isNotEmpty()) {
checkedItem = list2[0]
checkedItem!!.photoUri = lastPhotoUri
checkedItem!!.isChecked = true
adapter.notifyItemChanged(0)
updateCurrentFood(checkedItem)
lastPhotoUri = null
LightManager.closeRedLight()
binding.flPay.visible()
binding.tvToSearch.let {
it.text = "以上都不是,手动搜索"
it.visible()
}
} else {
binding.flPay.gone()
binding.tvToSearch.gone()
checkedItem = list[0].also {
it.photoUri = lastPhotoUri
it.isChecked = true
}
adapter.notifyItemChanged(0)
updateCurrentFood(checkedItem)
// lastPhotoUri = null
LightManager.closeRedLight()
binding.tvToSearch.let {
it.text = "以上都不是,手动搜索"
it.visible()
}
}
@@ -653,14 +673,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.tvTitleTime.text = dateTime
}
private var isPageVisible = true
public var isPageVisible = true
override fun onResume() {
super.onResume()
isPageVisible = true
// 启动定时器
handler.postDelayed(timeoutRunnable, TIME_OUT)
// ToastUtils.showToast("isPageVisible=$isPageVisible")
if (isFirstOpen) {
//首次
setupSecondaryDisplay()
@@ -778,6 +798,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
foodOrderId = orderId
block()
if (checkedItem!!.isFromSearch == true) {
//当前菜名为手动搜索选择,非识别结果,保存向量数据
saveFoodVector(checkedItem!!)
}
}
}
}
@@ -886,6 +911,111 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
/**
* 将uri转为文件和向量数据并提交
*/
private fun saveFoodVector(foodInfo: FoodInfo) {
try {
lastPhotoUri?.let { uri ->
uri2File(uri) { imageFile, imageVector ->
runBlocking {
uploadCollectFoodPics(foodInfo, imageFile, imageVector)
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 上传菜品信息
*/
private suspend fun uploadCollectFoodPics(
foodInfo: FoodInfo,
imageFile: File?,
imageVector: FloatArray?
) {
if (imageFile == null || imageVector == null) {
Timber.tag(TAG)
.d("是否null判断,imageFile == null:${imageFile == null},imageVector == null:${imageVector == null}")
return
}
val foodId = foodInfo.foodId
val foodName = foodInfo.foodName ?: ""
val foodModelVersion = GlobalData.foodModelVersion
val params = HashMap<String, RequestBody>()
params["foodId"] = foodId.toRequestBody()
params["foodName"] = foodName.toRequestBody()
params["version"] = foodModelVersion.toRequestBody()
val files = listOf(imageFile)
val vectors = listOf(imageVector)
val foodVectorList = vectors.map {
it.joinToString(
separator = ",",
prefix = "[",
postfix = "]"
)
}
val foodVectorJson =
foodVectorList.joinToString(separator = ",", prefix = "[", postfix = "]")
Timber.tag(TAG).d("json=$foodVectorJson")
params["foodVector"] = foodVectorJson.toRequestBody()
val idList = viewModel.uploadCollectFoodPics(files, params)
if (idList.isNullOrEmpty()) {
loadRemindDialog("未返回id")
Timber.tag(TAG).d("idList为空")
return
}
Timber.tag(TAG)
.d("uploadCollectFoodPics-已采集向量总数:${box.all.filter { it.isDel.not() }.size}条")
val filterList = box.all.filter { it.collectId == idList[0] }
if (filterList.isNotEmpty()) {
loadRemindDialog("返回的id${idList[0]}已存在")
return
}
box.put(
Food(
collectId = idList[0],
foodId = foodId,
foodName = foodName,
foodVector = imageVector,
version = foodModelVersion
)
)
}
private fun loadRemindDialog(msg: String) {
runOnUiThread {
RemindDialog(
context = context,
content = msg,
confirmBlock = {}
).show()
}
}
private lateinit var box: Box<Food>
private fun uri2File(uri: Uri, block: (File?, FloatArray?) -> Unit) {
ImageUtil.uriToBitmap(this, uri)?.let { bitmap ->
val imageVector = try {
FoodModule.bitmap2FloatArray(bitmap)
} catch (e: Exception) {
e.printStackTrace()
return@let
}
val imageFile = BitmapSaver.saveToAppFilesDir(
bitmap, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
)
Timber.d("${this.javaClass.simpleName}-cameraCallback-裁剪bitmap保存文件路径:${imageFile?.absolutePath}")
block(imageFile, imageVector)
if (bitmap.isRecycled.not()) {
bitmap.recycle()
}
}
}
override fun onDestroy() {
//SensorScaleUtils.closeScale()
faceTaskJob?.cancel()
@@ -1091,13 +1221,18 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
hideWaitingDialog()
Timber.d("registerDataChange photoUri 识别数据名称:$foodName")
binding.flPay.run {
val chargeMode = SPUtil.getInstance().get(GlobalKey.KEY_CHARGE_MODE, 0)
//0-计费,1-不计费
if (chargeMode == 0) visible() else gone()
}
if (TextUtils.isEmpty(foodName)) {
LightManager.closeGreenLight()
LightManager.closeRedLight()
//binding.layoutRescan.visibility = View.VISIBLE
binding.flPay.visible()
binding.tvToSearch.let {
it.text = "未识别到,手动搜索"
it.text = "未识别到,手动搜索"
it.visible()
}
} else {
@@ -1117,4 +1252,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
// @Subscribe(threadMode = ThreadMode.MAIN)
// public fun onResetBox(event: ResetBoxEvent) {
// ObjectBox.boxStore.close()
// ObjectBox.init(this)
// }
}