java - Canny Edge Detection using Processing -


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

enter image description here

>>changed image

enter image description here

>>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