# Windows SDK

该对接协议适用于AI秤服务版。

# 版本记录

版本号 发版时间 更新说明
2.5.0.31 2022/10/25 1、增加摄像头异常恢复机制
2、增加学习数据自动恢复机制
3、识别服务激活逻辑完善
4、修复:识别服务标定范围后没有保存bug
2.5.0.32 2022/10/30 1、集成新版本算法,支持预置模型
2、重构后台数据库读写逻辑,解决数据增加大时可能引起的数据损坏和异常
3、增加通过云图库获取商品图片接口(6.4)
4、识别服务托盘图标点击直接弹出选项界面
5、其他bug修复
2.5.0.33 2022/11/02 1、标定范围支持任意四边形,增加对应读写接口(5.4,5.5)
2、学习数据导入功能完善,增加追加导入
3、其他bug修复
2.5.0.34 2022/11/10 1、32位读秤中间件
2、增加主动学习、特征清理、摄像头列表接口
2.5.0.35 2022/11/19 1、增加demo
2、识别服务完善

# 一、前言

# 1.1 传输协议

  • TCP,建议长链接

# 1.2 地址

  • IP(固定):127.0.0.1
  • 端口号(固定):5566

# 1.3 解释

  • Y->必传/必反
  • N->非必传/必反

# 1.4 接口指令

指令 说明
200 识别
201 反馈(学习)
202 激活
203 检测激活状态
204 获取当前捕捉图片(服务接管摄像头时有效)
205 设置标定范围(矩形)
206 获取标定范围(矩形)
207 清除学习特征(单个商品或全部)
208 解绑设备
209 查询版本号
210 初始化摄像头
211 导出学习文件
212 导入学习文件
213 获取商品示例图片
214 设置标定范围(4点)
215 获取标定范围(4点)
216 主动学习
217 特征清理(删除与当前识别商品相似的特征)
218 获取摄像头列表

# 1.5 配置要求

  • 操作系统:64位Win7或Win10
  • CPU:J1900+
  • 内存:4G+
  • 硬盘:128G+

# 1.6 常见问题

  • Q:WinSDK为什么采用TCP服务的方式?

A:一方面,是因为很多收银软件是32位版本,没办法直接调用64位动态库(算法需要64位环境);另一方面,独立服务集成了基本的界面交互,方便用户快速对接**

  • Q:摄像头建议服务接管,还是收银软件自己管理?

A:建议服务接管,减少对接工作量,当需要预览图片时,可以通过“获取图片”接口来获取当前拍照图片。如果确实需要收银软件自己管理摄像头的,应避免实时渲染摄像头画面,图像渲染会占用大量CPU,导致设备卡顿及识别速度下降

  • Q:识别速度慢,或时快时慢是什么原因?

A:正常识别速度在 200 ms/次左右,识别速度慢通常是CPU可用资源不足导致的,首先确认设备是否满足最低配置要求(见1.5节),然后通过任务管理器查看CPU占用情况,J1900上大约需要预留40%的CPU给算法。通常远程软件(向日葵、TODESK等)、播放摄像头画面都会占用大量CPU

  • Q:建议什么时候调用或多久调用一次识别?

A:建议当重量满足一定条件时触发一次(触发重量可以作为参数放开,如20g),也可以加一个延时来控制首次识别的时机。如果担心前面的时机不好控制,可以在重量稳定以后再触发一次识别,也就是一次称重最多调用两次识别就够了

  • Q:什么时候重置识别状态,即开始下一次识别?

A:秤盘清空时重置识别状态。但经常会有秤不归零的情况,导致识别状态重置失败,无法触发下一次识别。因此当重量稳定且小于触发重量时,就可以认为秤盘清空了。相关代码逻辑可以参考DEMO实现

  • Q:感觉学不会?

A:首次学习后识别一定会有结果。首先确认一下学习接口是否返回成功。学习接口需要传入最新识别结果返回的requestId,如果requestId不传或不是最新的,就会导致学习失败

  • Q:感觉识别不准?

A:确认一下标定范围设置是否正确(服务托盘图标,选项,设置识别范围),另外看一下识别返回结果的置信度,如果不相似的商品置信度很低,那就是正常的。收银软件可以根据实现需求,对低置信度候选进行过滤

  • Q:接口参数都按要求传了,但返回结果不符合预期

A:确保参数类型正确,如数值和字符串不能混,子对象不能传string等

# 二、系统对接

# 2.1 对接流程

对接流程图

# 2.2 连接服务

TCP协议,IP固定为:127.0.0.1,端口固定为:5566

//连接识别服务
QTcpSocket *socket = new QTcpSocket();
socket->connectHost("127.0.0.1", 5566);
socket->waitForConnected(3000);

# 2.3 初始化摄像头

识别服务默认不接管摄像头,如需识别服务接管摄像头,则需要调用初始化接口,指定要接管的摄像头(只有一个摄像头的话,传cameraId传0即可)。

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:210
cameraId Y int -1:关闭摄像头;[0-N]:摄像头序号

请求示例

