增加 images图片处理函数

This commit is contained in:
hyb1996
2018-10-24 13:33:11 +08:00
parent d400591df4
commit cd71a7e1dd
8 changed files with 357 additions and 168 deletions

View File

@@ -1,11 +1,14 @@
<component name="ProjectDictionaryState"> <component name="ProjectDictionaryState">
<dictionary name="Stardust"> <dictionary name="Stardust">
<words> <words>
<w>autojs</w>
<w>capturer</w> <w>capturer</w>
<w>dismissable</w> <w>dismissable</w>
<w>flowable</w> <w>flowable</w>
<w>imgproc</w>
<w>interruptible</w> <w>interruptible</w>
<w>loopers</w> <w>loopers</w>
<w>opencv</w>
<w>prefill</w> <w>prefill</w>
<w>scriptable</w> <w>scriptable</w>
<w>storages</w> <w>storages</w>

View File

@@ -0,0 +1,82 @@
"ui";
var url = "https://www.autojs.org/assets/uploads/profile/3-profileavatar.png";
var logo = null;
ui.layout(
<vertical>
<img id="img" w="150" h="150" url="{{url}}" />
<button id="grayscale" text="灰度化" />
<button id="binary" text="二值化" />
<button id="hsv" text="RGB转HSV" />
<button id="blur" text="模糊" />
<button id="medianBlur" text="中值滤波" />
<button id="gaussianBlur" text="高斯模糊" />
</vertical>
);
//把一张图片设置到图片控件中
function setImage(img) {
ui.run(() => {
ui.img.setImageBitmap(img.bitmap);
});
}
//启动一个处理图片的线程
var imgProcess = threads.start(function () {
setInterval(() => { }, 1000);
});
//处理图片的函数,把任务交给图片处理线程处理
function processImg(process) {
imgProcess.setTimeout(() => {
if (logo == null) {
logo = images.load(url);
}
//处理图片
var result = process(logo);
//把处理后的图片设置到图片控件中
setImage(result);
}, 0);
}
ui.grayscale.on("click", () => {
processImg(img => {
//灰度化
return images.grayscale(img);
});
});
ui.binary.on("click", () => {
processImg(img => {
//二值化取灰度为30到200之间的图片
return images.threshold(images.grayscale(img), 100, 200);
});
});
ui.hsv.on("click", () => {
processImg(img => {
//RGB转HSV
return images.cvtColor(img, "BGR2HSV");
});
});
ui.blur.on("click", () => {
processImg(img => {
//RGB转HSV
return images.blur(img, [10, 10]);
});
});
ui.medianBlur.on("click", () => {
processImg(img => {
//RGB转HSV
return images.medianBlur(img, 10);
});
});
ui.gaussianBlur.on("click", () => {
processImg(img => {
//RGB转HSV
return images.gaussianBlur(img, [5, 5]);
});
});

View File

@@ -99,7 +99,7 @@ module.exports = function(runtime, global){
return arr; return arr;
} }
app.getUriForFile = function(file){ app.getUriForFile = function(path){
return android.support.v4.content.FileProvider.getUriForFile(context, return android.support.v4.content.FileProvider.getUriForFile(context,
"org.autojs.autojs.fileprovider", new java.io.File(files.path(path))); "org.autojs.autojs.fileprovider", new java.io.File(files.path(path)));
}; };

View File

