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}