Guest User

CannyEdgeDetector in Java

a guest
Apr 7th, 2013
1,287
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * This file is part of the LIRE project: http://www.semanticmetadata.net/lire
  3.  * LIRE is free software; you can redistribute it and/or modify
  4.  * it under the terms of the GNU General Public License as published by
  5.  * the Free Software Foundation; either version 2 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * LIRE is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with LIRE; if not, write to the Free Software
  15.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  16.  *
  17.  * We kindly ask you to refer the any or one of the following publications in
  18.  * any publication mentioning or employing Lire:
  19.  *
  20.  * Lux Mathias, Savvas A. Chatzichristofis. Lire: Lucene Image Retrieval –
  21.  * An Extensible Java CBIR Library. In proceedings of the 16th ACM International
  22.  * Conference on Multimedia, pp. 1085-1088, Vancouver, Canada, 2008
  23.  * URL: http://doi.acm.org/10.1145/1459359.1459577
  24.  *
  25.  * Lux Mathias. Content Based Image Retrieval with LIRE. In proceedings of the
  26.  * 19th ACM International Conference on Multimedia, pp. 735-738, Scottsdale,
  27.  * Arizona, USA, 2011
  28.  * URL: http://dl.acm.org/citation.cfm?id=2072432
  29.  *
  30.  * Mathias Lux, Oge Marques. Visual Information Retrieval using Java and LIRE
  31.  * Morgan & Claypool, 2013
  32.  * URL: http://www.morganclaypool.com/doi/abs/10.2200/S00468ED1V01Y201301ICR025
  33.  *
  34.  * Copyright statement:
  35.  * --------------------
  36.  * (c) 2002-2013 by Mathias Lux (mathias@juggle.at)
  37.  *     http://www.semanticmetadata.net/lire, http://www.lire-project.net
  38.  */
  39.  
  40. package net.semanticmetadata.lire.imageanalysis.filters;
  41.  
  42. import net.semanticmetadata.lire.utils.ImageUtils;
  43.  
  44. import java.awt.color.ColorSpace;
  45. import java.awt.image.BufferedImage;
  46. import java.awt.image.ColorConvertOp;
  47. import java.awt.image.ConvolveOp;
  48. import java.awt.image.Kernel;
  49.  
  50.  /**
  51.  * This class is a simple implementation of a Canny Edge Detector.
  52.  *
  53.  * @author Mathias Lux, mathias@juggle.at, 05.04.13
  54.  */
  55. public class CannyEdgeDetector {
  56.     static ConvolveOp gaussian = new ConvolveOp(new Kernel(5, 5, ImageUtils.makeGaussianKernel(5, 1.4f)));
  57.     static ColorConvertOp grayscale = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
  58.  
  59.     int[] tmp255 = {255};
  60.     int[] tmp128 = {128};
  61.     int[] tmp000 = {0};
  62.     int[] tmpPixel = {0};
  63.     // double thresholds for Canny edge detector
  64.     double thresholdLow = 60, thresholdHigh = 100;
  65.  
  66.     BufferedImage bimg;
  67.  
  68.      /**
  69.       * Create a Canny Edge Detector for the given image. Set the thresholds yourself. Use {@link CannyEdgeDetector#filter} to create
  70.       * the edge image.
  71.       * @param image the input image.
  72.       * @param thresholdHigh higher of the thresholds
  73.       * @param thresholdLow lower of the thresholds
  74.       */
  75.     public CannyEdgeDetector(BufferedImage image, double thresholdHigh, double thresholdLow) {
  76.         this.bimg = image;
  77.         this.thresholdHigh = thresholdHigh;
  78.         this.thresholdLow = thresholdLow;
  79.     }
  80.  
  81.      /**
  82.       * Create a Canny Edge Detector for the given image. Set the thresholds yourself. Use {@link CannyEdgeDetector#filter} to create
  83.       * the edge image.
  84.       * @param bimg
  85.       */
  86.     public CannyEdgeDetector(BufferedImage bimg) {
  87.         this.bimg = bimg;
  88.     }
  89.  
  90.     /**
  91.      * Returns the edge image in grayscale. Edges are black (int 0) all other pixels are white (int 255)
  92.      * @return the filtered image.
  93.      */
  94.     public BufferedImage filter() {
  95.         // All for Canny Edge ...
  96.         BufferedImage gray;
  97.         double[][] gx, gy;
  98.         double[][] gd, gm;
  99.         int[][] gdRounded;
  100.  
  101.         // doing canny edge detection first:
  102.         // filter images:
  103.         gray = grayscale.filter(bimg, null);
  104.         gray = gaussian.filter(gray, null);
  105.         gx = sobelFilterX(gray);
  106.         gy = sobelFilterY(gray);
  107.         int width = gray.getWidth();
  108.         int height = gray.getHeight();
  109.         gd = new double[width][height];
  110.         gm = new double[width][height];
  111.         for (int x = 0; x < width; x++) {
  112.             for (int y = 0; y < height; y++) {
  113.                 // setting gradient magnitude and gradient direction
  114.                 if (gx[x][y] != 0) {
  115.                     gd[x][y] = Math.atan(gy[x][y] / gx[x][y]);
  116.                 } else {
  117.                     gd[x][y] = Math.PI / 2d;
  118.                 }
  119.                 gm[x][y] = Math.hypot(gy[x][y], gx[x][y]);
  120.             }
  121.         }
  122.         // Non-maximum suppression
  123.         for (int x = 0; x < width; x++) {
  124.             gray.getRaster().setPixel(x, 0, new int[]{255});
  125.             gray.getRaster().setPixel(x, height - 1, new int[]{255});
  126.         }
  127.         for (int y = 0; y < height; y++) {
  128.             gray.getRaster().setPixel(0, y, new int[]{255});
  129.             gray.getRaster().setPixel(width - 1, y, new int[]{255});
  130.         }
  131.         for (int x = 1; x < width - 1; x++) {
  132.             for (int y = 1; y < height - 1; y++) {
  133.                 if (gd[x][y] < (Math.PI / 8d) && gd[x][y] >= (-Math.PI / 8d)) {
  134.                     if (gm[x][y] > gm[x + 1][y] && gm[x][y] > gm[x - 1][y])
  135.                         setPixel(x, y, gray, gm[x][y]);
  136.                     else
  137.                         gray.getRaster().setPixel(x, y, tmp255);
  138.                 } else if (gd[x][y] < (3d * Math.PI / 8d) && gd[x][y] >= (Math.PI / 8d)) {
  139.                     if (gm[x][y] > gm[x - 1][y - 1] && gm[x][y] > gm[x - 1][y - 1])
  140.                         setPixel(x, y, gray, gm[x][y]);
  141.                     else
  142.                         gray.getRaster().setPixel(x, y, tmp255);
  143.                 } else if (gd[x][y] < (-3d * Math.PI / 8d) || gd[x][y] >= (3d * Math.PI / 8d)) {
  144.                     if (gm[x][y] > gm[x][y + 1] && gm[x][y] > gm[x][y + 1])
  145.                         setPixel(x, y, gray, gm[x][y]);
  146.                     else
  147.                         gray.getRaster().setPixel(x, y, tmp255);
  148.                 } else if (gd[x][y] < (-Math.PI / 8d) && gd[x][y] >= (-3d * Math.PI / 8d)) {
  149.                     if (gm[x][y] > gm[x + 1][y - 1] && gm[x][y] > gm[x - 1][y + 1])
  150.                         setPixel(x, y, gray, gm[x][y]);
  151.                     else
  152.                         gray.getRaster().setPixel(x, y, tmp255);
  153.                 } else {
  154.                     gray.getRaster().setPixel(x, y, tmp255);
  155.                 }
  156.             }
  157.         }
  158.         // hysteresis ... walk along lines of strong pixels and make the weak ones strong.
  159.         int[] tmp = {0};
  160.         for (int x = 1; x < width - 1; x++) {
  161.             for (int y = 1; y < height - 1; y++) {
  162.                 if (gray.getRaster().getPixel(x, y, tmp)[0] < 50) {
  163.                     // It's a strong pixel, lets find the neighbouring weak ones.
  164.                     trackWeakOnes(x, y, gray);
  165.                 }
  166.             }
  167.         }
  168.         // removing the single weak pixels.
  169.         for (int x = 2; x < width - 2; x++) {
  170.             for (int y = 2; y < height - 2; y++) {
  171.                 if (gray.getRaster().getPixel(x, y, tmp)[0] > 50) {
  172.                     gray.getRaster().setPixel(x, y, tmp255);
  173.                 }
  174.             }
  175.         }
  176.         return gray;
  177.     }
  178.  
  179.     /**
  180.      * Recursive tracking of weak points.
  181.      *
  182.      * @param x
  183.      * @param y
  184.      * @param gray
  185.      */
  186.     private void trackWeakOnes(int x, int y, BufferedImage gray) {
  187.         for (int xx = x - 1; xx <= x + 1; xx++)
  188.             for (int yy = y - 1; yy <= y + 1; yy++) {
  189.                 if (isWeak(xx, yy, gray)) {
  190.                     gray.getRaster().setPixel(xx, yy, tmp000);
  191.                     trackWeakOnes(xx, yy, gray);
  192.                 }
  193.             }
  194.     }
  195.  
  196.     private boolean isWeak(int x, int y, BufferedImage gray) {
  197.         return (gray.getRaster().getPixel(x, y, tmpPixel)[0] > 0 && gray.getRaster().getPixel(x, y, tmpPixel)[0] < 255);
  198.     }
  199.  
  200.     private void setPixel(int x, int y, BufferedImage gray, double v) {
  201.         if (v > thresholdHigh) gray.getRaster().setPixel(x, y, tmp000);
  202.         else if (v > thresholdLow) gray.getRaster().setPixel(x, y, tmp128);
  203.         else gray.getRaster().setPixel(x, y, tmp255);
  204.     }
  205.  
  206.     private double[][] sobelFilterX(BufferedImage gray) {
  207.         double[][] result = new double[gray.getWidth()][gray.getHeight()];
  208.         int[] tmp = new int[1];
  209.         int tmpSum;
  210.         for (int x = 1; x < gray.getWidth() - 1; x++) {
  211.             for (int y = 1; y < gray.getHeight() - 1; y++) {
  212.                 tmpSum = 0;
  213.                 tmpSum += gray.getRaster().getPixel(x - 1, y - 1, tmp)[0];
  214.                 tmpSum += 2 * gray.getRaster().getPixel(x - 1, y, tmp)[0];
  215.                 tmpSum += gray.getRaster().getPixel(x - 1, y + 1, tmp)[0];
  216.                 tmpSum -= gray.getRaster().getPixel(x + 1, y - 1, tmp)[0];
  217.                 tmpSum -= 2 * gray.getRaster().getPixel(x + 1, y, tmp)[0];
  218.                 tmpSum -= gray.getRaster().getPixel(x + 1, y + 1, tmp)[0];
  219.                 result[x][y] = tmpSum;
  220.             }
  221.         }
  222.         for (int x = 0; x < gray.getWidth(); x++) {
  223.             result[x][0] = 0;
  224.             result[x][gray.getHeight() - 1] = 0;
  225.         }
  226.         for (int y = 0; y < gray.getHeight(); y++) {
  227.             result[0][y] = 0;
  228.             result[gray.getWidth() - 1][y] = 0;
  229.         }
  230.         return result;
  231.     }
  232.  
  233.     private double[][] sobelFilterY(BufferedImage gray) {
  234.         double[][] result = new double[gray.getWidth()][gray.getHeight()];
  235.         int[] tmp = new int[1];
  236.         int tmpSum = 0;
  237.         for (int x = 1; x < gray.getWidth() - 1; x++) {
  238.             for (int y = 1; y < gray.getHeight() - 1; y++) {
  239.                 tmpSum = 0;
  240.                 tmpSum += gray.getRaster().getPixel(x - 1, y - 1, tmp)[0];
  241.                 tmpSum += 2 * gray.getRaster().getPixel(x, y - 1, tmp)[0];
  242.                 tmpSum += gray.getRaster().getPixel(x + 1, y - 1, tmp)[0];
  243.                 tmpSum -= gray.getRaster().getPixel(x - 1, y + 1, tmp)[0];
  244.                 tmpSum -= 2 * gray.getRaster().getPixel(x, y + 1, tmp)[0];
  245.                 tmpSum -= gray.getRaster().getPixel(x + 1, y + 1, tmp)[0];
  246.                 result[x][y] = tmpSum;
  247.             }
  248.         }
  249.         for (int x = 0; x < gray.getWidth(); x++) {
  250.             result[x][0] = 0;
  251.             result[x][gray.getHeight() - 1] = 0;
  252.         }
  253.         for (int y = 0; y < gray.getHeight(); y++) {
  254.             result[0][y] = 0;
  255.             result[gray.getWidth() - 1][y] = 0;
  256.         }
  257.         return result;
  258.     }
  259.  
  260.  
  261. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×