parent
e8b8114014
commit
aa2cbfab15
@ -1,4 +1,5 @@
|
||||
target/
|
||||
pictures/
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
@ -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…
Reference in new issue