diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.h b/app/src/main/cpp/yolo.h index b047291..1cbd0e5 100644 --- a/app/src/main/cpp/yolo.h +++ b/app/src/main/cpp/yolo.h @@ -39,10 +39,11 @@ /** * Yolo当前状态 *
---------------
- * 0 - 分类
- * 1 - 分割
- * 2 - 检测
- * 3 - 绘制
+ * 0 - 暂停
+ * 1 - 分类
+ * 2 - 分割
+ * 3 - 检测
+ * 4 - 绘制
* */ int j_state = 0; diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.h b/app/src/main/cpp/yolo.h index b047291..1cbd0e5 100644 --- a/app/src/main/cpp/yolo.h +++ b/app/src/main/cpp/yolo.h @@ -39,10 +39,11 @@ /** * Yolo当前状态 *
---------------
- * 0 - 分类
- * 1 - 分割
- * 2 - 检测
- * 3 - 绘制
+ * 0 - 暂停
+ * 1 - 分类
+ * 2 - 分割
+ * 3 - 检测
+ * 4 - 绘制
* */ int j_state = 0; diff --git a/app/src/main/cpp/yolov8ncnn.cpp b/app/src/main/cpp/yolov8ncnn.cpp index 38cdadc..61df411 100644 --- a/app/src/main/cpp/yolov8ncnn.cpp +++ b/app/src/main/cpp/yolov8ncnn.cpp @@ -207,14 +207,14 @@ g_yolo = new Yolo; int state; if (use_classify) { - state = 0; - } - if (use_segmentation) { state = 1; } - if (use_detect) { + if (use_segmentation) { state = 2; } + if (use_detect) { + state = 3; + } g_yolo->j_state = state; g_yolo->load( mgr, @@ -256,7 +256,7 @@ } else { if (!g_yolo) g_yolo = new Yolo; - g_yolo->j_state = 1; + g_yolo->j_state = 2; if (*id == 0) { g_yolo->load( mgr, @@ -328,4 +328,16 @@ Java_com_casic_br_app_external_Yolov8ncnn_getYoloCurrentState(JNIEnv *env, jobject thiz) { return g_yolo->j_state; } + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onPause(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 0; + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onRestart(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 3; + return JNI_TRUE; +} } \ No newline at end of file diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.h b/app/src/main/cpp/yolo.h index b047291..1cbd0e5 100644 --- a/app/src/main/cpp/yolo.h +++ b/app/src/main/cpp/yolo.h @@ -39,10 +39,11 @@ /** * Yolo当前状态 *
---------------
- * 0 - 分类
- * 1 - 分割
- * 2 - 检测
- * 3 - 绘制
+ * 0 - 暂停
+ * 1 - 分类
+ * 2 - 分割
+ * 3 - 检测
+ * 4 - 绘制
* */ int j_state = 0; diff --git a/app/src/main/cpp/yolov8ncnn.cpp b/app/src/main/cpp/yolov8ncnn.cpp index 38cdadc..61df411 100644 --- a/app/src/main/cpp/yolov8ncnn.cpp +++ b/app/src/main/cpp/yolov8ncnn.cpp @@ -207,14 +207,14 @@ g_yolo = new Yolo; int state; if (use_classify) { - state = 0; - } - if (use_segmentation) { state = 1; } - if (use_detect) { + if (use_segmentation) { state = 2; } + if (use_detect) { + state = 3; + } g_yolo->j_state = state; g_yolo->load( mgr, @@ -256,7 +256,7 @@ } else { if (!g_yolo) g_yolo = new Yolo; - g_yolo->j_state = 1; + g_yolo->j_state = 2; if (*id == 0) { g_yolo->load( mgr, @@ -328,4 +328,16 @@ Java_com_casic_br_app_external_Yolov8ncnn_getYoloCurrentState(JNIEnv *env, jobject thiz) { return g_yolo->j_state; } + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onPause(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 0; + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onRestart(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 3; + return JNI_TRUE; +} } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt new file mode 100644 index 0000000..8d414f7 --- /dev/null +++ b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt @@ -0,0 +1,25 @@ +package com.casic.br.app.extensions + +import com.casic.br.app.external.YoloResult + +fun FloatArray.convert2YoloResult(): YoloResult { + /** + * 前四位是目标Rect,第五位是目标名对应的角标,第六位是可信度 + * + * [135.88397,120.17752,68.061325,204.02115,28.0,43.642334] + * */ + val yolo = YoloResult() + + val array = FloatArray(4) + array[0] = this[0] + array[1] = this[1] + array[2] = this[2] + array[3] = this[3] + yolo.position = array + + yolo.type = this[4].toInt() + + //保留两位有效小数 + yolo.prob = "${String.format("%.2f", this[5])}%" + return yolo +} \ No newline at end of file diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.h b/app/src/main/cpp/yolo.h index b047291..1cbd0e5 100644 --- a/app/src/main/cpp/yolo.h +++ b/app/src/main/cpp/yolo.h @@ -39,10 +39,11 @@ /** * Yolo当前状态 *
---------------
- * 0 - 分类
- * 1 - 分割
- * 2 - 检测
- * 3 - 绘制
+ * 0 - 暂停
+ * 1 - 分类
+ * 2 - 分割
+ * 3 - 检测
+ * 4 - 绘制
* */ int j_state = 0; diff --git a/app/src/main/cpp/yolov8ncnn.cpp b/app/src/main/cpp/yolov8ncnn.cpp index 38cdadc..61df411 100644 --- a/app/src/main/cpp/yolov8ncnn.cpp +++ b/app/src/main/cpp/yolov8ncnn.cpp @@ -207,14 +207,14 @@ g_yolo = new Yolo; int state; if (use_classify) { - state = 0; - } - if (use_segmentation) { state = 1; } - if (use_detect) { + if (use_segmentation) { state = 2; } + if (use_detect) { + state = 3; + } g_yolo->j_state = state; g_yolo->load( mgr, @@ -256,7 +256,7 @@ } else { if (!g_yolo) g_yolo = new Yolo; - g_yolo->j_state = 1; + g_yolo->j_state = 2; if (*id == 0) { g_yolo->load( mgr, @@ -328,4 +328,16 @@ Java_com_casic_br_app_external_Yolov8ncnn_getYoloCurrentState(JNIEnv *env, jobject thiz) { return g_yolo->j_state; } + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onPause(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 0; + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onRestart(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 3; + return JNI_TRUE; +} } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt new file mode 100644 index 0000000..8d414f7 --- /dev/null +++ b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt @@ -0,0 +1,25 @@ +package com.casic.br.app.extensions + +import com.casic.br.app.external.YoloResult + +fun FloatArray.convert2YoloResult(): YoloResult { + /** + * 前四位是目标Rect,第五位是目标名对应的角标,第六位是可信度 + * + * [135.88397,120.17752,68.061325,204.02115,28.0,43.642334] + * */ + val yolo = YoloResult() + + val array = FloatArray(4) + array[0] = this[0] + array[1] = this[1] + array[2] = this[2] + array[3] = this[3] + yolo.position = array + + yolo.type = this[4].toInt() + + //保留两位有效小数 + yolo.prob = "${String.format("%.2f", this[5])}%" + return yolo +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt index ba7bca8..9e1b265 100644 --- a/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt +++ b/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt @@ -43,4 +43,8 @@ ): Boolean external fun getYoloCurrentState(): Int + + external fun onPause(): Boolean + + external fun onRestart(): Boolean } \ No newline at end of file diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.h b/app/src/main/cpp/yolo.h index b047291..1cbd0e5 100644 --- a/app/src/main/cpp/yolo.h +++ b/app/src/main/cpp/yolo.h @@ -39,10 +39,11 @@ /** * Yolo当前状态 *
---------------
- * 0 - 分类
- * 1 - 分割
- * 2 - 检测
- * 3 - 绘制
+ * 0 - 暂停
+ * 1 - 分类
+ * 2 - 分割
+ * 3 - 检测
+ * 4 - 绘制
* */ int j_state = 0; diff --git a/app/src/main/cpp/yolov8ncnn.cpp b/app/src/main/cpp/yolov8ncnn.cpp index 38cdadc..61df411 100644 --- a/app/src/main/cpp/yolov8ncnn.cpp +++ b/app/src/main/cpp/yolov8ncnn.cpp @@ -207,14 +207,14 @@ g_yolo = new Yolo; int state; if (use_classify) { - state = 0; - } - if (use_segmentation) { state = 1; } - if (use_detect) { + if (use_segmentation) { state = 2; } + if (use_detect) { + state = 3; + } g_yolo->j_state = state; g_yolo->load( mgr, @@ -256,7 +256,7 @@ } else { if (!g_yolo) g_yolo = new Yolo; - g_yolo->j_state = 1; + g_yolo->j_state = 2; if (*id == 0) { g_yolo->load( mgr, @@ -328,4 +328,16 @@ Java_com_casic_br_app_external_Yolov8ncnn_getYoloCurrentState(JNIEnv *env, jobject thiz) { return g_yolo->j_state; } + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onPause(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 0; + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onRestart(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 3; + return JNI_TRUE; +} } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt new file mode 100644 index 0000000..8d414f7 --- /dev/null +++ b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt @@ -0,0 +1,25 @@ +package com.casic.br.app.extensions + +import com.casic.br.app.external.YoloResult + +fun FloatArray.convert2YoloResult(): YoloResult { + /** + * 前四位是目标Rect,第五位是目标名对应的角标,第六位是可信度 + * + * [135.88397,120.17752,68.061325,204.02115,28.0,43.642334] + * */ + val yolo = YoloResult() + + val array = FloatArray(4) + array[0] = this[0] + array[1] = this[1] + array[2] = this[2] + array[3] = this[3] + yolo.position = array + + yolo.type = this[4].toInt() + + //保留两位有效小数 + yolo.prob = "${String.format("%.2f", this[5])}%" + return yolo +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt index ba7bca8..9e1b265 100644 --- a/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt +++ b/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt @@ -43,4 +43,8 @@ ): Boolean external fun getYoloCurrentState(): Int + + external fun onPause(): Boolean + + external fun onRestart(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt index d3c9d85..dddf2cc 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt @@ -4,22 +4,22 @@ import android.content.Intent import android.graphics.PixelFormat import android.os.Bundle -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.SurfaceHolder import android.view.View import android.view.WindowManager import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.amap.api.location.AMapLocation import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckByYoloBinding +import com.casic.br.app.extensions.convert2YoloResult import com.casic.br.app.extensions.getSceneByTarget import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.external.INativeCallback import com.casic.br.app.external.YoloResult -import com.casic.br.app.external.YoloStateConst import com.casic.br.app.external.Yolov8ncnn import com.casic.br.app.model.DictionaryModel import com.casic.br.app.utils.LocaleConstant @@ -36,15 +36,14 @@ import com.pengxh.kt.lite.extensions.toJson import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import org.opencv.core.Mat class StartCheckByYoloActivity : KotlinBaseActivity(), - SurfaceHolder.Callback, INativeCallback { + SurfaceHolder.Callback, INativeCallback, Handler.Callback { private val kTag = "StartCheckActivity" private val context = this @@ -58,18 +57,25 @@ private val detectedSceneSet by lazy { HashSet() } private val yolov8ncnn by lazy { Yolov8ncnn() } private val mat by lazy { Mat() } + private val weakReferenceHandler by lazy { WeakReferenceHandler(this) } private val detectResultDialog by lazy { DetectResultDialog(this) } private lateinit var inspectionViewModel: InspectionViewModel private lateinit var configViewModel: ConfigViewModel private var inspectionAddress = "" private var inspectionId = "" private var mainDicModels: MutableList = ArrayList() - private var isShowing = false + private var isDetectTarget = false private var detectedScene = "" override fun initOnCreate(savedInstanceState: Bundle?) { window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + //加载算法模型 + yolov8ncnn.loadModel( + assets, 2, useGpu = false, + useClassify = false, useSegmentation = false, useDetect = true + ) + binding.surfaceView.holder.setFormat(PixelFormat.RGBA_8888) binding.surfaceView.holder.addCallback(this) @@ -162,6 +168,11 @@ } override fun onRightClick() { + if (isDetectTarget) { + "目标检测中,不可修改场景".show(context) + return + } + BottomActionSheet.Builder() .setContext(context) .setActionItemTitle(arrayListOf("手动选择场景", "重置已选场景")) @@ -177,6 +188,7 @@ 1 -> { binding.titleView.setTitle("") detectedScene = "" + isDetectTarget = false "场景重置成功".show(context) } } @@ -194,6 +206,7 @@ val sceneName = data.getStringExtra("sceneName").toString() binding.titleView.setTitle(sceneName) detectedScene = sceneName + isDetectTarget = true } }) @@ -210,59 +223,7 @@ } override fun onClassify(possibles: FloatArray) { - if (isShowing) { - return - } - //找出最大值的下标 - var max = possibles[0] - var maxIndex = 0 - possibles.forEachIndexed { index, fl -> - if (fl > max) { - max = fl - maxIndex = index - } - } - Log.d(kTag, "maxIndex: $maxIndex") - - try { - lifecycleScope.launch(Dispatchers.Main) { - isShowing = true - if (maxIndex == 2) { - //非居 - AlertControlDialog.Builder() - .setContext(context) - .setTitle("提示") - .setMessage("识别到${classArray[maxIndex]}场景,是否开始排查该场景的隐患?") - .setNegativeButton("稍后") - .setPositiveButton("好的").setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - //需要同时调用分割和检测模型 - yolov8ncnn.loadMultiModel(assets, intArrayOf(0, 2), false) - } - - override fun onCancelClick() { - isShowing = false - } - }).build().show() - } else { - if (yolov8ncnn.getYoloCurrentState() != YoloStateConst.DETECT) { - //调用检测模型 - yolov8ncnn.loadModel( - assets, - 2, - useGpu = false, - useClassify = false, - useSegmentation = false, - useDetect = true - ) - } - } - } - } catch (e: ArrayIndexOutOfBoundsException) { - e.printStackTrace() - } } override fun onSegmentation( @@ -287,59 +248,69 @@ output.forEach { val yolo = it.convert2YoloResult() results.add(yolo) - - //需要根据检测结果反推属于什么场景 - val label = LocaleConstant.CLASS_NAMES_ARRAY[yolo.type] - - targetSet.add(label) - detectedScene = label.getSceneByTarget() - detectedSceneSet.add(detectedScene) - lifecycleScope.launch(Dispatchers.Main) { - binding.titleView.setTitle(detectedScene) - //显示角标 - binding.tipsTagView.visibility = View.VISIBLE - binding.tipsTagView.text = "${targetSet.size}" - - binding.listTagView.visibility = View.VISIBLE - binding.listTagView.text = "${detectedSceneSet.size}" - - //显示弹框 -// if (!detectResultDialog.isShowing) { -// detectResultDialog.updateDialogMessage(label) -// detectResultDialog.show() -// } - } } - binding.detectView.updateTargetPosition(results) -// if (mat.width() > 0 && mat.height() > 0) { -// val bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888) -// Utils.matToBitmap(mat, bitmap, true) -// bitmap.saveImage("${createImageFileDir()}/${System.currentTimeMillis()}.png") -// } else { -// Log.d(kTag, "width: ${mat.width()}, height: ${mat.height()}") -// } + + if (results.isEmpty()) { + return + } + + if (isDetectTarget) { + binding.detectView.updateTargetPosition(results) + results.forEach { + val label = LocaleConstant.CLASS_NAMES_ARRAY[it.type] + targetSet.add(label) + } + //显示角标 + weakReferenceHandler.sendEmptyMessage(2024082902) + } else { + //暂停算法 + yolov8ncnn.onPause() + + val firstYoloResult = results.first() + //取结果的第一个为场景判断 + val label = LocaleConstant.CLASS_NAMES_ARRAY[firstYoloResult.type] + val scene = label.getSceneByTarget() + + val message = weakReferenceHandler.obtainMessage() + message.what = 2024082901 + message.obj = scene + weakReferenceHandler.sendMessage(message) + } } - private fun FloatArray.convert2YoloResult(): YoloResult { - /** - * 前四位是目标Rect,第五位是目标名对应的角标,第六位是可信度 - * - * [135.88397,120.17752,68.061325,204.02115,28.0,43.642334] - * */ - val yolo = YoloResult() + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2024082901) { + val scene = msg.obj as String + AlertControlDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("识别到${scene}场景,是否开始检查?") + .setNegativeButton("重新识别") + .setPositiveButton("开始检查") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + detectedScene = scene + detectedSceneSet.add(scene) + binding.titleView.setTitle(scene) + //显示场景清单 + binding.listTagView.visibility = View.VISIBLE + binding.listTagView.text = "${detectedSceneSet.size}" - val array = FloatArray(4) - array[0] = this[0] - array[1] = this[1] - array[2] = this[2] - array[3] = this[3] - yolo.position = array + //继续调用检测模型检测无标物品 + yolov8ncnn.onRestart() + isDetectTarget = true + } - yolo.type = this[4].toInt() - - //保留两位有效小数 - yolo.prob = "${String.format("%.2f", this[5])}%" - return yolo + override fun onCancelClick() { + yolov8ncnn.onRestart() + } + }).build().show() + } else if (msg.what == 2024082902) { + binding.tipsTagView.visibility = View.VISIBLE + binding.tipsTagView.text = "${targetSet.size}" + } + return true } override fun surfaceCreated(holder: SurfaceHolder) {} @@ -348,16 +319,6 @@ override fun onResume() { super.onResume() - //加载算法模型 - yolov8ncnn.loadModel( - assets, - 1, - useGpu = false, - useClassify = true, - useSegmentation = false, - useDetect = false - ) - yolov8ncnn.openCamera(1) } diff --git a/app/src/main/cpp/yolo.cpp b/app/src/main/cpp/yolo.cpp index 0c01c4e..b72a381 100644 --- a/app/src/main/cpp/yolo.cpp +++ b/app/src/main/cpp/yolo.cpp @@ -447,7 +447,7 @@ } int Yolo::classify(const cv::Mat &rgb) { - if (j_state == 0) { + if (j_state == 1) { static const float scale_values[3] = {0.017f, 0.017f, 0.017f}; int width = rgb.cols; @@ -490,7 +490,7 @@ int Yolo::segmentation(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 1) { + if (j_state == 2) { int width = rgb.cols; int height = rgb.rows; @@ -700,7 +700,7 @@ int Yolo::detect(const cv::Mat &rgb, std::vector &objects, float prob_threshold, float nms_threshold) { - if (j_state == 2) { + if (j_state == 3) { int width = rgb.cols; int height = rgb.rows; @@ -830,6 +830,10 @@ auto *res = (cv::Mat *) j_mat_addr; res->create(rgb.rows, rgb.cols, rgb.type()); memcpy(res->data, rgb.data, rgb.rows * rgb.step); + } else { + __android_log_print( + ANDROID_LOG_DEBUG, "ncnn", "yolo_d detect is paused, state = %d", j_state + ); } return 0; } diff --git a/app/src/main/cpp/yolo.h b/app/src/main/cpp/yolo.h index b047291..1cbd0e5 100644 --- a/app/src/main/cpp/yolo.h +++ b/app/src/main/cpp/yolo.h @@ -39,10 +39,11 @@ /** * Yolo当前状态 *
---------------
- * 0 - 分类
- * 1 - 分割
- * 2 - 检测
- * 3 - 绘制
+ * 0 - 暂停
+ * 1 - 分类
+ * 2 - 分割
+ * 3 - 检测
+ * 4 - 绘制
* */ int j_state = 0; diff --git a/app/src/main/cpp/yolov8ncnn.cpp b/app/src/main/cpp/yolov8ncnn.cpp index 38cdadc..61df411 100644 --- a/app/src/main/cpp/yolov8ncnn.cpp +++ b/app/src/main/cpp/yolov8ncnn.cpp @@ -207,14 +207,14 @@ g_yolo = new Yolo; int state; if (use_classify) { - state = 0; - } - if (use_segmentation) { state = 1; } - if (use_detect) { + if (use_segmentation) { state = 2; } + if (use_detect) { + state = 3; + } g_yolo->j_state = state; g_yolo->load( mgr, @@ -256,7 +256,7 @@ } else { if (!g_yolo) g_yolo = new Yolo; - g_yolo->j_state = 1; + g_yolo->j_state = 2; if (*id == 0) { g_yolo->load( mgr, @@ -328,4 +328,16 @@ Java_com_casic_br_app_external_Yolov8ncnn_getYoloCurrentState(JNIEnv *env, jobject thiz) { return g_yolo->j_state; } + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onPause(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 0; + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_com_casic_br_app_external_Yolov8ncnn_onRestart(JNIEnv *env, jobject thiz) { + g_yolo->j_state = 3; + return JNI_TRUE; +} } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt new file mode 100644 index 0000000..8d414f7 --- /dev/null +++ b/app/src/main/java/com/casic/br/app/extensions/FloatArray.kt @@ -0,0 +1,25 @@ +package com.casic.br.app.extensions + +import com.casic.br.app.external.YoloResult + +fun FloatArray.convert2YoloResult(): YoloResult { + /** + * 前四位是目标Rect,第五位是目标名对应的角标,第六位是可信度 + * + * [135.88397,120.17752,68.061325,204.02115,28.0,43.642334] + * */ + val yolo = YoloResult() + + val array = FloatArray(4) + array[0] = this[0] + array[1] = this[1] + array[2] = this[2] + array[3] = this[3] + yolo.position = array + + yolo.type = this[4].toInt() + + //保留两位有效小数 + yolo.prob = "${String.format("%.2f", this[5])}%" + return yolo +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt b/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt index ba7bca8..9e1b265 100644 --- a/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt +++ b/app/src/main/java/com/casic/br/app/external/Yolov8ncnn.kt @@ -43,4 +43,8 @@ ): Boolean external fun getYoloCurrentState(): Int + + external fun onPause(): Boolean + + external fun onRestart(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt index d3c9d85..dddf2cc 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckByYoloActivity.kt @@ -4,22 +4,22 @@ import android.content.Intent import android.graphics.PixelFormat import android.os.Bundle -import android.util.Log +import android.os.Handler +import android.os.Message import android.view.SurfaceHolder import android.view.View import android.view.WindowManager import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.amap.api.location.AMapLocation import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckByYoloBinding +import com.casic.br.app.extensions.convert2YoloResult import com.casic.br.app.extensions.getSceneByTarget import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.external.INativeCallback import com.casic.br.app.external.YoloResult -import com.casic.br.app.external.YoloStateConst import com.casic.br.app.external.Yolov8ncnn import com.casic.br.app.model.DictionaryModel import com.casic.br.app.utils.LocaleConstant @@ -36,15 +36,14 @@ import com.pengxh.kt.lite.extensions.toJson import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertControlDialog import com.pengxh.kt.lite.widget.dialog.BottomActionSheet -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import org.opencv.core.Mat class StartCheckByYoloActivity : KotlinBaseActivity(), - SurfaceHolder.Callback, INativeCallback { + SurfaceHolder.Callback, INativeCallback, Handler.Callback { private val kTag = "StartCheckActivity" private val context = this @@ -58,18 +57,25 @@ private val detectedSceneSet by lazy { HashSet() } private val yolov8ncnn by lazy { Yolov8ncnn() } private val mat by lazy { Mat() } + private val weakReferenceHandler by lazy { WeakReferenceHandler(this) } private val detectResultDialog by lazy { DetectResultDialog(this) } private lateinit var inspectionViewModel: InspectionViewModel private lateinit var configViewModel: ConfigViewModel private var inspectionAddress = "" private var inspectionId = "" private var mainDicModels: MutableList = ArrayList() - private var isShowing = false + private var isDetectTarget = false private var detectedScene = "" override fun initOnCreate(savedInstanceState: Bundle?) { window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + //加载算法模型 + yolov8ncnn.loadModel( + assets, 2, useGpu = false, + useClassify = false, useSegmentation = false, useDetect = true + ) + binding.surfaceView.holder.setFormat(PixelFormat.RGBA_8888) binding.surfaceView.holder.addCallback(this) @@ -162,6 +168,11 @@ } override fun onRightClick() { + if (isDetectTarget) { + "目标检测中,不可修改场景".show(context) + return + } + BottomActionSheet.Builder() .setContext(context) .setActionItemTitle(arrayListOf("手动选择场景", "重置已选场景")) @@ -177,6 +188,7 @@ 1 -> { binding.titleView.setTitle("") detectedScene = "" + isDetectTarget = false "场景重置成功".show(context) } } @@ -194,6 +206,7 @@ val sceneName = data.getStringExtra("sceneName").toString() binding.titleView.setTitle(sceneName) detectedScene = sceneName + isDetectTarget = true } }) @@ -210,59 +223,7 @@ } override fun onClassify(possibles: FloatArray) { - if (isShowing) { - return - } - //找出最大值的下标 - var max = possibles[0] - var maxIndex = 0 - possibles.forEachIndexed { index, fl -> - if (fl > max) { - max = fl - maxIndex = index - } - } - Log.d(kTag, "maxIndex: $maxIndex") - - try { - lifecycleScope.launch(Dispatchers.Main) { - isShowing = true - if (maxIndex == 2) { - //非居 - AlertControlDialog.Builder() - .setContext(context) - .setTitle("提示") - .setMessage("识别到${classArray[maxIndex]}场景,是否开始排查该场景的隐患?") - .setNegativeButton("稍后") - .setPositiveButton("好的").setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - //需要同时调用分割和检测模型 - yolov8ncnn.loadMultiModel(assets, intArrayOf(0, 2), false) - } - - override fun onCancelClick() { - isShowing = false - } - }).build().show() - } else { - if (yolov8ncnn.getYoloCurrentState() != YoloStateConst.DETECT) { - //调用检测模型 - yolov8ncnn.loadModel( - assets, - 2, - useGpu = false, - useClassify = false, - useSegmentation = false, - useDetect = true - ) - } - } - } - } catch (e: ArrayIndexOutOfBoundsException) { - e.printStackTrace() - } } override fun onSegmentation( @@ -287,59 +248,69 @@ output.forEach { val yolo = it.convert2YoloResult() results.add(yolo) - - //需要根据检测结果反推属于什么场景 - val label = LocaleConstant.CLASS_NAMES_ARRAY[yolo.type] - - targetSet.add(label) - detectedScene = label.getSceneByTarget() - detectedSceneSet.add(detectedScene) - lifecycleScope.launch(Dispatchers.Main) { - binding.titleView.setTitle(detectedScene) - //显示角标 - binding.tipsTagView.visibility = View.VISIBLE - binding.tipsTagView.text = "${targetSet.size}" - - binding.listTagView.visibility = View.VISIBLE - binding.listTagView.text = "${detectedSceneSet.size}" - - //显示弹框 -// if (!detectResultDialog.isShowing) { -// detectResultDialog.updateDialogMessage(label) -// detectResultDialog.show() -// } - } } - binding.detectView.updateTargetPosition(results) -// if (mat.width() > 0 && mat.height() > 0) { -// val bitmap = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888) -// Utils.matToBitmap(mat, bitmap, true) -// bitmap.saveImage("${createImageFileDir()}/${System.currentTimeMillis()}.png") -// } else { -// Log.d(kTag, "width: ${mat.width()}, height: ${mat.height()}") -// } + + if (results.isEmpty()) { + return + } + + if (isDetectTarget) { + binding.detectView.updateTargetPosition(results) + results.forEach { + val label = LocaleConstant.CLASS_NAMES_ARRAY[it.type] + targetSet.add(label) + } + //显示角标 + weakReferenceHandler.sendEmptyMessage(2024082902) + } else { + //暂停算法 + yolov8ncnn.onPause() + + val firstYoloResult = results.first() + //取结果的第一个为场景判断 + val label = LocaleConstant.CLASS_NAMES_ARRAY[firstYoloResult.type] + val scene = label.getSceneByTarget() + + val message = weakReferenceHandler.obtainMessage() + message.what = 2024082901 + message.obj = scene + weakReferenceHandler.sendMessage(message) + } } - private fun FloatArray.convert2YoloResult(): YoloResult { - /** - * 前四位是目标Rect,第五位是目标名对应的角标,第六位是可信度 - * - * [135.88397,120.17752,68.061325,204.02115,28.0,43.642334] - * */ - val yolo = YoloResult() + override fun handleMessage(msg: Message): Boolean { + if (msg.what == 2024082901) { + val scene = msg.obj as String + AlertControlDialog.Builder() + .setContext(this) + .setTitle("温馨提示") + .setMessage("识别到${scene}场景,是否开始检查?") + .setNegativeButton("重新识别") + .setPositiveButton("开始检查") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + detectedScene = scene + detectedSceneSet.add(scene) + binding.titleView.setTitle(scene) + //显示场景清单 + binding.listTagView.visibility = View.VISIBLE + binding.listTagView.text = "${detectedSceneSet.size}" - val array = FloatArray(4) - array[0] = this[0] - array[1] = this[1] - array[2] = this[2] - array[3] = this[3] - yolo.position = array + //继续调用检测模型检测无标物品 + yolov8ncnn.onRestart() + isDetectTarget = true + } - yolo.type = this[4].toInt() - - //保留两位有效小数 - yolo.prob = "${String.format("%.2f", this[5])}%" - return yolo + override fun onCancelClick() { + yolov8ncnn.onRestart() + } + }).build().show() + } else if (msg.what == 2024082902) { + binding.tipsTagView.visibility = View.VISIBLE + binding.tipsTagView.text = "${targetSet.size}" + } + return true } override fun surfaceCreated(holder: SurfaceHolder) {} @@ -348,16 +319,6 @@ override fun onResume() { super.onResume() - //加载算法模型 - yolov8ncnn.loadModel( - assets, - 1, - useGpu = false, - useClassify = true, - useSegmentation = false, - useDetect = false - ) - yolov8ncnn.openCamera(1) } diff --git a/app/src/main/java/com/casic/br/app/widgets/DetectResultDialog.kt b/app/src/main/java/com/casic/br/app/widgets/DetectResultDialog.kt index ff2c3f6..4715033 100644 --- a/app/src/main/java/com/casic/br/app/widgets/DetectResultDialog.kt +++ b/app/src/main/java/com/casic/br/app/widgets/DetectResultDialog.kt @@ -15,7 +15,10 @@ super.onCreate(savedInstanceState) initDialogLayoutParams(0.8f) - binding.confirmButton.setOnClickListener { } + binding.confirmButton.setOnClickListener { + //TODO 上传隐患 + dismiss() + } binding.cancelButton.setOnClickListener { dismiss() } }