#JSON数据
{
   	"cmd": 210,
    "cameraId" 0
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":210,
	"status":0,
	"message":"Success"
}

# 三、识别学习

# 3.1 识别

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:200
topK Y int 期望返回的识别候选数量 ,如:5
img N string 图片base64,先把图片压缩到640*480再传输。由服务接管摄像头时,该字段不需要填。

请求示例

#JSON数据
{
    "cmd":200,
    "topK":5,
    "img"::[BASE64]
}
#C++调用Demo
//发送请求
QJsonObject js;
js["cmd"] = 200;
js["topK"] = 5;

//服务接管摄像头时,img字段不需要传;否则需要传入待识别的图片
{
    QByteArra imgData;
    QFile f('test.jpg');
    if (f.open(QIODevice::readOnly))
    {
        QByteArray ba = f.readAll();
        imgData = ba.toBase64();
    }
    js["img"] = imgData;
}

QByteArray ba = QJsonDocument(js).toJson();
QString data = "FEEE_" + ba + "_EEEF";
socket->write(data.toUtf8());
if (socket->waitForBytesWritten(10000))
{
    qDebug() << "success";
}
else
{
    qDebug() << "failed";
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 200
2 status Y int 成功:0,失败:其他
3 requestId Y string 识别记录id,反馈时需要回传
4 data Y Array 识别结果,按置信度排序
5 +code Y string PLU码
6 +confidence Y double 置信度

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd": 200,
    "data": [
        {
            "code": "101",
            "confidence": 0.9879869818687439
        }
    ],
    "requestId": "{0fbd0406-6806-42dc-93e5-d5e72f57b80e}",
    "status": 0
}

# 3.2 反馈

收银软件每次确认商品后,都需要调用反馈接口,将实际选择的商品信息反馈给识别服务,从而不断优化识别准确率。反馈接口传入的requestId与识别接口返回的requestId对应。

每次识别会返回新的requestId,相应的每个requestId也只应该反馈一次,反馈后应该及时清空。

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:201
requestId Y string 识别记录id,随识别结果返回
data Y Object
+code Y string 商品PLU码
+name Y string 商品名称

请求示例

#JSON数据
{
   	"cmd": 201,
	"requestId" : "{0fbd0406-6806-42dc-93e5-d5e72f57b80e}",
	"data": {
		"code" : "101",
		"name" : "苹果"
	}
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":201,
	"status":0,
	"message":"Success"
}

# 四、设备激活

# 4.1 激活

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:202
data Y Object
+merchant Y string 商户名称
+shopName Y string 门店名称
+posNo Y string POS编号
+storeNo Y string 激活账号,食方提供给渠道
+license Y string 激活码,食方提供给渠道

请求示例

#JSON数据
{
   	"cmd": 202,
	"data": {
		"merchant" : "北京物美",
		"shopName" : "中关村店",
		"posNo" : "POS1",
		"storeNo" : "SN-XXXXXX",
		"license" : "5UZ7-5E2R-3LX4-XXXX",
	}
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":202,
	"status":0,
	"message":"Success"
}

# 4.2 解绑

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:208

请求示例

#JSON数据
{
   	"cmd": 208
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":208,
	"status":0,
	"message":"Success"
}

# 4.3 是否已激活

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:203

请求示例

#JSON数据
{
   	"cmd": 203
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 已激活:0,未激活:1
3 message Y string 已激活:activated,未激活:inactive

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":203,
	"status":0,
	"message":"activated"
}

# 五、范围标定

# 5.1 获取图片

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:204

请求示例

#JSON数据
{
   	"cmd": 204
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因
4 img Y string 图片BASE64

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":204,
	"status":0,
	"message":"Success",
    "img":"[BASE64]"
}

# 5.2 设置识别范围_v1

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:205
data Y Object
+x Y int left
+y Y int top
+w Y int width
+h Y int height

请求示例

#JSON数据
{
   	"cmd": 205,
    "data": {
        "x": 407,
        "y": 543,
        "w": 52,
        "h": 30        
    }
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":205,
	"status":0,
	"message":"Success"
}

# 5.3 获取识别范围_v1

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:206

请求示例

#JSON数据
{
   	"cmd": 206
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因
4 data Y Object
5 +x Y int left
6 +y Y int top
7 +w Y int width
8 +h Y int height

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":206,
	"status":0,
	"message":"Success",
    "data": {
        "x": 407,
        "y": 543,
        "w": 52,
        "h": 30        
    }
}

# 5.4 设置识别范围_v2

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:214
data Y Object
+topLeft Y Object 左上角点
++x Y int x坐标
++y Y int y坐标
+topRight Y Object 右上角点
++x Y int x坐标
++y Y int y坐标
+bottomRight Y Object 右下角点
++x Y int x坐标
++y Y int y坐标
+bottomLeft Y Object 左下角点
++x Y int x坐标
++y Y int y坐标

请求示例

