diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt index f03f4e2..2b8d588 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt @@ -144,10 +144,17 @@ ): String /** + * 获取场景 + */ + @Multipart + @POST("/getScene") + suspend fun getScene(@PartMap body: MutableMap): String + + /** * 获取画面识别结果 */ @Multipart - @POST("detect") + @POST("/detect") suspend fun getRecognizeResult(@PartMap body: MutableMap): String /** diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt index f03f4e2..2b8d588 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt @@ -144,10 +144,17 @@ ): String /** + * 获取场景 + */ + @Multipart + @POST("/getScene") + suspend fun getScene(@PartMap body: MutableMap): String + + /** * 获取画面识别结果 */ @Multipart - @POST("detect") + @POST("/detect") suspend fun getRecognizeResult(@PartMap body: MutableMap): String /** diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt index 5f70985..60826c9 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt @@ -201,13 +201,22 @@ } /** + * 获取场景 + * */ + suspend fun getScene(base64: String): String { + val map: MutableMap = mutableMapOf() + map["img"] = "data:image/png;base64,${base64}".toRequestBody() + return aiApi.getScene(map) + } + + /** * 获取画面识别结果 * */ - suspend fun getRecognizeResult(base64: String, scene: String, xujian_id: String): String { + suspend fun getRecognizeResult(base64: String, scene: String, inspectionId: String): String { val map: MutableMap = mutableMapOf() map["img"] = "data:image/png;base64,${base64}".toRequestBody() map["scene"] = scene.toRequestBody() - map["xujian_id"] = xujian_id.toRequestBody() + map["xunjian_id"] = inspectionId.toRequestBody() return aiApi.getRecognizeResult(map) } diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt index f03f4e2..2b8d588 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt @@ -144,10 +144,17 @@ ): String /** + * 获取场景 + */ + @Multipart + @POST("/getScene") + suspend fun getScene(@PartMap body: MutableMap): String + + /** * 获取画面识别结果 */ @Multipart - @POST("detect") + @POST("/detect") suspend fun getRecognizeResult(@PartMap body: MutableMap): String /** diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt index 5f70985..60826c9 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt @@ -201,13 +201,22 @@ } /** + * 获取场景 + * */ + suspend fun getScene(base64: String): String { + val map: MutableMap = mutableMapOf() + map["img"] = "data:image/png;base64,${base64}".toRequestBody() + return aiApi.getScene(map) + } + + /** * 获取画面识别结果 * */ - suspend fun getRecognizeResult(base64: String, scene: String, xujian_id: String): String { + suspend fun getRecognizeResult(base64: String, scene: String, inspectionId: String): String { val map: MutableMap = mutableMapOf() map["img"] = "data:image/png;base64,${base64}".toRequestBody() map["scene"] = scene.toRequestBody() - map["xujian_id"] = xujian_id.toRequestBody() + map["xunjian_id"] = inspectionId.toRequestBody() return aiApi.getRecognizeResult(map) } diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index a43683f..2f9eeae 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -36,6 +36,7 @@ import com.casic.br.app.vm.InspectionViewModel import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.convertColor import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.rotateImage import com.pengxh.kt.lite.extensions.show @@ -44,6 +45,8 @@ import com.pengxh.kt.lite.extensions.toJson import com.pengxh.kt.lite.utils.SaveKeyValues import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import java.io.ByteArrayOutputStream import java.io.IOException import java.util.concurrent.ExecutionException @@ -80,28 +83,33 @@ private lateinit var inspectionViewModel: InspectionViewModel private lateinit var configViewModel: ConfigViewModel private lateinit var imageFileViewModel: ImageFileViewModel + private var detectedScene = "" private var inspectionId = "" - private var isRecognizing = false + private var inspectionAddress = "" + private var isDetectingScene = false //是否正在识别场景 + private var isDetectingTarget = false //是否正在识别目标 private var mainDicModels: MutableList = ArrayList() override fun initOnCreate(savedInstanceState: Bundle?) { - inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] - locationManager.getCurrentLocation(true, object : LocationManager.OnGetLocationListener { + locationManager.getCurrentLocation(false, object : LocationManager.OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { location?.apply { - val inspectionUser = SaveKeyValues.getValue( - LocaleConstant.ACCOUNT, "" - ) as String - - val currentTimeMillis = System.currentTimeMillis() - val inspectionDate = currentTimeMillis.timestampToDate() - val startTime = currentTimeMillis.timestampToTime() - inspectionViewModel.startInspection( - context, inspectionUser, address, inspectionDate, startTime - ) + inspectionAddress = address } } }) + + inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] + val inspectionUser = SaveKeyValues.getValue( + LocaleConstant.ACCOUNT, "" + ) as String + + val currentTimeMillis = System.currentTimeMillis() + val inspectionDate = currentTimeMillis.timestampToDate() + val startTime = currentTimeMillis.timestampToTime() + inspectionViewModel.startInspection( + context, inspectionUser, inspectionAddress, inspectionDate, startTime + ) inspectionViewModel.addResultModel.observe(this) { if (it.code == 200) { inspectionId = it.data @@ -117,12 +125,43 @@ } imageFileViewModel = ViewModelProvider(this)[ImageFileViewModel::class.java] + imageFileViewModel.sceneResult.observe(this) { + AlertControlDialog.Builder().setContext(this).setTitle("提示") + .setMessage("识别到目标场景,是否开始排查该场景的隐患?").setNegativeButton("稍后") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + binding.titleView.setTitle(it) + detectedScene = it + } + + override fun onCancelClick() { + + } + }).build().show() + } + imageFileViewModel.recognizeResult.observe(this) { + /** + * { + * "scene": "配电箱", + * "inferneceStart": "2024-04-26 16:16:03.653", + * "code": 200, + * "inferneceEnd": "2024-04-26 16:16:03.774", + * "inferneceInterval": "0:00:00.121", + * "result": [ + * + * ] + * } + * */ if (it.code == 200) { - binding.titleView.setTitle(it.scene) - binding.detectView.updateTargetPosition(it.result) + if (it.result.isEmpty()) { + binding.detectView.updateTargetPosition(null) + } else { + binding.detectView.updateTargetPosition(it.result) + } } - isRecognizing = false + isDetectingTarget = false } // Initialize our background executor @@ -195,46 +234,45 @@ executor.execute { val image = imageProxy.image image?.apply { - if (!isRecognizing) { - isRecognizing = true + /** + * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap + * */ + val yBuffer = this.planes[0].buffer + val uBuffer = this.planes[1].buffer + val vBuffer = this.planes[2].buffer - /** - * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap - * */ - val yBuffer = this.planes[0].buffer - val uBuffer = this.planes[1].buffer - val vBuffer = this.planes[2].buffer + val ySize = yBuffer.remaining() + val uSize = uBuffer.remaining() + val vSize = vBuffer.remaining() - val ySize = yBuffer.remaining() - val uSize = uBuffer.remaining() - val vSize = vBuffer.remaining() + val nv21 = ByteArray(ySize + uSize + vSize) + yBuffer.get(nv21, 0, ySize) + vBuffer.get(nv21, ySize, vSize) + uBuffer.get(nv21, ySize + vSize, uSize) - val nv21 = ByteArray(ySize + uSize + vSize) - yBuffer.get(nv21, 0, ySize) - vBuffer.get(nv21, ySize, vSize) - uBuffer.get(nv21, ySize + vSize, uSize) + val yuvImage = YuvImage( + nv21, ImageFormat.NV21, this.width, this.height, null + ) + val out = ByteArrayOutputStream() + yuvImage.compressToJpeg( + Rect(0, 0, yuvImage.width, yuvImage.height), 100, out + ) - val yuvImage = YuvImage( - nv21, ImageFormat.NV21, this.width, this.height, null + val imageBytes = out.toByteArray() + val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + val base64 = bitmap.rotateImage(90).encodeToBase64() + //先识别场景 + if (!isDetectingScene) { + isDetectingScene = true + imageFileViewModel.getScene(context, base64) + } + + //再识别隐患 + if (!isDetectingTarget && detectedScene.isNotBlank()) { + isDetectingTarget = true + imageFileViewModel.getRecognizeResult( + context, base64, detectedScene, inspectionId ) - val out = ByteArrayOutputStream() - yuvImage.compressToJpeg( - Rect(0, 0, yuvImage.width, yuvImage.height), 100, out - ) - - val imageBytes = out.toByteArray() - val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) - - val base64 = bitmap.rotateImage(90).encodeToBase64() - if (inspectionId.isNotBlank()) { - imageFileViewModel.getRecognizeResult( - context, base64, binding.titleView.getTitle(), inspectionId - ) - } else { - runOnUiThread { - "巡检ID异常,请重新建立巡检任务".show(context) - } - } } } //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 @@ -297,21 +335,41 @@ } override fun onRightClick() { - val intent = Intent(context, SelectSceneActivity::class.java) - selectSceneLauncher.launch(intent) + BottomActionSheet.Builder() + .setContext(context) + .setActionItemTitle(arrayListOf("手动选择场景", "重置已选场景")) + .setItemTextColor(R.color.themeColor.convertColor(context)) + .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener { + override fun onActionItemClick(position: Int) { + when (position) { + 0 -> { + val intent = Intent(context, SelectSceneActivity::class.java) + selectSceneLauncher.launch(intent) + } + + 1 -> { + binding.titleView.setTitle("") + isDetectingScene = false + detectedScene = "" + "场景重置成功".show(context) + } + } + } + }).build().show() } }) } - private val selectSceneLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult(), - ActivityResultCallback { - if (it.resultCode == Activity.RESULT_OK) { - val data = it.data ?: return@ActivityResultCallback - val sceneName = data.getStringExtra("sceneName").toString() - binding.titleView.setTitle(sceneName) - } - }) + private val selectSceneLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult(), + ActivityResultCallback { + if (it.resultCode == Activity.RESULT_OK) { + val data = it.data ?: return@ActivityResultCallback + val sceneName = data.getStringExtra("sceneName").toString() + binding.titleView.setTitle(sceneName) + detectedScene = sceneName + } + }) private fun aspectRatio(width: Int, height: Int): Int { val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt index f03f4e2..2b8d588 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt @@ -144,10 +144,17 @@ ): String /** + * 获取场景 + */ + @Multipart + @POST("/getScene") + suspend fun getScene(@PartMap body: MutableMap): String + + /** * 获取画面识别结果 */ @Multipart - @POST("detect") + @POST("/detect") suspend fun getRecognizeResult(@PartMap body: MutableMap): String /** diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt index 5f70985..60826c9 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt @@ -201,13 +201,22 @@ } /** + * 获取场景 + * */ + suspend fun getScene(base64: String): String { + val map: MutableMap = mutableMapOf() + map["img"] = "data:image/png;base64,${base64}".toRequestBody() + return aiApi.getScene(map) + } + + /** * 获取画面识别结果 * */ - suspend fun getRecognizeResult(base64: String, scene: String, xujian_id: String): String { + suspend fun getRecognizeResult(base64: String, scene: String, inspectionId: String): String { val map: MutableMap = mutableMapOf() map["img"] = "data:image/png;base64,${base64}".toRequestBody() map["scene"] = scene.toRequestBody() - map["xujian_id"] = xujian_id.toRequestBody() + map["xunjian_id"] = inspectionId.toRequestBody() return aiApi.getRecognizeResult(map) } diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index a43683f..2f9eeae 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -36,6 +36,7 @@ import com.casic.br.app.vm.InspectionViewModel import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.convertColor import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.rotateImage import com.pengxh.kt.lite.extensions.show @@ -44,6 +45,8 @@ import com.pengxh.kt.lite.extensions.toJson import com.pengxh.kt.lite.utils.SaveKeyValues import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import java.io.ByteArrayOutputStream import java.io.IOException import java.util.concurrent.ExecutionException @@ -80,28 +83,33 @@ private lateinit var inspectionViewModel: InspectionViewModel private lateinit var configViewModel: ConfigViewModel private lateinit var imageFileViewModel: ImageFileViewModel + private var detectedScene = "" private var inspectionId = "" - private var isRecognizing = false + private var inspectionAddress = "" + private var isDetectingScene = false //是否正在识别场景 + private var isDetectingTarget = false //是否正在识别目标 private var mainDicModels: MutableList = ArrayList() override fun initOnCreate(savedInstanceState: Bundle?) { - inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] - locationManager.getCurrentLocation(true, object : LocationManager.OnGetLocationListener { + locationManager.getCurrentLocation(false, object : LocationManager.OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { location?.apply { - val inspectionUser = SaveKeyValues.getValue( - LocaleConstant.ACCOUNT, "" - ) as String - - val currentTimeMillis = System.currentTimeMillis() - val inspectionDate = currentTimeMillis.timestampToDate() - val startTime = currentTimeMillis.timestampToTime() - inspectionViewModel.startInspection( - context, inspectionUser, address, inspectionDate, startTime - ) + inspectionAddress = address } } }) + + inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] + val inspectionUser = SaveKeyValues.getValue( + LocaleConstant.ACCOUNT, "" + ) as String + + val currentTimeMillis = System.currentTimeMillis() + val inspectionDate = currentTimeMillis.timestampToDate() + val startTime = currentTimeMillis.timestampToTime() + inspectionViewModel.startInspection( + context, inspectionUser, inspectionAddress, inspectionDate, startTime + ) inspectionViewModel.addResultModel.observe(this) { if (it.code == 200) { inspectionId = it.data @@ -117,12 +125,43 @@ } imageFileViewModel = ViewModelProvider(this)[ImageFileViewModel::class.java] + imageFileViewModel.sceneResult.observe(this) { + AlertControlDialog.Builder().setContext(this).setTitle("提示") + .setMessage("识别到目标场景,是否开始排查该场景的隐患?").setNegativeButton("稍后") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + binding.titleView.setTitle(it) + detectedScene = it + } + + override fun onCancelClick() { + + } + }).build().show() + } + imageFileViewModel.recognizeResult.observe(this) { + /** + * { + * "scene": "配电箱", + * "inferneceStart": "2024-04-26 16:16:03.653", + * "code": 200, + * "inferneceEnd": "2024-04-26 16:16:03.774", + * "inferneceInterval": "0:00:00.121", + * "result": [ + * + * ] + * } + * */ if (it.code == 200) { - binding.titleView.setTitle(it.scene) - binding.detectView.updateTargetPosition(it.result) + if (it.result.isEmpty()) { + binding.detectView.updateTargetPosition(null) + } else { + binding.detectView.updateTargetPosition(it.result) + } } - isRecognizing = false + isDetectingTarget = false } // Initialize our background executor @@ -195,46 +234,45 @@ executor.execute { val image = imageProxy.image image?.apply { - if (!isRecognizing) { - isRecognizing = true + /** + * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap + * */ + val yBuffer = this.planes[0].buffer + val uBuffer = this.planes[1].buffer + val vBuffer = this.planes[2].buffer - /** - * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap - * */ - val yBuffer = this.planes[0].buffer - val uBuffer = this.planes[1].buffer - val vBuffer = this.planes[2].buffer + val ySize = yBuffer.remaining() + val uSize = uBuffer.remaining() + val vSize = vBuffer.remaining() - val ySize = yBuffer.remaining() - val uSize = uBuffer.remaining() - val vSize = vBuffer.remaining() + val nv21 = ByteArray(ySize + uSize + vSize) + yBuffer.get(nv21, 0, ySize) + vBuffer.get(nv21, ySize, vSize) + uBuffer.get(nv21, ySize + vSize, uSize) - val nv21 = ByteArray(ySize + uSize + vSize) - yBuffer.get(nv21, 0, ySize) - vBuffer.get(nv21, ySize, vSize) - uBuffer.get(nv21, ySize + vSize, uSize) + val yuvImage = YuvImage( + nv21, ImageFormat.NV21, this.width, this.height, null + ) + val out = ByteArrayOutputStream() + yuvImage.compressToJpeg( + Rect(0, 0, yuvImage.width, yuvImage.height), 100, out + ) - val yuvImage = YuvImage( - nv21, ImageFormat.NV21, this.width, this.height, null + val imageBytes = out.toByteArray() + val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + val base64 = bitmap.rotateImage(90).encodeToBase64() + //先识别场景 + if (!isDetectingScene) { + isDetectingScene = true + imageFileViewModel.getScene(context, base64) + } + + //再识别隐患 + if (!isDetectingTarget && detectedScene.isNotBlank()) { + isDetectingTarget = true + imageFileViewModel.getRecognizeResult( + context, base64, detectedScene, inspectionId ) - val out = ByteArrayOutputStream() - yuvImage.compressToJpeg( - Rect(0, 0, yuvImage.width, yuvImage.height), 100, out - ) - - val imageBytes = out.toByteArray() - val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) - - val base64 = bitmap.rotateImage(90).encodeToBase64() - if (inspectionId.isNotBlank()) { - imageFileViewModel.getRecognizeResult( - context, base64, binding.titleView.getTitle(), inspectionId - ) - } else { - runOnUiThread { - "巡检ID异常,请重新建立巡检任务".show(context) - } - } } } //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 @@ -297,21 +335,41 @@ } override fun onRightClick() { - val intent = Intent(context, SelectSceneActivity::class.java) - selectSceneLauncher.launch(intent) + BottomActionSheet.Builder() + .setContext(context) + .setActionItemTitle(arrayListOf("手动选择场景", "重置已选场景")) + .setItemTextColor(R.color.themeColor.convertColor(context)) + .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener { + override fun onActionItemClick(position: Int) { + when (position) { + 0 -> { + val intent = Intent(context, SelectSceneActivity::class.java) + selectSceneLauncher.launch(intent) + } + + 1 -> { + binding.titleView.setTitle("") + isDetectingScene = false + detectedScene = "" + "场景重置成功".show(context) + } + } + } + }).build().show() } }) } - private val selectSceneLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult(), - ActivityResultCallback { - if (it.resultCode == Activity.RESULT_OK) { - val data = it.data ?: return@ActivityResultCallback - val sceneName = data.getStringExtra("sceneName").toString() - binding.titleView.setTitle(sceneName) - } - }) + private val selectSceneLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult(), + ActivityResultCallback { + if (it.resultCode == Activity.RESULT_OK) { + val data = it.data ?: return@ActivityResultCallback + val sceneName = data.getStringExtra("sceneName").toString() + binding.titleView.setTitle(sceneName) + detectedScene = sceneName + } + }) private fun aspectRatio(width: Int, height: Int): Int { val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) diff --git a/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt b/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt index 8821e65..1529bc6 100644 --- a/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt +++ b/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt @@ -18,31 +18,67 @@ class ImageFileViewModel : BaseViewModel() { private val gson by lazy { Gson() } + val sceneResult = MutableLiveData() val recognizeResult = MutableLiveData() val resultModel = MutableLiveData() - fun getRecognizeResult(context: Context, base64: String, scene: String, xujian_id: String) = - launch({ - loadState.value = LoadState.Loading - val response = RetrofitServiceManager.getRecognizeResult(base64, scene, xujian_id) - when (response.getResponseCode()) { - 200 -> { - loadState.value = LoadState.Success - recognizeResult.value = gson.fromJson( - response, object : TypeToken() {}.type - ) - } - - else -> { - val element = JsonParser.parseString(response) - val jsonObject = element.asJsonObject - jsonObject.get("result").asString.show(context) + fun getScene(context: Context, base64: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.getScene(base64) + when (response.getResponseCode()) { + 200 -> { + /** + * { + * "code": 200, + * "scene": "配电箱" + * } + * */ + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + val scene = jsonObject.get("scene").asString + if (scene == "没有检查到任何场景") { loadState.value = LoadState.Fail + scene.show(context) + } else { + loadState.value = LoadState.Success + sceneResult.value = scene } } - }, { - loadState.value = LoadState.Fail - }) + + else -> { + loadState.value = LoadState.Fail + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + jsonObject.get("result").asString.show(context) + } + } + }, { + loadState.value = LoadState.Fail + }) + + fun getRecognizeResult( + context: Context, base64: String, scene: String, inspectionId: String + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.getRecognizeResult(base64, scene, inspectionId) + when (response.getResponseCode()) { + 200 -> { + loadState.value = LoadState.Success + recognizeResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) + } + + else -> { + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + jsonObject.get("result").asString.show(context) + loadState.value = LoadState.Fail + } + } + }, { + loadState.value = LoadState.Fail + }) fun uploadImage(image: File) = launch({ loadState.value = LoadState.Loading diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt index f03f4e2..2b8d588 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt @@ -144,10 +144,17 @@ ): String /** + * 获取场景 + */ + @Multipart + @POST("/getScene") + suspend fun getScene(@PartMap body: MutableMap): String + + /** * 获取画面识别结果 */ @Multipart - @POST("detect") + @POST("/detect") suspend fun getRecognizeResult(@PartMap body: MutableMap): String /** diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt index 5f70985..60826c9 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt @@ -201,13 +201,22 @@ } /** + * 获取场景 + * */ + suspend fun getScene(base64: String): String { + val map: MutableMap = mutableMapOf() + map["img"] = "data:image/png;base64,${base64}".toRequestBody() + return aiApi.getScene(map) + } + + /** * 获取画面识别结果 * */ - suspend fun getRecognizeResult(base64: String, scene: String, xujian_id: String): String { + suspend fun getRecognizeResult(base64: String, scene: String, inspectionId: String): String { val map: MutableMap = mutableMapOf() map["img"] = "data:image/png;base64,${base64}".toRequestBody() map["scene"] = scene.toRequestBody() - map["xujian_id"] = xujian_id.toRequestBody() + map["xunjian_id"] = inspectionId.toRequestBody() return aiApi.getRecognizeResult(map) } diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index a43683f..2f9eeae 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -36,6 +36,7 @@ import com.casic.br.app.vm.InspectionViewModel import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.convertColor import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.rotateImage import com.pengxh.kt.lite.extensions.show @@ -44,6 +45,8 @@ import com.pengxh.kt.lite.extensions.toJson import com.pengxh.kt.lite.utils.SaveKeyValues import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import java.io.ByteArrayOutputStream import java.io.IOException import java.util.concurrent.ExecutionException @@ -80,28 +83,33 @@ private lateinit var inspectionViewModel: InspectionViewModel private lateinit var configViewModel: ConfigViewModel private lateinit var imageFileViewModel: ImageFileViewModel + private var detectedScene = "" private var inspectionId = "" - private var isRecognizing = false + private var inspectionAddress = "" + private var isDetectingScene = false //是否正在识别场景 + private var isDetectingTarget = false //是否正在识别目标 private var mainDicModels: MutableList = ArrayList() override fun initOnCreate(savedInstanceState: Bundle?) { - inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] - locationManager.getCurrentLocation(true, object : LocationManager.OnGetLocationListener { + locationManager.getCurrentLocation(false, object : LocationManager.OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { location?.apply { - val inspectionUser = SaveKeyValues.getValue( - LocaleConstant.ACCOUNT, "" - ) as String - - val currentTimeMillis = System.currentTimeMillis() - val inspectionDate = currentTimeMillis.timestampToDate() - val startTime = currentTimeMillis.timestampToTime() - inspectionViewModel.startInspection( - context, inspectionUser, address, inspectionDate, startTime - ) + inspectionAddress = address } } }) + + inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] + val inspectionUser = SaveKeyValues.getValue( + LocaleConstant.ACCOUNT, "" + ) as String + + val currentTimeMillis = System.currentTimeMillis() + val inspectionDate = currentTimeMillis.timestampToDate() + val startTime = currentTimeMillis.timestampToTime() + inspectionViewModel.startInspection( + context, inspectionUser, inspectionAddress, inspectionDate, startTime + ) inspectionViewModel.addResultModel.observe(this) { if (it.code == 200) { inspectionId = it.data @@ -117,12 +125,43 @@ } imageFileViewModel = ViewModelProvider(this)[ImageFileViewModel::class.java] + imageFileViewModel.sceneResult.observe(this) { + AlertControlDialog.Builder().setContext(this).setTitle("提示") + .setMessage("识别到目标场景,是否开始排查该场景的隐患?").setNegativeButton("稍后") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + binding.titleView.setTitle(it) + detectedScene = it + } + + override fun onCancelClick() { + + } + }).build().show() + } + imageFileViewModel.recognizeResult.observe(this) { + /** + * { + * "scene": "配电箱", + * "inferneceStart": "2024-04-26 16:16:03.653", + * "code": 200, + * "inferneceEnd": "2024-04-26 16:16:03.774", + * "inferneceInterval": "0:00:00.121", + * "result": [ + * + * ] + * } + * */ if (it.code == 200) { - binding.titleView.setTitle(it.scene) - binding.detectView.updateTargetPosition(it.result) + if (it.result.isEmpty()) { + binding.detectView.updateTargetPosition(null) + } else { + binding.detectView.updateTargetPosition(it.result) + } } - isRecognizing = false + isDetectingTarget = false } // Initialize our background executor @@ -195,46 +234,45 @@ executor.execute { val image = imageProxy.image image?.apply { - if (!isRecognizing) { - isRecognizing = true + /** + * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap + * */ + val yBuffer = this.planes[0].buffer + val uBuffer = this.planes[1].buffer + val vBuffer = this.planes[2].buffer - /** - * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap - * */ - val yBuffer = this.planes[0].buffer - val uBuffer = this.planes[1].buffer - val vBuffer = this.planes[2].buffer + val ySize = yBuffer.remaining() + val uSize = uBuffer.remaining() + val vSize = vBuffer.remaining() - val ySize = yBuffer.remaining() - val uSize = uBuffer.remaining() - val vSize = vBuffer.remaining() + val nv21 = ByteArray(ySize + uSize + vSize) + yBuffer.get(nv21, 0, ySize) + vBuffer.get(nv21, ySize, vSize) + uBuffer.get(nv21, ySize + vSize, uSize) - val nv21 = ByteArray(ySize + uSize + vSize) - yBuffer.get(nv21, 0, ySize) - vBuffer.get(nv21, ySize, vSize) - uBuffer.get(nv21, ySize + vSize, uSize) + val yuvImage = YuvImage( + nv21, ImageFormat.NV21, this.width, this.height, null + ) + val out = ByteArrayOutputStream() + yuvImage.compressToJpeg( + Rect(0, 0, yuvImage.width, yuvImage.height), 100, out + ) - val yuvImage = YuvImage( - nv21, ImageFormat.NV21, this.width, this.height, null + val imageBytes = out.toByteArray() + val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + val base64 = bitmap.rotateImage(90).encodeToBase64() + //先识别场景 + if (!isDetectingScene) { + isDetectingScene = true + imageFileViewModel.getScene(context, base64) + } + + //再识别隐患 + if (!isDetectingTarget && detectedScene.isNotBlank()) { + isDetectingTarget = true + imageFileViewModel.getRecognizeResult( + context, base64, detectedScene, inspectionId ) - val out = ByteArrayOutputStream() - yuvImage.compressToJpeg( - Rect(0, 0, yuvImage.width, yuvImage.height), 100, out - ) - - val imageBytes = out.toByteArray() - val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) - - val base64 = bitmap.rotateImage(90).encodeToBase64() - if (inspectionId.isNotBlank()) { - imageFileViewModel.getRecognizeResult( - context, base64, binding.titleView.getTitle(), inspectionId - ) - } else { - runOnUiThread { - "巡检ID异常,请重新建立巡检任务".show(context) - } - } } } //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 @@ -297,21 +335,41 @@ } override fun onRightClick() { - val intent = Intent(context, SelectSceneActivity::class.java) - selectSceneLauncher.launch(intent) + BottomActionSheet.Builder() + .setContext(context) + .setActionItemTitle(arrayListOf("手动选择场景", "重置已选场景")) + .setItemTextColor(R.color.themeColor.convertColor(context)) + .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener { + override fun onActionItemClick(position: Int) { + when (position) { + 0 -> { + val intent = Intent(context, SelectSceneActivity::class.java) + selectSceneLauncher.launch(intent) + } + + 1 -> { + binding.titleView.setTitle("") + isDetectingScene = false + detectedScene = "" + "场景重置成功".show(context) + } + } + } + }).build().show() } }) } - private val selectSceneLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult(), - ActivityResultCallback { - if (it.resultCode == Activity.RESULT_OK) { - val data = it.data ?: return@ActivityResultCallback - val sceneName = data.getStringExtra("sceneName").toString() - binding.titleView.setTitle(sceneName) - } - }) + private val selectSceneLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult(), + ActivityResultCallback { + if (it.resultCode == Activity.RESULT_OK) { + val data = it.data ?: return@ActivityResultCallback + val sceneName = data.getStringExtra("sceneName").toString() + binding.titleView.setTitle(sceneName) + detectedScene = sceneName + } + }) private fun aspectRatio(width: Int, height: Int): Int { val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) diff --git a/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt b/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt index 8821e65..1529bc6 100644 --- a/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt +++ b/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt @@ -18,31 +18,67 @@ class ImageFileViewModel : BaseViewModel() { private val gson by lazy { Gson() } + val sceneResult = MutableLiveData() val recognizeResult = MutableLiveData() val resultModel = MutableLiveData() - fun getRecognizeResult(context: Context, base64: String, scene: String, xujian_id: String) = - launch({ - loadState.value = LoadState.Loading - val response = RetrofitServiceManager.getRecognizeResult(base64, scene, xujian_id) - when (response.getResponseCode()) { - 200 -> { - loadState.value = LoadState.Success - recognizeResult.value = gson.fromJson( - response, object : TypeToken() {}.type - ) - } - - else -> { - val element = JsonParser.parseString(response) - val jsonObject = element.asJsonObject - jsonObject.get("result").asString.show(context) + fun getScene(context: Context, base64: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.getScene(base64) + when (response.getResponseCode()) { + 200 -> { + /** + * { + * "code": 200, + * "scene": "配电箱" + * } + * */ + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + val scene = jsonObject.get("scene").asString + if (scene == "没有检查到任何场景") { loadState.value = LoadState.Fail + scene.show(context) + } else { + loadState.value = LoadState.Success + sceneResult.value = scene } } - }, { - loadState.value = LoadState.Fail - }) + + else -> { + loadState.value = LoadState.Fail + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + jsonObject.get("result").asString.show(context) + } + } + }, { + loadState.value = LoadState.Fail + }) + + fun getRecognizeResult( + context: Context, base64: String, scene: String, inspectionId: String + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.getRecognizeResult(base64, scene, inspectionId) + when (response.getResponseCode()) { + 200 -> { + loadState.value = LoadState.Success + recognizeResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) + } + + else -> { + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + jsonObject.get("result").asString.show(context) + loadState.value = LoadState.Fail + } + } + }, { + loadState.value = LoadState.Fail + }) fun uploadImage(image: File) = launch({ loadState.value = LoadState.Loading diff --git a/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt b/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt index 0745937..8745fef 100644 --- a/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt +++ b/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt @@ -68,5 +68,6 @@ ) canvas.drawRect(rect, borderPaint) } + invalidate() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java index 1d52d3f..4cf2e03 100644 --- a/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java +++ b/app/src/main/java/com/casic/br/app/model/RecognizeResultModel.java @@ -6,10 +6,10 @@ private String scene; private String inferneceStart; + private int code; private String inferneceEnd; private String inferneceInterval; private List result; - private Integer code; public String getScene() { return scene; @@ -27,6 +27,14 @@ this.inferneceStart = inferneceStart; } + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + public String getInferneceEnd() { return inferneceEnd; } @@ -51,17 +59,9 @@ this.result = result; } - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - public static class ResultModel { private String label; - private Double conf; + private double conf; private List box; public String getLabel() { @@ -72,11 +72,11 @@ this.label = label; } - public Double getConf() { + public double getConf() { return conf; } - public void setConf(Double conf) { + public void setConf(double conf) { this.conf = conf; } diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt index f03f4e2..2b8d588 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitService.kt @@ -144,10 +144,17 @@ ): String /** + * 获取场景 + */ + @Multipart + @POST("/getScene") + suspend fun getScene(@PartMap body: MutableMap): String + + /** * 获取画面识别结果 */ @Multipart - @POST("detect") + @POST("/detect") suspend fun getRecognizeResult(@PartMap body: MutableMap): String /** diff --git a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt index 5f70985..60826c9 100644 --- a/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/br/app/retrofit/RetrofitServiceManager.kt @@ -201,13 +201,22 @@ } /** + * 获取场景 + * */ + suspend fun getScene(base64: String): String { + val map: MutableMap = mutableMapOf() + map["img"] = "data:image/png;base64,${base64}".toRequestBody() + return aiApi.getScene(map) + } + + /** * 获取画面识别结果 * */ - suspend fun getRecognizeResult(base64: String, scene: String, xujian_id: String): String { + suspend fun getRecognizeResult(base64: String, scene: String, inspectionId: String): String { val map: MutableMap = mutableMapOf() map["img"] = "data:image/png;base64,${base64}".toRequestBody() map["scene"] = scene.toRequestBody() - map["xujian_id"] = xujian_id.toRequestBody() + map["xunjian_id"] = inspectionId.toRequestBody() return aiApi.getRecognizeResult(map) } diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index a43683f..2f9eeae 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -36,6 +36,7 @@ import com.casic.br.app.vm.InspectionViewModel import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.convertColor import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.rotateImage import com.pengxh.kt.lite.extensions.show @@ -44,6 +45,8 @@ import com.pengxh.kt.lite.extensions.toJson import com.pengxh.kt.lite.utils.SaveKeyValues import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog +import com.pengxh.kt.lite.widget.dialog.BottomActionSheet import java.io.ByteArrayOutputStream import java.io.IOException import java.util.concurrent.ExecutionException @@ -80,28 +83,33 @@ private lateinit var inspectionViewModel: InspectionViewModel private lateinit var configViewModel: ConfigViewModel private lateinit var imageFileViewModel: ImageFileViewModel + private var detectedScene = "" private var inspectionId = "" - private var isRecognizing = false + private var inspectionAddress = "" + private var isDetectingScene = false //是否正在识别场景 + private var isDetectingTarget = false //是否正在识别目标 private var mainDicModels: MutableList = ArrayList() override fun initOnCreate(savedInstanceState: Bundle?) { - inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] - locationManager.getCurrentLocation(true, object : LocationManager.OnGetLocationListener { + locationManager.getCurrentLocation(false, object : LocationManager.OnGetLocationListener { override fun onAMapLocationGet(location: AMapLocation?) { location?.apply { - val inspectionUser = SaveKeyValues.getValue( - LocaleConstant.ACCOUNT, "" - ) as String - - val currentTimeMillis = System.currentTimeMillis() - val inspectionDate = currentTimeMillis.timestampToDate() - val startTime = currentTimeMillis.timestampToTime() - inspectionViewModel.startInspection( - context, inspectionUser, address, inspectionDate, startTime - ) + inspectionAddress = address } } }) + + inspectionViewModel = ViewModelProvider(this)[InspectionViewModel::class.java] + val inspectionUser = SaveKeyValues.getValue( + LocaleConstant.ACCOUNT, "" + ) as String + + val currentTimeMillis = System.currentTimeMillis() + val inspectionDate = currentTimeMillis.timestampToDate() + val startTime = currentTimeMillis.timestampToTime() + inspectionViewModel.startInspection( + context, inspectionUser, inspectionAddress, inspectionDate, startTime + ) inspectionViewModel.addResultModel.observe(this) { if (it.code == 200) { inspectionId = it.data @@ -117,12 +125,43 @@ } imageFileViewModel = ViewModelProvider(this)[ImageFileViewModel::class.java] + imageFileViewModel.sceneResult.observe(this) { + AlertControlDialog.Builder().setContext(this).setTitle("提示") + .setMessage("识别到目标场景,是否开始排查该场景的隐患?").setNegativeButton("稍后") + .setPositiveButton("好的").setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + binding.titleView.setTitle(it) + detectedScene = it + } + + override fun onCancelClick() { + + } + }).build().show() + } + imageFileViewModel.recognizeResult.observe(this) { + /** + * { + * "scene": "配电箱", + * "inferneceStart": "2024-04-26 16:16:03.653", + * "code": 200, + * "inferneceEnd": "2024-04-26 16:16:03.774", + * "inferneceInterval": "0:00:00.121", + * "result": [ + * + * ] + * } + * */ if (it.code == 200) { - binding.titleView.setTitle(it.scene) - binding.detectView.updateTargetPosition(it.result) + if (it.result.isEmpty()) { + binding.detectView.updateTargetPosition(null) + } else { + binding.detectView.updateTargetPosition(it.result) + } } - isRecognizing = false + isDetectingTarget = false } // Initialize our background executor @@ -195,46 +234,45 @@ executor.execute { val image = imageProxy.image image?.apply { - if (!isRecognizing) { - isRecognizing = true + /** + * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap + * */ + val yBuffer = this.planes[0].buffer + val uBuffer = this.planes[1].buffer + val vBuffer = this.planes[2].buffer - /** - * CameraX 原始预览Image数据(imageProxy.format == ImageFormat.YUV_420_888)转Bitmap - * */ - val yBuffer = this.planes[0].buffer - val uBuffer = this.planes[1].buffer - val vBuffer = this.planes[2].buffer + val ySize = yBuffer.remaining() + val uSize = uBuffer.remaining() + val vSize = vBuffer.remaining() - val ySize = yBuffer.remaining() - val uSize = uBuffer.remaining() - val vSize = vBuffer.remaining() + val nv21 = ByteArray(ySize + uSize + vSize) + yBuffer.get(nv21, 0, ySize) + vBuffer.get(nv21, ySize, vSize) + uBuffer.get(nv21, ySize + vSize, uSize) - val nv21 = ByteArray(ySize + uSize + vSize) - yBuffer.get(nv21, 0, ySize) - vBuffer.get(nv21, ySize, vSize) - uBuffer.get(nv21, ySize + vSize, uSize) + val yuvImage = YuvImage( + nv21, ImageFormat.NV21, this.width, this.height, null + ) + val out = ByteArrayOutputStream() + yuvImage.compressToJpeg( + Rect(0, 0, yuvImage.width, yuvImage.height), 100, out + ) - val yuvImage = YuvImage( - nv21, ImageFormat.NV21, this.width, this.height, null + val imageBytes = out.toByteArray() + val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + val base64 = bitmap.rotateImage(90).encodeToBase64() + //先识别场景 + if (!isDetectingScene) { + isDetectingScene = true + imageFileViewModel.getScene(context, base64) + } + + //再识别隐患 + if (!isDetectingTarget && detectedScene.isNotBlank()) { + isDetectingTarget = true + imageFileViewModel.getRecognizeResult( + context, base64, detectedScene, inspectionId ) - val out = ByteArrayOutputStream() - yuvImage.compressToJpeg( - Rect(0, 0, yuvImage.width, yuvImage.height), 100, out - ) - - val imageBytes = out.toByteArray() - val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) - - val base64 = bitmap.rotateImage(90).encodeToBase64() - if (inspectionId.isNotBlank()) { - imageFileViewModel.getRecognizeResult( - context, base64, binding.titleView.getTitle(), inspectionId - ) - } else { - runOnUiThread { - "巡检ID异常,请重新建立巡检任务".show(context) - } - } } } //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 @@ -297,21 +335,41 @@ } override fun onRightClick() { - val intent = Intent(context, SelectSceneActivity::class.java) - selectSceneLauncher.launch(intent) + BottomActionSheet.Builder() + .setContext(context) + .setActionItemTitle(arrayListOf("手动选择场景", "重置已选场景")) + .setItemTextColor(R.color.themeColor.convertColor(context)) + .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener { + override fun onActionItemClick(position: Int) { + when (position) { + 0 -> { + val intent = Intent(context, SelectSceneActivity::class.java) + selectSceneLauncher.launch(intent) + } + + 1 -> { + binding.titleView.setTitle("") + isDetectingScene = false + detectedScene = "" + "场景重置成功".show(context) + } + } + } + }).build().show() } }) } - private val selectSceneLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult(), - ActivityResultCallback { - if (it.resultCode == Activity.RESULT_OK) { - val data = it.data ?: return@ActivityResultCallback - val sceneName = data.getStringExtra("sceneName").toString() - binding.titleView.setTitle(sceneName) - } - }) + private val selectSceneLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult(), + ActivityResultCallback { + if (it.resultCode == Activity.RESULT_OK) { + val data = it.data ?: return@ActivityResultCallback + val sceneName = data.getStringExtra("sceneName").toString() + binding.titleView.setTitle(sceneName) + detectedScene = sceneName + } + }) private fun aspectRatio(width: Int, height: Int): Int { val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) diff --git a/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt b/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt index 8821e65..1529bc6 100644 --- a/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt +++ b/app/src/main/java/com/casic/br/app/vm/ImageFileViewModel.kt @@ -18,31 +18,67 @@ class ImageFileViewModel : BaseViewModel() { private val gson by lazy { Gson() } + val sceneResult = MutableLiveData() val recognizeResult = MutableLiveData() val resultModel = MutableLiveData() - fun getRecognizeResult(context: Context, base64: String, scene: String, xujian_id: String) = - launch({ - loadState.value = LoadState.Loading - val response = RetrofitServiceManager.getRecognizeResult(base64, scene, xujian_id) - when (response.getResponseCode()) { - 200 -> { - loadState.value = LoadState.Success - recognizeResult.value = gson.fromJson( - response, object : TypeToken() {}.type - ) - } - - else -> { - val element = JsonParser.parseString(response) - val jsonObject = element.asJsonObject - jsonObject.get("result").asString.show(context) + fun getScene(context: Context, base64: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.getScene(base64) + when (response.getResponseCode()) { + 200 -> { + /** + * { + * "code": 200, + * "scene": "配电箱" + * } + * */ + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + val scene = jsonObject.get("scene").asString + if (scene == "没有检查到任何场景") { loadState.value = LoadState.Fail + scene.show(context) + } else { + loadState.value = LoadState.Success + sceneResult.value = scene } } - }, { - loadState.value = LoadState.Fail - }) + + else -> { + loadState.value = LoadState.Fail + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + jsonObject.get("result").asString.show(context) + } + } + }, { + loadState.value = LoadState.Fail + }) + + fun getRecognizeResult( + context: Context, base64: String, scene: String, inspectionId: String + ) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.getRecognizeResult(base64, scene, inspectionId) + when (response.getResponseCode()) { + 200 -> { + loadState.value = LoadState.Success + recognizeResult.value = gson.fromJson( + response, object : TypeToken() {}.type + ) + } + + else -> { + val element = JsonParser.parseString(response) + val jsonObject = element.asJsonObject + jsonObject.get("result").asString.show(context) + loadState.value = LoadState.Fail + } + } + }, { + loadState.value = LoadState.Fail + }) fun uploadImage(image: File) = launch({ loadState.value = LoadState.Loading diff --git a/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt b/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt index 0745937..8745fef 100644 --- a/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt +++ b/app/src/main/java/com/casic/br/app/widgets/AITargetDetectView.kt @@ -68,5 +68,6 @@ ) canvas.drawRect(rect, borderPaint) } + invalidate() } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_check_result.xml b/app/src/main/res/layout/activity_check_result.xml index 8b0dc1d..13c3b57 100644 --- a/app/src/main/res/layout/activity_check_result.xml +++ b/app/src/main/res/layout/activity_check_result.xml @@ -42,6 +42,8 @@ android:background="@drawable/bg_stroke_gray_1" android:hint="请输入巡检地点" android:paddingHorizontal="@dimen/dp_5" + android:singleLine="true" + android:textColor="@color/white" android:textColorHint="@color/white" />