引言
- 本插件是基于百度EasyEdge开发的AutojsPro插件,插件 完全免费
- 已在安卓13、安卓14机型测试,目前没发现有啥问题
- 插件最新版 已支持 雷电9模拟器,其它模拟器和云机自行测试,原则上讲同样适配
- 若需定制脚本请移步 软件|源码定制 页
- 插件提供了两个架构:armeabi-v7a 、arm64-v8a
QQ交流群
Autojs、按键精灵、易语言、懒人精灵等自动化编程学习交流,知识探讨,共同进步!欢迎萌新与大佬们的加入!
自动化编程学习交流群
:606759894
插件界面
插件下载
注:如果用手机浏览器打开的话会显示非会员无法浏览,去浏览器的设置里把浏览器标识设置为
桌面端
再打开就行了!
蓝奏云网盘:点我跳转下载页(密码:aup0)
对接视频教程(附实战)
待录制...估计2024.11.5前录制
识别模型
插件提供了两个OCR识别模型:
- PP-OCRv3(精度高)
检测模块基于DB算法优化,识别模型基于文本识别算法SVTR,并对其进行产业适配,模型大小为15.6M。 - PP-OCRv3-tiny(速度快)
PP-OCRv3模型的量化版本,在稍微精度损失的条件下,模型压缩到6M。
关于报错的解决办法
这是没选好对应插件架构的问题
详细报错如下:
Wrapped com.stardust.autojs.core.plugin.Plugin$PluginLoadException:
com.stardust.autojs.core.plugin.Plugin$PluginLoadException:
java.lang.UnsatisfiedLinkError: dlopen failed:
"/data/app/com.daowuya.ppocrv3-nslAuNQgs_svQInvH0Vghw==/lib/arm/libdwynbProtect.so" is 32-bit instead of 64-bit
解决方式:
- 如果是调试时报错,换另一个架构的插件就行了
- 如果是打包后报错,强烈建议aj打包界面的CPU结构选项不要选择
armeabi-v7a,arm64-v8a
,建议单独选一个就好了,选的是哪个就对应使用哪个架构的插件。
为啥呢?因为可能出现某些情况:例如如果两个架构都勾选,有些模拟器可能使用脚本的v7a架构,但却使用插件的v8架构,这样就触发了上面的报错了!
Autojs对接代码
插件JSON返回示例
- text:识别到的文本
- region:文本所在范围:左上角x,左上角y,右上角x,右上角y
- confidence:置信度
[
{ text: '道无涯',
region: [173, 666, 302, 1133],
confidence: 0.91
},
{ text: '插件',
region: [298, 674, 1161, 1076],
confidence: 0.94
}
]
读取本地图片进行识别
/***
* 作者: 道无涯i,脚本定制联系:daowuya02
* 日期: 2024-10-1 15:21:29
* 描述: 读取本地图片进行OCR识别代码示例
* 必填参数1:imagePath,图片路径
* 必填参数2:confidence,识别置信度
*/
// 加载插件,只需要加载一次
var ppOCR = $plugins.load("com.daowuya.ppocrv3");
// 是否加载PP-OCRv3-tiny量化模型,true为加载;否则默认加载PP-OCRv3模型
var tiny = false
//初始化,加载模型,只需要加载一次
ppOCR.init(tiny)
var imagePath = "/storage/emulated/0/daowuya.png"
var confidence = 0.3
var ocr_image = null
ocr_image = images.read(imagePath)
var result = ppOCR.ocr(ocr_image.bitmap, confidence)
console.log(result)
// 识别完回收图片,防止内存泄漏
ocr_image.recycle()
ocr_image = null
events.on("exit", function () {
//脚本退出或者不需要识别时调用,卸载模型,释放内存
ppOCR.exit()
if(ocr_image){
ocr_image.recycle()
}
});
实时截屏识别并绘制
/***
* 作者: 道无涯i,脚本定制联系:daowuya02
* 日期: 2024-10-1 15:21:29
* 描述: 实时截屏进行OCR识别代码示例
* 必填参数:confidence,识别置信度
* 注意:使用下面代码前,请在根目录创建drawFloaty.js,并将文章文末的【附录:drawFloaty.js】内容黏贴并保存
*/
// 加载插件,只需要加载一次
var ppOCR = $plugins.load("com.daowuya.ppocrv3");
// 是否加载PP-OCRv3-tiny量化模型,true为加载;否则默认加载PP-OCRv3模型
var tiny = false
//初始化,加载模型,只需要加载一次
ppOCR.init(tiny)
// 绘制初始化
var drawFloaty = require('./drawFloaty.js');
drawFloaty.init({
statusBarHeight: drawFloaty.getStatusBarHeight()
});
var capture = null
events.on("exit", function () {
//脚本退出或者不需要识别时调用,卸载模型,释放内存
ppOCR.exit()
if(capture){
capture.recycle()
}
});
var confidence = 0.3
while (true) {
capture = $automator.takeScreenshot();
// // 如果需要裁剪的话
// capture = images.clip(capture, left, top, w, h);
var result = ppOCR.ocr(capture.bitmap, confidence)
var bbox = []
for (let i = 0; i < result.length; i++) {
bbox.push({
region: result[i].region,
text: result[i].text
})
}
drawFloaty.draw(bbox, 500);
console.log(`\n本次共识别到${result.length}个结果`)
capture.recycle()
capture = null
sleep(1000);
}
附录:drawFloaty.js
实时绘制代码,本代码来自群聊 webpack-autojs 群文件,最新代码优化自 Ling
let drawFloaty = {
instance: null,
toDraw: [],
option: {
statusBarHeight: 0
},
getStatusBarHeight() {
let resources = context.getResources();
let resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
let height = resources.getDimensionPixelSize(resourceId);
return height;
},
init(option) {
if (!!this.instance) return;
this.option.statusBarHeight = option.statusBarHeight || 0;
this.instance = floaty.rawWindow(
<frame id="frame">
<canvas id="board" />
</frame>
);
ui.run(() => {
this.instance.frame.getRootView().getLayoutParams().alpha = 0.8; // alpha设置0.8,在安卓12以上实现悬浮窗穿透
this.instance.setTouchable(false);
this.instance.setSize(-1, -1);
});
// 绘制区域 描边
let paintRect = new Paint();
paintRect.setStyle(Paint.Style.STROKE); // 设置画笔样式,描边
paintRect.setAntiAlias(false); // 设置是否开启抗锯齿,一般在绘制棱角分明的图形比如矩形,位图时不需要开启
paintRect.setFilterBitmap(true); // 对位图进行滤波处理,如果该项设置为 true,则图像在动画进行中会滤掉对 Bitmap 图像的优化操作,加快显示
paintRect.setStrokeWidth(10); // 设置画笔宽度
paintRect.setARGB(204, 255, 48, 48); // 设置画笔透明度和颜色
// 绘制区域 填充内部和描边
let paintRect2 = new Paint();
paintRect2.setStyle(Paint.Style.FILL_AND_STROKE); // 设置画笔样式,填充内部和描边
paintRect2.setAntiAlias(false); // 设置是否开启抗锯齿,一般在绘制棱角分明的图形比如矩形,位图时不需要开启
paintRect2.setFilterBitmap(true); // 对位图进行滤波处理,如果该项设置为 true,则图像在动画进行中会滤掉对 Bitmap 图像的优化操作,加快显示
paintRect2.setStrokeWidth(10); // 设置画笔宽度
paintRect2.setARGB(204, 255, 48, 48); // 设置画笔透明度和颜色
// 绘制文字 填充内部
let paintText = new Paint();
paintText.setStyle(Paint.Style.FILL); // 设置画笔样式,填充内部
paintText.setAntiAlias(true); // 设置是否开启抗锯齿,一般在绘制棱角分明的图形比如矩形,位图时不需要开启
paintText.setFilterBitmap(true); // 对位图进行滤波处理,如果该项设置为 true,则图像在动画进行中会滤掉对 Bitmap 图像的优化操作,加快显示
paintText.setFakeBoldText(false); // 模拟实现粗体文字,设置在小字体上效果会非常差
paintText.setTextSize(32); // 设置字体大小,必须大于0
paintText.setARGB(255, 255, 255, 255); // 设置画笔透明度和颜色
// 参数为 LAYER_TYPE_SOFTWARE 时,使用软件来绘制 View Layer,绘制到一个 Bitmap,并顺便关闭硬件加速;
// 参数为 LAYER_TYPE_HARDWARE 时,使用 GPU 来绘制 View Layer,绘制到一个 OpenGL texture(如果硬件加速关闭,那么行为和 VIEW_TYPE_SOFTWARE 一致)
// 参数为 LAYER_TYPE_NONE 时,关闭 View Layer。 View Layer 可以加速无 invalidate() 时的刷新效率,但对于需要调用 invalidate() 的刷新无法加速。
this.instance.board.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
this.instance.board.on("draw", canvas => {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
let now = Date.now();
let toDraw = this.toDraw || [];
toDraw.forEach((item, i) => {
if (item && now >= item.old) {
this.toDraw.splice(i, 1);
return;
}
canvas.drawRect(item.region[0], item.region[1], item.region[2], item.region[3], paintRect);
if (item.text) {
let textWidth = paintText.measureText(item.text);
canvas.drawRect(item.region[0], item.region[1] - 38, item.region[0] + textWidth + 10, item.region[1], paintRect2);
canvas.drawText(item.text, item.region[0] + 6, item.region[1] - 8, paintText);
}
});
});
},
draw(arr, time) {
if (arr.length == 0) return;
arr.forEach(item => {
item.region[1] = item.region[1] - this.option.statusBarHeight;
item.region[3] = item.region[3] - this.option.statusBarHeight;
item.old = Date.now() + (time || 500);
})
this.toDraw = arr
// this.toDraw = this.toDraw.concat(arr);
},
drawImg(arr, image, path) {
// 绘制区域 描边
let paintRect = new Paint();
paintRect.setStyle(Paint.Style.STROKE); // 设置画笔样式,描边
paintRect.setAntiAlias(false); // 设置是否开启抗锯齿,一般在绘制棱角分明的图形比如矩形,位图时不需要开启
paintRect.setFilterBitmap(true); // 对位图进行滤波处理,如果该项设置为 true,则图像在动画进行中会滤掉对 Bitmap 图像的优化操作,加快显示
paintRect.setStrokeWidth(4); // 设置画笔宽度
paintRect.setARGB(153, 255, 48, 48); // 设置画笔透明度和颜色
// 绘制区域 填充内部和描边
let paintRect2 = new Paint();
paintRect2.setStyle(Paint.Style.FILL_AND_STROKE); // 设置画笔样式,填充内部和描边
paintRect2.setAntiAlias(false); // 设置是否开启抗锯齿,一般在绘制棱角分明的图形比如矩形,位图时不需要开启
paintRect2.setFilterBitmap(true); // 对位图进行滤波处理,如果该项设置为 true,则图像在动画进行中会滤掉对 Bitmap 图像的优化操作,加快显示
paintRect2.setStrokeWidth(4); // 设置画笔宽度
paintRect2.setARGB(153, 255, 48, 48); // 设置画笔透明度和颜色
// 绘制文字 填充内部
let paintText = new Paint();
paintText.setStyle(Paint.Style.FILL); // 设置画笔样式,填充内部
paintText.setAntiAlias(true); // 设置是否开启抗锯齿,一般在绘制棱角分明的图形比如矩形,位图时不需要开启
paintText.setFilterBitmap(true); // 对位图进行滤波处理,如果该项设置为 true,则图像在动画进行中会滤掉对 Bitmap 图像的优化操作,加快显示
paintText.setFakeBoldText(false); // 模拟实现粗体文字,设置在小字体上效果会非常差
paintText.setTextSize(32); // 设置字体大小,必须大于0
paintText.setARGB(204, 255, 255, 255); // 设置画笔透明度和颜色
let canvas = new Canvas(image);
arr.forEach(item => {
let region = item.region;
let text = item.text;
canvas.drawRect(region[0], region[1], region[2], region[3], paintRect);
if (text) {
let textWidth = paintText.measureText(text);
canvas.drawRect(region[0], region[1] - 38, region[0] + textWidth + 10, region[1], paintRect2);
canvas.drawText(text, region[0] + 6, region[1] - 8, paintText);
}
});
let image = canvas.toImage();
images.save(image, path);
media.scanFile(path)
image.recycle();
},
destroy() {
if (this.instance) {
this.instance.board.removeAllListeners();
this.instance.close();
this.instance = null;
}
}
};
module.exports = drawFloaty;