#JSON数据
{
   	"cmd": 214,
    "data": {
		"bottomLeft": {
			"x": 0,
			"y": 480
		},
		"bottomRight": {
			"x": 640,
			"y": 480
		},
		"topLeft": {
			"x": 0,
			"y": 0
		},
		"topRight": {
			"x": 640,
			"y": 0
		}     
    }
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":214,
	"status":0,
	"message":"Success"
}

# 5.5 获取识别范围_v2

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:215

请求示例

#JSON数据
{
   	"cmd": 215
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因
4 data Y Object
5 +topLeft Y Object 左上角点
6 ++x Y int x坐标
7 ++y Y int y坐标
8 +topRight Y Object 右上角点
9 ++x Y int x坐标
10 ++y Y int y坐标
11 +bottomRight Y Object 右下角点
12 ++x Y int x坐标
13 ++y Y int y坐标
14 +bottomLeft Y Object 左下角点
15 ++x Y int x坐标
16 ++y Y int y坐标

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":215,
	"status":0,
	"message":"Success",
    "data": {
		"bottomLeft": {
			"x": 0,
			"y": 480
		},
		"bottomRight": {
			"x": 640,
			"y": 480
		},
		"topLeft": {
			"x": 0,
			"y": 0
		},
		"topRight": {
			"x": 640,
			"y": 0
		}     
    }
}

# 六、其他接口

# 6.1 清除学习数据

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:207
code N string 指定code时,只清对应商品数据;否则清除所有学习数据

请求示例

#JSON数据
{
   	"cmd": 207,
    "code":"1001"
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":207,
	"status":0,
	"message":"Success"
}

# 6.2 导出学习数据

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:211
outputDir Y string 特征文件导出文件夹

请求示例

#JSON数据
{
   	"cmd": 211,
    "outputDir":"D:/"
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因
4 file Y string 导出的特征文件路径

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":211,
	"status":0,
	"message":"Success",
    "file":"D:/2022-10-22.sfd"
}

# 6.3 导入学习数据

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:212
file Y string 特征文件路径

请求示例

#JSON数据
{
   	"cmd": 212,
    "file":"D:/2022-10-22.sfd"
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":212,
	"status":0,
	"message":"Success"
}

# 6.4 获取商品图片

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:213
name Y string 商品名称
savefile Y string 图片保存路径

请求示例

#JSON数据
{
   	"cmd": 213,
    "name":"苹果",
    "savefile":"D:/sample/苹果.jpg"
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":213,
	"status":0,
	"message":"Success"
}

# 6.5 获取版本号

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:209

请求示例

#JSON数据
{
   	"cmd": 209
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因
4 ver Y string 版本号,如:2.5.0.27

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":209,
	"status":0,
	"message":"Success",
    "ver":"2.5.0.27"
}

# 6.6 主动学习

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:216
code Y string 商品PLU
name N string 商品名称
imageFile Y string 商品图片

请求示例

#JSON数据
{
   	"cmd": 216,
    “code”:"1001",
    "name":"苹果",
    "imageFile":"C:\\pg.jpg"
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":216,
	"status":0,
	"message":"Success"
}

# 6.7 特征清理

特征清理接口用于主动反馈错误的候选结果。识别服务本身在学习和反馈的过程中会自动清理异常特征,但我们会认为主动调用特征清理接口具有更高的优先级。当待清理的商品类别的平均特征与当前识别特征有明显差别时,特征清理接口会清除这些异常特征。当待清理商品类别本身特征数据较少或与当前识别特征差别较小时,接口会清除该商品类别下的全部特征,请谨慎操作。

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:217
code Y string 商品PLU
requestId Y string 最后一次识别返回的requestId

请求示例

#JSON数据
{
    "cmd": 217,
    "code": "1002",
    "requestId": "{0fbd0406-6806-42dc-93e5-d5e72f57b80e}"
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":217,
	"status":0,
	"message":"Success"
}

# 6.8 获取摄像头列表

参数

FEEE_ + JSON数据 + _EEEF

参数名称 必填 类型和范围 说明
cmd Y int 固定值:218

请求示例

#JSON数据
{
   	"cmd": 218
}

返回参数

序号 参数名 是否必返 类型 注释
1 cmd Y int 操作指令
2 status Y int 成功:0,失败:1
3 message Y string 成功:Success,失败:返回错误原因
4 data Y array 摄像头列表

返回示例(带起止符):

FEEE_ + JSON数据 + _EEEF

#JSON数据
{
    "cmd":218,
	"status":0,
	"message":"Success",
    "data":[
        "RGB Camera",
        "USB Camera"
    ]
}

# 七、选项参数

基础设置图

# 7.1 摄像头设置

除了可以通过接口设置摄像头,也可以通过识别服务的的选项设置修改摄像头参数

# 7.2 识别范围标定

只有识别服务接管摄像头时,才能在服务端标定识别范围。识别范围需包含秤盘边缘,如图所示:

识别范围图

# 7.3 清除数据

清除数据,会清除所有学习数据,请谨慎操作。

# 八、设备信息

# 8.1 设备信息

设备信息图

# 8.2 激活注销

账号和授权码请联系食方商务申请。

激活码图