Files
AutoJs6/autojs/src/main/assets/modules/__images__.js
hyb1996 d05b65ba51 修复 matchTemplate函数返回的结果相等或接近的问题
修复 app.getUriForFile()等报错的问题
2018-12-21 16:35:09 +08:00

555 lines
21 KiB
JavaScript

module.exports = function (runtime, scope) {
const ResultAdapter = require("result_adapter");
var MatchingResult = (function () {
var comparators = {
"left": (l, r) => l.point.x - r.point.x,
"top": (l, r) => l.point.y - r.point.y,
"right": (l, r) => r.point.x - l.point.x,
"bottom": (l, r) => r.point.y - l.point.y
}
function MatchingResult(list) {
if (Array.isArray(list)) {
this.matches = list;
} else {
this.matches = runtime.bridges.bridges.toArray(list);
}
this.__defineGetter__("points", () => {
if (typeof (this.__points__) == 'undefined') {
this.__points__ = this.matches.map(m => m.point);
}
return this.__points__;
});
}
MatchingResult.prototype.first = function () {
if (this.matches.length == 0) {
return null;
}
return this.matches[0];
}
MatchingResult.prototype.last = function () {
if (this.matches.length == 0) {
return null;
}
return this.matches[this.matches.length - 1];
}
MatchingResult.prototype.findMax = function (cmp) {
if (this.matches.length == 0) {
return null;
}
var target = this.matches[0];
this.matches.forEach(m => {
if (cmp(target, m) > 0) {
target = m;
}
});
return target;
}
MatchingResult.prototype.leftmost = function () {
return this.findMax(comparators.left);
}
MatchingResult.prototype.topmost = function () {
return this.findMax(comparators.top);
}
MatchingResult.prototype.rightmost = function () {
return this.findMax(comparators.right);
}
MatchingResult.prototype.bottommost = function () {
return this.findMax(comparators.bottom);
}
MatchingResult.prototype.worst = function () {
return this.findMax((l, r) => l.similarity - r.similarity);
}
MatchingResult.prototype.best = function () {
return this.findMax((l, r) => r.similarity - l.similarity);
}
MatchingResult.prototype.sortBy = function (cmp) {
var comparatorFn = null;
if (typeof (cmp) == 'string') {
cmp.split("-").forEach(direction => {
var buildInFn = comparators[direction];
if (!buildInFn) {
throw new Error("unknown direction '" + direction + "' in '" + cmp + "'");
}
(function (fn) {
if (comparatorFn == null) {
comparatorFn = fn;
} else {
comparatorFn = (function (comparatorFn, fn) {
return function (l, r) {
var cmpValue = comparatorFn(l, r);
if (cmpValue == 0) {
return fn(l, r);
}
return cmpValue;
}
})(comparatorFn, fn);
}
})(buildInFn);
});
} else {
comparatorFn = cmp;
}
var clone = this.matches.slice();
clone.sort(comparatorFn);
return new MatchingResult(clone);
}
return MatchingResult;
})();
function images() {
}
if (android.os.Build.VERSION.SDK_INT >= 21) {
util.__assignFunctions__(runtime.images, images, ['captureScreen', 'read', 'copy', 'load', 'clip', 'pixel'])
}
images.opencvImporter = JavaImporter(
org.opencv.core.Point,
org.opencv.core.Point3,
org.opencv.core.Rect,
org.opencv.core.Algorithm,
org.opencv.core.Scalar,
org.opencv.core.Size,
org.opencv.core.Core,
org.opencv.core.CvException,
org.opencv.core.CvType,
org.opencv.core.TermCriteria,
org.opencv.core.RotatedRect,
org.opencv.core.Range,
org.opencv.imgproc.Imgproc,
com.stardust.autojs.core.opencv
);
with (images.opencvImporter) {
const defaultColorThreshold = 4;
var colors = Object.create(runtime.colors);
colors.alpha = function (color) {
color = parseColor(color);
return color >>> 24;
}
colors.red = function (color) {
color = parseColor(color);
return (color >> 16) & 0xFF;
}
colors.green = function (color) {
color = parseColor(color);
return (color >> 8) & 0xFF;
}
colors.blue = function (color) {
color = parseColor(color);
return color & 0xFF;
}
colors.isSimilar = function (c1, c2, threshold, algorithm) {
c1 = parseColor(c1);
c2 = parseColor(c2);
threshold = threshold == undefined ? 4 : threshold;
algorithm = algorithm == undefined ? "diff" : algorithm;
var colorDetector = getColorDetector(c1, algorithm, threshold);
return colorDetector.detectsColor(colors.red(c2), colors.green(c2), colors.blue(c2));
}
var javaImages = runtime.getImages();
var colorFinder = javaImages.colorFinder;
images.requestScreenCapture = function (landscape) {
let ScreenCapturer = com.stardust.autojs.core.image.capture.ScreenCapturer;
var orientation = ScreenCapturer.ORIENTATION_AUTO;
if (landscape === true) {
orientation = ScreenCapturer.ORIENTATION_LANDSCAPE;
}
if (landscape === false) {
orientation = ScreenCapturer.ORIENTATION_PORTRAIT;
}
return ResultAdapter.wait(javaImages.requestScreenCapture(orientation));
}
images.save = function (img, path, format, quality) {
format = format || "png";
quality = quality == undefined ? 100 : quality;
return javaImages.save(img, path, format, quality);
}
images.saveImage = images.save;
images.grayscale = function (img, dstCn) {
return images.cvtColor(img, "BGR2GRAY", dstCn);
}
images.threshold = function (img, threshold, maxVal, type) {
initIfNeeded();
var mat = new Mat();
type = type || "BINARY";
type = Imgproc["THRESH_" + type];
Imgproc.threshold(img.mat, mat, threshold, maxVal, type);
return images.matToImage(mat);
}
images.inRange = function (img, lowerBound, upperBound) {
initIfNeeded();
var lb = new Scalar(colors.red(lowerBound), colors.green(lowerBound),
colors.blue(lowerBound), colors.alpha(lowerBound));
var ub = new Scalar(colors.red(upperBound), colors.green(upperBound),
colors.blue(upperBound), colors.alpha(lowerBound))
var bi = new Mat();
Core.inRange(img.mat, lb, ub, bi);
return images.matToImage(bi);
}
images.interval = function (img, color, threshold) {
initIfNeeded();
var lb = new Scalar(colors.red(color) - threshold, colors.green(color) - threshold,
colors.blue(color) - threshold, colors.alpha(color));
var ub = new Scalar(colors.red(color) + threshold, colors.green(color) + threshold,
colors.blue(color) + threshold, colors.alpha(color));
var bi = new Mat();
Core.inRange(img.mat, lb, ub, bi);
return images.matToImage(bi);
}
images.adaptiveThreshold = function (img, maxValue, adaptiveMethod, thresholdType, blockSize, C) {
initIfNeeded();
var mat = new Mat();
adaptiveMethod = Imgproc["ADAPTIVE_THRESH_" + adaptiveMethod];
thresholdType = Imgproc["THRESH_" + thresholdType];
Imgproc.adaptiveThreshold(img.mat, mat, maxValue, adaptiveMethod, thresholdType, blockSize, C);
return images.matToImage(mat);
}
images.blur = function (img, size, point, type) {
initIfNeeded();
var mat = new Mat();
size = newSize(size);
type = Core["BORDER_" + (type || "DEFAULT")];
if (point == undefined) {
Imgproc.blur(img.mat, mat, size);
} else {
Imgproc.blur(img.mat, mat, size, new Point(point[0], point[1]), type);
}
return images.matToImage(mat);
}
images.medianBlur = function (img, size) {
initIfNeeded();
var mat = new Mat();
Imgproc.medianBlur(img.mat, mat, size);
return images.matToImage(mat);
}
images.gaussianBlur = function (img, size, sigmaX, sigmaY, type) {
initIfNeeded();
var mat = new Mat();
size = newSize(size);
sigmaX = sigmaX == undefined ? 0 : sigmaX;
sigmaY = sigmaY == undefined ? 0 : sigmaY;
type = Core["BORDER_" + (type || "DEFAULT")];
Imgproc.GaussianBlur(img.mat, mat, size, sigmaX, sigmaY, type);
return images.matToImage(mat);
}
images.cvtColor = function (img, code, dstCn) {
initIfNeeded();
var mat = new Mat();
code = Imgproc["COLOR_" + code];
if (dstCn == undefined) {
Imgproc.cvtColor(img.mat, mat, code);
} else {
Imgproc.cvtColor(img.mat, mat, code, dstCn);
}
return images.matToImage(mat);
}
images.findCircles = function (grayImg, options) {
initIfNeeded();
options = options || {};
var mat = options.region == undefined ? grayImg.mat : new Mat(grayImg.mat, buildRegion(options.region, grayImg));
var resultMat = new Mat()
var dp = options.dp == undefined ? 1 : options.dp;
var minDst = options.minDst == undefined ? grayImg.height / 8 : options.minDst;
var param1 = options.param1 == undefined ? 100 : options.param1;
var param2 = options.param2 == undefined ? 100 : options.param2;
var minRadius = options.minRadius == undefined ? 0 : options.minRadius;
var maxRadius = options.maxRadius == undefined ? 0 : options.maxRadius;
Imgproc.HoughCircles(mat, resultMat, Imgproc.CV_HOUGH_GRADIENT, dp, minDst, param1, param2, minRadius, maxRadius);
var result = [];
for (var i = 0; i < resultMat.rows(); i++) {
for (var j = 0; j < resultMat.cols(); j++) {
var d = resultMat.get(i, j);
result.push({
x: d[0],
y: d[1],
radius: d[2]
});
}
}
if (options.region != undefined) {
mat.release();
}
resultMat.release();
return result;
}
images.resize = function (img, size, interpolation) {
initIfNeeded();
var mat = new Mat();
interpolation = Imgproc["INTER_" + (interpolation || "LINEAR")];
Imgproc.resize(img.mat, mat, newSize(size), 0, 0, interpolation);
return images.matToImage(mat);
}
images.scale = function (img, fx, fy, interpolation) {
initIfNeeded();
var mat = new Mat();
interpolation = Imgproc["INTER_" + (interpolation || "LINEAR")];
Imgproc.resize(img.mat, mat, newSize([0, 0]), fx, fy, interpolation);
return images.matToImage(mat);
}
images.rotate = function (img, degree, x, y) {
initIfNeeded();
if (x == undefined) {
x = img.width / 2;
}
if (y == undefined) {
y = img.height / 2;
}
return javaImages.rotate(img, x, y, degree);
}
images.concat = function (img1, img2, direction) {
initIfNeeded();
direction = direction || "right";
return javaImages.concat(img1, img2, android.view.Gravity[direction.toUpperCase()]);
}
images.detectsColor = function (img, color, x, y, threshold, algorithm) {
initIfNeeded();
color = parseColor(color);
algorithm = algorithm || "diff";
threshold = threshold || defaultColorThreshold;
var colorDetector = getColorDetector(color, algorithm, threshold);
var pixel = images.pixel(img, x, y);
return colorDetector.detectsColor(colors.red(pixel), colors.green(pixel), colors.blue(pixel));
}
images.findColor = function (img, color, options) {
initIfNeeded();
color = parseColor(color);
options = options || {};
var region = options.region || [];
if (options.similarity) {
var threshold = parseInt(255 * (1 - options.similarity));
} else {
var threshold = options.threshold || defaultColorThreshold;
}
if (options.region) {
return colorFinder.findColor(img, color, threshold, buildRegion(options.region, img));
} else {
return colorFinder.findColor(img, color, threshold, null);
}
}
images.findColorInRegion = function (img, color, x, y, width, height, threshold) {
return findColor(img, color, {
region: [x, y, width, height],
threshold: threshold
});
}
images.findColorEquals = function (img, color, x, y, width, height) {
return findColor(img, color, {
region: [x, y, width, height],
threshold: 0
});
}
images.findAllPointsForColor = function (img, color, options) {
initIfNeeded();
color = parseColor(color);
options = options || {};
if (options.similarity) {
var threshold = parseInt(255 * (1 - options.similarity));
} else {
var threshold = options.threshold || defaultColorThreshold;
}
if (options.region) {
return toPointArray(colorFinder.findAllPointsForColor(img, color, threshold, buildRegion(options.region, img)));
} else {
return toPointArray(colorFinder.findAllPointsForColor(img, color, threshold, null));
}
}
images.findMultiColors = function (img, firstColor, paths, options) {
initIfNeeded();
options = options || {};
firstColor = parseColor(firstColor);
var list = java.lang.reflect.Array.newInstance(java.lang.Integer.TYPE, paths.length * 3);
for (var i = 0; i < paths.length; i++) {
var p = paths[i];
list[i * 3] = p[0];
list[i * 3 + 1] = p[1];
list[i * 3 + 2] = parseColor(p[2]);
}
var region = options.region ? buildRegion(options.region, img) : null;
var threshold = options.threshold === undefined ? defaultColorThreshold : options.threshold;
return colorFinder.findMultiColors(img, firstColor, threshold, region, list);
}
images.findImage = function (img, template, options) {
initIfNeeded();
options = options || {};
var threshold = options.threshold || 0.9;
var maxLevel = -1;
if (typeof (options.level) == 'number') {
maxLevel = options.level;
}
var weakThreshold = options.weakThreshold || 0.6;
if (options.region) {
return javaImages.findImage(img, template, weakThreshold, threshold, buildRegion(options.region, img), maxLevel);
} else {
return javaImages.findImage(img, template, weakThreshold, threshold, null, maxLevel);
}
}
images.matchTemplate = function (img, template, options) {
initIfNeeded();
options = options || {};
var threshold = options.threshold || 0.9;
var maxLevel = -1;
if (typeof (options.level) == 'number') {
maxLevel = options.level;
}
var max = options.max || 5;
var weakThreshold = options.weakThreshold || 0.6;
var result;
if (options.region) {
result = javaImages.matchTemplate(img, template, weakThreshold, threshold, buildRegion(options.region, img), maxLevel, max);
} else {
result = javaImages.matchTemplate(img, template, weakThreshold, threshold, null, maxLevel, max);
}
return new MatchingResult(result);
}
images.findImageInRegion = function (img, template, x, y, width, height, threshold) {
return images.findImage(img, template, {
region: [x, y, width, height],
threshold: threshold
});
}
images.fromBase64 = function (base64) {
return javaImages.fromBase64(base64);
}
images.toBase64 = function (img, format, quality) {
format = format || "png";
quality = quality == undefined ? 100 : quality;
return javaImages.toBase64(img, format, quality);
}
images.fromBytes = function (bytes) {
return javaImages.fromBytes(bytes);
}
images.toBytes = function (img, format, quality) {
format = format || "png";
quality = quality == undefined ? 100 : quality;
return javaImages.toBytes(img, format, quality);
}
images.readPixels = function (path) {
var img = images.read(path);
var bitmap = img.getBitmap();
var w = bitmap.getWidth();
var h = bitmap.getHeight();
var pixels = util.java.array("int", w * h);
bitmap.getPixels(pixels, 0, w, 0, 0, w, h);
img.recycle();
return {
data: pixels,
width: w,
height: h
};
}
images.matToImage = function (img) {
initIfNeeded();
return Image.ofMat(img);
}
function getColorDetector(color, algorithm, threshold) {
switch (algorithm) {
case "rgb":
return new com.stardust.autojs.core.image.ColorDetector.RGBDistanceDetector(color, threshold);
case "equal":
return new com.stardust.autojs.core.image.ColorDetector.EqualityDetector(color);
case "diff":
return new com.stardust.autojs.core.image.ColorDetector.DifferenceDetector(color, threshold);
case "rgb+":
return new com.stardust.autojs.core.image.ColorDetector.WeightedRGBDistanceDetector(color, threshold);
case "hs":
return new com.stardust.autojs.core.image.ColorDetector.HSDistanceDetector(color, threshold);
}
throw new Error("Unknown algorithm: " + algorithm);
}
function toPointArray(points) {
var arr = [];
for (var i = 0; i < points.length; i++) {
arr.push(points[i]);
}
return arr;
}
function buildRegion(region, img) {
if (region == undefined) {
region = [];
}
var x = region[0] === undefined ? 0 : region[0];
var y = region[1] === undefined ? 0 : region[1];
var width = region[2] === undefined ? img.getWidth() - x : region[2];
var height = region[3] === undefined ? (img.getHeight() - y) : region[3];
var r = new org.opencv.core.Rect(x, y, width, height);
if (x < 0 || y < 0 || x + width > img.width || y + height > img.height) {
throw new Error("out of region: region = [" + [x, y, width, height] + "], image.size = [" + [img.width, img.height] + "]");
}
return r;
}
function parseColor(color) {
if (typeof (color) == 'string') {
color = colors.parseColor(color);
}
return color;
}
function newSize(size) {
if (!Array.isArray(size)) {
size = [size, size];
}
if (size.length == 1) {
size = [size[0], size[0]];
}
return new Size(size[0], size[1]);
}
function initIfNeeded() {
javaImages.initOpenCvIfNeeded();
}
scope.__asGlobal__(images, ['requestScreenCapture', 'captureScreen', 'findImage', 'findImageInRegion', 'findColor', 'findColorInRegion', 'findColorEquals', 'findMultiColors']);
scope.colors = colors;
return images;
}
}