Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
A
Android_Catering_service
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
姜天宇
Android_Catering_service
Commits
43c3bc9e
Commit
43c3bc9e
authored
Sep 26, 2024
by
姜天宇
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(v1.0.2): 增加识别记录上传
parent
4a984f16
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
810 additions
and
19 deletions
+810
-19
IdentifyRecordDTO.java
...main/java/com/wmdigit/common/model/IdentifyRecordDTO.java
+50
-0
BitmapUtils.java
...n/src/main/java/com/wmdigit/common/utils/BitmapUtils.java
+1
-0
CropView.java
...main/java/com/wmdigit/common/view/imageview/CropView.java
+3
-0
CMakeLists.txt
core/src/main/cpp/CMakeLists.txt
+1
-1
catering_dish_detection.cpp
core/src/main/cpp/catering_dish_detection.cpp
+3
-3
features_hnsw.cpp
core/src/main/cpp/features_hnsw.cpp
+4
-3
features_hnsw.h
core/src/main/cpp/include/features_hnsw.h
+2
-2
CoreModule.java
core/src/main/java/com/wmdigit/core/CoreModule.java
+1
-1
TargetDetection.java
.../main/java/com/wmdigit/core/catering/TargetDetection.java
+5
-0
TargetDetectionRepository.java
.../com/wmdigit/core/catering/TargetDetectionRepository.java
+8
-0
DishDetection.java
...in/java/com/wmdigit/core/catering/dish/DishDetection.java
+10
-0
PlateDetection.java
.../java/com/wmdigit/core/catering/plate/PlateDetection.java
+10
-0
Hnsw.java
core/src/main/java/com/wmdigit/core/hnsw/Hnsw.java
+4
-3
HnswRepository.java
core/src/main/java/com/wmdigit/core/hnsw/HnswRepository.java
+10
-5
DiskRepository.java
...java/com/wmdigit/data/disk/repository/DiskRepository.java
+61
-0
UserLocalRepository.java
...com/wmdigit/data/mmkv/repository/UserLocalRepository.java
+8
-0
CateringIdentifyRecord.java
.../wmdigit/network/bean/request/CateringIdentifyRecord.java
+87
-0
IdentifyRecordRepository.java
.../wmdigit/network/repository/IdentifyRecordRepository.java
+76
-0
PosService.java
...src/main/java/com/wmdigit/network/service/PosService.java
+9
-0
history.txt
history.txt
+3
-1
DataLearningViewModel.java
.../com/wmdigit/setting/viewmodel/DataLearningViewModel.java
+21
-0
元芒数字餐饮服务(WmCateringService)Android端接口说明文档-V1.0.2.md
元芒数字餐饮服务(WmCateringService)Android端接口说明文档-V1.0.2.md
+433
-0
No files found.
common/src/main/java/com/wmdigit/common/model/IdentifyRecordDTO.java
0 → 100644
View file @
43c3bc9e
package
com
.
wmdigit
.
common
.
model
;
import
java.io.Serializable
;
import
java.util.List
;
/**
* 识别结果DTO
* @author dizi
*/
public
class
IdentifyRecordDTO
implements
Serializable
{
private
int
[][]
rectArray
;
private
String
[]
productNames
;
private
String
[]
productCodes
;
public
IdentifyRecordDTO
()
{
}
public
IdentifyRecordDTO
(
int
[][]
rectArray
,
String
[]
productNames
,
String
[]
productCodes
)
{
this
.
rectArray
=
rectArray
;
this
.
productNames
=
productNames
;
this
.
productCodes
=
productCodes
;
}
public
int
[][]
getRectArray
()
{
return
rectArray
;
}
public
void
setRectArray
(
int
[][]
rectArray
)
{
this
.
rectArray
=
rectArray
;
}
public
String
[]
getProductNames
()
{
return
productNames
;
}
public
void
setProductNames
(
String
[]
productNames
)
{
this
.
productNames
=
productNames
;
}
public
String
[]
getProductCodes
()
{
return
productCodes
;
}
public
void
setProductCodes
(
String
[]
productCodes
)
{
this
.
productCodes
=
productCodes
;
}
}
common/src/main/java/com/wmdigit/common/utils/BitmapUtils.java
View file @
43c3bc9e
...
...
@@ -149,6 +149,7 @@ public class BitmapUtils {
public
static
void
saveBitmap
(
Bitmap
bitmap
,
String
path
)
{
try
{
File
file
=
new
File
(
path
);
file
.
getParentFile
().
mkdirs
();
FileOutputStream
fos
=
new
FileOutputStream
(
file
);
bitmap
.
compress
(
Bitmap
.
CompressFormat
.
JPEG
,
100
,
fos
);
fos
.
flush
();
...
...
common/src/main/java/com/wmdigit/common/view/imageview/CropView.java
View file @
43c3bc9e
...
...
@@ -1165,6 +1165,9 @@ public class CropView extends AppCompatImageView {
if
(
presetCropCoordinate
==
null
){
return
;
}
if
(
mImageRectF
==
null
){
return
;
}
int
l
=
presetCropCoordinate
.
left
;
int
t
=
presetCropCoordinate
.
top
;
int
w
=
presetCropCoordinate
.
right
-
l
;
...
...
core/src/main/cpp/CMakeLists.txt
View file @
43c3bc9e
...
...
@@ -56,7 +56,7 @@ set_target_properties(
${
CMAKE_SOURCE_DIR
}
/../jniLibs/
${
ANDROID_ABI
}
/libret.so
)
# 分类、特征提取库
#
菜品
分类、特征提取库
add_library
(
clsretri SHARED IMPORTED
)
set_target_properties
(
clsretri
...
...
core/src/main/cpp/catering_dish_detection.cpp
View file @
43c3bc9e
...
...
@@ -28,7 +28,7 @@ Java_com_wmdigit_core_catering_dish_DishDetection_process(JNIEnv *env, jobject t
LOGD
(
"准备推理菜品"
);
// 推理
int
ret
=
DETFEA_Process
(
input
,
&
output
,
handle
);
LOGD
(
"推理结果:%
d
"
,
ret
);
LOGD
(
"推理结果:%
x
"
,
ret
);
if
(
ret
!=
0
){
mat
.
release
();
mat_bgr
.
release
();
...
...
@@ -40,7 +40,7 @@ Java_com_wmdigit_core_catering_dish_DishDetection_process(JNIEnv *env, jobject t
int
cols
=
4
;
// 统计符合阈值的框数量
for
(
size_t
i
=
0
;
i
<
output
.
output_list
.
size
();
++
i
)
{
if
(
output
.
output_list
[
i
].
prob
>=
0.
7
){
if
(
output
.
output_list
[
i
].
prob
>=
0.
8
){
rows
++
;
}
}
...
...
@@ -59,7 +59,7 @@ Java_com_wmdigit_core_catering_dish_DishDetection_process(JNIEnv *env, jobject t
// 遍历识别结果
for
(
size_t
i
=
0
;
i
<
output
.
output_list
.
size
();
++
i
)
{
// 根据阈值,筛选出有效的框
if
(
output
.
output_list
[
i
].
prob
>=
0.
75
){
if
(
output
.
output_list
[
i
].
prob
>=
0.
8
){
// 记录框的左上、右下点坐标
rect_array
[
i
][
0
]
=
(
int
)
output
.
output_list
[
i
].
x1
;
rect_array
[
i
][
1
]
=
(
int
)
output
.
output_list
[
i
].
y1
;
...
...
core/src/main/cpp/features_hnsw.cpp
View file @
43c3bc9e
...
...
@@ -5,9 +5,10 @@
*/
extern
"C"
JNIEXPORT
jint
JNICALL
Java_com_wmdigit_core_hnsw_Hnsw_init
(
JNIEnv
*
env
,
jobject
thiz
)
{
Java_com_wmdigit_core_hnsw_Hnsw_init
(
JNIEnv
*
env
,
jobject
thiz
,
jint
dimension
)
{
std
::
vector
<
std
::
pair
<
long
,
std
::
string
>>
().
swap
(
vector
);
idx
=
new
libhnsw
::
Index
(
FEATURES_DIMENSION
,
FEATURES_TOTAL
,
mode
);
idx
=
new
libhnsw
::
Index
(
dimension
,
FEATURES_TOTAL
,
mode
);
output_dimension
=
dimension
;
LOGI
(
"索引库初始化完成"
);
return
0
;
}
...
...
@@ -96,7 +97,7 @@ Java_com_wmdigit_core_hnsw_Hnsw_retrieveMostSimilarResult(JNIEnv *env, jobject t
libhnsw
::
RequireSample
requireSample
;
idx
->
Selectsample
(
requireSample
,
label
);
// 计算相似度
float
similarity
=
calculateSimilar
(
array
,
requireSample
.
data
,
FEATURES_DIMENSION
);
float
similarity
=
calculateSimilar
(
array
,
requireSample
.
data
,
output_dimension
);
if
(
similarity
>=
threshold
){
// 相似度大于设定阈值,在vector中检索出对应的code
for
(
auto
it
=
vector
.
begin
();
it
!=
vector
.
end
();
it
++
)
{
...
...
core/src/main/cpp/include/features_hnsw.h
View file @
43c3bc9e
...
...
@@ -16,8 +16,6 @@
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG, __VA_ARGS__)
// 特征维度
#define FEATURES_DIMENSION 160
// 特征总数
#define FEATURES_TOTAL 50000
// 索引
...
...
@@ -33,6 +31,8 @@ libhnsw::SPACE_TYPE st = libhnsw::L2_DISTANCE;
// second->商品code
std
::
vector
<
std
::
pair
<
long
,
std
::
string
>>
vector
;
int
output_dimension
=
128
;
/**
* 计算相似度
* @param v1
...
...
core/src/main/java/com/wmdigit/core/CoreModule.java
View file @
43c3bc9e
...
...
@@ -36,7 +36,7 @@ public class CoreModule {
// 初始化视频流
VideoPipeRepository
.
getInstance
().
initVideoPipe
();
// 初始化索引库
HnswRepository
.
getInstance
().
init
();
HnswRepository
.
getInstance
().
init
(
TargetDetectionRepository
.
getInstance
().
getDimension
()
);
}
public
static
Context
getAppContext
()
{
...
...
core/src/main/java/com/wmdigit/core/catering/TargetDetection.java
View file @
43c3bc9e
...
...
@@ -33,4 +33,9 @@ public interface TargetDetection {
*/
int
getAiMode
();
/**
* 获取输出维度
* @return
*/
int
getDimension
();
}
core/src/main/java/com/wmdigit/core/catering/TargetDetectionRepository.java
View file @
43c3bc9e
...
...
@@ -95,4 +95,12 @@ public class TargetDetectionRepository {
public
void
close
(){
targetDetection
.
close
();
}
/**
* 获取向量维度
* @return
*/
public
int
getDimension
(){
return
targetDetection
.
getDimension
();
}
}
core/src/main/java/com/wmdigit/core/catering/dish/DishDetection.java
View file @
43c3bc9e
...
...
@@ -16,6 +16,11 @@ public class DishDetection implements TargetDetection {
System
.
loadLibrary
(
"catering_dish_detection"
);
}
/**
* 输出维度
*/
private
final
int
OUTPUT_DIMENSION
=
160
;
/**
* JNI初始化目标检测算法
* @return
...
...
@@ -76,4 +81,9 @@ public class DishDetection implements TargetDetection {
return
TargetDetectionRepository
.
AI_MODE_DISH_DETECTION
;
}
@Override
public
int
getDimension
()
{
return
OUTPUT_DIMENSION
;
}
}
core/src/main/java/com/wmdigit/core/catering/plate/PlateDetection.java
View file @
43c3bc9e
...
...
@@ -16,6 +16,11 @@ public class PlateDetection implements TargetDetection {
System
.
loadLibrary
(
"catering_plate_detection"
);
}
/**
* 算法输出维度
*/
private
final
int
OUTPUT_DIMENSION
=
160
;
/**
* JNI初始化目标检测算法
* @return
...
...
@@ -80,4 +85,9 @@ public class PlateDetection implements TargetDetection {
public
int
getAiMode
()
{
return
TargetDetectionRepository
.
AI_MODE_PLATE_DETECTION
;
}
@Override
public
int
getDimension
()
{
return
OUTPUT_DIMENSION
;
}
}
core/src/main/java/com/wmdigit/core/hnsw/Hnsw.java
View file @
43c3bc9e
...
...
@@ -14,9 +14,10 @@ public class Hnsw {
/**
* 初始化方法
* @param dimension
* @return
*/
private
native
int
init
();
private
native
int
init
(
int
dimension
);
/**
* 写入索引
...
...
@@ -45,9 +46,9 @@ public class Hnsw {
*/
private
final
Object
syncLock
=
new
Object
();
public
void
initHnsw
(){
public
void
initHnsw
(
int
dimension
){
synchronized
(
syncLock
){
int
ret
=
init
();
int
ret
=
init
(
dimension
);
XLog
.
i
(
"hnsw初始化结果:"
+
ret
);
}
}
...
...
core/src/main/java/com/wmdigit/core/hnsw/HnswRepository.java
View file @
43c3bc9e
...
...
@@ -3,6 +3,7 @@ package com.wmdigit.core.hnsw;
import
android.text.TextUtils
;
import
com.elvishew.xlog.XLog
;
import
com.wmdigit.core.catering.TargetDetectionRepository
;
import
com.wmdigit.data.database.entity.FeaturesPO
;
import
com.wmdigit.data.database.entity.ProductsPO
;
import
com.wmdigit.data.database.repository.FeaturesRepository
;
...
...
@@ -44,6 +45,8 @@ public class HnswRepository {
private
boolean
initComplete
=
false
;
private
OnHnswInitListener
listener
;
private
int
dimension
=
128
;
public
HnswRepository
()
{
hnsw
=
new
Hnsw
();
compositeDisposable
=
new
CompositeDisposable
();
...
...
@@ -52,9 +55,10 @@ public class HnswRepository {
/**
* 初始化
*/
public
void
init
(){
public
void
init
(
int
dimension
){
this
.
dimension
=
dimension
;
initComplete
=
false
;
hnsw
.
initHnsw
();
hnsw
.
initHnsw
(
dimension
);
Disposable
disposable
=
Observable
.
create
(
emitter
->
{
// 遍历特征库
queryAndWriteFeaturesIntoHnsw
();
...
...
@@ -125,6 +129,7 @@ public class HnswRepository {
/**
* 查询并写入特征
* @param dimension
*/
private
void
queryAndWriteFeaturesIntoHnsw
(){
int
page
=
1
;
...
...
@@ -133,10 +138,10 @@ public class HnswRepository {
List
<
FeaturesPO
>
list
=
FeaturesRepository
.
getInstance
().
getFeaturesByPage
(
page
,
pageSize
);
for
(
FeaturesPO
featuresPO
:
list
){
String
[]
featureStrArray
=
featuresPO
.
getFeature
().
split
(
","
);
if
(
featureStrArray
.
length
!=
160
){
if
(
featureStrArray
.
length
!=
dimension
){
continue
;
}
float
[]
feature
=
new
float
[
160
];
float
[]
feature
=
new
float
[
dimension
];
for
(
int
i
=
0
;
i
<
feature
.
length
;
i
++){
feature
[
i
]
=
Float
.
parseFloat
(
featureStrArray
[
i
].
trim
().
replace
(
"["
,
""
).
replace
(
"]"
,
""
));
}
...
...
@@ -158,7 +163,7 @@ public class HnswRepository {
}
close
();
hnsw
.
deleteAll
();
hnsw
.
initHnsw
();
hnsw
.
initHnsw
(
dimension
);
}
public
void
setListener
(
OnHnswInitListener
listener
)
{
...
...
data-local/src/main/java/com/wmdigit/data/disk/repository/DiskRepository.java
0 → 100644
View file @
43c3bc9e
package
com
.
wmdigit
.
data
.
disk
.
repository
;
import
android.content.Context
;
import
android.graphics.Bitmap
;
import
android.text.TextUtils
;
import
com.wmdigit.common.utils.BitmapUtils
;
import
com.wmdigit.data.LocalDataModule
;
import
com.wmdigit.data.database.entity.ProductsPO
;
import
java.io.File
;
import
java.util.List
;
import
java.util.UUID
;
public
class
DiskRepository
{
private
static
DiskRepository
instance
;
public
static
DiskRepository
getInstance
(){
if
(
instance
==
null
){
synchronized
(
DiskRepository
.
class
){
if
(
instance
==
null
){
instance
=
new
DiskRepository
();
}
}
}
return
instance
;
}
private
DiskRepository
(){}
/**
* 保存识别记录到磁盘
* @param bitmap
* @param rectArray
* @param products
* @return 返回原图的路径
*/
public
String
saveIdentifyRecordToDisk
(
Bitmap
bitmap
,
int
[][]
rectArray
,
List
<
ProductsPO
>
products
){
Context
context
=
LocalDataModule
.
getAppContext
();
// 识别记录根目录
String
identifyRecordsRootPath
=
context
.
getExternalFilesDir
(
"IdentifyRecords"
).
getAbsolutePath
();
// 商品的学习记录根目录
String
productLearningRecordsRootPath
=
context
.
getExternalFilesDir
(
"ProductLearningRecords"
).
getAbsolutePath
();
String
imageFilename
=
UUID
.
randomUUID
().
toString
()
+
".jpg"
;
// 保存图片
BitmapUtils
.
saveBitmap
(
bitmap
,
identifyRecordsRootPath
+
"/"
+
imageFilename
);
// 根据框的坐标,拆分原图
for
(
int
i
=
0
;
i
<
rectArray
.
length
;
i
++)
{
if
(
products
.
get
(
i
)
==
null
||
TextUtils
.
isEmpty
(
products
.
get
(
i
).
getProductCode
())){
continue
;
}
Bitmap
bitmapTemp
=
Bitmap
.
createBitmap
(
bitmap
,
rectArray
[
i
][
0
],
rectArray
[
i
][
1
],
rectArray
[
i
][
2
]
-
rectArray
[
i
][
0
],
rectArray
[
i
][
3
]
-
rectArray
[
i
][
1
]);
// 保存裁出来的图片
BitmapUtils
.
saveBitmap
(
bitmapTemp
,
productLearningRecordsRootPath
+
"/"
+
products
.
get
(
i
).
getProductCode
()
+
"/"
+
imageFilename
.
replace
(
".jpg"
,
""
)
+
"_"
+
i
+
".jpg"
);
bitmapTemp
.
recycle
();
}
return
identifyRecordsRootPath
+
"/"
+
imageFilename
;
}
}
data-local/src/main/java/com/wmdigit/data/mmkv/repository/UserLocalRepository.java
View file @
43c3bc9e
...
...
@@ -107,4 +107,12 @@ public class UserLocalRepository {
return
result
;
}
/**
* 获取PosId
* @return
*/
public
String
getPosId
(){
return
MMKV
.
defaultMMKV
().
getString
(
MmkvCons
.
MMKV_KEY_DEVICE_ID
,
""
);
}
}
data-remote/src/main/java/com/wmdigit/network/bean/request/CateringIdentifyRecord.java
0 → 100644
View file @
43c3bc9e
package
com
.
wmdigit
.
network
.
bean
.
request
;
import
java.io.Serializable
;
/**
* 餐饮识别记录
* @author dizi
*/
public
class
CateringIdentifyRecord
implements
Serializable
{
/**
* POS机ID,该值为后台PosMachine的主键
*/
private
String
posCode
;
/**
* 框图URL
*/
private
String
frameImageUrl
;
/**
* 原图URL
*/
private
String
imageUrl
;
/**
* 裁剪坐标JSON
*/
private
String
smallImageSite
;
/**
* 识别时间
* yyyy-MM-dd HH:mm:ss
*/
private
String
identifyTime
;
public
CateringIdentifyRecord
()
{
}
public
CateringIdentifyRecord
(
String
posCode
,
String
frameImageUrl
,
String
imageUrl
,
String
smallImageSite
,
String
identifyTime
)
{
this
.
posCode
=
posCode
;
this
.
frameImageUrl
=
frameImageUrl
;
this
.
imageUrl
=
imageUrl
;
this
.
smallImageSite
=
smallImageSite
;
this
.
identifyTime
=
identifyTime
;
}
public
String
getPosCode
()
{
return
posCode
;
}
public
void
setPosCode
(
String
posCode
)
{
this
.
posCode
=
posCode
;
}
public
String
getFrameImageUrl
()
{
return
frameImageUrl
;
}
public
void
setFrameImageUrl
(
String
frameImageUrl
)
{
this
.
frameImageUrl
=
frameImageUrl
;
}
public
String
getImageUrl
()
{
return
imageUrl
;
}
public
void
setImageUrl
(
String
imageUrl
)
{
this
.
imageUrl
=
imageUrl
;
}
public
String
getSmallImageSite
()
{
return
smallImageSite
;
}
public
void
setSmallImageSite
(
String
smallImageSite
)
{
this
.
smallImageSite
=
smallImageSite
;
}
public
String
getIdentifyTime
()
{
return
identifyTime
;
}
public
void
setIdentifyTime
(
String
identifyTime
)
{
this
.
identifyTime
=
identifyTime
;
}
}
data-remote/src/main/java/com/wmdigit/network/repository/IdentifyRecordRepository.java
0 → 100644
View file @
43c3bc9e
package
com
.
wmdigit
.
network
.
repository
;
import
com.elvishew.xlog.XLog
;
import
com.wmdigit.common.utils.DateUtils
;
import
com.wmdigit.data.mmkv.repository.UserLocalRepository
;
import
com.wmdigit.network.bean.request.CateringIdentifyRecord
;
import
com.wmdigit.network.bean.response.BasePosResponse
;
import
com.wmdigit.network.factory.ServiceFactory
;
import
com.wmdigit.network.oss.OSSManager
;
import
com.wmdigit.network.utils.RxHelper
;
import
java.io.File
;
import
io.reactivex.Observable
;
import
io.reactivex.Observer
;
import
io.reactivex.disposables.Disposable
;
import
io.reactivex.functions.Consumer
;
public
class
IdentifyRecordRepository
{
private
static
IdentifyRecordRepository
instance
;
public
static
IdentifyRecordRepository
getInstance
(){
if
(
instance
==
null
){
synchronized
(
IdentifyRecordRepository
.
class
){
if
(
instance
==
null
){
instance
=
new
IdentifyRecordRepository
();
}
}
}
return
instance
;
}
private
IdentifyRecordRepository
(){
}
/**
* 上传识别记录
* 此方法用于上传用户的识别记录到服务器,包括图片的同步上传和识别记录的异步处理
*
* @param json 识别记录的JSON字符串,包含识别相关信息
* @param imagePath 待上传图片的路径
* @return 返回一个Disposable对象,用于取消订阅
*/
public
Disposable
uploadIdentifyRecord
(
String
json
,
String
imagePath
){
return
Observable
.
create
(
emitter
->
{
// 同步上传图片到对象存储服务
String
url
=
OSSManager
.
getInstance
().
syncUploadFileToOSS
(
new
File
(
imagePath
));
// 向观察者发射上传后的图片URL
emitter
.
onNext
(
url
);
}).
flatMap
(
url
->{
// 创建一个餐饮识别记录对象
CateringIdentifyRecord
record
=
new
CateringIdentifyRecord
();
// 设置POS机编号
record
.
setPosCode
(
UserLocalRepository
.
getInstance
().
getPosId
());
// 设置识别时间
record
.
setIdentifyTime
(
DateUtils
.
getTodayTime
());
// 设置图片URL
record
.
setImageUrl
((
String
)
url
);
// 设置帧图片URL
record
.
setFrameImageUrl
((
String
)
url
);
// 设置小图片站点信息
record
.
setSmallImageSite
(
json
);
// 异步上传餐饮识别记录到服务器
return
ServiceFactory
.
getServiceFactory
().
getPosService
()
.
uploadCateringIdentifyRecord
(
record
)
.
compose
(
RxHelper
.
handlePosResult
());
}).
subscribe
(
aLong
->
{
// 日志记录上传成功
XLog
.
i
(
"上传成功"
);
},
throwable
->
{
XLog
.
e
(
throwable
.
toString
());
});
}
}
data-remote/src/main/java/com/wmdigit/network/service/PosService.java
View file @
43c3bc9e
package
com
.
wmdigit
.
network
.
service
;
import
com.wmdigit.network.bean.request.CateringIdentifyRecord
;
import
com.wmdigit.network.bean.request.ProductIdentifyRecord
;
import
com.wmdigit.network.bean.request.QueryCommandParam
;
import
com.wmdigit.network.bean.request.QueryLatestAppVersionParam
;
...
...
@@ -94,4 +95,12 @@ public interface PosService {
@GET
(
"newretail/api/sys/app/version/getLatestWithType"
)
Observable
<
BasePosResponse
<
AppVersionDTO
>>
getLatestRemoteToolWithType
(
@Query
(
"type"
)
String
type
);
/**
* 上传餐饮识别记录
* @param record
* @return
*/
@POST
(
"newretail/api/search/cateringIdentifyRecord/saveCateringIdentifyRecord"
)
Observable
<
BasePosResponse
<
Long
>>
uploadCateringIdentifyRecord
(
@Body
CateringIdentifyRecord
record
);
}
history.txt
View file @
43c3bc9e
...
...
@@ -9,4 +9,6 @@ v1.0.2 2024/08/06 1.增加系统信息页
6.增加学习页
7.增加AIDL服务
8.集成标框、菜品识别、餐盘识别算法
9.集成索引库算法(索引库版本较老,可能存在最后一条索引删除不掉的BUG)
\ No newline at end of file
9.集成索引库算法(索引库版本较老,可能存在最后一条索引删除不掉的BUG)
10.todo 菜品算法更新128模型
11.增加数据上传
\ No newline at end of file
module-setting/src/main/java/com/wmdigit/setting/viewmodel/DataLearningViewModel.java
View file @
43c3bc9e
...
...
@@ -8,10 +8,12 @@ import androidx.annotation.NonNull;
import
androidx.databinding.ObservableField
;
import
androidx.lifecycle.MutableLiveData
;
import
com.google.gson.Gson
;
import
com.wmdigit.camera.listener.OnImageAnalyzeListener
;
import
com.wmdigit.common.base.mvvm.BaseViewModel
;
import
com.wmdigit.common.base.mvvm.SingleLiveEvent
;
import
com.wmdigit.common.model.CropValueDTO
;
import
com.wmdigit.common.model.IdentifyRecordDTO
;
import
com.wmdigit.common.model.ProductsVO
;
import
com.wmdigit.common.utils.ParcelHelper
;
import
com.wmdigit.core.catering.TargetDetectionRepository
;
...
...
@@ -23,7 +25,10 @@ import com.wmdigit.data.database.entity.ProductsPO;
import
com.wmdigit.data.database.mapper.ProductsMapper
;
import
com.wmdigit.data.database.repository.FeaturesRepository
;
import
com.wmdigit.data.database.repository.ProductsRepository
;
import
com.wmdigit.data.disk.repository.DiskRepository
;
import
com.wmdigit.data.mmkv.repository.CropLocalRepository
;
import
com.wmdigit.network.oss.OSSManager
;
import
com.wmdigit.network.repository.IdentifyRecordRepository
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -32,6 +37,10 @@ import java.util.concurrent.ScheduledExecutorService;
import
java.util.concurrent.ScheduledFuture
;
import
java.util.concurrent.TimeUnit
;
import
io.reactivex.Observable
;
import
io.reactivex.ObservableEmitter
;
import
io.reactivex.ObservableOnSubscribe
;
/**
* 学习菜品的ViewModel
* @author dizi
...
...
@@ -395,7 +404,11 @@ public class DataLearningViewModel extends BaseViewModel {
if
(
detectResult
==
null
||
detectResult
.
getProducts
()
==
null
){
return
;
}
String
[]
productNames
=
new
String
[
detectResult
.
getProducts
().
size
()];
String
[]
productCodes
=
new
String
[
detectResult
.
getProducts
().
size
()];
for
(
int
i
=
0
;
i
<
detectResult
.
getProducts
().
size
();
i
++){
productNames
[
i
]
=
""
;
productCodes
[
i
]
=
""
;
if
(
TextUtils
.
isEmpty
(
detectResult
.
getProducts
().
get
(
i
).
getProductCode
())){
continue
;
}
...
...
@@ -413,11 +426,19 @@ public class DataLearningViewModel extends BaseViewModel {
if
(
id
!=
-
1
)
{
HnswRepository
.
getInstance
().
writeFeatureIntoHnsw
(
id
,
detectResult
.
getProducts
().
get
(
i
).
getProductCode
(),
detectResult
.
getFeatures
()[
i
]);
}
productNames
[
i
]
=
detectResult
.
getProducts
().
get
(
i
).
getProductName
();
productCodes
[
i
]
=
detectResult
.
getProducts
().
get
(
i
).
getProductCode
();
}
String
imagePath
=
DiskRepository
.
getInstance
().
saveIdentifyRecordToDisk
(
detectResult
.
getBitmap
(),
detectResult
.
getRectArray
(),
detectResult
.
getProducts
());
toastMessage
.
postValue
(
getApplication
().
getString
(
com
.
wmdigit
.
common
.
R
.
string
.
save_success
));
// 异步上传后台
IdentifyRecordDTO
identifyRecordDTO
=
new
IdentifyRecordDTO
(
detectResult
.
getRectArray
(),
productNames
,
productCodes
);
String
json
=
new
Gson
().
toJson
(
identifyRecordDTO
);
compositeDisposable
.
add
(
IdentifyRecordRepository
.
getInstance
().
uploadIdentifyRecord
(
json
,
imagePath
));
}
}
public
OnImageAnalyzeListener
getOnImageAnalyzeListener
()
{
return
onImageAnalyzeListener
;
}
...
...
元芒数字餐饮服务(WmCateringService)Android端接口说明文档-V1.0.2.md
0 → 100644
View file @
43c3bc9e
# 元芒餐饮服务(WmCateringService)
## 安卓SDK接口说明文档

##### Version Release v1.0.2
##### 更新时间: 2024.09.24
#### 上海元芒数字科技有限公司
<div
style=
"page-break-after: always;"
></div>
[
TOC
]
<div
style=
"page-break-after: always;"
></div>
# Android端SDK接口文档
# 一、 文档说明
## 1.1 版本说明
| SDK版本号 | 发布日期 | 更新内容 |
| --------- | ---------- | ---------------------------------------- |
| 1.0.0 | 2024.07.18 | 1.餐饮识别效果演示版本 |
| 1.0.1 | 2024.08.01 | 1.算法模块集成
<br>
2.相机模块集成 |
| 1.0.2 | 2024.09.24 | 1.发版版本 |
## 1.2 文档概述
此文档用于说明元芒数字餐饮服务(WmCateringService)Android系统接
口开发使用,集成相关软件包,以实现相关功能的接口说明文档。
## 1.3 术语定义以及说明
1.
术语说明
+
WmCateringService:元芒餐饮服务
2.
本文中所有传输内容均使用UTF- 8编码;
3.
本文SDK适用于Android 11及以上,主板要求RK3568(带有NPU模块),使用JAVA 1.8 版本;
4.
本文中的服务程序支持armeabi-v7a、arm64-v8a架构。
<div
style=
"page-break-after: always;"
></div>
# 二、 调用流程
## 2.1 集成方法说明
1.
把WmCateringService_v1.0.2_sdk.jar放在工程libs目录下;
2.
module的build.gradle中添加依赖:
```
Implementation files("libs/WmCateringService_v1.0.2_sdk.jar")
```
3.
AndroidManifest.xml中增加权限:
```
<uses-permissionandroid:name="android.permission.QUERY_ALL_PACKAGES"/>
```
4.
若程序开启代码混淆,在防混淆文件中增加:
```
-keep public class com.wmdigit.** {*;}
```
**接口调用流程描述 **
1.
推荐在主页Activity的onCreate()中调用bindService接口,绑定本地餐饮服务(需要预装服务程序);
2.
绑定成功后,调用init接口,对SDK进行初始化;
3.
初始化成功后,调用registerDetectionListener接口,注册识别结果的监听回调;
4.
同时,可以在Activity的onStart()和onStop()中,分别调用registerDetectionListener接口和unregisterDetectionListener接口,保证页面不可见时,不会因触发识别而占用设备性能。这两个接口具体的调用时机,可根据实际业务场景做调整;
5.
初次使用时,请调用openSettingPage接口或直接在系统桌面打开餐饮服务程序,进入设置页面,在设置页面中注册激活码和设定检测区域
6.
关于商品学习,请先调用importProducts接口,导入客户端的商品资料,然后打开餐饮服务设置页,进入数据学习页面
<div
style=
"page-break-after: always;"
></div>
# 三、 接口说明
## 主流程接口
## 3.1 bindService(绑定服务)
-
使用场景: 此接口用于绑定WmLPService本地服务,推荐在主页Activity的onCreate()中调用
-
函数名: bindService
-
函数原型
```
java
public
static
void
bindService
(
Context
context
,
IOnServiceConListener
listener
);
```
-
请求参数
| 请求参数 | 必填 | 类型 | 描述 |
| -------- | ---- | --------------------- | ---------------- |
| context | 是 | Context | Context上下文 |
| listener | 是 | IOnServiceConListener | 本地服务连接回调 |
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
bindService
(
mContext
,
new
IOnServiceConListener
()
{
@Override
public
void
onConnected
(
ComponentName
componentName
,
IBinder
iBinder
)
{
}
@Override
public
void
onDisconnected
(
ComponentName
componentName
)
{
}
});
```
## 3.2 init(初始化服务SDK)
-
使用场景:此接口用于初始化,请在服务绑定成功后调用一次
-
函数名:init
-
函数原型
```
java
public
static
void
init
();
```
-
请求参数
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
init
();
```
## 3.3 openSettingPage(打开设置页)
-
使用场景: 此接口用于打开设置页面
-
函数名: openSettingPage
-
函数原型
```
java
public
static
void
openSettingPage
();
```
-
请求参数
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
openSettingPage
();
```
## 3.4 autoDetect(商品识别)
-
使用场景: 当扫码枪收到条码时,调用此接口
-
函数名: autoDetect
-
函数原型
```
java
public
void
autoDetect
(
String
barcode
,
String
plu
,
String
sessionId
);
```
-
请求参数
| 请求参数 | 必填 | 类型 | 描述 |
| --------- | ---- | ------ | ------------------------------ |
| barcode | 是 | String | 扫码枪接收到的条码 |
| plu | 否 | String | 生鲜plu(仅生鲜类商品需要传plu) |
| sessionId | 否 | String | 区分相同条码的商品 |
-
返回说明
-
请求用例
```
java
// 接收到的条码
String
scanCode
=
"223057500988"
;
// 购物车中的行号,当相同barcode的商品第一次正确,第二次发生错扫,这时行号就可以区分是哪一个商品发生了错扫
String
sessionId
=
UUID
.
randomUUID
().
toString
();
// 不是生鲜码
if
(){
WmSdk
.
getInstance
().
autoDetect
(
scanCode
,
""
,
sessionId
);
}
else
{
// 是生鲜码
String
plu
=
"30575"
;
// 从条码中解析出对应的PLU
WmSdk
.
getInstance
().
autoDetect
(
scanCode
,
plu
,
sessionId
);
}
```
## 3.5 start(开启防损检测)
-
使用场景:用于开启检测,推荐在购物车页面的onResume()中调用
-
函数名:start
-
函数原型
```
java
public
int
start
(
IOnAlertEventCallback
callback
);
```
-
请求参数
| 请求参数 | 必填 | 类型 | 描述 |
| -------- | ---- | --------------------- | ------------------------------------------------------------ |
| callback | 是 | IOnAlertEventCallback | 当发生漏扫、错扫时,通过该回调函数进行通知,通知信息存储在回调参数AlertEvent中,AlertEvent属性:
<br>
bitmap : 识别图片,这里如果抓图异常,可能为空
<br/>
barcode : 条码
<br/>
plu : 生鲜码
<br/>
sessionId : 行号
<br/>
eventType : 识别类型,0错扫,1漏扫
<br/>
feature : 特征值 |
-
返回说明
| 返回值类型 | 说明 |
|-------|------------|
| 0 | 成功 |
| 2001 | 缺少密钥文件1 |
| 2002 | 缺少密钥文件2 |
| 2003 | 密钥文件1校验失败 |
| 2004 | 密钥文件2校验失败 |
| 2005 | 未注册 |
| 2007 | 未标定动作检测区域 |
| 2008 | 未标定物品识别区域 |
| 3001 | 摄像头USB未连接 |
| 3002 | 摄像头尚未初始化完成 |
| 3003 | 摄像头工作停止 |
-
请求用例
```
java
private
final
IOnAlertEventCallback
callback
=
new
IOnAlertEventCallback
.
Stub
()
{
@Override
public
void
onAlertEventCallback
(
AlertEvent
event
)
throws
RemoteException
{
switch
(
alertEventBean
.
getScanType
()){
case
1
:
System
.
out
.
println
(
"漏扫回调"
);
break
;
case
0
:
System
.
out
.
println
(
"错扫回调"
);
break
;
default
:
break
;
}
}
};
int
ret
=
WmSdk
.
getInstance
().
start
(
callback
);
String
message
=
""
;
switch
(
ret
){
case
0
:
// 成功
message
=
"检测开启成功"
;
break
;
case
2001
:
case
2002
:
message
=
"缺少密钥文件,请先注册激活"
;
break
;
case
2003
:
case
2004
:
message
=
"密钥文件校验失败"
;
break
;
case
2005
:
message
=
"未注册,请先注册激活"
;
break
;
case
2007
:
message
=
"未设置动作检测区域"
;
break
;
case
2008
:
message
=
"未设置物品识别区域"
;
break
;
case
3001
:
message
=
"摄像头USB断开连接"
;
break
;
case
3002
:
message
=
"摄像头工作停止"
;
break
;
default
:
message
=
"初始化失败"
+
ret
;
break
;
}
```
## 3.6 pause(暂停防损检测)
-
使用场景: 用于暂停检测,推荐在购物车页面的onPause()中
-
函数名:pause
-
函数原型
```
Java
public void pause();
```
-
请求参数
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
pause
();
```
## 3.7 unbindService(解绑服务)
-
使用场景: 用于解绑服务,推荐在主页Activity的onStop()中调用
-
函数名:unbindService
-
函数原型
```
Java
public void unbindService();
```
-
请求参数
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
unbindService
();
```
## 其他接口
## 4.1 feedback(保存识别结果)
-
使用场景: 用于保存识别记录
-
函数名:feedback
-
函数原型
```
Java
public void feedback(DetectResult result);
```
-
请求参数
| 请求参数 | 必填 | 类型 | 描述 |
| -------- | ---- | ------------ | ------------------------------------------------------------ |
| saveBean | 是 | DetectResult | 保存识别结果DetectResult的属性:
<br>
productId : 商品标识
<br>
feature : 特征值 |
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
feedback
(
result
);
```
## 4.2 setAdminPassword(设置管理员密码)
-
使用场景: 用于设置管理员密码
-
函数名:setAdminPassword
-
函数原型
```
Java
public void setAdminPassword(String password);
```
-
请求参数
| 请求参数 | 必填 | 类型 | 描述 |
| -------- | ---- | ------ | ---- |
| password | 是 | String | 密码 |
-
返回说明
-
请求用例
```
java
WmSdk
.
getInstance
().
setAdminPassword
(
password
);
```
<div
style=
"page-break-after: always;"
></div>
# 附录 1 :商品识别返回错误码
|
**错误码**
|
**描述**
|
**解决方案**
|
|---------|---------------------------------|-------------|
| 0 | 成功 | |
| 1001 | 初始化失败 | |
| 1002 | 模型初始化失败 | |
| 2001 | 缺少密钥文件1 | 重新注册激活 |
| 2002 | 缺少密钥文件2 | 重新注册激活 |
| 2003 | 密钥文件1校验失败 | 重新注册激活 |
| 2004 | 密钥文件2校验失败 | 重新注册激活 |
| 2005 | 未注册 | 重新注册激活 |
| 2007 | 未标定动作检测区域 | 设置页动作检测区域 |
| 2008 | 未标定物品识别区域 | 设置页图像识别区域 |
| 3001 | 摄像头USB断连 | 检查摄像头USB口连接 |
| 3002 | 摄像头尚未初始化完成 | 等待摄像头初始化 |
| 3003 | 摄像头停止工作 | 等待相机恢复 |
| 65006 | 此POS的MAC地址绑定过其他设备,请联系管理员确认POS编号 | |
| 65014 | SnCode未找到 | |
| 65017 | 该POS的MAC地址与服务器记录的地址不同,无法解绑 | |
| 65019 | SnCode并未绑定,无需解绑 | |
| 65024 | 该SN码不属于该租户 | |
| 65028 | 该SN码已被其他设备绑定 | |
# 附录 2 :用例说明
## 一、 识别服务程序使用说明
1.
在机器上安装WmLPService-v1.3.13-release.apk服务程序
2.
初次安装后请在桌面找到元芒防损服务程序,点击运行,会弹出权限申请界
面,请同意所需权限
3.
初次使用请先打开设置页面,完成激活码注册和检测区域标定
## 二、 注意事项
1.
相关接口使用请参考演示DEMO工程中的代码
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment