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