package imagetools; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; /* * The Class is used to Detect Edges Using a Laplace Based Filter. * See the Notes for More. */ public class GetEdges { BufferedImage image, original; String path; String[][] ve = null; private int upperthreshold = 30; private int lowerthreshold = 26; public GetEdges() { // TOODO Empty Constructor } public GetEdges(BufferedImage img) { // TODO constructor with only image if (img != null) { image = img; original = img; } else { // if no image is provided throws an exception try { throw new NoImgException(); } catch (NoImgException e) { e.printStackTrace(); } } } public GetEdges(BufferedImage img, String inpath) { // TODO constructor that takes in image and path --> performs the blur if (img != null) { image = img; original = img; path = inpath; } else { // if no image is provided throws an exception try { throw new NoImgException(); } catch (NoImgException e) { e.printStackTrace(); } } } public GetEdges(String inpath) { // TODO constructor that takes in a path and loads an image --> performs // the blur path = inpath; try { image = ImageIO.read(new File(path)); original = image; } catch (IOException e) { e.printStackTrace(); } } public void sethigh(int ut) { // TODO set the upper threshold for hysterisis upperthreshold = ut; } public void setlow(int lt) { // TODO set the lower threshold for hysterisis lowerthreshold = lt; } public void revert_to_original_image() { image = original; } public BufferedImage get_original() { // TODO return the buffered image return original; } public void set_path_and_image(String inpath) { // TODO sets a patha and attempts to create an image path = inpath; try { image = ImageIO.read(new File(path)); original = image; } catch (IOException e) { e.printStackTrace(); } } public void setImage(BufferedImage inimg) { // TODO set image via buffered image if (inimg != null) { image = inimg; original = image; } else { try { throw new NoImgException(); } catch (NoImgException e) { e.printStackTrace(); } } } public BufferedImage getImage() { // TODO return the image return image; } /* The Meat and Potatoes */ public void edge_detect() { // TODO Edge Detect using an Edge Detection Algorithm do_edge_detect(); } public void edge_detect(Boolean nonsloppy) { // TODO edge detect with the decision made as to whether or not to do a // thorough hysterisis analysis do_edge_detect(nonsloppy); } public void find_edges_laplace() { // TODO Get a rough idea of the edges using laplace (pre-processing may // render this useful if it is necessary) edge_detect_laplace(); } private void magnitude() { // TODO calculate magnitude /* * Kernels * * G(x) G(y) -1|0|1 -1|-2|-1 -2|0|2 0|0|0 -1|0|1 1|-2|1 * * |G|(magnitude for each cell)approx. =|G(x)|+|G(y)|= * |(p1+2p2+p3)-(p7+2p8+p9)|+|(p3+2p6+p9)|-|(p1+2p4+p7)|blank rows or * colums are left out of the calc. */ // the buffered image BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY); // gives ultimate control can also use image libraries // the current position properties int x = 0; int y = 0; // the image width and height properties int width = image.getWidth(); int height = image.getHeight(); // iterate throught the image for (y = 1; y < height - 1; y++) { for (x = 1; x < width - 1; x++) { // convert to greyscale by masking (32 bit color representing // intensity --> reduce to greyscale by taking only set bits) // gets the pixels surrounding hte center (the center is always // weighted at 0 in the convolution matrix) int c1 = (image.getRGB(x - 1, y - 1) & 0xFF); int c2 = (image.getRGB(x - 1, y) & 0xFF); int c3 = (image.getRGB(x - 1, y + 1) & 0xFF); int c4 = (image.getRGB(x, y - 1) & 0xFF); int c6 = (image.getRGB(x, y + 1) & 0xFF); int c7 = (image.getRGB(x + 1, y - 1) & 0xFF); int c8 = (image.getRGB(x + 1, y) & 0xFF); int c9 = (image.getRGB(x + 1, y + 1) & 0xFF); // apply the magnitude of the convolution kernal (blank // column/row not applied) // differential x and y gradients are as follows // this is non-max suppression /* * Lxx = |1,-2,1|*L Lyy= {1,-2,1}*L ({} because its vertical and * not horizontal) */ int color = Math.abs((c1 + (2 * c2) + c3) - (c7 + (2 * c8) + c9)) + Math.abs((c3 + (2 * c6) + c9) - (c1 + (2 * c4) + c7)); // trim to fit the appropriate color pattern color = Math.min(255, Math.max(0, color)); // suppress non-maximum // set new pixel of the edge image2.setRGB(x, y, color); } } // reset the image image = image2; } private void greedy_hysterisis() { // TODO when an image using 2nd and 3rd order matrices is not producing // high quality edges, this will take the upper and lower thresholds to // find better edges // this is the sloppy alg. meant to decrease time for a full // implementation DFS is advised, follow an edge to its conclusion and // go back to any unvisited edges (hash map advised) // I need my alg to run in under 3.5 seconds ideally so that I can run // stats and not timeout a web page during a capture breaking process /* * Requires a non-maximum suppressed image * * Hysterisis typically uses change in angle (a.k.a with time to * model/find changes)Edges will fall at the upper and lower end of the * spectrum */ /* * WARNING: This implementation assume, after non-max suppression and * sufficient pre-processing, that all things above/below threshold are * edges */ // get the image pixels which are now in greyscale int height = image.getHeight(); int width = image.getWidth(); // string for pixels int color = 0; Color temp = null; // note a higher upper threshold centers on more defined edges almost to // the point of isolating all outliers // iterate throught the image for (int y = 1; y < height - 1; y++) { for (int x = 1; x < width - 1; x++) { temp = (new Color(image.getRGB(x, y))); // get pixel int c5 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; // get neighbors temp = (new Color(image.getRGB(x - 1, y - 1))); int c1 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x - 1, y))); int c2 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x - 1, y + 1))); int c3 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x, y - 1))); int c4 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x, y + 1))); int c6 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x + 1, y - 1))); int c7 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x + 1, y))); int c8 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; temp = (new Color(image.getRGB(x + 1, y + 1))); int c9 = (temp.getRed() + temp.getBlue() + temp.getGreen()) / 3; // find hysterisis // if a neighbor meets the higher threshold value, set the // current pixel if (c5 >= lowerthreshold & (c1 >= upperthreshold | c2 >= upperthreshold | c3 >= upperthreshold | c4 >= upperthreshold | c6 >= upperthreshold | c7 >= upperthreshold | c8 >= upperthreshold | c9 >= upperthreshold)) { // set the color to max color = 255 * 3; // reset the value image.setRGB(x, y, color); } else { image.setRGB(x, y, new Color(0, 0, 0).getRGB()); } } } // go through the image one more time setting anything lower than 255 to // 0 for (int y = 1; y < height - 1; y++) { for (int x = 1; x < width - 1; x++) { // get pixel temp = (new Color(image.getRGB(x, y))); int c5 = (temp.getRed() + temp.getBlue() + temp.getGreen()); // find hysterisis // if a neighbor meets the higher threshold value, set the // current pixel if (c5 < 225) { // set the color to max color = 0; // reset the value image.setRGB(x, y, color); } } } } private void do_edge_detect() { // TODO find edges using sobel and hysterisis magnitude(); greedy_hysterisis(); } private void do_edge_detect(Boolean nonsloppy) { // TODO find edges with the decision made as to whether or not to do a // thorough hysterisis analysis magnitude(); if (nonsloppy == true) { hysterisis(); } else { greedy_hysterisis(); } } private void follow_edge(int j, int i, int width, int height) { // TODO recursively search edges (memory shouldn't be a problem here // since the set is finite and should there should be less steps than // number of pixels) // search the eight side boxes for a proper edge marking non-edges as // visitors, follow any edge with the for-loop acting // as the restarter int x = j - 1; int y = i - 1; Color curcol = null; for (int k = 0; k < 9; k++) { if (x >= 0 & x < width & y >= 0 & y < height & x != j & y != i) { curcol = new Color(image.getRGB(j, i)); // check color if (ve[x][y].compareTo("n") == 0 & ((curcol.getRed() + curcol.getBlue() + curcol .getGreen()) / 3) > lowerthreshold) { ve[x][y] = "c"; image.setRGB(j, i, new Color(255, 255, 255).getRGB()); follow_edge(x, y, width, height); } else if (ve[x][y].compareTo("n") == 0 & x != j & y != i) { ve[x][y] = "v"; image.setRGB(j, i, new Color(0, 0, 0).getRGB()); } } // check x and y by k if ((k % 3) == 0) { x = (j - 1); y++; } } } private void hysterisis() { // TODO perform a non-greedy hysterisis using upper and lower threshold // values int width = image.getWidth(); int height = image.getHeight(); Color curcol = null; int r = 0; int g = 0; int b = 0; ve = new String[width][height]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { ve[i][j] = "n"; } } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { curcol = new Color(image.getRGB(j, i)); if (ve[j][i].compareTo("n") == 0 & (((curcol.getRed() + curcol.getBlue() + curcol .getGreen()) / 3) > upperthreshold)) { ve[j][i] = "c"; image.setRGB(j, i, new Color(255, 255, 255).getRGB()); follow_edge(j, i, width, height); } else if (ve[j][i].compareTo("n") == 0) { ve[j][i] = "v"; image.setRGB(j, i, new Color(0, 0, 0).getRGB()); } } } } private void find_all_edges() { // TODO find all edges using laplace rather than sobel and hysterisis // (noise can interfere with the result) // the new buffered image containing the edges BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB); // gives ultimate control can also use image libraries // the current position properties int x = 0; int y = 0; // the image width and height properties int width = image.getWidth(); int height = image.getHeight(); /* * Denoise Using Rewritten Code found at * http://introcs.cs.princeton.edu/ * java/31datatype/LaplaceFilter.java.html * * Using laplace is better than averaging the neighbors from each part * of an image as it does a better job of getting rid of gaussian noise * without overdoing it * * Applies a default filter: * * -1|-1|-1 -1|8|-1 -1|-1|-1 */ // perform the laplace for each number for (y = 1; y < height - 1; y++) { for (x = 1; x < width - 1; x++) { // get the neighbor pixels for the transform Color c00 = new Color(image.getRGB(x - 1, y - 1)); Color c01 = new Color(image.getRGB(x - 1, y)); Color c02 = new Color(image.getRGB(x - 1, y + 1)); Color c10 = new Color(image.getRGB(x, y - 1)); Color c11 = new Color(image.getRGB(x, y)); Color c12 = new Color(image.getRGB(x, y + 1)); Color c20 = new Color(image.getRGB(x + 1, y - 1)); Color c21 = new Color(image.getRGB(x + 1, y)); Color c22 = new Color(image.getRGB(x + 1, y + 1)); /* apply the matrix */ // to check, try using gauss jordan // apply the transformation for r int r = -c00.getRed() - c01.getRed() - c02.getRed() + -c10.getRed() + 8 * c11.getRed() - c12.getRed() + -c20.getRed() - c21.getRed() - c22.getRed(); // apply the transformation for g int g = -c00.getGreen() - c01.getGreen() - c02.getGreen() + -c10.getGreen() + 8 * c11.getGreen() - c12.getGreen() + -c20.getGreen() - c21.getGreen() - c22.getGreen(); // apply the transformation for b int b = -c00.getBlue() - c01.getBlue() - c02.getBlue() + -c10.getBlue() + 8 * c11.getBlue() - c12.getBlue() + -c20.getBlue() - c21.getBlue() - c22.getBlue(); // set the new rgb values r = Math.min(255, Math.max(0, r)); g = Math.min(255, Math.max(0, g)); b = Math.min(255, Math.max(0, b)); Color c = new Color(r, g, b); image2.setRGB(x, y, c.getRGB()); } } image = image2; } private void edge_detect_laplace() { // TODO call for edge detection using laplacian filter // set the filetype string and if found, render the image if (path.lastIndexOf(".") > -1) { // if the path points to an image perform denoise find_all_edges(); } else { try { throw new FileTypeException(); } catch (FileTypeException e) { // no file type specified e.printStackTrace(); } } } public void save() { // TODO save the image if (path != null) { if (path.lastIndexOf(".") > -1) { // the file type string String filetype = path.substring((path.lastIndexOf(".") + 1)); try { // write the image to the path ImageIO.write(image, filetype.toUpperCase().trim(), new File(path)); } 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(); } } } }