package analyzer;
import imagetools.FileTypeException;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import sort.QuickSort;
import StatPack.IQR;
import imagetools.Crop;
/*
* Takes in a well edge detected image and finds letters in the set.
*
* Iterates through an image and finds what is likely to be a set of letters
* which are returned as arrays representing the minimum bounding box.
*
*NOTE: Java will store pointers to an image in memory. It is best to use the getters and setters when using a broader
*class.
*
* aevans 9.6.2013
*/
public class GetLetterSet {
private BufferedImage img;
// sets for statistics
private ArrayList<Double> heights = new ArrayList<Double>();
private ArrayList<Double> widths = new ArrayList<Double>();
private String[][] edges;
// set of letters
private ArrayList<int[]> letters = new ArrayList<int[]>();
// images
private byte[] bimage;
private String imagepath;
// relevant statistics
private int averagewidth;
private int averageheight;
// the outliers
private int uo = 0;
private int lo = 0;
// outlier specification(e.g. 1.5 or 3 times IQR)
private int extremes = 0;
// max and mins per letter
private int maxX = 0;
private int minX = 0;
private int maxY = 0;
private int minY = 0;
// current number in the set
private int current = -1;
public GetLetterSet() {
// TODO empty constructor
}
public GetLetterSet(byte[] img) {
// TODO constructor with image byte array and sets an image
bimage = img;
createFromBytes();
}
public GetLetterSet(String ip) {
// TODO constructor with image byte array and sets an image
imagepath = ip;
createFromImagePath();
}
public ArrayList<int[]> getSet() {
// TODO return the letter set
return letters;
}
public void setSet(ArrayList<int[]> inset) {
// TODO set the letter set
letters = inset;
current = 0;
}
public int getExtremes() {
// TODO returns the IQR*num used in outlier analysis
return extremes;
}
public void setExtremes(int inextremes) {
// TODO sets the extremes
extremes = inextremes;
}
public int[] getNext() {
// TODO return the next integer array in the set
if (letters.size() > 0) {
current++;
return letters.get(current);
}
return null;
}
public void setImg(BufferedImage inimg) {
// TODO set image
img = inimg;
}
public BufferedImage getImg() {
// TODO return image
return img;
}
public byte[] getBimage() {
// TODO return image bytes
return bimage;
}
public void setBimage(byte[] bi) {
// TODO set bimage
bimage = bi;
createFromBytes();
}
public void setImagepath(String ip) {
// TODO set image path and image from string
imagepath = ip;
createFromImagePath();
}
public String getImagepath() {
// TODO return image path
return imagepath;
}
private void createFromImagePath() {
// TODO create image from path
try {
img = ImageIO.read(new File(imagepath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void createFromBytes() {
// TODO set img from byte array using byte stream
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bimage);
img = ImageIO.read(bis);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void findPrettySet(int length, int height) {
// TODO find a set of letters from a word document or other easily
// formated set using given lengths and heights of a Letter Space
/*
* 1.)Iterate across the page looking for the first letter in the page.
* 2.)Create a window which moves across the page finding letters 3.)
* Return the set
*/
current = 0;
}
public void findPrettySet() {
// TODO find a set of letters from a word document or other easily
// formated set
/*
* 1.) Iterate across several rows marking edges until a decent number
* of lines are terminated. 4.) Get the Height and length of Several
* letters 3.) Get the Letter Set using a window that looks for the
* first part of the set 4.) Return the Set
*/
current = 0;
}
private int getHeights() {
// TODO get a set of heights and return an average height for the window
int avg = 0;
return avg;
}
private void followEdge(int x, int y) {
// TODO follow a letter edge using DFS storing height and width data
// iterate down the edge grabbing the maximum and minimum widths and
// heights
// set the max and mins if they are greater or less
// boolean for determining wheter an edge exists
Boolean edge = true;
// the color variable
Color c = null;
// the current x and y
int cx = x - 1;
int cy = y - 1;
// iterate across each potential color containing cell
for (int i = 0; i < 9; i++) {
// check the coordinate boundaries before checking the color
// boundaries
if (cx > -1 & cx < img.getWidth() & cy > -1 & cy < img.getHeight()) {
// get the new color
c = new Color(img.getRGB(cx, cy));
// check to see if coordinate is an edge
if (((c.getRed() + c.getBlue() + c.getGreen()) / 3) > 50
& edges[cx][cy].compareTo("n") == 0) {
// check against maxs and mins
if (cx > maxX) {
maxX = cx;
} else if (cx < minX) {
minX = cx;
}
if (cy > maxY) {
maxY = cy;
} else if (cy < minY) {
minY = cy;
}
edges[cx][cy] = "c";
followEdge(cx, cy);
} else if (edges[cx][cy].compareTo("n") == 0) {
edges[cx][cy] = "v";
}
}
if ((i % 3) == 0) {
cx = x - 1;
cy++;
} else {
cx++;
}
}
}
private void getLengths() {
// TODO gets a set of lengths to be processed
// image properties
int width = img.getWidth();
int height = img.getHeight();
Color c = null;
int x = 0;
int y = 0;
// iterate across the rows collecting a set of data and recording edges
/*
* Alternative to explore: store in map keyed at position of previous
* object part containing array of max and min x and y, every time the
* object is reached compare for stats, store new stats +: No need for
* recursion -: Still contains nested loops -: Accesses a map and an
* array many times -: fastest way would require iterating down the list
* at the end and creating totals per object
*/
for (int i = 0; i < (width * height); i++) {
// get the color
c = new Color(img.getRGB(x, y));
// check the colors and enter if statement if criteria is met
if ((c.getRed() + c.getGreen() + c.getBlue()) / 3 > 50
& edges[x][y].compareTo("n") == 0) {
// prepare for data collection
maxX = x;
minX = x;
maxY = y;
minY = y;
// get heights and widths
followEdge(x, y);
// add height and width to the appropriate sets
heights.add((double) (maxY - minY));
widths.add((double) (maxX - minX));
}
// prepare for the next iteration
if ((i % width) == 0) {
x = 0;
y++;
} else {
x++;
}
}
// initialize sort for heights
QuickSort<Double> qs = new QuickSort<Double>(heights);
qs.sort();
heights = qs.getData();
// sort widths
qs.setData(widths);
qs.sort();
widths = qs.getData();
// get IQR for heights
IQR iqr = new IQR(heights);
iqr.pullstats();
// get IQR for widths
iqr.setNums(widths);
iqr.pullstats();
// iterate across the edges map and get the set using the statistics
}
public void findSet() {
// TODO find the image sets and get them as byte arrays
// WARNING: Works with Horizontal Letters only |letters that cross over
// one another may fail depending on whether the
// best fit (based on statistics by quadrant) are skewed
// WARNING: To use this method the image must be split into multiple
// images representing each line (be good to yourself
// and try to give some time for garbage collection or space will be a
// problem)
/*
* iterate down the image marking changes in color & check the changes
* until finding an appropriately narrow set 1. Mark edges and store the
* largest lengths of each potential letter (ending where terminated) 2.
* Get Outlier Data and create a window for viewing letters in a set
* from the rows width he largest lengths 3. Move down the set and move
* the window, finding letters across the page that fall within the
* relevant statistics 4. Return the set
*/
current = 0;
// create the edge double array (instantiated only as needed)
setupEdges();
// boolean to control whether to mark or not
Boolean cswitch = false;
// get the lengths
getLengths();
}
private void setupEdges() {
// TODO create/recreate the edgs double array
edges = new String[img.getWidth()][img.getHeight()];
for (int i = 0; i < img.getWidth(); i++) {
for (int j = 0; j < img.getHeight(); j++) {
edges[i][j] = "n";
}
}
}
public void save() {
// TODO save the image if the path and image are set
if (imagepath != null & img != null) {
if (imagepath.lastIndexOf(".") > -1) {
// the file type string
String filetype = imagepath.substring((imagepath
.lastIndexOf(".") + 1));
try {
// write the image to the path
ImageIO.write(img, filetype.toUpperCase().trim(), new File(
imagepath));
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("No Path specified");
e.printStackTrace();
}
} else {
try {
throw new FileTypeException();
} catch (FileTypeException e) {
// no file type specified
e.printStackTrace();
}
}
} else {
try {
throw new FileTypeException();
} catch (FileTypeException e) {
// no file type specified
e.printStackTrace();
}
}
}
}