images 图像与截图
images 图像与截图
images 是 ScriptX 里负责“读图、存图、截图、改图、找色、找图、做简单图像分析”的模块对象。
这一页会尽量按“第一次接触也能直接照着写”的方式来讲,不只列方法名,还把这些细节说清楚:
- 参数到底能填什么。
- 哪些值是固定可选值。
- 不传参数时默认会怎样。
- 返回值是
null、false、图片对象,还是别的结果对象。 - 哪些地方是别名,哪些地方只是名字看起来像别名。
- 哪些参数当前源码里其实还没真正参与逻辑。
这一页只按 当前 ScriptX 源码已经实现 的能力来写,不按 Auto.js 旧印象脑补不存在的接口。
先记住这 15 条
images.captureScreen()走的是 MediaProjection 截图权限;而 automator.takeScreenshot() 走的是 无障碍截图,这两套不是一回事。images.requestScreenCaptureAsync()虽然名字叫 Async,但当前实现和images.requestScreenCapture()走的是同一套同步流程,脚本里拿到的仍然是布尔结果。- 大多数图像处理 API 都不会原地修改原图,而是返回一张新的
Image。 images.read()/images.load()解码失败时可能返回null;但像images.resize()、images.findColor()这种需要真图片对象的 API,传错就会直接抛错。- 颜色值不只支持
#RRGGBB,还支持0xRRGGBB、0xAARRGGBB、rgb(...)、[r, g, b]、[r, g, b, a]。 - 区域参数统一按
[x, y, width, height]理解;越界区域会被裁进图片范围里,而不是直接报错。 images.save()会把相对路径解析到当前脚本 / 当前项目目录;image.saveTo()则直接按你传入的原始文件路径去写,两者不要混。images.fromBytes()读的是真实字节内容,不是 Base64;Base64 请用images.fromBase64()。images.captureScreen(path)传了非空路径时,返回的是boolean;不传路径时,返回的是Image。images.findColor()的options里如果同时写了similarity和threshold,当前实现是similarity优先。images.findColorEquals()本质上就是threshold = 0的找色。images.blur()的anchor/type参数当前实现还没有真正用到;images.gaussianBlur()的type也一样。images.detectsColor()的algorithm参数当前实现也没有参与判断,只保留了调用位。images.cvtColor()如果你传了不认识的颜色转换码,当前实现不是抛错,而是直接拷贝原图返回。images.matchFeatures()当前实现更接近“按图框选目标区域”,它接受ImageFeatures,但现在主要还是使用底层图片本身,不是完整的特征描述子配准流程。
先分清 images.captureScreen() 和 automator.takeScreenshot()
这两个最容易让新手混掉。
| API | 依赖 | 系统要求 | 典型用途 |
|---|---|---|---|
images.requestScreenCapture() + images.captureScreen() | MediaProjection 截图授权 | Android 5.0+ | 持续截图、图像处理、找色找图 |
automator.takeScreenshot() | 无障碍服务截图能力 | Android 11+ | 自动化脚本里顺手拿一张当前界面图 |
如果你后面还要继续跑:
findColorfindImagematchTemplatedetectsMultiColors
这种图像分析 API,通常更适合走 images.captureScreen() 这一套。
通用参数写法
颜色值支持哪些写法
当前源码里,颜色参数统一会走同一套解析逻辑,所以下面这些写法都能用:
| 写法 | 例子 | 说明 |
|---|---|---|
| 十六进制数字 | 0xff00ff00 | 明确写 ARGB |
| 六位十六进制数字 | 0x00ff00 | 会自动补成 0xff00ff00 |
#RRGGBB | "#00ff00" | 会自动补不透明 alpha |
#AARRGGBB | "#ff00ff00" | 直接按带 alpha 颜色读 |
rgb(...) | "rgb(255, 0, 0)" | 第 4 个值可选,表示 alpha |
| 数组 | [255, 0, 0] | 代表 r, g, b |
| 四元数组 | [255, 0, 0, 128] | 代表 r, g, b, a |
注意两点:
- 数组顺序是
r, g, b, a,不是a, r, g, b。 images.fromBytes()不会把字符串当颜色;只有图像相关颜色参数才走这套解析。
区域参数怎么写
图像区域统一按下面这个顺序理解:
[x, y, width, height]
例如:
region: [100, 200, 300, 400]
表示:
- 左上角从
(100, 200)开始 - 宽
300 - 高
400
如果区域越界,当前实现会裁进图片可用范围内,而不是直接报错。
尺寸参数怎么写
像 images.resize() 这种接受尺寸的 API,当前支持两种主要写法:
| 写法 | 例子 | 含义 |
|---|---|---|
| 单个数字 | 256 | 宽高都变成 256 |
| 二元数组 | [720, 1280] | 宽 720,高 1280 |
插值参数有哪些值
resize() / scale() 这一组当前接受的插值字符串有:
| 可填值 | 实际效果 |
|---|---|
"nearest" / "nearest_neighbor" / "nearestneighbor" / false / "0" | 最近邻 |
"area" | 面积插值 |
"cubic" | 三次插值 |
"lanczos4" | Lanczos4 |
| 其他值或省略 | 线性插值 |
卷积核大小怎么处理
blur()、medianBlur()、gaussianBlur() 这类 API 需要核大小时,当前实现会帮你做一层修正:
- 小于
1会被抬到合法值 - 偶数会自动补成下一个奇数
所以你写:
images.medianBlur(img, 4);
实际会按 5 来做。
路径解析规则
images.read() / images.save() 这类 API 的路径规则是:
- 绝对路径:直接使用
- 相对路径:相对当前项目目录或当前脚本目录解析
content://.../file://...:按 URI 读取
而 image.saveTo(path) 当前是直接 new File(path) 去写,不会帮你走“当前脚本目录”那套相对路径解析逻辑。
如果你想写到项目目录里,优先用:
images.save(image, "./output/demo.png");
images.read(path)
从本地路径或 URI 读取图片。
参数
| 参数 | 类型 | 可填值 | 默认值 | 说明 |
|---|---|---|---|---|
path | string | 绝对路径、相对路径、content://、file:// | 无 | 路径为空时直接返回 null |
返回值
Image | null
真实行为
- 路径为空白字符串时返回
null - 文件不存在或不是普通文件时返回
null content:///file://会走ContentResolver- 成功后会转成
ARGB_8888图片对象
示例
const img = images.read("./assets/login.png");
if (!img) {
throw new Error("图片读取失败");
}
try {
log(`${img.width()} x ${img.height()}`);
} finally {
img.recycle();
}
images.load(url)
从 URL 加载图片;如果传的不是 http:// 或 https://,会回退成 images.read(...)。
参数
| 参数 | 类型 | 可填值 | 默认值 | 说明 |
|---|---|---|---|---|
url | string | http://...、https://... 或本地路径 | 无 | 为空时返回 null |
返回值
Image | null
真实行为
- 传空字符串:返回
null - 传本地路径:等价于
images.read(path) - 传 HTTP / HTTPS:用
HttpURLConnection下载,当前连接超时和读取超时都是15000ms - 远程内容下载成功但无法解码时会抛异常,而不是返回
null
示例
const img = images.load("https://example.com/logo.png");
if (!img) {
throw new Error("没有拿到图片");
}
try {
log(img.width());
} finally {
img.recycle();
}
images.copy(image)
复制一张图片。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
image | Image | 必须是真实图片对象 |
返回值
Image
适合什么时候用
- 你想保留原图,同时继续做裁剪、缩放、阈值处理
- 你拿到的是别的 API 返回图,不想直接和后续流程共用同一实例
示例
const src = images.read("./assets/login.png");
const copy = images.copy(src);
try {
log(`src=${src.width()} copy=${copy.width()}`);
} finally {
src.recycle();
copy.recycle();
}
images.save(image, path, format?, quality?)
把图片保存到本地文件。
参数
| 参数 | 类型 | 可填值 | 默认值 | 说明 |
|---|---|---|---|---|
image | Image | 图片对象 | 必填 | 要保存的图片 |
path | string | 相对路径或绝对路径 | 必填 | 会自动创建父目录 |
format | string | "PNG"、"JPG"、"JPEG"、"WEBP"、"WEBP_LOSSLESS"、"WEBP_LOSSY" | "PNG" | 输出格式 |
quality | number | 0..100 | 100 | 压缩质量 |
返回值
boolean
格式取值说明
| 取值 | 说明 |
|---|---|
"PNG" | 默认值,最稳 |
"JPG" / "JPEG" | 有损压缩,不保留透明通道 |
"WEBP" | WebP |
"WEBP_LOSSLESS" | Android 11+ 会走真正的无损 WebP;更低版本会回退 |
"WEBP_LOSSY" | Android 11+ 会走真正的有损 WebP;更低版本会回退 |
真实行为
quality会被夹到0..100- 相对路径会按当前脚本 / 项目目录解析
- 成功返回
true - 图片对象无效、路径非法、磁盘写入失败时会抛异常
示例
const img = images.read("./assets/login.png");
try {
images.save(img, "./output/login-copy.png");
images.save(img, "./output/login-copy.jpg", "JPEG", 90);
} finally {
img.recycle();
}
images.fromBase64(base64)
把 Base64 文本解码成图片。
参数
| 参数 | 类型 | 可填值 | 说明 |
|---|---|---|---|
base64 | string | 纯 Base64,或 data:image/...;base64,... | 空字符串时返回 null |
返回值
Image | null
真实行为
- 会先把
base64,前面的头剥掉 - 然后按 Base64 解码成字节,再解码成图片
- 解码失败会抛异常,不是默默返回空图
示例
const b64 = "iVBORw0KGgoAAAANSUhEUgAA...";
const img = images.fromBase64(b64);
if (img) {
try {
log(img.height());
} finally {
img.recycle();
}
}
images.toBase64(image, format?, quality?)
把图片编码成 Base64 字符串。
参数
和 images.save(...) 的 format / quality 规则一致。
返回值
string
要注意什么
- 返回的是纯 Base64 字符串
- 当前实现不会自动补
data:image/png;base64,这种前缀
示例
const img = images.read("./assets/login.png");
try {
const b64 = images.toBase64(img, "PNG", 100);
log(b64.substring(0, 48));
} finally {
img.recycle();
}
images.fromBytes(bytes)
从字节数组解码图片。
参数
| 参数 | 类型 | 可填值 | 说明 |
|---|---|---|---|
bytes | byte[] / number[] / Collection / Array | 真实图片字节 | string 会按 UTF-8 字节处理,不会当 Base64 |
返回值
Image | null
特别提醒
如果你手里拿的是 Base64 文本,不要传给 fromBytes(),而是:
images.fromBase64(base64Text);
示例
const img = images.read("./assets/login.png");
try {
const bytes = images.toBytes(img, "PNG", 100);
const img2 = images.fromBytes(bytes);
try {
log(img2.width());
} finally {
img2.recycle();
}
} finally {
img.recycle();
}
images.toBytes(image, format?, quality?)
把图片编码成字节数组。
返回值
byte[]
什么时候用
- 你想自己上传图片
- 你要把图片交给别的 Java / JS 接口
- 你后面准备再
fromBytes(...)还原
示例
const img = images.read("./assets/login.png");
try {
const bytes = images.toBytes(img, "JPEG", 85);
log(bytes.length);
} finally {
img.recycle();
}
images.readPixels(path)
一次性读取整张图片的像素数组。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
path | string | 这里读的是路径,不是 Image 对象 |
返回值
PixelsResult
返回对象有 3 个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data | number[] | 展平后的像素数组 |
width | number | 图片宽度 |
height | number | 图片高度 |
示例
const pixels = images.readPixels("./assets/login.png");
log(`w=${pixels.width} h=${pixels.height}`);
log(`first=${pixels.data[0]}`);
images.clip(image, x, y, width?, height?)
从原图裁一个矩形区域。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
image | Image | 无 | 原图 |
x | number | 0 | 起始 X |
y | number | 0 | 起始 Y |
width | number | 从 x 到图右边剩余宽度 | 会自动裁到合法范围 |
height | number | 从 y 到图底部剩余高度 | 会自动裁到合法范围 |
返回值
Image
真实行为
x/y会被夹进图片范围里width/height至少会被修正到1- 超出边界的部分会自动截断
示例
const img = images.read("./assets/login.png");
const part = images.clip(img, 100, 200, 300, 160);
try {
log(`${part.width()} x ${part.height()}`);
} finally {
img.recycle();
part.recycle();
}
images.resize(image, size, interpolation?)
直接把图片缩放到指定宽高。
参数
| 参数 | 类型 | 可填值 | 默认值 |
|---|---|---|---|
image | Image | 图片对象 | 无 |
size | number / number[] | 256 或 [720, 1280] | 原图尺寸 |
interpolation | string / boolean / number | 见上面的插值表 | 线性插值 |
返回值
Image
示例
const img = images.read("./assets/login.png");
const resized = images.resize(img, [720, 1280], "cubic");
try {
log(`${resized.width()} x ${resized.height()}`);
} finally {
img.recycle();
resized.recycle();
}
images.scale(image, fx, fy?, interpolation?)
按倍数缩放。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fx | number | 1.0 | X 方向倍率 |
fy | number | fx | Y 方向倍率 |
interpolation | 同 resize | 线性插值 | 缩放算法 |
返回值
Image
示例
const img = images.read("./assets/login.png");
const half = images.scale(img, 0.5);
try {
log(`${half.width()} x ${half.height()}`);
} finally {
img.recycle();
half.recycle();
}
images.rotate(image, degree, x?, y?)
按指定角度旋转图片。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
degree | number | 0 | 旋转角度 |
x | number | 图片中心点 X | 旋转中心 |
y | number | 图片中心点 Y | 旋转中心 |
返回值
Image
真实行为
- 当前实现保持输出画布大小和原图一致
- 旋转后超出原画布的内容会被裁掉
- 空白区域会用透明黑填充
示例
const img = images.read("./assets/login.png");
const rotated = images.rotate(img, 15);
try {
images.save(rotated, "./output/login-rotated.png");
} finally {
img.recycle();
rotated.recycle();
}
images.concat(image1, image2, direction?)
把两张图拼接起来。
参数
| 参数 | 类型 | 可填值 | 默认值 |
|---|---|---|---|
image1 | Image | 图片对象 | 无 |
image2 | Image | 图片对象 | 无 |
direction | string | "left"、"right"、"top"、"bottom" | "right" |
返回值
Image
示例
const left = images.read("./assets/part1.png");
const right = images.read("./assets/part2.png");
const merged = images.concat(left, right, "right");
try {
images.save(merged, "./output/merged.png");
} finally {
left.recycle();
right.recycle();
merged.recycle();
}
images.grayscale(image)
把图片转成灰度图。
返回值
Image
示例
const img = images.read("./assets/login.png");
const gray = images.grayscale(img);
try {
images.save(gray, "./output/login-gray.png");
} finally {
img.recycle();
gray.recycle();
}
images.threshold(image, threshold?, maxValue?, type?)
做固定阈值二值化 / 截断。
参数
| 参数 | 类型 | 可填值 | 默认值 |
|---|---|---|---|
threshold | number | 0..255 | 127 |
maxValue | number | 0..255 | 255 |
type | string | "BINARY"、"BINARY_INV"、"TRUNC"、"TOZERO"、"TOZERO_INV" | "BINARY" |
返回值
Image
示例
const img = images.read("./assets/login.png");
const binary = images.threshold(img, 180, 255, "BINARY");
try {
images.save(binary, "./output/login-binary.png");
} finally {
img.recycle();
binary.recycle();
}
images.adaptiveThreshold(image, maxValue?, adaptiveMethod?, thresholdType?, blockSize?, c?)
做自适应阈值处理。
参数
| 参数 | 类型 | 可填值 | 默认值 | 说明 |
|---|---|---|---|---|
maxValue | number | 0..255 | 255 | 输出白色值 |
adaptiveMethod | string | "MEAN_C"、"GAUSSIAN_C"、"GAUSSIAN" | "MEAN_C" | 自适应方法 |
thresholdType | string | 当前解析器支持 BINARY、BINARY_INV、TRUNC、TOZERO、TOZERO_INV | "BINARY" | 实战更建议只用 BINARY / BINARY_INV |
blockSize | number | >= 3 的奇数 | 11 | 偶数会自动补奇数 |
c | number | 任意整数 | 2 | 从局部均值里减去的常量 |
返回值
Image
示例
const img = images.read("./assets/login.png");
const out = images.adaptiveThreshold(img, 255, "GAUSSIAN_C", "BINARY", 15, 4);
try {
images.save(out, "./output/login-adaptive.png");
} finally {
img.recycle();
out.recycle();
}
images.cvtColor(image, code, dstCn?)
转换颜色空间。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
code | string | 无 | 颜色转换码 |
dstCn | number | 0 | 目标通道数,通常不用填 |
当前支持的 code 值
| 值 | 说明 |
|---|---|
RGBA2GRAY | RGBA 转灰度 |
BGRA2GRAY | BGRA 转灰度 |
RGB2GRAY | RGB 转灰度 |
BGR2GRAY | BGR 转灰度 |
GRAY2RGBA | 灰度转 RGBA |
GRAY2BGRA | 灰度转 BGRA |
GRAY2RGB | 灰度转 RGB |
GRAY2BGR | 灰度转 BGR |
RGBA2RGB | RGBA 去 alpha 转 RGB |
RGBA2BGR | RGBA 转 BGR |
BGRA2RGBA | BGRA 转 RGBA |
BGR2RGB | BGR 转 RGB |
RGB2BGR | RGB 转 BGR |
一个很关键的行为
如果 code 不在上面这张表里,当前实现会:
- 不抛异常
- 直接复制原图返回
示例
const img = images.read("./assets/login.png");
const gray = images.cvtColor(img, "RGBA2GRAY");
try {
images.save(gray, "./output/login-gray2.png");
} finally {
img.recycle();
gray.recycle();
}
images.inRange(image, lower, upper)
按颜色范围生成遮罩图。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
lower | 颜色值 | 下界颜色 |
upper | 颜色值 | 上界颜色 |
返回值
Image
怎么理解
它更像是“做一张命中范围遮罩图”,不是直接返回点位。
示例
const img = images.read("./assets/login.png");
const mask = images.inRange(img, "#f0f0f0", "#ffffff");
try {
images.save(mask, "./output/login-mask.png");
} finally {
img.recycle();
mask.recycle();
}
images.interval(image, color, interval?)
保留“接近目标颜色”的像素,把其他地方清掉。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
color | 颜色值 | 无 | 目标颜色 |
interval | number | 4 | 每个通道允许上下浮动多少 |
返回值
Image
示例
const img = images.read("./assets/login.png");
const out = images.interval(img, "#00ff00", 12);
try {
images.save(out, "./output/login-green-only.png");
} finally {
img.recycle();
out.recycle();
}
images.blur(image, size, anchor?, type?)
做盒式模糊。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
size | number / number[] | 3 | 卷积核大小 |
anchor | 任意 | 无 | 当前实现未使用 |
type | 任意 | 无 | 当前实现未使用 |
返回值
Image
示例
const img = images.read("./assets/login.png");
const out = images.blur(img, [5, 5]);
try {
images.save(out, "./output/login-blur.png");
} finally {
img.recycle();
out.recycle();
}
images.medianBlur(image, size?)
做中值滤波。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
size | number | 3 | 会自动修正成奇数且至少为 3 |
返回值
Image
示例
const img = images.read("./assets/noise.png");
const out = images.medianBlur(img, 5);
try {
images.save(out, "./output/noise-median.png");
} finally {
img.recycle();
out.recycle();
}
images.gaussianBlur(image, size, sigmaX?, sigmaY?, type?)
做高斯模糊。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
size | number / number[] | 3 | 核大小,会自动修正为奇数 |
sigmaX | number | kernelWidth / 3 | X 方向 sigma |
sigmaY | number | kernelHeight / 3 | Y 方向 sigma |
type | 任意 | 无 | 当前实现未使用 |
返回值
Image
示例
const img = images.read("./assets/login.png");
const out = images.gaussianBlur(img, [7, 7], 2.0, 2.0);
try {
images.save(out, "./output/login-gaussian.png");
} finally {
img.recycle();
out.recycle();
}
images.getSimilarity(image1, image2, options?)
衡量两张图有多相似。
参数
options 当前最关键的是:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
threshold | number | 4 | 灰度图逐像素允许误差 |
返回值
number
范围通常可以按 0.0 ~ 1.0 理解,越接近 1.0 越相似。
真实行为
- 两张图会先转灰度
- 如果尺寸不同,第二张图会先被缩放到第一张图大小
- 然后按阈值统计“有多少像素算接近”
示例
const a = images.read("./assets/a.png");
const b = images.read("./assets/b.png");
try {
const score = images.getSimilarity(a, b, { threshold: 6 });
log(`similarity=${score}`);
} finally {
a.recycle();
b.recycle();
}
images.matToImage(value)
把兼容值转成 Image 对象。
参数当前支持哪些类型
| 类型 | 会怎样处理 |
|---|---|
Image | 返回一张拷贝 |
Mat | 从 OpenCV Mat 转成图片 |
byte[] / number[] | 按图片字节解码 |
data:image/...;base64,... 字符串 | 按 Base64 图片解码 |
| 普通字符串 | 按本地路径读取 |
返回值
Image | null
示例
const raw = images.toBytes(images.read("./assets/login.png"));
const img = images.matToImage(raw);
if (img) {
try {
log(img.width());
} finally {
img.recycle();
}
}
images.requestScreenCapture(options?)
申请 MediaProjection 截图权限,并建立截图会话。
参数支持 4 种写法
1. 不传参数
images.requestScreenCapture();
表示按当前屏幕默认方向和尺寸申请。
2. 传布尔值
images.requestScreenCapture(true); // landscape=true
images.requestScreenCapture(false); // landscape=false
这里的 true / false 表示你偏好的方向。
3. 传两个数字
images.requestScreenCapture(1080, 2400);
表示显式指定截图宽高。
4. 传对象
images.requestScreenCapture({
landscape: false,
width: 1080,
height: 2400
});
对象里当前支持的字段只有:
| 字段 | 类型 | 说明 |
|---|---|---|
landscape | boolean | 偏好的横竖屏方向 |
width | number | 显式截图宽度 |
height | number | 显式截图高度 |
返回值
boolean
真实行为
- Android 5.0 以下会直接抛错
- 用户授权成功时返回
true - 用户取消授权时返回
false - 如果当前已经有同样参数的会话在跑,会直接返回
true - 当前实现会自动启动前台服务来托住 MediaProjection 会话
一个很重要的方向细节
只有在 你没有显式传 width 和 height 时,landscape 才会通过“必要时交换宽高”的方式参与尺寸决策。
如果你已经自己写死了 width / height,那就以你传的尺寸为准。
示例
const ok = images.requestScreenCapture({
landscape: false
});
if (!ok) {
toastLog("用户没有同意截图权限");
exit();
}
images.requestScreenCaptureAsync(options?)
这是 requestScreenCapture() 的兼容别名。
返回值
boolean
真实行为
当前实现没有额外的异步返回对象,也不会给你 Promise。
它和 images.requestScreenCapture() 调的是同一个入口,所以:
- 参数规则一样
- 返回值一样
- 权限行为一样
示例
const ok = images.requestScreenCaptureAsync(true);
log(ok);
images.getScreenCaptureOptions()
读取当前截图会话记录下来的选项。
返回值
ScreenCaptureOptions
字段如下:
| 字段 | 类型 | 说明 |
|---|---|---|
landscape | `boolean | null` |
width | `number | null` |
height | `number | null` |
示例
const options = images.getScreenCaptureOptions();
log(JSON.stringify(options, null, 2));
images.stopScreenCapture()
停止当前 MediaProjection 截图会话。
返回值
boolean
规则
| 场景 | 返回值 |
|---|---|
| 当前确实有会话 | true |
| 当前没有会话 | false |
额外行为
停止后,images.getScreenCaptureOptions() 会回到空配置。
示例
if (images.stopScreenCapture()) {
log("截图会话已停止");
}
images.captureScreen(path?)
真正抓取当前屏幕的一帧图像。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
path | string | 不传 | 传了非空路径时会直接保存到文件 |
返回值
| 调用方式 | 返回值 |
|---|---|
images.captureScreen() | Image |
images.captureScreen("./a.png") | boolean |
前提
必须先成功调用过:
images.requestScreenCapture(...)
否则会直接抛:
captureScreen() requires requestScreenCapture() first
真实行为
- 当前会从 MediaProjection 会话里取最新一帧
- 内部等待帧的超时大约是
2000ms - 如果你传了路径,内部会先保存,再把临时图片对象回收掉
示例
if (!images.requestScreenCapture()) {
exit();
}
const img = images.captureScreen();
try {
log(`${img.width()} x ${img.height()}`);
} finally {
img.recycle();
}
if (!images.requestScreenCapture()) {
exit();
}
images.captureScreen("./output/screen.png");
images.pixel(image, x, y)
读取单个像素颜色。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
image | Image | 图片对象 |
x | number | 横坐标 |
y | number | 纵坐标 |
返回值
number
真实行为
当前实现会把 x / y 自动夹到合法范围:
- 小于
0会被提到0 - 大于边界会被压到最后一个像素
示例
const img = images.read("./assets/login.png");
try {
const color = images.pixel(img, 10, 20);
log(color);
} finally {
img.recycle();
}
images.findColor(image, color, options?)
在整张图或指定区域里找一个颜色。
options 支持哪些字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
region | number[] | 整张图 | [x, y, width, height] |
threshold | number | 4 | 每个通道允许误差 |
similarity | number | 无 | 0.0 ~ 1.0,会换算成阈值;写了它时优先于 threshold |
返回值
Point | null
示例
const img = images.captureScreen();
try {
const p = images.findColor(img, "#ffcc00", {
region: [100, 300, 500, 400],
threshold: 8
});
log(p);
} finally {
img.recycle();
}
images.findColorInRegion(image, color, x, y, width, height, threshold?)
按显式区域参数找色。
返回值
Point | null
什么时候更适合用它
- 你已经手里就有
x, y, width, height - 你不想再组
options.region
示例
const img = images.captureScreen();
try {
const p = images.findColorInRegion(img, "#ffcc00", 100, 300, 500, 400, 8);
log(p);
} finally {
img.recycle();
}
images.findAllPointsForColor(image, color, options?)
找出所有命中的点位。
返回值
Point[]
适合场景
- 你不是只要“有没有”
- 而是要拿到整批点位自己筛,比如选最左、最右、最靠下那个
示例
const img = images.captureScreen();
try {
const points = images.findAllPointsForColor(img, "#ffffff", {
region: [0, 0, img.width(), img.height()],
threshold: 6
});
log(`count=${points.length}`);
} finally {
img.recycle();
}
images.findColorEquals(image, color, x, y, width, height)
找“完全相等”的颜色。
返回值
Point | null
真实行为
当前实现本质上等于:
images.findColorInRegion(image, color, x, y, width, height, 0)
也就是阈值直接固定成 0。
示例
const img = images.captureScreen();
try {
const p = images.findColorEquals(img, "#ffffffff", 0, 0, 500, 500);
log(p);
} finally {
img.recycle();
}
images.findMultiColors(image, firstColor, colors, options?)
按“主颜色 + 偏移颜色组”的方式找图案。
参数
colors 的每一项都按下面这个结构写:
[dx, dy, color]
例如:
[
[12, 0, "#ffffff"],
[0, 18, "#00ff00"],
[12, 18, "#000000"]
]
options 支持字段
和 findColor() 基本一致:
| 字段 | 类型 | 默认值 |
|---|---|---|
region | number[] | 整张图 |
threshold | number | 4 |
similarity | number | 无,写了就优先 |
返回值
Point | null
返回的是主颜色命中的那个起点坐标。
示例
const img = images.captureScreen();
try {
const p = images.findMultiColors(img, "#ff0000", [
[10, 0, "#00ff00"],
[0, 10, "#0000ff"]
], {
threshold: 10,
region: [100, 100, 600, 800]
});
log(p);
} finally {
img.recycle();
}
images.detectsColor(image, color, x, y, threshold?, algorithm?)
判断某一个像素是不是接近指定颜色。
参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
threshold | number | 4 | 每个通道允许误差 |
algorithm | 任意 | 无 | 当前实现未使用 |
返回值
boolean
一个容易忽略的点
如果 x / y 越界,当前实现直接返回 false,不会像 images.pixel() 那样帮你自动夹进边界。
示例
const img = images.captureScreen();
try {
const ok = images.detectsColor(img, "#ffffff", 200, 300, 6);
log(ok);
} finally {
img.recycle();
}
images.detectsMultiColors(image, x, y, firstColor, colors, options?)
从一个已知起点出发,验证主颜色和偏移颜色组是否同时成立。
参数
colors 和 findMultiColors() 一样,也是:
[dx, dy, color]
options 当前最关键的字段只有:
| 字段 | 类型 | 默认值 |
|---|---|---|
threshold | number | 4 |
返回值
boolean
真实行为
x/y越界时直接返回false- 偏移后的任意一个点超出图片范围,也会返回
false - 它不会扫整张图,只检查你指定的那个起点
示例
const img = images.captureScreen();
try {
const ok = images.detectsMultiColors(img, 200, 300, "#ff0000", [
[10, 0, "#00ff00"],
[0, 10, "#0000ff"]
], {
threshold: 8
});
log(ok);
} finally {
img.recycle();
}
images.findImage(image, template, options?)
在大图里找模板图,返回最佳命中点。
options 支持哪些字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
threshold | number | 0.9 | 通过阈值,0.0 ~ 1.0 |
weakThreshold | number | 0.6 | 主要用于 fallback 模板匹配的预筛选 |
region | number[] | 整张图 | 搜索区域 |
max | number | 5 | 对 findImage() 本身意义不大,主要给多结果匹配共用 |
transparentMask | boolean | false | 是否利用模板 alpha 做透明遮罩 |
返回值
Point | null
transparentMask 怎么理解
如果模板 PNG 有透明背景,而你又只关心模板里真正有内容的部分,可以开:
transparentMask: true
当前实现会把 alpha 大于 16 的模板像素当成有效区域。
示例
const screen = images.captureScreen();
const tpl = images.read("./assets/btn-login.png");
try {
const p = images.findImage(screen, tpl, {
threshold: 0.92,
transparentMask: true
});
log(p);
} finally {
screen.recycle();
tpl.recycle();
}
images.findImageInRegion(image, template, x, y, width, height, threshold?)
在指定区域里找模板图。
返回值
Point | null
真实行为
当前实现内部会把这组位置参数先组装成:
regionthreshold
再复用 images.findImage(...) 的核心逻辑。
示例
const screen = images.captureScreen();
const tpl = images.read("./assets/btn-login.png");
try {
const p = images.findImageInRegion(screen, tpl, 100, 200, 500, 600, 0.9);
log(p);
} finally {
screen.recycle();
tpl.recycle();
}
images.matchTemplate(image, template, options?)
找出多个模板命中结果。
返回值
MatchingResult
options 关键字段
和 findImage() 一样,但这里 max 会真正影响返回结果数量:
| 字段 | 默认值 |
|---|---|
threshold | 0.9 |
weakThreshold | 0.6 |
region | 整张图 |
max | 5 |
transparentMask | false |
示例
const screen = images.captureScreen();
const tpl = images.read("./assets/red-dot.png");
try {
const result = images.matchTemplate(screen, tpl, {
threshold: 0.88,
max: 10
});
log(`count=${result.size()}`);
log(result.best());
} finally {
screen.recycle();
tpl.recycle();
}
images.findCircles(image, options?)
在图片里找圆形或近似圆形区域。
options 支持字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
region | number[] | 整张图 | 搜索区域 |
minRadius | number | 6 | 最小半径 |
maxRadius | number | 自动估算 | 最大半径 |
max | number | 12 | 最多返回多少个结果 |
返回值
Circle[]
每个结果对象包含:
xyradiusscore
示例
const img = images.read("./assets/circles.png");
try {
const circles = images.findCircles(img, {
minRadius: 12,
maxRadius: 48,
max: 6
});
log(JSON.stringify(circles, null, 2));
} finally {
img.recycle();
}
images.detectAndComputeFeatures(image, options?)
提取图片里的特征点。
options 支持字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
maxFeatures | number | 128 | 至少会被抬到 8 |
返回值
ImageFeatures
包含:
widthheightpointscount()
要怎么理解当前实现
当前实现更接近“提取一批角点 / 梯度明显的点”,并不是完整暴露 ORB 描述子对象给脚本层。
示例
const img = images.read("./assets/login.png");
try {
const features = images.detectAndComputeFeatures(img, {
maxFeatures: 80
});
log(features.count());
log(features.points[0]);
} finally {
img.recycle();
}
images.matchFeatures(scene, object, options?)
对场景图和目标图做匹配,返回目标大致框。
参数
scene / object 当前都支持两类值:
| 类型 | 说明 |
|---|---|
Image | 直接拿图片匹配 |
ImageFeatures | 会取里面绑定的原图继续匹配 |
options 当前最关键的是:
| 字段 | 类型 | 默认值 |
|---|---|---|
threshold | number | 0.8 |
返回值
ObjectFrame | null
一个非常重要的现状说明
虽然名字叫 matchFeatures(),但当前脚本层实现并不是把两边特征描述子真正做一整套几何配准后把变换矩阵暴露出来。
它现在更像“接受特征图对象也行,但最终仍然按底层图像去找一个最优框”。
所以你应该把它理解成:
- 返回一个大致目标区域框
- 适合拿来点中心、画框、做二次验证
- 不是精细姿态估计接口
示例
const scene = images.captureScreen();
const object = images.read("./assets/btn-login.png");
try {
const frame = images.matchFeatures(scene, object, {
threshold: 0.82
});
log(frame);
} finally {
scene.recycle();
object.recycle();
}
图片对象 Image
这一组是 images.read()、images.captureScreen()、images.copy() 等 API 返回的图片实例方法。
image.width()
返回图片宽度。
const img = images.read("./assets/login.png");
try {
log(img.width());
} finally {
img.recycle();
}
image.height()
返回图片高度。
const img = images.read("./assets/login.png");
try {
log(img.height());
} finally {
img.recycle();
}
image.getWidth()
width() 的别名。
image.getHeight()
height() 的别名。
image.getBitmap()
取底层 Bitmap。
要注意什么
- 对普通读图 / 处理图,它通常直接拿已有
Bitmap - 对
captureScreen()返回的截图图,它可能会在这里把底层MediaImage材料化成Bitmap
image.getMat()
取底层 OpenCV Mat。
返回值
Mat
要注意什么
- 当前会确保图像可转成 OpenCV Mat
- 这是更偏底层的接口,脚本里通常只有在你自己还要喂给别的 OpenCV 逻辑时才用
image.getMediaImage()
取底层 android.media.Image。
返回值
MediaImage | null
什么时候可能是 null
images.read()images.load()images.copy()images.resize()这类普通图像处理结果
这几类图片本来就是 Bitmap 路径生成的,不带原始 MediaImage。
image.getPlane()
取底层首个 Image.Plane。
返回值
Image.Plane | null
和 getMediaImage() 一样,通常只有 captureScreen() 这种截图路径返回的图片更可能带这个值。
image.getPointer()
取当前图像底层 OpenCV Mat 的 native pointer。
返回值
number
更适合什么时候用
- 你要和底层 native / Java OpenCV 桥接
- 你明确知道自己要的是底层指针地址
image.pixel(x, y)
读取某个像素颜色。
const img = images.read("./assets/login.png");
try {
log(img.pixel(10, 20));
} finally {
img.recycle();
}
image.getPixel(x, y)
pixel(x, y) 的别名。
image.saveTo(path)
直接把这张图片写到指定路径。
返回值
boolean
和 images.save(...) 的区别
image.saveTo(path) 当前直接按原始 path 写文件;images.save(image, path) 会帮你按当前脚本 / 项目目录解析相对路径。
image.clone()
克隆一张独立图片。
返回值
Image
image.ensureNotRecycled()
确认图片还没被回收。
返回值
无返回值;如果图片已回收会直接抛异常。
image.recycle()
回收图片,释放内存和底层资源。
返回值
boolean
| 场景 | 返回值 |
|---|---|
| 第一次成功回收 | true |
| 之前已经回收过 | false |
image.isRecycled()
判断图片是否已经回收。
返回值
boolean
点位对象 Point
找色、找图这类 API 常见会返回 Point。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
x | number | 横坐标 |
y | number | 纵坐标 |
示例
const p = images.findColor(images.captureScreen(), "#ffffff");
if (p) {
log(`x=${p.x} y=${p.y}`);
}
匹配结果对象 MatchingResult
这是 images.matchTemplate() 的返回对象。
result.points
返回所有命中点位的 Point[]。
result.size()
返回匹配数量。
result.empty()
没有任何命中时返回 true。
result.nonEmpty()
至少有一个命中时返回 true。
result.get(index)
取指定下标的匹配项,越界时返回 null。
result.first()
返回第一个匹配项,没有则 null。
result.last()
返回最后一个匹配项,没有则 null。
result.best()
返回相似度最高的匹配项。
result.worst()
返回相似度最低的匹配项。
result.matches()
返回完整匹配项数组。
result.sortBy(order)
按指定规则排序并返回自身。
order 支持哪些字符串
| 值 | 说明 |
|---|---|
"left" | 按左边界从小到大 |
"top" | 按上边界从小到大 |
"right" | 按右边界从小到大 |
"bottom" | 按下边界从小到大 |
"left-top" / "lefttop" / "lt" | 先左再上 |
"top-left" / "topleft" / "tl" | 先上再左 |
"right-top" / "righttop" / "rt" | 先右再上 |
"top-right" / "topright" / "tr" | 先上再右 |
"similarity" / "score" / "best" | 按相似度从高到低 |
也支持函数比较器
你也可以传一个函数,返回负数 / 0 / 正数来控制顺序。
示例
const screen = images.captureScreen();
const tpl = images.read("./assets/red-dot.png");
try {
const result = images.matchTemplate(screen, tpl, { max: 8 });
result.sortBy("left-top");
log(result.first());
} finally {
screen.recycle();
tpl.recycle();
}
单个匹配项 Match
这是 MatchingResult.get()、first()、best() 这一组返回的单项对象。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
point | Point | 命中起点 |
x | number | 等于 point.x |
y | number | 等于 point.y |
left | number | 左边界 |
top | number | 上边界 |
right | number | 右边界 |
bottom | number | 下边界 |
similarity | number | 相似度 |
width | number | 模板宽度 |
height | number | 模板高度 |
match.centerX()
返回命中框中心点 X。
match.centerY()
返回命中框中心点 Y。
match.bounds()
返回一个 UiRect 风格的边界对象。
圆检测结果 Circle
这是 images.findCircles() 返回数组里的单项对象。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
x | number | 圆心 X |
y | number | 圆心 Y |
radius | number | 半径 |
score | number | 可信度分数,越大通常越像 |
像素结果 PixelsResult
这是 images.readPixels() 的返回对象。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
data | number[] | 展平像素数组 |
width | number | 宽度 |
height | number | 高度 |
截图选项对象 ScreenCaptureOptions
这是 images.getScreenCaptureOptions() 的返回对象。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
landscape | `boolean | null` |
width | `number | null` |
height | `number | null` |
特征结果对象 ImageFeatures
这是 images.detectAndComputeFeatures() 的返回对象。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
width | number | 原图宽度 |
height | number | 原图高度 |
points | Point[] | 提取出来的特征点列表 |
features.count()
返回特征点数量。
目标框对象 ObjectFrame
这是 images.matchFeatures() 返回的区域框对象。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
left | number | 左边界 |
top | number | 上边界 |
right | number | 右边界 |
bottom | number | 下边界 |
score | number | 匹配分数 |
frame.width()
返回框宽度。
frame.height()
返回框高度。
frame.centerX()
返回中心点 X。
frame.centerY()
返回中心点 Y。
frame.bounds()
返回 UiRect 风格边界对象。
frame.corners()
返回四个角点,顺序是:
- 左上
- 右上
- 右下
- 左下
全局别名
除了 images.xxx() 以外,当前源码还额外挂了下面这些全局快捷函数:
| 全局函数 | 等价入口 |
|---|---|
requestScreenCapture(...) | images.requestScreenCapture(...) |
requestScreenCaptureAsync(...) | images.requestScreenCaptureAsync(...) |
captureScreen(...) | images.captureScreen(...) |
findImage(...) | images.findImage(...) |
findImageInRegion(...) | images.findImageInRegion(...) |
findColor(...) | images.findColor(...) |
findColorInRegion(...) | images.findColorInRegion(...) |
findColorEquals(...) | images.findColorEquals(...) |
findMultiColors(...) | images.findMultiColors(...) |
也就是说,你既可以写:
const p = images.findColor(img, "#ffffff");
也可以写:
const p = findColor(img, "#ffffff");
只是为了减少歧义,长期维护的脚本我还是更建议你优先写 images.xxx()。
