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 imagingbook.lib.math.Matrix;
015
016/**
017 * Multi-Gradient ("DiZenzo/Cumani-style") color edge detector, as described in UTICS Vol. 3, Alg. 4.2.
018 * @author W. Burger
019 * @version 2013/05/30
020 */
021public class DiZenzoCumaniEdgeDetector extends ColorEdgeDetector {
022        
023        /**
024         * Currently unused, no parameters to set
025         */
026        public static class Parameters {
027        }
028        
029        final Parameters params;
030        
031        int M;  // image width
032        int N;  // image height
033        ColorProcessor I;       // original image
034        FloatProcessor E_mag;   // edge magnitude map
035        FloatProcessor E_ort;   // edge orientation map
036
037        // Sobel-kernels for x/y-derivatives:
038    final float[] HxS = Matrix.multiply(1.0f/8, 
039        new float[] {
040                        -1, 0, 1,
041                    -2, 0, 2,
042                    -1, 0, 1
043                    });
044    
045    final float[] HyS = Matrix.multiply(1.0f/8, 
046                 new float[] {
047                        -1, -2, -1,
048                         0,  0,  0,
049                         1,  2,  1
050                         });
051    
052    final int R = 0, G = 1, B = 2;              // RGB channel indexes
053        
054    FloatProcessor[] Ix;
055    FloatProcessor[] Iy;
056 
057        public DiZenzoCumaniEdgeDetector(ColorProcessor I) {
058                this(I, new Parameters());
059        }
060        
061        public DiZenzoCumaniEdgeDetector(ColorProcessor I, Parameters params) {
062                this.params = params;
063                this.I = I;
064                setup();
065                findEdges();
066        }
067        
068        protected void setup() {
069                M = this.I.getWidth();
070                N = this.I.getHeight();
071                E_mag = new FloatProcessor(M, N);
072                E_ort = new FloatProcessor(M, N);
073                Ix = new FloatProcessor[3];
074                Iy = new FloatProcessor[3];
075        }
076
077        void findEdges() {
078                for (int c = R; c <= B; c++) {
079                        Ix[c] =  getRgbFloatChannel(I, c);
080                        Iy[c] =  getRgbFloatChannel(I, c);
081                        Ix[c].convolve(HxS, 3, 3);
082                        Iy[c].convolve(HyS, 3, 3);
083                }
084                
085                for (int v = 0; v < N; v++) {
086                        for (int u = 0; u < M; u++) {
087                                float Rx = Ix[R].getf(u, v);    float Ry = Iy[R].getf(u, v);
088                                float Gx = Ix[G].getf(u, v);    float Gy = Iy[G].getf(u, v);
089                                float Bx = Ix[B].getf(u, v);    float By = Iy[B].getf(u, v);
090                                
091                                float AA = sqr(Rx) + sqr(Gx) + sqr(Bx);
092                                float BB = sqr(Ry) + sqr(Gy) + sqr(By);
093                                float CC = Rx * Ry + Gx * Gy + Bx * By;
094                                
095                                float lambda1 = 0.5f * (AA + BB + (float) Math.sqrt(sqr(AA-BB) + 4 * sqr(CC)));
096                                float theta1 = 0.5f * (float) Math.atan2(2 * CC, AA - BB);
097
098                                E_mag.setf(u, v, (float) Math.sqrt(lambda1));
099                                E_ort.setf(u, v, theta1);
100//                              edgeOrientation.setf(u, v, 2 * CC);
101//                              edgeOrientation.setf(u, v, AA - BB);
102                                
103                        }
104                }
105        }
106        
107        public FloatProcessor getEdgeMagnitude() {
108                return E_mag;
109        }
110
111        public FloatProcessor getEdgeOrientation() {
112                return E_ort;
113        }
114        
115        float sqr(float x) {
116                return x * x;
117        }
118}