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(); } } } }