@@ -1,236 +1,308 @@
module.exports = function(__runtime__, scope){ module.exports = function (__runtime__, scope) {
const defaultColorThreshold = 4; const defaultColorThreshold = 4;
importPackage(org.opencv.core);
const Imgproc = org.opencv.imgproc.Imgproc;
var images = {}; var images = {};
var colors = Object.create(__runtime__.colors); var colors = Object.create(__runtime__.colors);
colors.alpha = function(color){ colors.alpha = function (color) {
color = parseColor(color); color = parseColor(color);
return color >>> 24; return color >>> 24;
} }
colors.red = function(color){ colors.red = function (color) {
color = parseColor(color); color = parseColor(color);
return (color >> 16) & 0xFF; return (color >> 16) & 0xFF;
} }
colors.green = function(color){ colors.green = function (color) {
color = parseColor(color); color = parseColor(color);
return (color >> 8) & 0xFF; return (color >> 8) & 0xFF;
} }
colors.blue = function(color){ colors.blue = function (color) {
color = parseColor(color); color = parseColor(color);
return color & 0xFF; return color & 0xFF;
} }
colors.isSimilar = function(c1, c2, threshold, algorithm){ colors.isSimilar = function (c1, c2, threshold, algorithm) {
c1 = parseColor(c1); c1 = parseColor(c1);
c2 = parseColor(c2); c2 = parseColor(c2);
threshold = threshold == undefined ? 4 : threshold; threshold = threshold == undefined ? 4 : threshold;
algorithm = algorithm == undefined ? "diff" : algorithm; algorithm = algorithm == undefined ? "diff" : algorithm;
var colorDetector = getColorDetector(c1, algorithm, threshold); var colorDetector = getColorDetector(c1, algorithm, threshold);
return colorDetector.detectsColor(colors.red(c2), colors.green(c2), colors.blue(c2)); return colorDetector.detectsColor(colors.red(c2), colors.green(c2), colors.blue(c2));
} }
if(android.os.Build.VERSION.SDK_INT < 19){ if (android.os.Build.VERSION.SDK_INT < 19) {
return images; return images;
} }
var rtImages = __runtime__.getImages(); var rtImages = __runtime__.getImages();
var colorFinder = rtImages.colorFinder; var colorFinder = rtImages.colorFinder;
images.requestScreenCapture = rtImages.requestScreenCapture.bind(rtImages); images.requestScreenCapture = rtImages.requestScreenCapture.bind(rtImages);
images.captureScreen = rtImages.captureScreen.bind(rtImages); images.captureScreen = rtImages.captureScreen.bind(rtImages);
images.read = rtImages.read.bind(rtImages); images.read = rtImages.read.bind(rtImages);
images.copy = rtImages.copy.bind(rtImages); images.copy = rtImages.copy.bind(rtImages);
images.load = rtImages.load.bind(rtImages); images.load = rtImages.load.bind(rtImages);
images.clip = rtImages.clip.bind(rtImages); images.clip = rtImages.clip.bind(rtImages);
images.save = function(img, path, format, quality){ images.save = function (img, path, format, quality) {
format = format || "png"; format = format || "png";
quality = quality == undefined ? 100 : quality; quality = quality == undefined ? 100 : quality;
return rtImages.save(img, path, format, quality); return rtImages.save(img, path, format, quality);
} }
images.saveImage = images.save; images.saveImage = images.save;
images.pixel = rtImages.pixel; images.pixel = rtImages.pixel;
images.detectsColor = function(img, color, x, y, threshold, algorithm){ images.grayscale = function (img, dstCn) {
return images.cvtColor(img, "BGR2GRAY", dstCn);
}
images.threshold = function (img, threshold, maxVal, type) {
var mat = newMat();
type = type || "binary";
type = Imgproc["THRESH_" + type.toUpperCase()];
Imgproc.threshold(img.mat, mat, threshold, maxVal, type);
return matToImage(mat);
}
images.blur = function (img, size, point, type) {
var mat = newMat();
size = newSize(size);
type = Imgproc["BORDER_" + (type || "CONSTANT")];
if (point == undefined) {
Imgproc.blur(img.mat, mat, size);
} else {
Imgproc.blur(img.mat, mat, size, new Point(point[0], point[1]), type);
}
return matToImage(mat);
}
images.medianBlur = function (img, size) {
var mat = newMat();
Imgproc.medianBlur(img.mat, mat, size);
return matToImage(mat);
}
images.gaussianBlur = function (img, size, sigmaX, sigmaY, type) {
var mat = newMat();
size = newSize(size);
sigmaX = sigmaX == undefined ? 0 : sigmaX;
sigmaY = sigmaY == undefined ? 0 : sigmaY;
type = Imgproc["BORDER_" + (type || "DEFAULT")];
Imgproc.GaussianBlur(img.mat, mat, size, sigmaX, sigmaY, type);
return matToImage(mat);
}
images.cvtColor = function (img, code, dstCn) {
var mat = newMat();
code = Imgproc["COLOR_" + code];
if (dstCn == undefined) {
Imgproc.cvtColor(img.mat, mat, code);
} else {
Imgproc.cvtColor(img.mat, mat, code, dstCn);
}
return matToImage(mat);
}
images.detectsColor = function (img, color, x, y, threshold, algorithm) {
color = parseColor(color); color = parseColor(color);
algorithm = algorithm || "diff"; algorithm = algorithm || "diff";
threshold = threshold || defaultColorThreshold; threshold = threshold || defaultColorThreshold;
var colorDetector = getColorDetector(color, algorithm, threshold); var colorDetector = getColorDetector(color, algorithm, threshold);
var pixel = images.pixel(img, x, y); var pixel = images.pixel(img, x, y);
return colorDetector.detectsColor(colors.red(pixel), colors.green(pixel), colors.blue(pixel)); return colorDetector.detectsColor(colors.red(pixel), colors.green(pixel), colors.blue(pixel));
} }
images.findColor = function(img, color, options){ images.findColor = function (img, color, options) {
color = parseColor(color); color = parseColor(color);
options = options || {}; options = options || {};
var region = options.region || []; var region = options.region || [];
if(options.similarity){ if (options.similarity) {
var threshold = parseInt(255 * (1 - options.similarity)); var threshold = parseInt(255 * (1 - options.similarity));
}else{ } else {
var threshold = options.threshold || defaultColorThreshold; var threshold = options.threshold || defaultColorThreshold;
} }
if(options.region){ if (options.region) {
return colorFinder.findColor(img, color, threshold, buildRegion(options.region, img)); return colorFinder.findColor(img, color, threshold, buildRegion(options.region, img));
}else{ } else {
return colorFinder.findColor(img, color, threshold, null); return colorFinder.findColor(img, color, threshold, null);
} }
} }
images.findColorInRegion = function(img, color, x, y, width, height, threshold){ images.findColorInRegion = function (img, color, x, y, width, height, threshold) {
return findColor(img, color, { return findColor(img, color, {
region: [x, y, width, height], region: [x, y, width, height],
threshold: threshold threshold: threshold
}); });
} }
images.findColorEquals = function(img, color, x, y, width, height){ images.findColorEquals = function (img, color, x, y, width, height) {
return findColor(img, color, { return findColor(img, color, {
region: [x, y, width, height], region: [x, y, width, height],
threshold: 0 threshold: 0
}); });
} }
images.findAllPointsForColor = function(img, color, options){ images.findAllPointsForColor = function (img, color, options) {
color = parseColor(color); color = parseColor(color);
options = options || {}; options = options || {};
if(options.similarity){ if (options.similarity) {
var threshold = parseInt(255 * (1 - options.similarity)); var threshold = parseInt(255 * (1 - options.similarity));
}else{ } else {
var threshold = options.threshold || defaultColorThreshold; var threshold = options.threshold || defaultColorThreshold;
} }
if(options.region){ if (options.region) {
return toPointArray(colorFinder.findAllPointsForColor(img, color, threshold, buildRegion(options.region, img))); return toPointArray(colorFinder.findAllPointsForColor(img, color, threshold, buildRegion(options.region, img)));
}else{ } else {
return toPointArray(colorFinder.findAllPointsForColor(img, color, threshold, null)); return toPointArray(colorFinder.findAllPointsForColor(img, color, threshold, null));
} }
} }
images.findMultiColors = function(img, firstColor, paths, options){ images.findMultiColors = function (img, firstColor, paths, options) {
options = options || {}; options = options || {};
firstColor = parseColor(firstColor); firstColor = parseColor(firstColor);
var list = java.lang.reflect.Array.newInstance(java.lang.Integer.TYPE, paths.length * 3); var list = java.lang.reflect.Array.newInstance(java.lang.Integer.TYPE, paths.length * 3);
for(var i = 0; i < paths.length; i++){ for (var i = 0; i < paths.length; i++) {
var p = paths[i]; var p = paths[i];
list[i * 3] = p[0]; list[i * 3] = p[0];
list[i * 3 + 1] = p[1]; list[i * 3 + 1] = p[1];
list[i * 3 + 2] = parseColor(p[2]); list[i * 3 + 2] = parseColor(p[2]);
} }
var region = options.region ? buildRegion(options.region, img) : null; var region = options.region ? buildRegion(options.region, img) : null;
var threshold = options.threshold === undefined ? defaultColorThreshold : options.threshold; var threshold = options.threshold === undefined ? defaultColorThreshold : options.threshold;
return colorFinder.findMultiColors(img, firstColor, threshold, region, list); return colorFinder.findMultiColors(img, firstColor, threshold, region, list);
} }
images.findImage = function(img, template, options){ images.findImage = function (img, template, options) {
options = options || {}; options = options || {};
var threshold = options.threshold || 0.9; var threshold = options.threshold || 0.9;
var maxLevel = -1; var maxLevel = -1;
if(typeof(options.level) == 'number'){ if (typeof (options.level) == 'number') {
maxLevel = options.level; maxLevel = options.level;
} }
var weakThreshold = options.weakThreshold || 0.7; var weakThreshold = options.weakThreshold || 0.7;
if(options.region){ if (options.region) {
return rtImages.findImage(img, template, weakThreshold, threshold, buildRegion(options.region, img), maxLevel); return rtImages.findImage(img, template, weakThreshold, threshold, buildRegion(options.region, img), maxLevel);
}else{ } else {
return rtImages.findImage(img, template, weakThreshold, threshold, null, maxLevel); return rtImages.findImage(img, template, weakThreshold, threshold, null, maxLevel);
} }
} }
images.findImageInRegion = function(img, template, x, y, width, height, threshold){ images.findImageInRegion = function (img, template, x, y, width, height, threshold) {
return images.findImage(img, template, { return images.findImage(img, template, {
region: [x, y, width, height], region: [x, y, width, height],
threshold: threshold threshold: threshold
}); });
} }
images.fromBase64 = function(base64){ images.fromBase64 = function (base64) {
return rtImages.fromBase64(base64); return rtImages.fromBase64(base64);
} }
images.toBase64 = function(img, format, quality){ images.toBase64 = function (img, format, quality) {
format = format || "png"; format = format || "png";
quality = quality == undefined ? 100 : quality; quality = quality == undefined ? 100 : quality;
return rtImages.toBase64(img, format, quality); return rtImages.toBase64(img, format, quality);
} }
images.fromBytes = function(bytes){ images.fromBytes = function (bytes) {
return rtImages.fromBytes(bytes); return rtImages.fromBytes(bytes);
} }
images.toBytes = function(img, format, quality){ images.toBytes = function (img, format, quality) {
format = format || "png"; format = format || "png";
quality = quality == undefined ? 100 : quality; quality = quality == undefined ? 100 : quality;
return rtImages.toBytes(img, format, quality); return rtImages.toBytes(img, format, quality);
} }
images.readPixels = function(path){ images.readPixels = function (path) {
var img = images.read(path); var img = images.read(path);
var bitmap = img.getBitmap(); var bitmap = img.getBitmap();
var w = bitmap.getWidth(); var w = bitmap.getWidth();
var h = bitmap.getHeight(); var h = bitmap.getHeight();
var pixels = util.java.array("int", w * h); var pixels = util.java.array("int", w * h);
bitmap.getPixels(pixels, 0, w, 0, 0, w, h); bitmap.getPixels(pixels, 0, w, 0, 0, w, h);
img.recycle(); img.recycle();
return { return {
data: pixels, data: pixels,
width: w, width: w,
height: h height: h
}; };
} }
function getColorDetector(color, algorithm, threshold){ function getColorDetector(color, algorithm, threshold) {
switch(algorithm){ switch (algorithm) {
case "rgb": case "rgb":
return new com.stardust.autojs.core.image.ColorDetector.RGBDistanceDetector(color, threshold); return new com.stardust.autojs.core.image.ColorDetector.RGBDistanceDetector(color, threshold);
case "equal": case "equal":
return new com.stardust.autojs.core.image.ColorDetector.EqualityDetector(color); return new com.stardust.autojs.core.image.ColorDetector.EqualityDetector(color);
case "diff": case "diff":
return new com.stardust.autojs.core.image.ColorDetector.DifferenceDetector(color, threshold); return new com.stardust.autojs.core.image.ColorDetector.DifferenceDetector(color, threshold);
case "rgb+": case "rgb+":
return new com.stardust.autojs.core.image.ColorDetector.WeightedRGBDistanceDetector(color, threshold); return new com.stardust.autojs.core.image.ColorDetector.WeightedRGBDistanceDetector(color, threshold);
case "hs": case "hs":
return new com.stardust.autojs.core.image.ColorDetector.HSDistanceDetector(color, threshold); return new com.stardust.autojs.core.image.ColorDetector.HSDistanceDetector(color, threshold);
} }
throw new Error("Unknown algorithm: " + algorithm); throw new Error("Unknown algorithm: " + algorithm);
} }
function toPointArray(points){ function toPointArray(points) {
var arr = []; var arr = [];
for(var i = 0; i < points.length; i++){ for (var i = 0; i < points.length; i++) {
arr.push(points[i]); arr.push(points[i]);
} }
return arr; return arr;
} }
function buildRegion(region, img){ function buildRegion(region, img) {
var x = region[0] === undefined ? 0 : region[0]; var x = region[0] === undefined ? 0 : region[0];
var y = region[1] === undefined ? 0 : region[1]; var y = region[1] === undefined ? 0 : region[1];
var width = region[2] === undefined ? img.getWidth() - x : region[2]; var width = region[2] === undefined ? img.getWidth() - x : region[2];
var height = region[3] === undefined ? (img.getHeight() - y) : region[3]; var height = region[3] === undefined ? (img.getHeight() - y) : region[3];
var r = new org.opencv.core.Rect(x, y, width, height); var r = new org.opencv.core.Rect(x, y, width, height);
return r; return r;
} }
function parseColor(color){ function parseColor(color) {
if(typeof(color) == 'string'){ if (typeof (color) == 'string') {
color = colors.parseColor(color); color = colors.parseColor(color);
} }
return color; return color;
} }
scope.__asGlobal__(images, ['requestScreenCapture', 'captureScreen', 'findImage', 'findImageInRegion', 'findColor', 'findColorInRegion', 'findColorEquals', 'findMultiColors']); function newMat() {
return new org.opencv.core.Mat();
}
scope.colors = colors; function matToImage(mat) {
return com.stardust.autojs.core.image.ImageWrapper.ofMat(mat);
}
return images; 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]);
}
scope.__asGlobal__(images, ['requestScreenCapture', 'captureScreen', 'findImage', 'findImageInRegion', 'findColor', 'findColorInRegion', 'findColorEquals', 'findMultiColors']);
scope.colors = colors;
return images;
} }

