feat: RGB Histogram

master
qhga 3 years ago
parent e8b8114014
commit aa2cbfab15
Signed by: phga
GPG Key ID: 5249548AA705F019

1
.gitignore vendored

@ -1,4 +1,5 @@
target/ target/
pictures/
.settings/ .settings/
.project .project
.classpath .classpath

@ -15,13 +15,17 @@ DEVICE=1
# 30 = All Prefix related implementations at once # 30 = All Prefix related implementations at once
# 31 - 32 = Prefix1 - Prefix2 respectively # 31 - 32 = Prefix1 - Prefix2 respectively
# 40 = Rauschfilter (Spawns a javafx window) # 40 = Rauschfilter (Spawns a javafx window)
# 50 = Mandelbrot (Spawns a javafx window)
# 60 = RGBHistogramm (Spawns a javafx window)
# DEFAULT = 0 # DEFAULT = 0
TARGET=31 TARGET=31
# Parameter for various tasks (e.g. if N should be shifted 3 times, MULTI_PARAM should be 3) # Parameter for various tasks (e.g. if N should be shifted 3 times, MULTI_PARAM should be 3)
# Targes 2X and 3X depend on this parameter (1 << MULTI_PARAM) # Targes 2X and 3X depend on this parameter (1 << MULTI_PARAM)
# Target 4X (N to the left and right of x_0) # Target 4X (N to the left and right of x_0)
# DEFAULT = 25 # Target 50 Zoom Factor (20 should be used to get good results)
# Target 60 filename of a picture (Place in folder $PROJECT_ROOT/pictures/my_pic.jpg) [jpg,bmp,png]
# DEFAULT = 25 / "lena.bmp"
MULTI_PARAM=3 MULTI_PARAM=3
mvn -B clean compile assembly:single && java -jar target/*.jar $DEVICE $TARGET $MULTI_PARAM mvn -B clean compile assembly:single && java -jar target/*.jar $DEVICE $TARGET $MULTI_PARAM

@ -7,6 +7,7 @@ public class App {
public static int choice; public static int choice;
public static OpenCLDevice device; public static OpenCLDevice device;
public static int multiParam; public static int multiParam;
public static String selectedImage;
private static void printHeader(final String txt) { private static void printHeader(final String txt) {
final String spacer = final String spacer =
"######################################################################"; "######################################################################";
@ -20,15 +21,24 @@ public class App {
App.choice = Integer.parseInt(args[0]) - 1; App.choice = Integer.parseInt(args[0]) - 1;
} }
App.device = Devices.selectDevice(); App.device = Devices.selectDevice();
App.device.setMaxWorkGroupSize(256); // used for 2D, 3D derive
App.device.setMaxWorkItemSize(0, 256); // used for 1D
App.device.setMaxWorkItemSize(1, 16); // used for 2D
int target = 0; int target = 0;
if (args.length > 1) { if (args.length > 1) {
target = Integer.parseInt(args[1]); target = Integer.parseInt(args[1]);
} }
App.multiParam = 25; App.multiParam = 25;
App.selectedImage = "lena.bmp";
if (args.length > 2) { if (args.length > 2) {
App.multiParam = Integer.parseInt(args[2]); if (target >= 60 && target < 70)
App.selectedImage = args[2];
else {
App.multiParam = Integer.parseInt(args[2]);
}
} }
App.selectedImage = "file:./pictures/" + App.selectedImage;
final int[] b; final int[] b;
switch (target) { switch (target) {
case 0: case 0:
@ -116,6 +126,10 @@ public class App {
System.out.println("Spawning window Mandelbrot"); System.out.println("Spawning window Mandelbrot");
Application.launch(Mandelbrot.class); Application.launch(Mandelbrot.class);
break; break;
case 60:
System.out.println("Spawning window RGBHistogramm");
Application.launch(RGBHistogramm.class);
break;
} }
} }
} }

@ -5,11 +5,16 @@ import com.aparapi.device.Device;
public class OpenCLGetMemoryInfo { public class OpenCLGetMemoryInfo {
public static void getInfo() { public static void getInfo() {
int localMem = (int) App.device.getLocalMemSize(); int localMem = (int) App.device.getLocalMemSize();
int maxAlloc = (int) App.device.getMaxMemAllocSize();
int maxWISize1 = (int) App.device.getMaxWorkItemSize()[0];
int maxWISize2 = (int) App.device.getMaxWorkItemSize()[1];
int maxWISize3 = (int) App.device.getMaxWorkItemSize()[2];
int maxWGSize = App.device.getMaxWorkGroupSize(); int maxWGSize = App.device.getMaxWorkGroupSize();
int localSize = Math.min(maxWGSize, localMem / 4); int localSize = Math.min(maxWGSize, localMem / 4);
System.out.printf("Memsize: %d, Max-WGSize: %d, LocalSize: %d\n", System.out.printf("LocalMemsize: %d KB\nMaxMemAlloc: %dMB\n" +
localMem, maxWGSize, localSize); "MaxWorkItemSizes Dim(1,2,3): %d, %d, %d\nMax-WGSize: %d\nLocalSize: %d\n",
localMem / 1024, maxAlloc / 1024 / 1024, maxWISize1, maxWISize2, maxWISize3, maxWGSize, localSize);
} }
} }

@ -10,7 +10,7 @@ public class OpenCLPrefix1 {
int N = a.length; int N = a.length;
int b[] = new int[N * 2]; int b[] = new int[N * 2];
java.util.Arrays.fill(b, 1); java.util.Arrays.fill(b, 1);
Range r = Range.create(App.device, N, 4); Range r = Range.create(App.device, N);
OpenCLPrefix1Kernel k = new OpenCLPrefix1Kernel(b); OpenCLPrefix1Kernel k = new OpenCLPrefix1Kernel(b);
k.setExplicit(true); k.setExplicit(true);
k.setStepSize(1); k.setStepSize(1);

@ -18,7 +18,9 @@ public class OpenCLPrefix2 {
int N = a.length; int N = a.length;
int b[] = new int[N]; int b[] = new int[N];
java.util.Arrays.fill(b, 1); java.util.Arrays.fill(b, 1);
Range r = Range.create(App.device, N, 4); Range r = Range.create(App.device, N);
System.out.println("Range: " + r);
OpenCLPrefix2Kernel k = new OpenCLPrefix2Kernel(a, b); OpenCLPrefix2Kernel k = new OpenCLPrefix2Kernel(a, b);
k.setExplicit(true); k.setExplicit(true);
k.setStepSize(1); k.setStepSize(1);

@ -0,0 +1,113 @@
package edu.thi.phga.aparapi_test;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import com.aparapi.Range;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class RGBHistogramm extends Application {
private static String DATEI = App.selectedImage;
private static Rectangle2D screen = Screen.getPrimary().getBounds();
private static final int HGAP = 10;
// Abstand Bild/Histogramm
private static final int MIN_HISTO_WIDTH = 256;
private static final int MAX_HISTO_WIDTH = 512;
private int[] r = new int[256];
private int[] g = new int[256];
private int[] b = new int[256];
@Override
public void start(Stage stage) {
System.out.println("File: " + DATEI);
Image image = new Image(DATEI);
int w = (int) image.getWidth();
int h = (int) image.getHeight();
int[] pixel = new int[w * h];
System.out.println("Image: " + w + "x" + h);
image.getPixelReader().getPixels(
0, 0, w, h, PixelFormat.getIntArgbInstance(), pixel, 0, w
);
Range range = Range.create2D(App.device, w, h);
System.out.println("Range: " + range);
// for (int i = 0; i < 20; i++) {
// // 1111 1111 0000 0000
// int col = 0xff00;
// int val = (col & pixel[i]) >> 8;
// // int res = val / col;
// System.out.printf("%d: %x & %x = %d (%x)\n", pixel[i], pixel[i],
// col, val, val);
// }
new RGBHistogrammKernel(pixel, r, g, b).execute(range);
ImageView view = scale(image);
HBox hbox = new HBox(HGAP, view, histogram(view));
stage.setScene(new Scene(hbox));
stage.setTitle("KAO: RGB-Histogram (" + DATEI + ")[" + w + "x" + h + "]");
stage.setResizable(false);
stage.sizeToScene();
stage.show();
}
private ImageView scale(Image image) {
// Skaliere das Bild so, dass es auf den Bildschirm passt
// und für das Histogramm wenigstens die minimale Breite bleibt.
ImageView view = new ImageView(image);
double maxWidth = screen.getWidth () * 0.7 - HGAP - MIN_HISTO_WIDTH;
double maxHeight = screen.getHeight() * 0.8;
if (image.getWidth () > maxWidth ) view.setFitWidth (maxWidth );
if (image.getHeight() > maxHeight) view.setFitHeight(maxHeight);
view.setPreserveRatio(true);
return view;
}
private Node histogram(ImageView view) {
Bounds scaledImage = view.getBoundsInParent();
double deltaW = screen.getWidth() - scaledImage.getWidth();
double width = Math.min(deltaW, MAX_HISTO_WIDTH);
double height = scaledImage.getHeight();
Canvas histo = new Canvas(width, height);
// Ermittle für die y-Skalierung den maximalen Häufigkeitswert.
int max = Stream.of(r, g, b)
.flatMapToInt(IntStream::of)
.max()
.getAsInt();
draw(histo, width / 256, height / max);
return histo;
}
private void draw(Canvas histo, double xScale, double yScale) {
GraphicsContext graphics = histo.getGraphicsContext2D();
graphics.setLineWidth(3);
graphics.setGlobalBlendMode(BlendMode.ADD);
double[] x = new double[256], y = new double[256];
Arrays.parallelSetAll(x, i -> i * xScale);
var pairs = Map.of(r, Color.RED, g, Color.GREEN, b, Color.BLUE);
double h = histo.getHeight();
for (var pair : pairs.entrySet()) {
Arrays.parallelSetAll(y, i -> h - pair.getKey()[i] * yScale);
graphics.setStroke(pair.getValue());
graphics.strokePolyline(x, y, 256);
}
}
}

@ -0,0 +1,38 @@
package edu.thi.phga.aparapi_test;
import com.aparapi.Kernel;
public class RGBHistogrammKernel extends Kernel {
private int[] pixel;
private int[] r;
private int[] g;
private int[] b;
public RGBHistogrammKernel(int[] pixel, int[] r, int[] g, int[] b) {
this.pixel = pixel;
this.r = r;
this.g = g;
this.b = b;
}
@Override
public void run() {
int x = getGlobalId(0);
int y = getGlobalId(1);
// int redM = 0x00ff0000;
// int greenM = 0x0000ff00;
// int blueM = 0x000000ff;
int index = y * getGlobalSize(0) + x;
// atomicAdd(r,(pixel[index] & redM) >> 16, 1);
// atomicAdd(g,(pixel[index] & greenM) >> 8, 1);
// atomicAdd(b, pixel[index] & blueM, 1);
int cp = pixel[index];
atomicAdd(r, (cp >> 16) & 0xff, 1);
atomicAdd(g, (cp >> 8) & 0xff, 1);
atomicAdd(b, cp & 0xff, 1);
}
}
Loading…
Cancel
Save