Skip to content

Commit

Permalink
WIP: Add ImageAnalysis features
Browse files Browse the repository at this point in the history
  • Loading branch information
Zomis committed Jan 10, 2016
1 parent e842f0f commit ce05abf
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/main/groovy/net/zomis/machlearn/images/ImageAnalysis.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package net.zomis.machlearn.images;

import java.awt.image.BufferedImage;

public class ImageAnalysis {

private final int width;
private final int height;
private final boolean useGrayscale;

public ImageAnalysis(int width, int height, boolean useGrayscale) {
this.width = width;
this.height = height;
this.useGrayscale = useGrayscale;
}

public ImageNetworkBuilder neuralNetwork(int... hiddenLayerSizes) {
return new ImageNetworkBuilder(width * height * partsPerPixel(), hiddenLayerSizes);
}

public double[] imagePart(BufferedImage image, int x, int y) {
return imagePart(image, x, y, width, height, useGrayscale);
}

public static double[] imagePart(BufferedImage image, int x, int y, int width, int height, boolean useGrayscale) {
int partsPerPixel = useGrayscale ? 1 : 3;
double[] result = new double[width * height * partsPerPixel];
int i = 0;
for (int yy = y; yy < y + height; yy++) {
for (int xx = x; xx < x + width; xx++) {
double[] rgbGray = getRGB(image, xx, yy);

This comment has been minimized.

Copy link
@skiwi2

skiwi2 Jan 10, 2016

If you are concerned about performance at this point, then I'd suggest you to read http://stackoverflow.com/a/9470843/2057294 to learn more about BufferedImage#getRGB(int x, int y).

This comment has been minimized.

Copy link
@Zomis

Zomis Jan 11, 2016

Author Owner

@skiwi2 this is not where my code spends the most time (it does that training the Neural Network), but it could be worth using another approach to get the RGB values indeed.

if (useGrayscale) {
result[i++] = rgbGray[3];
} else {
result[i++] = rgbGray[0];
result[i++] = rgbGray[1];
result[i++] = rgbGray[2];
}
}
}
return result;
}

private int partsPerPixel() {
return useGrayscale ? 1 : 3;
}

public SlidingWindow slidingWindow(ImageNetwork network, BufferedImage image) {
return new SlidingWindow(network, image);
}

/**
* Returns the color of a pixel
*
* @param image The image to get the pixel from
* @param x X coordinate
* @param y Y coordinate
* @return An array of Alpha, Red, Green, Blue, and Gray-scale
*/
public static double[] getRGB(BufferedImage image, int x, int y) {
if (x < 0) {
x = image.getWidth() + x;
}
if (y < 0) {
y = image.getHeight() + y;
}
int rgb = image.getRGB(x, y);
int a = (rgb >> 24) & 0xFF;
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
double gray = 0.2989 * r + 0.5870 * g + 0.1140 * b;
return new double[] { a / 255d, r / 255d, g / 255d, b / 255d, gray / 255d };
}

public void image(BufferedImage image) {

}
}
42 changes: 42 additions & 0 deletions src/main/groovy/net/zomis/machlearn/images/ImageNetwork.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package net.zomis.machlearn.images;

