Advertisement
Guest User

CannyEdgeDetector in Java

a guest
Apr 7th, 2013
1,449
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.59 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement