feat: RGB Histogram
This commit is contained in:
parent
e8b8114014
commit
aa2cbfab15
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
target/
|
||||
pictures/
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
@ -15,13 +15,17 @@ DEVICE=1
|
||||
# 30 = All Prefix related implementations at once
|
||||
# 31 - 32 = Prefix1 - Prefix2 respectively
|
||||
# 40 = Rauschfilter (Spawns a javafx window)
|
||||
# 50 = Mandelbrot (Spawns a javafx window)
|
||||
# 60 = RGBHistogramm (Spawns a javafx window)
|
||||
# DEFAULT = 0
|
||||
TARGET=31
|
||||
|
||||
# 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)
|
||||
# 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
|
||||
|
||||
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 OpenCLDevice device;
|
||||
public static int multiParam;
|
||||
public static String selectedImage;
|
||||
private static void printHeader(final String txt) {
|
||||
final String spacer =
|
||||
"######################################################################";
|
||||
@ -20,15 +21,24 @@ public class App {
|
||||
App.choice = Integer.parseInt(args[0]) - 1;
|
||||
}
|
||||
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;
|
||||
if (args.length > 1) {
|
||||
target = Integer.parseInt(args[1]);
|
||||
}
|
||||
App.multiParam = 25;
|
||||
App.selectedImage = "lena.bmp";
|
||||
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;
|
||||
switch (target) {
|
||||
case 0:
|
||||
@ -116,6 +126,10 @@ public class App {
|
||||
System.out.println("Spawning window Mandelbrot");
|
||||
Application.launch(Mandelbrot.class);
|
||||
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 static void getInfo() {
|
||||
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 localSize = Math.min(maxWGSize, localMem / 4);
|
||||
|
||||
System.out.printf("Memsize: %d, Max-WGSize: %d, LocalSize: %d\n",
|
||||
localMem, maxWGSize, localSize);
|
||||
System.out.printf("LocalMemsize: %d KB\nMaxMemAlloc: %dMB\n" +
|
||||
"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 b[] = new int[N * 2];
|
||||
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);
|
||||
k.setExplicit(true);
|
||||
k.setStepSize(1);
|
||||
|
@ -18,7 +18,9 @@ public class OpenCLPrefix2 {
|
||||
int N = a.length;
|
||||
int b[] = new int[N];
|
||||
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);
|
||||
k.setExplicit(true);
|
||||
k.setStepSize(1);
|
||||
|
113
src/main/java/edu/thi/phga/aparapi_test/RGBHistogramm.java
Normal file
113
src/main/java/edu/thi/phga/aparapi_test/RGBHistogramm.java
Normal file
@ -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…
x
Reference in New Issue
Block a user