001/******************************************************************************* 002 * This software is provided as a supplement to the authors' textbooks on digital 003 * image processing published by Springer-Verlag in various languages and editions. 004 * Permission to use and distribute this software is granted under the BSD 2-Clause 005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit http://imagingbook.com for additional details. 008 *******************************************************************************/ 009 010package imagingbook.pub.color.edge; 011 012import ij.process.ColorProcessor; 013import ij.process.FloatProcessor; 014import ij.process.ImageProcessor; 015import imagingbook.lib.math.Matrix; 016 017/** 018 * Simple grayscale edge detector for color images. The color image 019 * is converted to grayscale for edge detection. 020 * @author W. Burger 021 * @version 2014/02/17 022 */ 023public class GrayscaleEdgeDetector extends ColorEdgeDetector { 024 025 026 final ImageProcessor I; 027 final int M; // image width 028 final int N; // image height 029 final Parameters params; 030 031 final FloatProcessor Emag; // edge magnitude map 032 final FloatProcessor Eort; // edge orientation map 033 034 double wr = 0.2126, wg = 0.7152, wb = 0.0722; // ITU BR.709 luma weights 035 036 /** 037 * Currently unused, no parameters to set 038 */ 039 public static class Parameters { 040 } 041 042 // Sobel-kernels for x/y-derivatives: 043 final float[] HxS = Matrix.multiply(1.0f/8, new float[] { 044 -1, 0, 1, 045 -2, 0, 2, 046 -1, 0, 1 047 }); 048 049 final float[] HyS = Matrix.multiply(1.0f/8, new float[] { 050 -1, -2, -1, 051 0, 0, 0, 052 1, 2, 1 053 }); 054 055 final int R = 0, G = 1, B = 2; // RGB channel indexes 056 057 private FloatProcessor Ix; 058 private FloatProcessor Iy; 059 060 public GrayscaleEdgeDetector(ImageProcessor I) { 061 this(I, new Parameters()); 062 } 063 064 public GrayscaleEdgeDetector(ImageProcessor I, Parameters params) { 065 this.params = params; 066 this.I = I; 067 this.M = this.I.getWidth(); 068 this.N = this.I.getHeight(); 069 Emag = new FloatProcessor(M, N); 070 Eort = new FloatProcessor(M, N); 071 setup(); 072 findEdges(); 073 } 074 075 protected void setup() { 076 // convert to a grayscale (float) image with specified RGB weights: 077 if (I instanceof ColorProcessor) { 078 ((ColorProcessor)I).setRGBWeights(wr, wg, wb); 079 } 080 Ix = I.convertToFloatProcessor(); 081 Iy = (FloatProcessor) Ix.duplicate(); 082 } 083 084 void findEdges() { 085 Ix.convolve(HxS, 3, 3); 086 Iy.convolve(HyS, 3, 3); 087 088 for (int v = 0; v < N; v++) { 089 for (int u = 0; u < M; u++) { 090 // extract the gradients of the R, G, B channels: 091 final float dx = Ix.getf(u, v); 092 final float dy = Iy.getf(u, v); 093 094 // calculate local edge magnitude: 095 final float eMag = (float) Math.sqrt(dx * dx + dy * dy); 096 Emag.setf(u, v, eMag); 097 098 // calculate edge orientation for the maximum channel: 099 float eOrt = (float) Math.atan2(dy, dx); 100 Eort.setf(u, v, eOrt); 101 } 102 } 103 } 104 105 public FloatProcessor getEdgeMagnitude() { 106 return Emag; 107 } 108 109 public FloatProcessor getEdgeOrientation() { 110 return Eort; 111 } 112 113}