import net.zomis.machlearn.neural.NeuralNetwork;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class ImageNetwork {

private final NeuralNetwork network;
private final Object[] outputs;

public ImageNetwork(NeuralNetwork network, Object[] outputs) {
if (network.getOutputLayer().size() != outputs.length) {
throw new IllegalArgumentException(
String.format("Network output layer (%d) does not match object array length (%d)",
network.getOutputLayer().size(), outputs.length));
}
this.network = network;
this.outputs = Arrays.copyOf(outputs, outputs.length);
}

public Object[] getOutputs() {
return Arrays.copyOf(outputs, outputs.length);
}

public Map<Object, Double> run(double[] imageData) {
double[] outputs = network.run(imageData);
System.out.println(Arrays.toString(outputs));
Map<Object, Double> result = new HashMap<>();
for (int i = 0; i < outputs.length; i++) {
result.put(this.outputs[i], outputs[i]);
}
return result;
}

public NeuralNetwork getNetwork() {
return this.network;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package net.zomis.machlearn.images;

import net.zomis.machlearn.neural.BackPropagation;
import net.zomis.machlearn.neural.LearningData;
import net.zomis.machlearn.neural.NeuralNetwork;
import net.zomis.machlearn.neural.NeuronLayer;

import java.util.*;
import java.util.stream.Collectors;

public class ImageNetworkBuilder {

private final NeuralNetwork network;
private final Map<Object, List<double[]>> classifications = new HashMap<>();

public ImageNetworkBuilder(int inputSize, int... hiddenLayerSizes) {
this.network = new NeuralNetwork();
NeuronLayer layer = this.network.createLayer("INPUT");
for (int i = 0; i < inputSize; i++) {
layer.createNeuron();
}

int hiddenIndex = 1;
for (int layerSize : hiddenLayerSizes) {
NeuronLayer parentLayer = layer;
layer = this.network.createLayer("HIDDEN " + (hiddenIndex++));
for (int i = 0; i < layerSize; i++) {
layer.createNeuron().addInputs(parentLayer);
}
}
}

public ImageNetworkBuilder classify(Object result, double[] input) {
classifications.putIfAbsent(result, new ArrayList<>());
classifications.get(result).add(Arrays.copyOf(input, input.length));
return this;
}

public ImageNetwork learn() {
int outputNodes = classifications.size() - 1;

NeuronLayer parentLayer = this.network.getLastLayer();
NeuronLayer layer = this.network.createLayer("OUTPUT");
for (int i = 0; i < outputNodes; i++) {
layer.createNeuron().addInputs(parentLayer);
}

List<LearningData> learningData = new ArrayList<>();
int outputIndex = 0;
Object[] objects = new Object[outputNodes];
for (Map.Entry<Object, List<double[]>> entry : classifications.entrySet()) {
double[] outputs = new double[outputNodes];
if (entry.getKey() != null) {
outputs[outputIndex] = 1;
objects[outputIndex] = entry.getKey();
outputIndex++;
}
learningData.addAll(entry.getValue().stream()
.map(inputs -> new LearningData(inputs, outputs))
.collect(Collectors.toList()));
}
BackPropagation backprop = new BackPropagation(0.5, 100);
backprop.setLogRate(10);
backprop.backPropagationLearning(learningData, network);

return new ImageNetwork(network, objects);
}

public ImageNetworkBuilder classifyNone(double[] input) {
classifications.putIfAbsent(null, new ArrayList<>());
classifications.get(null).add(Arrays.copyOf(input, input.length));
return this;
}

}
40 changes: 40 additions & 0 deletions src/main/groovy/net/zomis/machlearn/images/SlidingWindow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package net.zomis.machlearn.images;

import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;

public class SlidingWindow {

private final ImageNetwork network;
private final BufferedImage image;
private int minScaleX;
private int maxScaleX;
private int step;
private boolean overlapping;

public SlidingWindow(ImageNetwork network, BufferedImage image) {
this.network = network;
this.image = image;
}

public SlidingWindow scaleX(int min, int max) {
this.minScaleX = min;
this.maxScaleX = max;
return this;
}

public SlidingWindow step(int stepSize) {
this.step = stepSize;
return this;
}

public SlidingWindowResult run() {
return null;
}

public SlidingWindow overlapping(boolean b) {
this.overlapping = b;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.zomis.machlearn.images;

import java.util.Map;
import java.util.Set;

public class SlidingWindowResult {

Map<ZPoint, Set<Object>> points;

}
7 changes: 7 additions & 0 deletions src/main/groovy/net/zomis/machlearn/images/ZPoint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.zomis.machlearn.images;

public class ZPoint {

int x, y;

}

0 comments on commit ce05abf

Please sign in to comment.