From 090e415d5e1bbbc74c7d8a51c70fb8af67a09f52 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 21 Apr 2020 21:09:58 +0200 Subject: [PATCH] Adds parallel-streams for performance --- src/milchreis/imageprocessing/Brightness.java | 55 +++++++------- src/milchreis/imageprocessing/Glitch.java | 51 ++++++++----- src/milchreis/imageprocessing/Scanlines.java | 56 +++++++------- .../imageprocessing/utils/Tools.java | 74 ++++++++++--------- 4 files changed, 130 insertions(+), 106 deletions(-) diff --git a/src/milchreis/imageprocessing/Brightness.java b/src/milchreis/imageprocessing/Brightness.java index 7ca15e4..e8a432f 100644 --- a/src/milchreis/imageprocessing/Brightness.java +++ b/src/milchreis/imageprocessing/Brightness.java @@ -4,33 +4,38 @@ import processing.core.PApplet; import processing.core.PImage; -/** +import java.util.stream.IntStream; + +/** * @author milchreis */ public class Brightness { - public static PImage apply(PImage image, int intensity) { - - PImage output = image.copy(); - - for(int x=0; x < image.width; x++) { - for(int y=0; y < image.height; y++) { - - int[] rgb = Tools.getColors(image, x, y); - - rgb[0] += intensity; - rgb[1] += intensity; - rgb[2] += intensity; - - rgb[0] = PApplet.constrain(rgb[0], 0, 255); - rgb[1] = PApplet.constrain(rgb[1], 0, 255); - rgb[2] = PApplet.constrain(rgb[2], 0, 255); - - Tools.set(output, x, y, rgb[0], rgb[1], rgb[2]); - } - } - - return output; - } - + public static PImage apply(PImage image, int intensity) { + + PImage output = image.copy(); + + IntStream.range(1, image.width * image.height) + .parallel() + .forEach(i -> { + int x = i % image.width; + int y = i / image.height; + + + int[] rgb = Tools.getColors(image, x, y); + + rgb[0] += intensity; + rgb[1] += intensity; + rgb[2] += intensity; + + rgb[0] = PApplet.constrain(rgb[0], 0, 255); + rgb[1] = PApplet.constrain(rgb[1], 0, 255); + rgb[2] = PApplet.constrain(rgb[2], 0, 255); + + Tools.set(output, x, y, rgb[0], rgb[1], rgb[2]); + }); + + return output; + } + } diff --git a/src/milchreis/imageprocessing/Glitch.java b/src/milchreis/imageprocessing/Glitch.java index ee6a609..568f2bc 100644 --- a/src/milchreis/imageprocessing/Glitch.java +++ b/src/milchreis/imageprocessing/Glitch.java @@ -5,59 +5,76 @@ public class Glitch { + private static long last = System.currentTimeMillis(); + public static PImage apply(PImage image) { return apply(image, 3, 1); } - + public static PImage apply(PImage image, int glitchAmount) { return apply(image, glitchAmount, 1); } - + public static PImage apply(PImage image, int glitchAmount, int scanlines) { - + if(image.width <= 0 || image.height <= 0) return image; - + + long start = System.currentTimeMillis(); + + System.out.println(start + ": Start"); + PImage output = image.copy(); + log("Loaded"); int maxOffset = (int)(glitchAmount * glitchAmount / 100.0 * image.width); - + for(int i=0; i < glitchAmount * 2; i++) { - + int startY = (int) image.parent.random(0, image.height); int chunkHeight = (int) image.parent.random(1, image.height / 4); chunkHeight = Math.min(chunkHeight, image.height - startY); int offset = (int) image.parent.random(-maxOffset, maxOffset); - + if(offset == 0) continue; - + if(offset < 0) { - + output.copy(image, -offset, startY, image.width + offset, chunkHeight, 0, startY, image.width + offset, chunkHeight); output.copy(image, 0, startY, -offset, chunkHeight, image.width + offset, startY, -offset, chunkHeight); - + } else { output.copy(image, 0, startY, image.width, chunkHeight, offset, startY, image.width, chunkHeight); output.copy(image, image.width - offset, startY, offset, chunkHeight, 0, startY, offset, chunkHeight); } } - + int ccX = (int) image.parent.random(-glitchAmount * 2, glitchAmount*2); int ccY = (int) image.parent.random(-glitchAmount * 2, glitchAmount*2); - + int channel = getRandChannel(); Tools.copyChannel(image, output, 0, 0, image.width, image.height, ccX, ccY, channel, channel); - + log("Copy channel "); + output = Brightness.apply(output, 30); - + log("Brightness "); + if(scanlines == 0) return output; - - return Scanlines.apply(output, scanlines, 130); + + PImage apply = Scanlines.apply(output, scanlines, 130); + log("Scanlines "); + return apply; } - + + private static void log(String message) { + long time = System.currentTimeMillis() - last; + last = System.currentTimeMillis(); + System.out.println(time + ": " + message); + } + private static int getRandChannel() { double r = Math.random(); if (r < .33) { diff --git a/src/milchreis/imageprocessing/Scanlines.java b/src/milchreis/imageprocessing/Scanlines.java index 1c8368b..4a4a3b5 100644 --- a/src/milchreis/imageprocessing/Scanlines.java +++ b/src/milchreis/imageprocessing/Scanlines.java @@ -6,33 +6,33 @@ public class Scanlines { - public static PImage apply(PImage image) { - return apply(image, 2, 200); - } - - public static PImage apply(PImage image, int scanlineHeight) { - return apply(image, scanlineHeight, 200); - } - - public static PImage apply(PImage image, int scanlineHeight, int alpha) { - - if(scanlineHeight <= 0) - return image; - - PGraphics canvas = image.parent.createGraphics(image.width, image.width); - canvas.beginDraw(); - - canvas.image(image, 0, 0); - - canvas.noStroke(); - canvas.fill(0, 0, 0, alpha); - - for(int h = scanlineHeight; h < image.height; h += 2*scanlineHeight) { - canvas.rect(0, h, image.width, scanlineHeight); + public static PImage apply(PImage image) { + return apply(image, 2, 200); } - - canvas.endDraw(); - return canvas.get(); - } - + + public static PImage apply(PImage image, int scanlineHeight) { + return apply(image, scanlineHeight, 200); + } + + public static PImage apply(PImage image, int scanlineHeight, int alpha) { + + if (scanlineHeight <= 0) + return image; + + PGraphics canvas = image.parent.createGraphics(image.width, image.width); + canvas.beginDraw(); + + canvas.image(image, 0, 0); + + canvas.noStroke(); + canvas.fill(0, 0, 0, alpha); + + for (int h = scanlineHeight; h < image.height; h += 2 * scanlineHeight) { + canvas.rect(0, h, image.width, scanlineHeight); + } + + canvas.endDraw(); + return canvas.get(); + } + } diff --git a/src/milchreis/imageprocessing/utils/Tools.java b/src/milchreis/imageprocessing/utils/Tools.java index 6de4c91..b09bce5 100644 --- a/src/milchreis/imageprocessing/utils/Tools.java +++ b/src/milchreis/imageprocessing/utils/Tools.java @@ -3,13 +3,14 @@ import java.awt.Color; import java.util.ArrayList; import java.util.List; +import java.util.stream.IntStream; import processing.core.PApplet; import processing.core.PGraphics; import processing.core.PImage; /** - * + * * @author nick */ public class Tools { @@ -21,29 +22,29 @@ public static void set(PImage img, int x, int y, int color) { public static void set(PImage image, int x, int y, int[] rgb) { set(image, x, y, rgb[0], rgb[1], rgb[2]); } - + public static void set(PImage img, int x, int y, int r, int g, int b) { img.pixels[x + img.width * y] = (r << 16) | (g << 8) | (b); } - + public static int get(PImage img, int x, int y) { if ((x < 0) || (y < 0) || (x >= img.width) || (y >= img.height)) return 0; return img.pixels[x + img.width * y]; } - + public static int[] getColors(PImage img, int x, int y) { return getRGB(get(img, x, y)); } - + public static PImage createImage(int w, int h, int format) { PImage image = new PImage(w, h, format); return image; } public static List getNeighbors(PImage image, int x, int y) { - + List neighbors = new ArrayList(); - + for(int i=-1; i<=1; i++) { for(int j=-1; j<=1; j++) { neighbors.add(image.get(x+i, y+j)); @@ -51,7 +52,7 @@ public static List getNeighbors(PImage image, int x, int y) { } return neighbors; } - + public static PImage createImage(int w, int h, int format, PImage original) { PImage image = createImage(w, h, format); image.parent = original.parent; // make save() work @@ -72,11 +73,11 @@ public int[] getArray(int arr[], int val) { public static PImage createBlankImageLike(PImage image) { return createImage(image.width, image.height, image.format, image); } - + /** * Returns an array for red, green, blue in * range from 0 to 255. - * + * * @param rgb * @return */ @@ -90,7 +91,7 @@ public static int[] getRGB(int rgb) { public static int getRGB(int red, int green, int blue) { return (red << 16) | (green << 8) | (blue); } - + /** * Returns an array for hue, saturation and brightness * in range: @@ -125,7 +126,7 @@ public static float[] rgbToHsb(int r, int g, int b) { float[] hsb = Color.RGBtoHSB(r, g, b, new float[3]); hsb[0] = PApplet.map(hsb[0], 0f, 1f, 0, 360); - + return hsb; } @@ -156,32 +157,33 @@ public static boolean in(int x, int start, int end) { public static boolean in(float x, float start, float end) { return x >= start && x <= end; } - + public static void copyChannel(PImage source, PImage target, int sourceX, int sourceY, int w, int h, int targetX, int targetY, int sourceChannel, int destChannel) { - - for(int y = 0; y < h; y++) { - for(int x = 0; x < w; x++) { - - int[] rgb = Tools.getColors(source, x, y); - int channel = 0; - - switch(sourceChannel) { - case 1: channel = rgb[0]; break; - case 2: channel = rgb[1]; break; - case 3: channel = rgb[2]; break; - } - - int[] rgbT = Tools.getColors(target, x, y); - - switch(destChannel) { - case 1: rgbT[0] = channel; break; - case 2: rgbT[1] = channel; break; - case 3: rgbT[2] = channel; break; - } - - target.set(x, y, getRGB(rgbT[0], rgbT[1], rgbT[2])); + + IntStream.range(1, w * h).parallel().forEach(i -> { + int x = i % w; + int y = i / h; + + int[] rgb = Tools.getColors(source, x, y); + int channel = 0; + + switch(sourceChannel) { + case 1: channel = rgb[0]; break; + case 2: channel = rgb[1]; break; + case 3: channel = rgb[2]; break; } - } + + int[] rgbT = Tools.getColors(target, x, y); + + switch(destChannel) { + case 1: rgbT[0] = channel; break; + case 2: rgbT[1] = channel; break; + case 3: rgbT[2] = channel; break; + } + + int rgb1 = getRGB(rgbT[0], rgbT[1], rgbT[2]); + set(target, x, y,rgb1); + }); } public static int getGrey(int color) {