Commit 2b780db7 authored by 姜天宇's avatar 姜天宇

feat(v1.0.2): 集成标框、菜品识别、餐盘识别算法

parent f33082d6
package com.wmdigit.common.view.spinner;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ArrayAdapter;
import android.widget.ListPopupWindow;
import android.widget.PopupWindow;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.elvishew.xlog.XLog;
import com.wmdigit.common.R;
import java.lang.reflect.Field;
import java.util.List;
/**
* 自定义Spinner
* @author dizi
*/
public class MySpinner extends ConstraintLayout {
private Spinner spinner;
public MySpinner(@NonNull Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.layout_dropdown_spinner, this, true);
initView();
}
public MySpinner(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.layout_dropdown_spinner, this, true);
initView();
}
public MySpinner(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater.from(context).inflate(R.layout.layout_dropdown_spinner, this, true);
initView();
}
public MySpinner(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(R.layout.layout_dropdown_spinner, this, true);
initView();
}
private void initView() {
spinner = findViewById(R.id.spinner);
try {
Field listPopupField = Spinner.class.getDeclaredField("mPopup");
listPopupField.setAccessible(true);
Object listPopup = listPopupField.get(spinner);
if (listPopup instanceof ListPopupWindow) {
Field popupField = ListPopupWindow.class.getDeclaredField("mPopup");
popupField.setAccessible(true);
Object popup = popupField.get((ListPopupWindow) listPopup);
if (popup instanceof PopupWindow) {
((PopupWindow) popup).setFocusable(false);
}
}
}
catch (Exception e){
XLog.e(e.toString());
}
}
public void setSpinnerEntries(List<String> value){
spinner.setAdapter(new ArrayAdapter(getContext(), R.layout.spinner_item, value));
}
public void setSpinnerEntriesFromResource(int resId){
spinner.setAdapter(ArrayAdapter.createFromResource(getContext(), resId, R.layout.spinner_item));
}
// public static void
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/spinner"
style="@style/spinner_base.w492"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:src="@drawable/ic_drop_down"
android:layout_marginEnd="@dimen/dp_10"
app:layout_constraintTop_toTopOf="@+id/spinner"
app:layout_constraintBottom_toBottomOf="@+id/spinner"
app:layout_constraintEnd_toEndOf="@+id/spinner"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<TextView
style="@style/edittext_base"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" />
\ No newline at end of file
...@@ -377,4 +377,17 @@ ...@@ -377,4 +377,17 @@
<item name="android:layout_height">@dimen/dp_3</item> <item name="android:layout_height">@dimen/dp_3</item>
<item name="android:background">@color/gray_676767</item> <item name="android:background">@color/gray_676767</item>
</style> </style>
<!--下拉框-->
<style name="spinner_base">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:spinnerMode">dropdown</item>
<item name="android:background">@drawable/rect_4_gray</item>
<item name="android:textSize">@dimen/sp_26</item>
</style>
<style name="spinner_base.w492">
<item name="android:layout_width">@dimen/dp_492</item>
</style>
</resources> </resources>
\ No newline at end of file
...@@ -31,14 +31,22 @@ set_target_properties( ...@@ -31,14 +31,22 @@ set_target_properties(
) )
# 分类、特征提取库 # 分类、特征提取库
#add_library(clsretri SHARED IMPORTED) add_library(clsretri SHARED IMPORTED)
#set_target_properties( set_target_properties(
# clsretri clsretri
# PROPERTIES IMPORTED_LOCATION PROPERTIES IMPORTED_LOCATION
# ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libclsretri.a ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libclsretri.a
#) )
# 检测库 # 餐盘分类、特征提取库
add_library(clsretri_plate SHARED IMPORTED)
set_target_properties(
clsretri_plate
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libclsretri_plate_color.a
)
# 目标检测库
add_library(det SHARED IMPORTED) add_library(det SHARED IMPORTED)
set_target_properties( set_target_properties(
det det
...@@ -47,12 +55,20 @@ set_target_properties( ...@@ -47,12 +55,20 @@ set_target_properties(
) )
# 特征识别库 # 特征识别库
#add_library(detfea SHARED IMPORTED) add_library(detfea SHARED IMPORTED)
#set_target_properties( set_target_properties(
# detfea detfea
# PROPERTIES IMPORTED_LOCATION PROPERTIES IMPORTED_LOCATION
# ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libdetfea.a ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libdetfea.a
#) )
# 餐盘特征识别库
add_library(detfea_color SHARED IMPORTED)
set_target_properties(
detfea_color
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libdetfea_color.a
)
#视频流 #视频流
add_library(videopipe STATIC IMPORTED) add_library(videopipe STATIC IMPORTED)
...@@ -135,7 +151,7 @@ target_link_libraries( ...@@ -135,7 +151,7 @@ target_link_libraries(
image_tools image_tools
${log-lib}) ${log-lib})
# 餐饮目标检测 # 餐饮菜品识别
add_library( add_library(
catering_detection catering_detection
SHARED SHARED
...@@ -148,8 +164,30 @@ target_link_libraries( ...@@ -148,8 +164,30 @@ target_link_libraries(
android android
jnigraphics jnigraphics
det det
# clsretri clsretri
# detfea detfea
c++_shared
wmai
opencv
image_tools
${log-lib}
)
# 餐饮餐盘识别
add_library(
catering_plate_detection
SHARED
catering_plate_detection.cpp
)
target_link_libraries(
catering_plate_detection
android
jnigraphics
det
clsretri_plate
detfea_color
c++_shared c++_shared
wmai wmai
opencv opencv
......
//
// Created by dizi on 2024/7/11.
//
#include "include/catering_detection.h" #include "include/catering_detection.h"
void* handle; void* handle;
...@@ -13,7 +9,7 @@ extern "C" ...@@ -13,7 +9,7 @@ extern "C"
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_com_wmdigit_core_catering_TargetDetectionManager_init(JNIEnv *env, jobject thiz) { Java_com_wmdigit_core_catering_TargetDetectionManager_init(JNIEnv *env, jobject thiz) {
LOGD("初始化DET"); LOGD("初始化DET");
return DET_Init(nullptr, DET_CPU, &handle); return DETFEA_Init(nullptr, nullptr, DETFEA_CPU, &handle);
} }
/** /**
...@@ -22,8 +18,8 @@ Java_com_wmdigit_core_catering_TargetDetectionManager_init(JNIEnv *env, jobject ...@@ -22,8 +18,8 @@ Java_com_wmdigit_core_catering_TargetDetectionManager_init(JNIEnv *env, jobject
extern "C" extern "C"
JNIEXPORT jobject JNICALL JNIEXPORT jobject JNICALL
Java_com_wmdigit_core_catering_TargetDetectionManager_process(JNIEnv *env, jobject thiz, jobject bitmap) { Java_com_wmdigit_core_catering_TargetDetectionManager_process(JNIEnv *env, jobject thiz, jobject bitmap) {
DET_INPUT input; DETFEA_INPUT input;
DET_OUTPUT output; DETFEA_OUTPUT output;
// bitmap转mat // bitmap转mat
cv::Mat mat = convert_bitmap_to_mat(env, bitmap); cv::Mat mat = convert_bitmap_to_mat(env, bitmap);
cv::Mat mat_bgr; cv::Mat mat_bgr;
...@@ -31,7 +27,7 @@ Java_com_wmdigit_core_catering_TargetDetectionManager_process(JNIEnv *env, jobje ...@@ -31,7 +27,7 @@ Java_com_wmdigit_core_catering_TargetDetectionManager_process(JNIEnv *env, jobje
input.img = mat_bgr; input.img = mat_bgr;
LOGD("准备推理"); LOGD("准备推理");
// 推理 // 推理
int ret = DET_Process(input, &output, handle); int ret = DETFEA_Process(input, &output, handle);
LOGD("推理结果:%d", ret); LOGD("推理结果:%d", ret);
std::string labels; std::string labels;
if (ret == 0){ if (ret == 0){
...@@ -54,6 +50,10 @@ Java_com_wmdigit_core_catering_TargetDetectionManager_process(JNIEnv *env, jobje ...@@ -54,6 +50,10 @@ Java_com_wmdigit_core_catering_TargetDetectionManager_process(JNIEnv *env, jobje
output.output_list[i].y2, output.output_list[i].y2,
output.output_list[i].prob, output.output_list[i].prob,
output.output_list[i].label); output.output_list[i].label);
for (int j = 0; j < 160; ++j) {
LOGD("%f, ", output.output_list[i].feat[j]);
}
} }
} }
// 将Mat转Bitmap // 将Mat转Bitmap
......
#include "include/catering_plate_detection.h"
void* handle;
extern "C"
JNIEXPORT jint JNICALL
Java_com_wmdigit_core_catering_PlateDetectionManager_init(JNIEnv *env, jobject thiz) {
LOGD("初始化餐盘识别模型");
return DETFEA_COLOR_Init(nullptr, nullptr, DETFEA_COLOR_CPU, &handle);
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_wmdigit_core_catering_PlateDetectionManager_process(JNIEnv *env, jobject thiz,
jobject bitmap) {
DETFEA_COLOR_INPUT input;
DETFEA_COLOR_OUTPUT output;
// bitmap转mat
cv::Mat mat = convert_bitmap_to_mat(env, bitmap);
cv::Mat mat_bgr;
cv::cvtColor(mat, mat_bgr, CV_RGBA2BGR);
input.img = mat_bgr;
LOGD("准备推理");
// 推理
int ret = DETFEA_COLOR_Process(input, &output, handle);
LOGD("推理结果:%d", ret);
std::string labels;
if (ret == 0){
//132.546875, 20.646881, 258.856262, 140.718750, 0.957893, 0
//230.787506, 164.109375, 368.012512, 296.656250, 0.952677, 0
//300.959381, 59.631256, 413.234375, 160.990631, 0.946472, 0
for (size_t i = 0; i < output.output_list.size(); ++i) {
if (output.output_list[i].prob >= 0.55){
mat_bgr = draw_rect_on_mat(mat_bgr,
(int)output.output_list[i].x1,
(int)output.output_list[i].y1,
(int)output.output_list[i].x2,
(int)output.output_list[i].y2);
labels += std::to_string(output.output_list[i].label) + ",";
}
LOGD("%f, %f, %f, %f, %f, %d",
output.output_list[i].x1,
output.output_list[i].y1,
output.output_list[i].x2,
output.output_list[i].y2,
output.output_list[i].prob,
output.output_list[i].label);
for (int j = 0; j < 160; ++j) {
LOGD("%f, ", output.output_list[i].feat[j]);
}
}
}
// 将Mat转Bitmap
cv::Mat mat_rgb;
cv::cvtColor(mat_bgr, mat_rgb, CV_BGR2RGB);
bitmap = convert_mat_to_bitmap(env, mat_rgb);
mat.release();
mat_bgr.release();
// 找到实体类
jclass targetDetectResultClass = env->FindClass("com/wmdigit/core/catering/model/TargetDetectResult");
// 获取构造函数ID
jmethodID constructor = env->GetMethodID(targetDetectResultClass, "<init>", "(Landroid/graphics/Bitmap;Ljava/lang/String;)V");
// 创建实体类
jobject result = env->NewObject(targetDetectResultClass, constructor, bitmap, env->NewStringUTF(labels.c_str()));
return result;
}
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef CATERINGDETECT_CATERING_DETECTION_H #ifndef CATERINGDETECT_CATERING_DETECTION_H
#define CATERINGDETECT_CATERING_DETECTION_H #define CATERINGDETECT_CATERING_DETECTION_H
#include <jni.h> #include <jni.h>
#include "libdet.h" #include "libdetfea.h"
#include "image_tools.h" #include "image_tools.h"
//#include <OpenCL/opencl.h> //#include <OpenCL/opencl.h>
......
//
// Created by dizi on 2024/9/3.
//
#ifndef CATERINGDETECT_CATERING_PLATE_DETECTION_H
#define CATERINGDETECT_CATERING_PLATE_DETECTION_H
#include <jni.h>
#include "libdetfea_color.h"
#include "image_tools.h"
#endif //CATERINGDETECT_CATERING_PLATE_DETECTION_H
#pragma once
#ifndef _DETFEA_LIB_H_
#define _DETFEA_LIB_H_
#include <vector>
#include "opencv2/opencv.hpp"
#define DETFEA_CLS_TOP_N 10
#define DETFEA_FEAT_DIM 160
#define DETFEA_ALL_OK 0x00000000 //
#define DETFEA_HANDLE_NULL 0x10050001 // 输入句柄为空
#define DETFEA_INPUT_IMAGE_EMPTY 0x10050002 // 输入图像为空
#define DETFEA_OUTPUT_NULL 0x10050003 // 输入的输出结构体为空
typedef struct _DETFEA_INPUT_
{
cv::Mat img;
}DETFEA_INPUT;
typedef struct _DETFEA_SINGLE_OUTPUT_
{
float x1;
float y1;
float x2;
float y2;
float prob;
int id;
int label;
float feat[DETFEA_FEAT_DIM];
}DETFEA_SINGLE_OUTPUT;
typedef struct _DETFEA_OUTPUT_
{
std::vector < DETFEA_SINGLE_OUTPUT> output_list;
}DETFEA_OUTPUT;
// 定义算法的识别设备
typedef enum _DETFEA_DEVICE_
{
DETFEA_CPU = 0x0000, // CPU
DETFEA_GPU = 0x0001, // GPU
}DETFEA_DEVICE;
/***************************************************************************************************
* 功 能: 初始化
* 参 数:
* const char* model_path - I 模型路径(这个可以设为NULL,表示用内置的模型)
* DETFEA_DEVICE device_name - I 设备类型
* void** detfea_handle - O 句柄
* 返回值: 错误码
***************************************************************************************************/
int DETFEA_Init(const char* model_path1,
const char* model_path2,
DETFEA_DEVICE device_type,
void** handle);
/***************************************************************************************************
* 功 能: 识别
* 参 数:
* DETFEA_INPUT in_img - I 输入图片
* DETFEA_OUTPUT* detfea_output - O 返回识别结果
* void* handle - I 句柄
* 返回值: 错误码
***************************************************************************************************/
int DETFEA_Process(DETFEA_INPUT in_img, DETFEA_OUTPUT* detfea_output, void* handle);
/***************************************************************************************************
* 功 能: 释放句柄
* 参 数:
* void** handle - I 句柄
* 返回值: 错误码
***************************************************************************************************/
int DETFEA_Release(void** handle);
#endif
\ No newline at end of file
#pragma once #pragma once
#ifndef _DET_LIB_H_ #ifndef _DETFEA_COLOR_LIB_H_
#define _DET_LIB_H_ #define _DETFEA_COLOR_LIB_H_
#include <vector> #include <vector>
#include "opencv2/opencv.hpp" #include "opencv2/opencv.hpp"
#define DETFEA_COLOR_CLS_TOP_N 10
#define DETFEA_COLOR_FEAT_DIM 160
#define DETFEA_COLOR_ALL_OK 0x00000000 //
#define DETFEA_COLOR_HANDLE_NULL 0x10070001 // 输入句柄为空
#define DETFEA_COLOR_INPUT_IMAGE_EMPTY 0x10070002 // 输入图像为空
#define DETFEA_COLOR_OUTPUT_NULL 0x10070003 // 输入的输出结构体为空
#define DET_MAX_OBJ_NUM 15
#define DET_ALL_OK 0x00000000 // typedef struct _DETFEA_COLOR_INPUT_
#define DET_OUTPUT_SHAPE_ERROR 0x10040001 // 输出的维度有错误
#define DET_INPUT_IMAGE_EMPTY 0x10040002 // 输入的图像为空
#define DET_HANDLE_NULL 0x10040003 // 输入的句柄为空
#define DET_OUTPUT_NULL 0x10040004 // 输入的返回结构体为空
#define DET_SESSION_NULL 0x10040005 //
#define DET_INIT_MODEL_PATH_NOT_EXIST 0x10040006 // 输入的模型路径不存在
#define DET_CREATE_NET_FAILED 0x10040007 // 创建的模型失败
#define DET_GET_NET_INPUT_FAILED 0x10040008 // 获取输入tensor失败
#define DET_GET_NET_OUTPUT_13_FAILED 0x10040009 // 获取输出tensor失败
#define DET_GET_NET_OUTPUT_26_FAILED 0x1004000A // 获取输出tensor失败
#define DET_GET_NET_OUTPUT_52_FAILED 0x1004000B // 获取输出tensor失败
#define DET_OUTPUT_13_SHAPE_ERROR 0x1004000C // 获取输出tensor的shape与设置的不一致
#define DET_OUTPUT_26_SHAPE_ERROR 0x1004000D // 获取输出tensor的shape与设置的不一致
#define DET_OUTPUT_52_SHAPE_ERROR 0x10040010 // 获取输出tensor的shape与设置的不一致
#define DET_GET_NET_SESSION_FAILED 0x10040011 // 获取输出session失败
#define DET_FREE_SESSION_FAILED 0x10040012 // 释放session失败
#define DET_INPUT_SHAPE_ERROR 0x10040013 // 获取输入tensor的shape与设置的不一致
typedef struct _DET_INPUT_
{ {
cv::Mat img; cv::Mat img;
bool dump_debug_crop_image=false; // 是否打开dump debug图
}DET_INPUT; unsigned long int pts=0; // 输入时间戳,用于dump图时命名不同的输入图片
}DETFEA_COLOR_INPUT;
typedef struct _DET_SINGLE_OUTPUT_ typedef struct _DETFEA_COLOR_SINGLE_OUTPUT_
{ {
float x1; float x1;
float y1; float y1;
...@@ -46,20 +32,21 @@ typedef struct _DET_SINGLE_OUTPUT_ ...@@ -46,20 +32,21 @@ typedef struct _DET_SINGLE_OUTPUT_
float prob; float prob;
int id; int id;
int label; int label;
}DET_SINGLE_OUTPUT; float feat[DETFEA_COLOR_FEAT_DIM];
}DETFEA_COLOR_SINGLE_OUTPUT;
typedef struct _DET_OUTPUT_ typedef struct _DETFEA_COLOR_OUTPUT_
{ {
std::vector < DET_SINGLE_OUTPUT> output_list; std::vector < DETFEA_COLOR_SINGLE_OUTPUT> output_list;
}DET_OUTPUT; }DETFEA_COLOR_OUTPUT;
// 定义算法的识别设备 // 定义算法的识别设备
typedef enum _DET_DEVICE_ typedef enum _DETFEA_COLOR_DEVICE_
{ {
DET_CPU = 0x0000, // CPU DETFEA_COLOR_CPU = 0x0000, // CPU
DET_GPU = 0x0001, // GPU DETFEA_COLOR_GPU = 0x0001, // GPU
}DET_DEVICE; }DETFEA_COLOR_DEVICE;
...@@ -67,24 +54,25 @@ typedef enum _DET_DEVICE_ ...@@ -67,24 +54,25 @@ typedef enum _DET_DEVICE_
* 功 能: 初始化 * 功 能: 初始化
* 参 数: * 参 数:
* const char* model_path - I 模型路径(这个可以设为NULL,表示用内置的模型) * const char* model_path - I 模型路径(这个可以设为NULL,表示用内置的模型)
* DET_DEVICE device_name - I 设备类型 * DETFEA_COLOR_DEVICE device_name - I 设备类型
* void** clsretri_handle - O 句柄 * void** detfea_handle - O 句柄
* 返回值: 错误码 * 返回值: 错误码
***************************************************************************************************/ ***************************************************************************************************/
int DET_Init(const char* model_path, int DETFEA_COLOR_Init(const char* model_path1,
DET_DEVICE device_type, const char* model_path2,
void** clsretri_handle); DETFEA_COLOR_DEVICE device_type,
void** handle);
/*************************************************************************************************** /***************************************************************************************************
* 功 能: 识别 * 功 能: 识别
* 参 数: * 参 数:
* DET_INPUT in_img - I 输入图片 * DETFEA_COLOR_INPUT in_img - I 输入图片
* DET_OUTPUT* clsretri_output - O 返回识别结果 * DETFEA_COLOR_OUTPUT* detfea_output - O 返回识别结果
* void* handle - I 句柄 * void* handle - I 句柄
* 返回值: 错误码 * 返回值: 错误码
***************************************************************************************************/ ***************************************************************************************************/
int DET_Process(DET_INPUT in_img, DET_OUTPUT* clsretri_output, void* handle); int DETFEA_COLOR_Process(DETFEA_COLOR_INPUT in_img, DETFEA_COLOR_OUTPUT* detfea_output, void* handle);
/*************************************************************************************************** /***************************************************************************************************
...@@ -93,7 +81,7 @@ int DET_Process(DET_INPUT in_img, DET_OUTPUT* clsretri_output, void* handle); ...@@ -93,7 +81,7 @@ int DET_Process(DET_INPUT in_img, DET_OUTPUT* clsretri_output, void* handle);
* void** handle - I 句柄 * void** handle - I 句柄
* 返回值: 错误码 * 返回值: 错误码
***************************************************************************************************/ ***************************************************************************************************/
int DET_Release(void** handle); int DETFEA_COLOR_Release(void** handle);
......
...@@ -2,6 +2,7 @@ package com.wmdigit.core; ...@@ -2,6 +2,7 @@ package com.wmdigit.core;
import android.content.Context; import android.content.Context;
import com.wmdigit.core.catering.PlateDetectionManager;
import com.wmdigit.core.catering.TargetDetectionManager; import com.wmdigit.core.catering.TargetDetectionManager;
import com.wmdigit.core.videopipe.VideoPipeManager; import com.wmdigit.core.videopipe.VideoPipeManager;
...@@ -28,7 +29,8 @@ public class CoreModule { ...@@ -28,7 +29,8 @@ public class CoreModule {
*/ */
private static void initCore() { private static void initCore() {
// 初始化目标检测 // 初始化目标检测
TargetDetectionManager.getInstance().initTargetDetection(); // TargetDetectionManager.getInstance().initTargetDetection();
PlateDetectionManager.getInstance().initPlateDetection();
// 初始化视频流 // 初始化视频流
VideoPipeManager.getInstance().initVideoPipe(); VideoPipeManager.getInstance().initVideoPipe();
// todo 初始化索引库 // todo 初始化索引库
......
package com.wmdigit.core.catering;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.elvishew.xlog.XLog;
import com.wmdigit.core.catering.model.TargetDetectResult;
/**
* 餐盘识别管理类
* @author dizi
*/
public class PlateDetectionManager {
static{
System.loadLibrary("catering_plate_detection");
}
/**
* JNI初始化目标检测算法
* @return
*/
private native int init();
/**
* JNI推理图片
* @param bitmap
* @return
*/
private native TargetDetectResult process(Bitmap bitmap);
private volatile static PlateDetectionManager instance;
public static PlateDetectionManager getInstance(){
if (instance == null){
synchronized (PlateDetectionManager.class){
if (instance == null){
instance = new PlateDetectionManager();
}
}
}
return instance;
}
public void initPlateDetection(){
int ret = init();
XLog.i("目标检测算法初始化结果:%s", ret);
}
/**
* 推理图片
* @param imagePath
*/
public TargetDetectResult detectImage(String imagePath){
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
return detectImage(bitmap);
}
public TargetDetectResult detectImage(Bitmap bitmap){
long startTime = System.currentTimeMillis();
TargetDetectResult result = process(bitmap);
// 去掉最后一位逗号
if (result.getResults().endsWith(",")){
result.setResults(result.getResults().substring(0, result.getResults().length()-1));
}
XLog.i("推理耗时:" + (System.currentTimeMillis() - startTime) + "ms, 结果:" + result.getResults());
return result;
}
}
...@@ -62,4 +62,8 @@ public class MmkvCons { ...@@ -62,4 +62,8 @@ public class MmkvCons {
* 裁剪框高度 * 裁剪框高度
*/ */
public static final String MMKV_KEY_CROP_HEIGHT = "MMKV_KEY_CROP_HEIGHT"; public static final String MMKV_KEY_CROP_HEIGHT = "MMKV_KEY_CROP_HEIGHT";
/**
* 识别模式
*/
public static final String MMKV_KEY_AI_MODE = "MMKV_KEY_AI_MODE";
} }
package com.wmdigit.data.mmkv.repository;
import com.tencent.mmkv.MMKV;
import com.wmdigit.data.mmkv.constant.MmkvCons;
/**
* AI相关本地存储
* @author dizi
*/
public class AiLocalRepository {
private static AiLocalRepository instance;
public static AiLocalRepository getInstance(){
if (instance == null){
synchronized (AiLocalRepository.class){
if (instance == null){
instance = new AiLocalRepository();
}
}
}
return instance;
}
public AiLocalRepository() {
}
/**
* 设置AI模式 0-菜品模式 1-餐盘模式
* @param aiMode
*/
public void setAiMode(int aiMode){
MMKV.defaultMMKV().putInt(MmkvCons.MMKV_KEY_AI_MODE, aiMode);
}
/**
* 获取AI模式
* @return
*/
public int getAiMode(){
return MMKV.defaultMMKV().getInt(MmkvCons.MMKV_KEY_AI_MODE, 0);
}
}
...@@ -7,4 +7,5 @@ v1.0.2 2024/08/06 1.增加系统信息页 ...@@ -7,4 +7,5 @@ v1.0.2 2024/08/06 1.增加系统信息页
4.增加秤盘裁剪页 4.增加秤盘裁剪页
5.增加数据管理页 5.增加数据管理页
6.增加学习页 6.增加学习页
7.增加AIDL服务 7.增加AIDL服务
\ No newline at end of file 8.集成标框、菜品识别、餐盘识别算法
\ No newline at end of file
...@@ -46,6 +46,7 @@ dependencies { ...@@ -46,6 +46,7 @@ dependencies {
implementation project(path: ':data-local') implementation project(path: ':data-local')
implementation project(path: ':data-remote') implementation project(path: ':data-remote')
implementation project(path: ':camera') implementation project(path: ':camera')
implementation project(path: ':core')
implementation 'com.alibaba:arouter-api:1.5.2' implementation 'com.alibaba:arouter-api:1.5.2'
annotationProcessor 'com.alibaba:arouter-compiler:1.5.2' annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
......
package com.wmdigit.setting; package com.wmdigit.setting;
import android.view.View;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
...@@ -131,4 +133,17 @@ public class SettingActivity extends BaseMvvmNaviDrawerActivity<SettingViewModel ...@@ -131,4 +133,17 @@ public class SettingActivity extends BaseMvvmNaviDrawerActivity<SettingViewModel
// 导航到对应页面 // 导航到对应页面
navigation(FRAGMENTS_NAVI_IDS[position]); navigation(FRAGMENTS_NAVI_IDS[position]);
} }
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
} }
\ No newline at end of file
package com.wmdigit.setting.fragment; package com.wmdigit.setting.fragment;
import com.wmdigit.common.base.mvvm.BaseMvvmFragment; import com.wmdigit.common.base.mvvm.BaseMvvmFragment;
import com.wmdigit.core.catering.PlateDetectionManager;
import com.wmdigit.core.catering.TargetDetectionManager;
import com.wmdigit.setting.R; import com.wmdigit.setting.R;
import com.wmdigit.setting.databinding.FragmentSystemInfoBinding; import com.wmdigit.setting.databinding.FragmentSystemInfoBinding;
import com.wmdigit.setting.viewmodel.SystemInfoViewModel; import com.wmdigit.setting.viewmodel.SystemInfoViewModel;
...@@ -29,7 +31,11 @@ public class SystemInfoFragment extends BaseMvvmFragment<SystemInfoViewModel, Fr ...@@ -29,7 +31,11 @@ public class SystemInfoFragment extends BaseMvvmFragment<SystemInfoViewModel, Fr
protected void initData() { protected void initData() {
// 绑定ViewModel和DataBinding // 绑定ViewModel和DataBinding
mDataBinding.setViewModel(mViewModel); mDataBinding.setViewModel(mViewModel);
// 设置下拉框列表
mDataBinding.spinnerAiMode.setSpinnerEntriesFromResource(R.array.array_ai_mode);
// todo 测试
// TargetDetectionManager.getInstance().detectImage(requireContext().getExternalFilesDir("images").getAbsolutePath() + "/7.jpg");
PlateDetectionManager.getInstance().detectImage(requireContext().getExternalFilesDir("images").getAbsolutePath() + "/7.jpg");
} }
@Override @Override
......
...@@ -265,6 +265,48 @@ ...@@ -265,6 +265,48 @@
app:layout_constraintBottom_toBottomOf="@+id/edt_camera_crop" app:layout_constraintBottom_toBottomOf="@+id/edt_camera_crop"
app:layout_constraintEnd_toStartOf="@+id/edt_camera_crop"/> app:layout_constraintEnd_toStartOf="@+id/edt_camera_crop"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!--AI设置-->
<androidx.constraintlayout.widget.ConstraintLayout
style="@style/setting_module">
<!--绿色图标-->
<View
android:id="@+id/icon_ai_config"
style="@style/icon_title_green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_ai_config"
app:layout_constraintBottom_toBottomOf="@+id/tv_ai_config"/>
<!--标题-->
<TextView
android:id="@+id/tv_ai_config"
style="@style/text_base.title.module_title"
android:text="@string/module_setting_ai_config"
app:layout_constraintStart_toEndOf="@+id/icon_ai_config"
app:layout_constraintTop_toTopOf="parent" />
<!--算法类型下拉框-->
<com.wmdigit.common.view.spinner.MySpinner
android:id="@+id/spinner_ai_mode"
android:layout_width="@dimen/dp_492"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_200"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_ai_mode"
app:layout_constraintBottom_toBottomOf="@+id/tv_ai_mode"
/>
<!--激活状态-->
<TextView
android:id="@+id/tv_ai_mode"
style="@style/text_base.content"
android:text="@string/module_setting_ai_mode"
android:layout_marginTop="@dimen/dp_45"
android:layout_marginEnd="@dimen/dp_10"
app:layout_constraintTop_toBottomOf="@+id/tv_ai_config"
app:layout_constraintEnd_toStartOf="@+id/spinner_ai_mode"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--识别模式-->
<string-array name="array_ai_mode">
<item>@string/ai_mode_dish_recognition</item>
<item>@string/ai_mode_plate_recognition</item>
</string-array>
<!--识别阈值-->
<string-array name="array_recognition_threshold">
<item>0.90</item>
<item>0.85</item>
<item>0.80</item>
<item>0.75</item>
<item>0.70</item>
</string-array>
</resources>
\ No newline at end of file
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
<string name="module_setting_clear_products">清空商品数据</string> <string name="module_setting_clear_products">清空商品数据</string>
<string name="module_setting_unbind">SN解绑</string> <string name="module_setting_unbind">SN解绑</string>
<string name="module_setting_download_remote_tool">下载远程工具</string> <string name="module_setting_download_remote_tool">下载远程工具</string>
<!-- TODO: Remove or change this placeholder text --> <string name="module_setting_ai_config">AI配置</string>
<string name="hello_blank_fragment">Hello blank fragment</string> <string name="module_setting_ai_mode">识别模式:</string>
<string name="ai_mode_dish_recognition">菜品识别</string>
<string name="ai_mode_plate_recognition">餐盘识别</string>
</resources> </resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment