package cx.prutser.sudoku.ocr;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
/**
* @author Erik van Zijst
*/
public class OCRUtils {
public static BufferedImage toGrayScale(BufferedImage image) {
BufferedImage gray = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = gray.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return gray;
}
/**
* Normalizes the 8-bit pixel values to [0-1] doubles.
*
* @param pixels
* @return
*/
public static double[] pixelsToPattern(byte[] pixels) {
final double[] pattern = new double[pixels.length];
for (int i = 0; i < pixels.length; i++) {
pattern[i] = (((int)pixels[i]) & 0xFF) / 256D;
}
return pattern;
}
public static String patternToString(double[] pattern) {
StringBuilder buf = new StringBuilder();
for (double p : pattern) {
buf.append(String.format("%3d ", (int)(p * 100)));
}
return buf.toString();
}
public static String pixelsToString(byte[] pixels) {
StringBuilder buf = new StringBuilder();
for (byte b : pixels) {
buf.append(b >= 0 ? "." : "#");
}
return buf.toString();
}
public static byte[] getPixels(BufferedImage image) {
if (image.getColorModel().getPixelSize() != 8) {
throw new IllegalArgumentException("Color must be 8 bit gray scale.");
} else {
DataBufferByte buffer = (DataBufferByte)image.getRaster().getDataBuffer();
return buffer.getData();
}
}
/**
* Returns the "center of mass" for the specified image.
*
* @param pixels
* @param width
* @param height
* @param invert whether or not to invert the unsigned grey scale values.
* @return the coordinates of the pixel closest to the center of mass.
*/
public static Pair<Integer, Integer> centerOfMass(
byte[] pixels, int width, int height, boolean invert) {
assert width >= 0 && height >= 0 && pixels.length == width * height;
// center of mass:
double x1 = 0D;
double y1 = 0D;
double w1 = 0D;
for (int i = 0; i < pixels.length; i++) {
double x2 = i % width;
double y2 = i / width;
int w2 = (invert ? invert(pixels[i]) : pixels[i]) & 0xFF;
double dx = x2 - x1;
double dy = y2 - y1;
double ratio = (w1 + w2) == 0D ? 0D : (w2 / (w1 + w2));
x1 += dx * ratio;
y1 += dy * ratio;
w1 += w2;
}
assert x1 <= width && y1 <= height :
String.format("Center of mass out of bounds: (%d, %d)", x1, y1);
return Pair.newInstance(Math.round((float)x1), Math.round((float)y1));
}
public static byte invert(byte b) {
return (byte)~b;
}
}