第三方插件 - ThirdPartyPlugins
# 第三方插件
这里主要提供由第三方开发者开发的Auto.js插件。
## Pytorch插件
> 本插件及文档由第三方开发者`浩然`开发和提供,特此感谢。
[Pytorch插件下载](https://wws.lanzous.com/iiz67lpzf3e)(**密码: 4n6x**)
欲使用本模块,请安装Pytorch-AjPlugin扩展插件。并使用`let pytorch = $plugins.load("com.hraps.pytorch")`代码加载。
Pytorch模块提供了已完成的深度学习神经网络模型在安卓设备上执行的功能,可以实现常规程序难以实现的功能,如:图像识别,语言翻译,语言问答等。
使用前需确保已有训练完成的神经网络模型,通过Python将模型文件转化为安卓脚本型文件,通过Python函数`torch.jit.trace(model, input_tensor)`。
如对Pytorch了解较少,个人(指插件作者`浩然`)推荐可以去此网站学习了解:[深度学习Pytorch](http://tangshusen.me/Dive-into-DL-PyTorch/#/)。
可通过`pytorch.debugOd()`测试设备支持性,也可看到本模块在图像检测上的优质识别效果。
### Pytorch权重导出指导
需要将`.pt`文件转换为`.torchscript.pt`文件才可在移动端进行适配,通过张量流追踪,将模型转化至移动端可使用。模型对第三方支持库并不友好,建议使用纯Pytorch编写神经网络模型并训练。
以下为电脑端Python转换脚本。
```python
model = make_model('resnet18') # 导入模型结构
model.load_state_dict(torch.load(model_pt)) # 加载训练完成的权重参数
model.eval() # 模型设为评估模式,一定要开启该模式
input_tensor = torch.rand(1,3,224,224) # 设定输入数据格式,此处模拟了224*224的rgb3通道图片的格式,生成随机张量。
mobile = torch.jit.trace(model, input_tensor,strict=False) # 模型转化
mobile = optimize_for_mobile(mobile) # 移动端优化(可选)
mobile.save(mobile_pt) # 保存文件
```
### 基层函数
#### pytorch.load(path[,device])
* `path` {String} 模型所在路径
* `device` {int} 执行设备,0为CPU,1为VULKAN,默认为0。
* 返回 {PytorchModule}
导入网络模型。仅有少部分设备支持VULKAN,可不使用device参数。
当path的值为"yolov5s"时会导入内置目标检测模型,当path值为"textcnn时会导入内置情感分析模型。"
#### pytoch.forward(module,input)
* `module` {PytorchModule} 已导入的神经网络模型。
* `input` {Tensor} 模型输入张量。
* 返回 {Tensor} 模型的输出张量。
执行网络模型向前推进,得到计算结果。
#### pytoch.forwardTuple(module,input)
* `module` {PytorchModule} 已导入的神经网络模型。
* `input` {Tensor} 模型输入张量。
* 返回 {Tensor} 模型的输出张量。
执行网络模型向前推进,得到计算结果。
与pytorch.forward()的区别在于,他返回的是输出中元组的首项,适用于对应的模型,例如目标检测模型。
他的本质实际上是module.forward(IValue.from(inputTensor)).toTuple()[0].toTensor()。
#### pytorch.destory(module)
* `module` {PytorchModule} 要释放的神经网络模型。
释放神经网络。
### Tensor类
张量类为神经网络的通用输入输出数据结构,便于网络的高速处理,为一个高维数组。如一张图片,大小100*200,有RGB 3通道,那他在传入神经网络前会先转换成100*200*3长的浮点数数组。
#### pytorch.fromBlob(arr,shape)
* `arr` {List} js数组
* `shape` {List<Long>} 转换后张量的形状
* 返回 {Tensor} 生成的张量
从js数组构造张量。
#### tensor.getDataAsFloatArray()
* 返回 {List<float>} 返回张量转换成的float浮点数组
将张量转换成浮点数组。
#### tensor.getDataAs[Byte/Double/Float/Int/Long]Array()
* 返回 {List<...>} 返回张量转换后的数组
将张量转换成各类型数组。
### ObjectDetection 目标检测-功能函数
目标检测用于分析图像中各类物品的位置及其类型,如有不懂可使用pytorch.debugOd()查看效果噢。
#### pytorch.debugOd([modulePath,classPath])
* `modulePath` {String} 模型文件路径 (.pt/.pth文件)
* `classPath` {String} 标签名文件路径 (.txt文件)
测试目标检测模型文件,启动内置调试页。
空传入可使用内置目标检测权重,测试设备支持性。即直接pytorch.debugOd()。
#### pytorch.liveOd(modulePath,classPath)
* `modulePath` {String} 模型文件路径 (.pt/.pth文件)
* `classPath` {String} 标签名文件路径 (.txt文件)
进入摄像头实时识别页面,查看动态推流结果。
#### ObjectDetection(OD) 目标检测-常用函数
用于自行搭建目标检测网络,提供常用的函数。
#### pytorch.getIOU(a,b)
* `a` {Rect} 范围a
* `b` {Rect} 范围b
* 返回 {float} IOU值
计算两矩形的重合率(IOU值),重叠面积比总占面积。
#### pytorch.bitmapToTensor(img[,mean,std])
* `img` {Bitmap} 原始图像
* `mean` {List<float>} 归一化平均值,默认值为[0.485, 0.456, 0.406]
* `std` {List<float>} 归一化标准差,默认值为[0.229, 0.224, 0.225]
* 返回 {Tensor} 图像转换后的Tensor张量
将图像转换成Tensor张量类型,便于输入至网络模型。图像需使用bitmap类型,如图像是Autojs中的image类型,可通过image.getBitmap()转换至bitmap。
mean和std值用于将图片颜色归一化到一定范围之间,请根据模型训练值统一设置。不清楚可设置为[0,0,0] [1,1,1]。
```javascript
img = images.read("/sdcard/a.jpg");
inputTensor = pytorch.bitmapToTensor(img.getBitmap(),[0,0,0],[1,1,1]);
```
#### pytorch.floatsToResults(floats,row,column,imgScaleX,imgScaleY[,threshold])
* `floats` {List<float>} Yolo模型的输出数组
* `row` {int} 输出结果个数
* `column` {int} 每个结果的数据量
* `imgScaleX` {float} 图像X轴缩放比例
* `imgScaleY` {float} 图像Y轴缩放比例
* `threshold` {float} 保留结果的置信度最低值
* 返回 {List<OdResult>} 所有的输出结果
将Yolo模型的输出结果数组转换成识别结果类。floats为输出总数据,floats.length应等于row*column。
在输入模型时有将图片压缩成网络的固定输入大小,在这可通过输入imgScale的XY值反向计算结果位置在原图中的坐标。
Yolo类模型的输出由一个个检测块构成,每个检测块会固定输出结果中心点在其中的预测结果,每个检测结果由置信度,位置,每个类型的概率构成。
如在内置Yolo模型中,每个输出包含这个结果的边框(x,y,w,h)共4个值,这个结果的置信度(即正确率) 1个值,这个结果是每个类型的概率,如输出会有[car:0.2,bus:0.9,boat:0.1]这类数据,内置模型共可识别80种物品。所以最终的column值为4+1+80=85。
row块即为检测块的数量,每个检测块有column个输出数量。
#### pytorch.useNMS(results[,limit,threshold])
* `results` {List<OdResult>} 全部输出结果
* `limit` {int} 最大剩余结果限制
* `threshold` {float} 边框重复率阈值
* 返回 {List<OdResult>} NMS处理后的结果
过滤概率重复的结果。NMS算法即NonMaxSuppression,去除边框中重复率高于threshold的结果。
### OdResult类
用于表示目标检测单个结果的类,包含rect,score,classId三个参数的复合类。
#### odResuult.score
* `score` {float} 获取该结果的置信度,类似于正确率
#### odResult.rect
* `rect` {Rect} 获取该结果的边框位置,有关rect可见images模块的文档
#### odResult.classIndex
* `classIndex` {int} 该目标的类型序号
### NaturalLanguageProcessing(NLP) 自然语言类处理函数
提供自然语言处理模型的相关函数
#### pytorch.debugTec([modulePath,vocabPath])
* `modulePath` {String} 模型文件路径 (.pt/.pth文件)
* `vocabPath` {String} 词汇序号文件路径 (.txt文件)
测试自然语言情感分析TextCNN模型文件,启动内置调试页。
空传入可使用内置情感分析权重,测试设备支持性。即直接pytorch.debugTEC()。
#### pytorch.simplifySentence(sentence)
* `sentence` {String} 输入语句。
* 返回 {String} 化简后的语句。
简化英文语句。仅保留字母数字并全降为小写处理。
### Vocab类
词汇表类,提供较高效的词汇与序号间的转换功能。
#### pytorch.vocabPath(path)
* `path` {String} 词汇表文件路径
* 返回 {Vocab} 词汇表实体
文件应由每行一个单词构成,行号和单词的对应关系应与模型训练时使用的词向量文件一致。
#### pytorch.vocab(words)
* `words` {List<String>} 词汇列表
* 返回 {Vocab} 词汇表实体
#### vocab.size()
* 返回 {long} 词汇表大小
获取该词汇表的内含有的词汇量。
#### vocab.getWord(id)
* `id` {long} 词汇序号
* 返回 {String} 词汇文本
获取词汇表中词汇序号对应的词汇。
#### vocab.getId(word)
* `word` {String} 词汇文本
* 返回 {long} 词汇序号
获取词汇表中词汇文本对应的序号。
#### vocab.getWords(ids[,length])
* `ids` {List<long>} 词汇序号
* `length` {int} 返回列表的长度
* 返回 {List<String>} 词汇文本
获取词汇表中多个词汇序号的词汇文本列表。
#### vocab.getIds(words[,length])
* `words` {List<String>} 词汇文本
* `length` {int} 返回列表的长度,空缺处补0。
* 返回 {List<long>} 词汇序号
获取词汇表中多个词汇问本的词汇序号列表。
### 使用例子
#### 图像目标检测(Yolov5s模型)
```javascript
/**
* Pytorch插件 目标检测算法 Yolov5模型 实现示例
*
* 作者: 浩然(Q:2125764918)
*/
//体验本插件可视化识别效果,可使用此三行代码:
/*
pytorch = $plugins.load("com.hraps.pytorch")
pytorch.debugOd()
exit()
*/
//导入插件模块
pytorch = $plugins.load("com.hraps.pytorch")
//导入神经网络模型 输入模型文件路径 (此处导入了内置Yolov5s模型)
var model = pytorch.load("yolov5s")
//导入识别结果对应类型名 (为类名构成的字符串数组,可自己写死,如["car","plane","person"...])
var classes = pytorch.getCocoClasses()
//定义模型输入图片的边长 输入维度为w*h*3
var inputWidth = 640
var inputHeight = 640
//定义模型输出数量以及每个的大小 输出维度为row*column
//row为yolo模型的分格数,由输入大小有关
var outputRow = 25200
//column为每个分格的维度,由 位置(x,y,w,h)4个值,分数(score)1个值,类型(coco数据集80个类)80个值,共计85个值
var outputColumn = 4 + 1 + 80
//导入需识别的图片
var img = images.read("/sdcard/DCIM/Camera/b.jpg")
//缩放至模型输入维度
var inputImg = images.resize(img, [inputWidth, inputHeight])
//图片转换至张量 MEAN和STD值设置为000和111,即不启用特殊归一化
inputTensor = pytorch.bitmapToTensor(inputImg.getBitmap(), [0, 0, 0], [1, 1, 1])
//执行神经网络推进 获得输出张量
output = pytorch.forwardTuple(model, inputTensor)
//张量转浮点数组
f = output.getDataAsFloatArray()
log("模型输出维度: " + f.length)
//计算图形缩放比例
imgScaleX = img.getWidth() / inputWidth
imgScaleY = img.getHeight() / inputHeight
//还原识别结果的真实位置 转换至目标检测结果类数组
results = pytorch.floatsToResults(f, outputRow, outputColumn, imgScaleX, imgScaleY)
log("网络初始识别数量: " + results.size())
//NMS算法过滤重复结果
nmsResults = pytorch.useNMS(results)
toastLog("最终结果数量: " + nmsResults.size())
//遍历输出结果
for (var i = 0; i < nmsResults.size(); i++) {
result = nmsResults.get(i)
rect = result.rect
str = "类型: " + classes.get(result.classIndex) + " 置信度: " + result.score + " 位置: 左" + rect.left + " 上" + rect.top + " 右" + rect.right + " 下" + rect.bottom;
log(str)
}
```
#### 自然语言情感分析(TextCNN模型)
```javascript
/**
* Pytorch插件 语言情感分析算法 TextCNN模型 实现示例
*
* 作者: 浩然(Q:2125764918)
*/
//体验本插件效果,可使用此行代码:
/*
pytorch = $plugins.load("com.hraps.pytorch")
pytorch.debugTec()
exit()
*/
//需识别的语句
var text = "The program is useful!"
//导入插件模块
pytorch = $plugins.load("com.hraps.pytorch")
//导入神经网络模型 输入模型文件路径 (此处导入了内置textcnn模型)
var model = pytorch.load("textcnn")
//导入词汇表 由一行一单词的txt文件构成 行号和单词应与模型训练时词向量序号对应 (此处导入了内置模型对应词汇表)
var vocab = pytorch.getTextcnnVocab()
log("词汇表导入成功,共计" + vocab.size() + "个");
//语句简单化处理 过滤标点 全部小写
var textSimple = pytorch.simplifySentence(text)
log("简单化语句: " + textSimple);
//定义模型输入词汇量长度
var inputSize = 128
//根据词汇表将语句换成词向量序号 未知单词与长度不足处自动补0
var ids = vocab.getIds(textSimple.split(" "), inputSize)
log(ids)
//将列表构造成Tensor类型,适合网络输入
var inputTensor = pytorch.fromBlob(ids, [1, 128])
//执行模型得到输出结果
var outPutTensor = pytorch.forward(model, inputTensor)
//输出张量转换为浮点数组
var result = outPutTensor.getDataAsFloatArray()
log("模型输出: " + result[0] + " " + result[1])
//分析结果
console.info("语句:" + text)
if (result[0] <= result[1]) {
console.info("结果为:正面情感")
} else {
console.info("结果为:负面情感")
}
```
## OCR插件
> 本插件及文档由第三方开发者`浩然`开发和提供,特此感谢。
该模块可实现对图像中的文字进行识别,使用示例可见本章末。采用了最前沿的DbNet+AngleNet+CrnnNet的深度学习思路实现。
插件下载:[蓝奏云](https://wws.lanzous.com/iduulmofune) (**密码: habv**)
 
### 识别函数
#### ocr.detect(img[,ratio])
* `img` {Bitmap} 需识别的图像,为Bitmap类型,Autojs中的图像可通过图像的.getBitmap()方法进行转换。
* `ratio` {float} 缩放比率,默认为1,在识别较小的图片时可适当调小。
* 返回 {List<OcrResult>} 识别结果构成的列表,详情见下文OcrResult类。
OCR识别函数,初次调用会自动进行初始化。使用示例可见本章末。
### 结果过滤函数
#### ocr.filterScore(results,dbnetScore,angleScore,crnnScore)
* `results` {List<OcrResult>} 需过滤的结果列表
* `dbnetScore` {float} 该区域为文字的置信度的下限
* `angleScore` {float} 文字方向类型的置信度的下限
* `crnnScore` {float} 所有文字识别的平均置信度的下限
* 返回 {List<OcrResult>} 过滤后的结果列表
用于过滤一些置信度较低的结果,不需过滤的选项请填0。
 
### OcrResult类
该类为OCR的识别结果类,一个实类为一个结果项。
#### ocrResult.text
* {String} 识别结果的文本
#### ocrResult.frame
* {List<int>} 识别结果的位置
识别结果为一个任意四边形,返回的是长度为8的整形列表。
分别为四个顶点的横纵坐标,即[x1,y1,x2,y2,x3,y3,x4,y4]。
#### ocrResult.angleType
* {int} 结果的文本角度类型
#### ocrResult.dbnetScore
* {float} 结果区域为文字的置信度
#### ocrResult.angleScore
* {float} 结果文字角度类型的置信度
#### ocrResult.crnnScore
* {List<float>} 识别结果的每个字的置信度列表
### 使用示例
 
```javascript
//导入插件
ocr = $plugins.load("com.hraps.ocr")
//导入需识别的图片,请自行输入图片路径
img = images.read("./test.jpg")
//识别图片
results = ocr.detect(img.getBitmap(),1)
console.info("过滤前结果数:"+results.size())
//识别结果过滤
results = ocr.filterScore(results,0.5,0.5,0.5)
//输出最终结果
for(var i=0;i<results.size();i++){
var re = results.get(i)
log("结果:"+i+" 文字:"+re.text+" 位置:"+re.frame+" 角度类型:"+re.angleType)
log("区域置信度:"+re.dbScore+" 角度置信度:"+re.angleScore+" 文字置信度:"+re.crnnScore+"\n")
}
```