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.lib.math; 011 012public abstract class VectorNorm { 013 014 public abstract double magnitude(double[] x); 015 public abstract double magnitude(int[] x); 016 017 /** 018 * Calculates the distance between two vectors. 019 * 020 * @param a first vector 021 * @param b second vector 022 * @return the distance between vectors a and b 023 */ 024 public abstract double distance(double[] a, double[] b); 025 public abstract double distance(float[] a, float[] b); 026 public abstract double distance(int[] a, int[] b); 027 028 /** 029 * 030 * @param a first vector 031 * @param b second vector 032 * @return the squared distance between vectors a and b 033 */ 034 public abstract double distance2(double[] a, double[] b); 035 public abstract double distance2(float[] a, float[] b); 036 public abstract double distance2(int[] a, int[] b); 037 038 039 /** 040 * Returns a factor to scale magnitude and distance values 041 * to the range of the vector components of dimensionality 042 * n. This is prim. used for scaling color distances (n = 3). 043 * E.g., if components are distributed in [0,255], the distances 044 * multiplied by this factor should again be in [0,255]. 045 * 046 * @param n dimensionality 047 * @return scale factor 048 */ 049 public abstract double getScale(int n); 050 051 private interface Creator { 052 public VectorNorm create(); 053 } 054 055 public enum NormType implements Creator { 056 L1 {public VectorNorm create() {return new VectorNorm.L1();}}, 057 L2 {public VectorNorm create() {return new VectorNorm.L2();}}, 058 Linf {public VectorNorm create() {return new VectorNorm.Linf();} 059 }; 060 } 061 062 static String wrongLengthMessage = "feature vectors must be of same length"; 063 064 // ------------------------------------------------------------------------------ 065 066 public static class L1 extends VectorNorm { 067 068 public double magnitude(double[] X) { 069 double sum = 0.0; 070 for (int i = 0; i < X.length; i++) { 071 sum = sum + Math.abs(X[i]); 072 } 073 return sum; 074 } 075 076 public double magnitude(int[] X) { 077 long sum = 0; 078 for (int i = 0; i < X.length; i++) { 079 sum = sum + Math.abs(X[i]); 080 } 081 return (double) sum; 082 } 083 084 public double distance(final double[] X, final double[] Y) { 085 if (X.length != Y.length) { 086 throw new IllegalArgumentException(wrongLengthMessage); 087 } 088 double sum = 0.0; 089 for (int i = 0; i < X.length; i++) { 090 double d = X[i] - Y[i]; 091 sum = sum + Math.abs(d); 092 } 093 return sum; 094 } 095 096 public double distance(final int[] X, final int[] Y) { 097 if (X.length != Y.length) { 098 throw new IllegalArgumentException(wrongLengthMessage); 099 } 100 int sum = 0; 101 for (int i = 0; i < X.length; i++) { 102 sum = sum + Math.abs(X[i] - Y[i]); 103 } 104 return sum; 105 } 106 107 public double distance2(double[] a, double[] b) { 108 double d = distance(a, b); 109 return d * d; 110 } 111 112 public double distance2(int[] a, int[] b) { 113 double d = distance(a, b); 114 return d * d; 115 } 116 117 public double getScale(int n) { 118 return 1.0 / n; 119 } 120 121 @Override 122 public double distance2(float[] a, float[] b) { 123 double d = distance(a, b); 124 return d * d; 125 } 126 127 @Override 128 public double distance(float[] X, float[] Y) { 129 if (X.length != Y.length) { 130 throw new IllegalArgumentException(wrongLengthMessage); 131 } 132 double sum = 0; 133 for (int i = 0; i < X.length; i++) { 134 sum = sum + Math.abs(X[i] - Y[i]); 135 } 136 return sum; 137 } 138 } 139 140 // ------------------------------------------------------------------------------ 141 142 public static class L2 extends VectorNorm { 143 144 public double magnitude(double[] X) { 145 double sum = 0.0; 146 for (int i = 0; i < X.length; i++) { 147 sum = sum + X[i] * X[i]; 148 } 149 return Math.sqrt(sum); 150 } 151 152 public double magnitude(int[] X) { 153 long sum = 0; 154 for (int i = 0; i < X.length; i++) { 155 sum = sum + X[i] * X[i]; 156 } 157 return Math.sqrt(sum); 158 } 159 160 public double distance(double[] a, double[] b) { 161 return Math.sqrt(distance2(a, b)); 162 } 163 164 public double distance2(final double[] X, final double[] Y) { 165 if (X.length != Y.length) { 166 throw new IllegalArgumentException(wrongLengthMessage); 167 } 168 double sum = 0.0; 169 for (int i = 0; i < X.length; i++) { 170 double d = X[i] - Y[i]; 171 sum = sum + d * d; 172 } 173 return sum; 174 } 175 176 public double distance(int[] a, int[] b) { 177 return Math.sqrt(distance2(a, b)); 178 } 179 180 public double distance2(final int[] X, final int[] Y) { 181 if (X.length != Y.length) { 182 throw new IllegalArgumentException(wrongLengthMessage); 183 } 184 int sum = 0; 185 for (int i = 0; i < X.length; i++) { 186 int d = X[i] - Y[i]; 187 sum = sum + d * d; 188 } 189 return sum; 190 } 191 192 public double getScale(int n) { 193 return Math.sqrt(1.0 / n); 194 } 195 196 @Override 197 public double distance(float[] a, float[] b) { 198 return Math.sqrt(distance2(a, b)); 199 } 200 201 @Override 202 public double distance2(float[] X, float[] Y) { 203 if (X.length != Y.length) { 204 throw new IllegalArgumentException(wrongLengthMessage); 205 } 206 double sum = 0.0; 207 for (int i = 0; i < X.length; i++) { 208 double d = X[i] - Y[i]; 209 sum = sum + d * d; 210 } 211 return sum; 212 } 213 } 214 215 // ------------------------------------------------------------------------------ 216 217 public static class Linf extends VectorNorm { 218 219 public double magnitude(double[] X) { 220 double dmax = 0.0; 221 for (int i = 0; i < X.length; i++) { 222 dmax = Math.max(dmax, Math.abs(X[i])); 223 } 224 return dmax; 225 } 226 227 public double magnitude(int[] X) { 228 int dmax = 0; 229 for (int i = 0; i < X.length; i++) { 230 dmax = Math.max(dmax, Math.abs(X[i])); 231 } 232 return dmax; 233 } 234 235 public double distance(final double[] X, final double[] Y) { 236 if (X.length != Y.length) { 237 throw new IllegalArgumentException(wrongLengthMessage); 238 } 239 double dmax = 0.0; 240 for (int i = 0; i < X.length; i++) { 241 double d = X[i] - Y[i]; 242 dmax = Math.max(dmax, Math.abs(d)); 243 } 244 return dmax; 245 } 246 247 public double distance(final int[] X, final int[] Y) { 248 if (X.length != Y.length) { 249 throw new IllegalArgumentException(wrongLengthMessage); 250 } 251 int dmax = 0; 252 for (int i = 0; i < X.length; i++) { 253 int d = Math.abs(X[i] - Y[i]); 254 dmax = Math.max(dmax, d); 255 } 256 return dmax; 257 } 258 259 public double distance2(double[] a, double[] b) { 260 double d = distance(a, b); 261 return d * d; 262 } 263 264 public double distance2(int[] a, int[] b) { 265 double d = distance(a, b); 266 return d * d; 267 } 268 269 public double getScale(int n) { 270 return 1.0; 271 } 272 273 @Override 274 public double distance2(float[] a, float[] b) { 275 double d = distance(a, b); 276 return d * d; 277 } 278 279 @Override 280 public double distance(float[] X, float[] Y) { 281 if (X.length != Y.length) { 282 throw new IllegalArgumentException(wrongLengthMessage); 283 } 284 float dmax = 0; 285 for (int i = 0; i < X.length; i++) { 286 float d = Math.abs(X[i] - Y[i]); 287 dmax = Math.max(dmax, d); 288 } 289 return dmax; 290 } 291 } 292 293} 294