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}