i looking copy paste implementation of canny edge detection in processing language. have 0 idea image processing , little clue processing, though understand java pretty well.
can processing expert tell me if there way of implementing http://www.tomgibara.com/computer-vision/cannyedgedetector.java in processing?
i think if treat processing
in lights of java
of problems solved easily. means can use java classes such.
for demo using implementation have shared.
>>original image
>>changed image
>>code
import java.awt.image.bufferedimage; import java.util.arrays; pimage orig; pimage changed; void setup() { orig = loadimage("c:/temp/image.png"); size(250, 166); cannyedgedetector detector = new cannyedgedetector(); detector.setlowthreshold(0.5f); detector.sethighthreshold(1f); detector.setsourceimage((java.awt.image.bufferedimage)orig.getimage()); detector.process(); bufferedimage edges = detector.getedgesimage(); changed = new pimage(edges); noloop(); } void draw() { //image(orig, 0,0, width, height); image(changed, 0,0, width, height); } // code below taken "http://www.tomgibara.com/computer-vision/cannyedgedetector.java" // have stripped comments conciseness public class cannyedgedetector { // statics private final static float gaussian_cut_off = 0.005f; private final static float magnitude_scale = 100f; private final static float magnitude_limit = 1000f; private final static int magnitude_max = (int) (magnitude_scale * magnitude_limit); // fields private int height; private int width; private int picsize; private int[] data; private int[] magnitude; private bufferedimage sourceimage; private bufferedimage edgesimage; private float gaussiankernelradius; private float lowthreshold; private float highthreshold; private int gaussiankernelwidth; private boolean contrastnormalized; private float[] xconv; private float[] yconv; private float[] xgradient; private float[] ygradient; // constructors /** * constructs new detector default parameters. */ public cannyedgedetector() { lowthreshold = 2.5f; highthreshold = 7.5f; gaussiankernelradius = 2f; gaussiankernelwidth = 16; contrastnormalized = false; } public bufferedimage getsourceimage() { return sourceimage; } public void setsourceimage(bufferedimage image) { sourceimage = image; } public bufferedimage getedgesimage() { return edgesimage; } public void setedgesimage(bufferedimage edgesimage) { this.edgesimage = edgesimage; } public float getlowthreshold() { return lowthreshold; } public void setlowthreshold(float threshold) { if (threshold < 0) throw new illegalargumentexception(); lowthreshold = threshold; } public float gethighthreshold() { return highthreshold; } public void sethighthreshold(float threshold) { if (threshold < 0) throw new illegalargumentexception(); highthreshold = threshold; } public int getgaussiankernelwidth() { return gaussiankernelwidth; } public void setgaussiankernelwidth(int gaussiankernelwidth) { if (gaussiankernelwidth < 2) throw new illegalargumentexception(); this.gaussiankernelwidth = gaussiankernelwidth; } public float getgaussiankernelradius() { return gaussiankernelradius; } public void setgaussiankernelradius(float gaussiankernelradius) { if (gaussiankernelradius < 0.1f) throw new illegalargumentexception(); this.gaussiankernelradius = gaussiankernelradius; } public boolean iscontrastnormalized() { return contrastnormalized; } public void setcontrastnormalized(boolean contrastnormalized) { this.contrastnormalized = contrastnormalized; } // methods public void process() { width = sourceimage.getwidth(); height = sourceimage.getheight(); picsize = width * height; initarrays(); readluminance(); if (contrastnormalized) normalizecontrast(); computegradients(gaussiankernelradius, gaussiankernelwidth); int low = math.round(lowthreshold * magnitude_scale); int high = math.round( highthreshold * magnitude_scale); performhysteresis(low, high); thresholdedges(); writeedges(data); } // private utility methods private void initarrays() { if (data == null || picsize != data.length) { data = new int[picsize]; magnitude = new int[picsize]; xconv = new float[picsize]; yconv = new float[picsize]; xgradient = new float[picsize]; ygradient = new float[picsize]; } } private void computegradients(float kernelradius, int kernelwidth) { //generate gaussian convolution masks float kernel[] = new float[kernelwidth]; float diffkernel[] = new float[kernelwidth]; int kwidth; (kwidth = 0; kwidth < kernelwidth; kwidth++) { float g1 = gaussian(kwidth, kernelradius); if (g1 <= gaussian_cut_off && kwidth >= 2) break; float g2 = gaussian(kwidth - 0.5f, kernelradius); float g3 = gaussian(kwidth + 0.5f, kernelradius); kernel[kwidth] = (g1 + g2 + g3) / 3f / (2f * (float) math.pi * kernelradius * kernelradius); diffkernel[kwidth] = g3 - g2; } int initx = kwidth - 1; int maxx = width - (kwidth - 1); int inity = width * (kwidth - 1); int maxy = width * (height - (kwidth - 1)); //perform convolution in x , y directions (int x = initx; x < maxx; x++) { (int y = inity; y < maxy; y += width) { int index = x + y; float sumx = data[index] * kernel[0]; float sumy = sumx; int xoffset = 1; int yoffset = width; for(; xoffset < kwidth ;) { sumy += kernel[xoffset] * (data[index - yoffset] + data[index + yoffset]); sumx += kernel[xoffset] * (data[index - xoffset] + data[index + xoffset]); yoffset += width; xoffset++; } yconv[index] = sumy; xconv[index] = sumx; } } (int x = initx; x < maxx; x++) { (int y = inity; y < maxy; y += width) { float sum = 0f; int index = x + y; (int = 1; < kwidth; i++) sum += diffkernel[i] * (yconv[index - i] - yconv[index + i]); xgradient[index] = sum; } } (int x = kwidth; x < width - kwidth; x++) { (int y = inity; y < maxy; y += width) { float sum = 0.0f; int index = x + y; int yoffset = width; (int = 1; < kwidth; i++) { sum += diffkernel[i] * (xconv[index - yoffset] - xconv[index + yoffset]); yoffset += width; } ygradient[index] = sum; } } initx = kwidth; maxx = width - kwidth; inity = width * kwidth; maxy = width * (height - kwidth); (int x = initx; x < maxx; x++) { (int y = inity; y < maxy; y += width) { int index = x + y; int indexn = index - width; int indexs = index + width; int indexw = index - 1; int indexe = index + 1; int indexnw = indexn - 1; int indexne = indexn + 1; int indexsw = indexs - 1; int indexse = indexs + 1; float xgrad = xgradient[index]; float ygrad = ygradient[index]; float gradmag = hypot(xgrad, ygrad); //perform non-maximal supression float nmag = hypot(xgradient[indexn], ygradient[indexn]); float smag = hypot(xgradient[indexs], ygradient[indexs]); float wmag = hypot(xgradient[indexw], ygradient[indexw]); float emag = hypot(xgradient[indexe], ygradient[indexe]); float nemag = hypot(xgradient[indexne], ygradient[indexne]); float semag = hypot(xgradient[indexse], ygradient[indexse]); float swmag = hypot(xgradient[indexsw], ygradient[indexsw]); float nwmag = hypot(xgradient[indexnw], ygradient[indexnw]); float tmp; if (xgrad * ygrad <= (float) 0 /*(1)*/ ? math.abs(xgrad) >= math.abs(ygrad) /*(2)*/ ? (tmp = math.abs(xgrad * gradmag)) >= math.abs(ygrad * nemag - (xgrad + ygrad) * emag) /*(3)*/ && tmp > math.abs(ygrad * swmag - (xgrad + ygrad) * wmag) /*(4)*/ : (tmp = math.abs(ygrad * gradmag)) >= math.abs(xgrad * nemag - (ygrad + xgrad) * nmag) /*(3)*/ && tmp > math.abs(xgrad * swmag - (ygrad + xgrad) * smag) /*(4)*/ : math.abs(xgrad) >= math.abs(ygrad) /*(2)*/ ? (tmp = math.abs(xgrad * gradmag)) >= math.abs(ygrad * semag + (xgrad - ygrad) * emag) /*(3)*/ && tmp > math.abs(ygrad * nwmag + (xgrad - ygrad) * wmag) /*(4)*/ : (tmp = math.abs(ygrad * gradmag)) >= math.abs(xgrad * semag + (ygrad - xgrad) * smag) /*(3)*/ && tmp > math.abs(xgrad * nwmag + (ygrad - xgrad) * nmag) /*(4)*/ ) { magnitude[index] = gradmag >= magnitude_limit ? magnitude_max : (int) (magnitude_scale * gradmag); //note: orientation of edge not employed //implementation. simple matter compute @ //this point as: math.atan2(ygrad, xgrad); } else { magnitude[index] = 0; } } } } private float hypot(float x, float y) { return (float) math.hypot(x, y); } private float gaussian(float x, float sigma) { return (float) math.exp(-(x * x) / (2f * sigma * sigma)); } private void performhysteresis(int low, int high) { arrays.fill(data, 0); int offset = 0; (int y = 0; y < height; y++) { (int x = 0; x < width; x++) { if (data[offset] == 0 && magnitude[offset] >= high) { follow(x, y, offset, low); } offset++; } } } private void follow(int x1, int y1, int i1, int threshold) { int x0 = x1 == 0 ? x1 : x1 - 1; int x2 = x1 == width - 1 ? x1 : x1 + 1; int y0 = y1 == 0 ? y1 : y1 - 1; int y2 = y1 == height -1 ? y1 : y1 + 1; data[i1] = magnitude[i1]; (int x = x0; x <= x2; x++) { (int y = y0; y <= y2; y++) { int i2 = x + y * width; if ((y != y1 || x != x1) && data[i2] == 0 && magnitude[i2] >= threshold) { follow(x, y, i2, threshold); return; } } } } private void thresholdedges() { (int = 0; < picsize; i++) { data[i] = data[i] > 0 ? -1 : 0xff000000; } } private int luminance(float r, float g, float b) { return math.round(0.299f * r + 0.587f * g + 0.114f * b); } private void readluminance() { int type = sourceimage.gettype(); if (type == bufferedimage.type_int_rgb || type == bufferedimage.type_int_argb) { int[] pixels = (int[]) sourceimage.getdata().getdataelements(0, 0, width, height, null); (int = 0; < picsize; i++) { int p = pixels[i]; int r = (p & 0xff0000) >> 16; int g = (p & 0xff00) >> 8; int b = p & 0xff; data[i] = luminance(r, g, b); } } else if (type == bufferedimage.type_byte_gray) { byte[] pixels = (byte[]) sourceimage.getdata().getdataelements(0, 0, width, height, null); (int = 0; < picsize; i++) { data[i] = (pixels[i] & 0xff); } } else if (type == bufferedimage.type_ushort_gray) { short[] pixels = (short[]) sourceimage.getdata().getdataelements(0, 0, width, height, null); (int = 0; < picsize; i++) { data[i] = (pixels[i] & 0xffff) / 256; } } else if (type == bufferedimage.type_3byte_bgr) { byte[] pixels = (byte[]) sourceimage.getdata().getdataelements(0, 0, width, height, null); int offset = 0; (int = 0; < picsize; i++) { int b = pixels[offset++] & 0xff; int g = pixels[offset++] & 0xff; int r = pixels[offset++] & 0xff; data[i] = luminance(r, g, b); } } else { throw new illegalargumentexception("unsupported image type: " + type); } } private void normalizecontrast() { int[] histogram = new int[256]; (int = 0; < data.length; i++) { histogram[data[i]]++; } int[] remap = new int[256]; int sum = 0; int j = 0; (int = 0; < histogram.length; i++) { sum += histogram[i]; int target = sum*255/picsize; (int k = j+1; k <=target; k++) { remap[k] = i; } j = target; } (int = 0; < data.length; i++) { data[i] = remap[data[i]]; } } private void writeedges(int pixels[]) { if (edgesimage == null) { edgesimage = new bufferedimage(width, height, bufferedimage.type_int_argb); } edgesimage.getwritabletile(0, 0).setdataelements(0, 0, width, height, pixels); } }
Comments
Post a Comment