package cx.prutser.sudoku.ocr;
import java.util.Arrays;
/**
* Shamelessly taken from http://homepages.inf.ed.ac.uk/rbf/HIPR2/flatjavasrc/AdapThresh.java
* and slightly tweaked for performance.
*
* Also see: http://homepages.inf.ed.ac.uk/rbf/HIPR2
*/
public class AdapThresh {
//the width and height of this image in pixels
private int i_w, i_h;
//pixel arrays for input and output images
private int[] src_1d;
private int[] dest_1d;
/**
* Applies the adaptive thresholding operator to the specified image array
* using the mean function to find the threshold value
*
* @param src pixel array representing image to be thresholded
* @param width width of the image in pixels
* @param height height of the image in pixels
* @param size the size of the neigbourhood used in finding the threshold
* @param con the constant value subtracted from the mean
* @return a thresholded pixel array of the input image array
*/
public int[] mean_thresh(int[] src, int width, int height, int size,
int con) {
i_w = width;
i_h = height;
src_1d = new int[i_w * i_h];
dest_1d = new int[i_w * i_h];
int mean = 0;
int count = 0;
src_1d = src;
int[][] tmp_2d = new int[i_w][i_h];
//First convert input array from 1_d to 2_d for ease of processing
for (int i = 0; i < i_w; i++) {
for (int j = 0; j < i_h; j++) {
tmp_2d[i][j] = src_1d[i + (j * i_w)] & 0x000000ff;
}
}
final int HALF_SIZE = size / 2;
//Now find the sum of values in the size X size neigbourhood
for (int j = 0; j < i_h; j++) {
for (int i = 0; i < i_w; i++) {
mean = 0;
count = 0;
//Check the local neighbourhood
for (int k = 0; k < size; k++) {
for (int l = 0; l < size; l++) {
int x = i - HALF_SIZE + k;
int y = j - HALF_SIZE + l;
//If out of bounds then ignore pixel
if (x >= 0 && x < i_w && y >= 0 && y < i_h) {
mean = mean + tmp_2d[x][y];
count++;
}
}
}
//Find the mean value
mean = (mean / count) - con;
//Threshold below the mean
if (tmp_2d[i][j] > mean) {
dest_1d[i + (j * i_w)] = 0xffffffff;
} else {
dest_1d[i + (j * i_w)] = 0xff000000;
}
}
}
return dest_1d;
}
/**
* Applies the adaptive thresholding operator to the specified image array
* using the median function to find the threshold value
*
* @param src pixel array representing image to be thresholded
* @param width width of the image in pixels
* @param height height of the image in pixels
* @param size the size of the neigbourhood used in finding the threshold
* @param con the constant value subtracted from the median
* @return a thresholded pixel array of the input image array
*/
public int[] median_thresh(int[] src, int width, int height, int size,
int con) {
i_w = width;
i_h = height;
src_1d = new int[i_w * i_h];
dest_1d = new int[i_w * i_h];
int median = 0;
int[] values = new int[size * size];
int count = 0;
src_1d = src;
int[][] tmp_2d = new int[i_w][i_h];
//First convert input array from 1_d to 2_d for ease of processing
for (int i = 0; i < i_w; i++) {
for (int j = 0; j < i_h; j++) {
tmp_2d[i][j] = src_1d[i + (j * i_w)] & 0x000000ff;
}
}
//Now find the values in the size X size neigbourhood
for (int j = 0; j < i_h; j++) {
for (int i = 0; i < i_w; i++) {
median = 0;
count = 0;
values = new int[size * size];
//Check the local neighbourhood
for (int k = 0; k < size; k++) {
for (int l = 0; l < size; l++) {
try {
values[count] = tmp_2d[(i - ((int) (size / 2)) + k)]
[(j - ((int) (size / 2)) + l)];
count++;
}
//If out of bounds then ignore pixel
catch (ArrayIndexOutOfBoundsException e) {
// TODO: eliminate this
}
}
}
//Find the median value
//First Sort the array
Arrays.sort(values);
//Then select the median
count = count / 2;
median = values[count] - con;
//Threshold below the median
if (tmp_2d[i][j] >= median) {
dest_1d[i + (j * i_w)] = 0xffffffff;
} else {
dest_1d[i + (j * i_w)] = 0xff000000;
}
}
}
return dest_1d;
}
/**
* Applies the adaptive thresholding operator to the specified image array
* using the mean of max & min function to find the threshold value
*
* @param src pixel array representing image to be thresholded
* @param width width of the image in pixels
* @param height height of the image in pixels
* @param size the size of the neigbourhood used in finding the threshold
* @param con the constant value subtracted from the mean
* @return a thresholded pixel array of the input image array
*/
public int[] meanMaxMin_thresh(int[] src, int width, int height, int size,
int con) {
i_w = width;
i_h = height;
src_1d = new int[i_w * i_h];
dest_1d = new int[i_w * i_h];
int mean = 0;
int max, min;
int[] values = new int[size * size];
src_1d = src;
int[][] tmp_2d = new int[i_w][i_h];
//First convert input array from 1_d to 2_d for ease of processing
for (int i = 0; i < i_w; i++) {
for (int j = 0; j < i_h; j++) {
tmp_2d[i][j] = src_1d[i + (j * i_w)] & 0x000000ff;
}
}
int tmp;
//Now find the max and min of values in the size X size neigbourhood
for (int j = 0; j < i_h; j++) {
for (int i = 0; i < i_w; i++) {
mean = 0;
max = tmp_2d[i][j];
min = tmp_2d[i][j];
//Check the local neighbourhood
for (int k = 0; k < size; k++) {
for (int l = 0; l < size; l++) {
try {
tmp = tmp_2d[(i - ((int) (size / 2)) + k)]
[(j - ((int) (size / 2)) + l)];
if (tmp > max) {
max = tmp;
}
if (tmp < min) {
min = tmp;
}
}
//If out of bounds then ignore pixel
catch (ArrayIndexOutOfBoundsException e) {
// TODO: eliminate this
}
}
}
//Find the mean value
tmp = max + min;
tmp = tmp / 2;
mean = tmp - con;
//Threshold below the mean
if (tmp_2d[i][j] >= mean) {
dest_1d[i + (j * i_w)] = 0xffffffff;
} else {
dest_1d[i + (j * i_w)] = 0xff000000;
}
}
}
return dest_1d;
}
}