View File

@@ -282,13 +282,22 @@ public class StardustConsole extends AbstractConsole {
} }
if (options != null && options.length > 0) { if (options != null && options.length > 0) {
StringBuilder sb = new StringBuilder(data == null ? "" : data.toString()); StringBuilder sb = new StringBuilder(data == null ? "" : data.toString());
ArrayList<Object> newOptions = new ArrayList<>();
for (Object option : options) { for (Object option : options) {
if (option instanceof Throwable) { if (option instanceof Throwable) {
sb.append(getStackTrace((Throwable) option)).append(" "); sb.append(getStackTrace((Throwable) option)).append(" ");
} else {
newOptions.add(option);
} }
} }
data = sb.toString(); data = sb.toString();
if (newOptions.isEmpty()) {
super.error(data, newOptions.toArray());
} else {
super.error(data);
}
} else {
super.error(data, options);
} }
super.error(data, options);
} }
} }

View File

@@ -26,19 +26,19 @@ public class ImageWrapper {
private int mHeight; private int mHeight;
private Bitmap mBitmap; private Bitmap mBitmap;
public ImageWrapper(Mat mat) { protected ImageWrapper(Mat mat) {
mMat = mat; mMat = mat;
mWidth = mat.cols(); mWidth = mat.cols();
mHeight = mat.rows(); mHeight = mat.rows();
} }
public ImageWrapper(Bitmap bitmap) { protected ImageWrapper(Bitmap bitmap) {
mBitmap = bitmap; mBitmap = bitmap;
mWidth = bitmap.getWidth(); mWidth = bitmap.getWidth();
mHeight = bitmap.getHeight(); mHeight = bitmap.getHeight();
} }
public ImageWrapper(Bitmap bitmap, Mat mat) { protected ImageWrapper(Bitmap bitmap, Mat mat) {
mBitmap = bitmap; mBitmap = bitmap;
mMat = mat; mMat = mat;
mWidth = bitmap.getWidth(); mWidth = bitmap.getWidth();
@@ -58,6 +58,14 @@ public class ImageWrapper {
return new ImageWrapper(toBitmap(image)); return new ImageWrapper(toBitmap(image));
} }
public static ImageWrapper ofMat(Mat mat) {
if (mat == null) {
return null;
}
return new ImageWrapper(mat);
}
public static ImageWrapper ofBitmap(Bitmap bitmap) { public static ImageWrapper ofBitmap(Bitmap bitmap) {
if (bitmap == null) { if (bitmap == null) {
return null; return null;
@@ -123,6 +131,10 @@ public class ImageWrapper {
public Bitmap getBitmap() { public Bitmap getBitmap() {
ensureNotRecycled(); ensureNotRecycled();
if (mBitmap == null && mMat != null) {
mBitmap = Bitmap.createBitmap(mMat.width(), mMat.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mMat, mBitmap);
}
return mBitmap; return mBitmap;
} }
@@ -142,4 +154,21 @@ public class ImageWrapper {
if (mBitmap == null && mMat == null) if (mBitmap == null && mMat == null)
throw new IllegalStateException("image has been recycled"); throw new IllegalStateException("image has been recycled");
} }
@Override
protected void finalize() throws Throwable {
super.finalize();
recycle();
}
public ImageWrapper clone() {
ensureNotRecycled();
if (mBitmap == null) {
return ImageWrapper.ofMat(mMat.clone());
}
if (mMat == null) {
return ImageWrapper.ofBitmap(mBitmap.copy(mBitmap.getConfig(), true));
}
return new ImageWrapper(mBitmap.copy(mBitmap.getConfig(), true), mMat.clone());
}
} }

View File

@@ -44,7 +44,7 @@ public class TimerThread extends ThreadCompat {
new Handler().post(mTarget); new Handler().post(mTarget);
try { try {
Looper.loop(); Looper.loop();
} catch (Exception e) { } catch (Throwable e) {
if (!ScriptInterruptedException.causedByInterrupted(e)) { if (!ScriptInterruptedException.causedByInterrupted(e)) {
mRuntime.console.error(Thread.currentThread().toString() + ": ", e); mRuntime.console.error(Thread.currentThread().toString() + ": ", e);
} }

View File

@@ -30,9 +30,11 @@ import com.stardust.concurrent.VolatileDispose;
import com.stardust.pio.UncheckedIOException; import com.stardust.pio.UncheckedIOException;
import com.stardust.util.ScreenMetrics; import com.stardust.util.ScreenMetrics;
import org.opencv.core.Core;
import org.opencv.core.Mat; import org.opencv.core.Mat;
import org.opencv.core.Point; import org.opencv.core.Point;
import org.opencv.core.Rect; import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@@ -130,14 +132,7 @@ public class Images {
} }
public ImageWrapper copy(ImageWrapper image) { public ImageWrapper copy(ImageWrapper image) {
image.ensureNotRecycled(); return image.clone();
if (image.getBitmap() == null) {
return new ImageWrapper(image.getMat().clone());
}
if (image.getMat() == null) {
return new ImageWrapper(image.getBitmap().copy(image.getBitmap().getConfig(), true));
}
return new ImageWrapper(image.getBitmap().copy(image.getBitmap().getConfig(), true), image.getMat().clone());
} }
public boolean save(ImageWrapper image, String path, String format, int quality) throws IOException { public boolean save(ImageWrapper image, String path, String format, int quality) throws IOException {
@@ -279,5 +274,4 @@ public class Images {
return point; return point;
} }
} }