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-2023 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit https://imagingbook.com for additional details. 008 ******************************************************************************/ 009 010package imagingbook.common.math; 011 012import java.lang.reflect.Array; 013 014import static imagingbook.common.math.Arithmetic.sqr; 015 016/** 017 * This class defines various vector norms for calculating the magnitude of a vector and the distance between vectors. 018 * 019 * @author WB 020 * @version 2022/09/11 021 */ 022public abstract class VectorNorm { 023 024 private VectorNorm() {} 025 026 /** 027 * Returns the magnitude of the specified {@code double[]} vector under this norm. 028 * 029 * @param a a vector 030 * @return the magnitude of the vector 031 */ 032 public abstract double magnitude(double[] a); 033 034 /** 035 * Returns the magnitude of the specified {@code float[]} vector under this norm. 036 * @param a a vector 037 * @return the magnitude of the vector 038 */ 039 public abstract double magnitude(float[] a); 040 041 /** 042 * Returns the magnitude of the specified {@code int[]} vector under this norm. 043 * @param a a vector 044 * @return the magnitude of the vector 045 */ 046 public abstract double magnitude(int[] a); 047 048 /** 049 * Returns the distance between two {@code double[]} vectors under this norm. 050 * @param a first vector 051 * @param b second vector 052 * @return the distance between vectors a and b 053 */ 054 public abstract double distance(double[] a, double[] b); 055 056 /** 057 * Returns the distance between two {@code float[]} vectors under this norm. 058 * @param a first vector 059 * @param b second vector 060 * @return the distance between vectors a and b 061 */ 062 public abstract double distance(float[] a, float[] b); 063 064 /** 065 * Returns the distance between two {@code int[]} vectors under this norm. 066 * @param a first vector 067 * @param b second vector 068 * @return the distance between vectors a and b 069 */ 070 public abstract double distance(int[] a, int[] b); 071 072 /** 073 * Returns the squared distance between two {@code double[]} vectors under this norm. 074 * @param a first vector 075 * @param b second vector 076 * @return the distance between vectors a and b 077 */ 078 public abstract double distance2(double[] a, double[] b); 079 080 /** 081 * Returns the squared distance between two {@code float[]} vectors under this norm. 082 * @param a first vector 083 * @param b second vector 084 * @return the distance between vectors a and b 085 */ 086 public abstract double distance2(float[] a, float[] b); 087 088 /** 089 * Returns the squared distance between two {@code int[]} vectors under this norm. 090 * @param a first vector 091 * @param b second vector 092 * @return the distance between vectors a and b 093 */ 094 public abstract double distance2(int[] a, int[] b); 095 096 /** 097 * Returns a factor to scale magnitude and distance values to the range of the vector components of dimensionality 098 * n. This is prim. used for scaling color distances (n = 3). E.g., if components are distributed in [0,255], the 099 * distances multiplied by this factor should again be in [0,255]. 100 * 101 * @param n dimensionality 102 * @return scale factor 103 */ 104 public abstract double getScale(int n); 105 106 /** 107 * Enumeration type for {@link VectorNorm} to be used as 108 * parameter choice. 109 */ 110 public enum NormType { 111 /** L1 (Manhattan) norm/distance (see {@link VectorNorm.L1}). */ 112 L1 {@Override public VectorNorm getInstance() {return VectorNorm.L1.getInstance();}}, //(VectorNorm.L1.getInstance()), 113 /** L2 (Euclidean) norm/distance (see {@link VectorNorm.L2}). */ 114 L2 {@Override public VectorNorm getInstance() {return VectorNorm.L2.getInstance();}}, //(VectorNorm.L2.getInstance()), 115 /** L-infinity (maximum) norm/distance (see {@link VectorNorm.Linf}). */ 116 Linf {@Override public VectorNorm getInstance() {return VectorNorm.Linf.getInstance();}}; //(VectorNorm.Linf.getInstance()); 117 118 /** 119 * Returns the (singleton) {@link VectorNorm} instance associated with 120 * this specific {@link NormType}. 121 * @return the {@link VectorNorm} instance 122 */ 123 public abstract VectorNorm getInstance(); 124 } 125 126 // --------------------------------------------------------------------------- 127 128 private static void checkLengths(Object a, Object b) { 129 if (Array.getLength(a) != Array.getLength(b)) { 130 throw new IllegalArgumentException("vectors a, b must be of same length"); 131 } 132 } 133 134 // concrete classes ----------------------------------------------- 135 136 /** 137 * Implementation of the L1 vector norm (Manhattan norm/distance). This class defines no public constructor, use 138 * method {@link L1#getInstance()} to retrieve the associated (singleton) instance. 139 */ 140 public static class L1 extends VectorNorm { 141 142 private static final L1 instance = new L1(); 143 private L1() {} 144 145 /** 146 * Returns an instance of this specific {@link VectorNorm} type. 147 * @return a {@link VectorNorm} instance 148 */ 149 public static L1 getInstance() { 150 return L1.instance; 151 } 152 153 @Override 154 public double magnitude(double[] a) { 155 double sum = 0.0; 156 for (int i = 0; i < a.length; i++) { 157 sum = sum + Math.abs(a[i]); 158 } 159 return sum; 160 } 161 162 @Override 163 public double magnitude(float[] a) { 164 double sum = 0.0; 165 for (int i = 0; i < a.length; i++) { 166 sum = sum + Math.abs(a[i]); 167 } 168 return sum; 169 } 170 171 @Override 172 public double magnitude(int[] a) { 173 long sum = 0; 174 for (int i = 0; i < a.length; i++) { 175 sum = sum + Math.abs(a[i]); 176 } 177 return sum; 178 } 179 180 @Override 181 public double distance(final double[] a, final double[] b) { 182 checkLengths(a, b); 183 double sum = 0.0; 184 for (int i = 0; i < a.length; i++) { 185 double d = a[i] - b[i]; 186 sum = sum + Math.abs(d); 187 } 188 return sum; 189 } 190 191 @Override 192 public double distance(final int[] a, final int[] b) { 193 checkLengths(a, b); 194 int sum = 0; 195 for (int i = 0; i < a.length; i++) { 196 sum = sum + Math.abs(a[i] - b[i]); 197 } 198 return sum; 199 } 200 201 @Override 202 public double distance2(double[] a, double[] b) { 203 double d = distance(a, b); 204 return d * d; 205 } 206 207 public double distance2(int[] a, int[] b) { 208 double d = distance(a, b); 209 return d * d; 210 } 211 212 @Override 213 public double distance2(float[] a, float[] b) { 214 double d = distance(a, b); 215 return d * d; 216 } 217 218 @Override 219 public double distance(float[] a, float[] b) { 220 checkLengths(a, b); 221 double sum = 0; 222 for (int i = 0; i < a.length; i++) { 223 sum = sum + Math.abs(a[i] - b[i]); 224 } 225 return sum; 226 } 227 228 @Override 229 public double getScale(int n) { 230 return 1.0 / n; 231 } 232 233 } 234 235 // ------------------------------------------------------------------------------ 236 237 /** 238 * Implementation of the L2 vector norm (Euclidean norm/distance). This class defines no public constructor, use 239 * method {@link L2#getInstance()} to retrieve the associated (singleton) instance. 240 */ 241 public static class L2 extends VectorNorm { 242 243 private static final L2 instance = new L2(); 244 private L2() {} 245 246 /** 247 * Returns an instance of this specific {@link VectorNorm} type. 248 * @return a {@link VectorNorm} instance 249 */ 250 public static L2 getInstance() { 251 return L2.instance; 252 } 253 254 @Override 255 public double magnitude(double[] a) { 256 double sum = 0.0; 257 for (int i = 0; i < a.length; i++) { 258 sum = sum + a[i] * a[i]; 259 } 260 return Math.sqrt(sum); 261 } 262 263 @Override 264 public double magnitude(float[] a) { 265 double sum = 0.0; 266 for (int i = 0; i < a.length; i++) { 267 sum = sum + Arithmetic.sqr((double) a[i]); 268 } 269 return Math.sqrt(sum); 270 } 271 272 @Override 273 public double magnitude(int[] a) { 274 long sum = 0; 275 for (int i = 0; i < a.length; i++) { 276 sum = sum + a[i] * a[i]; 277 } 278 return Math.sqrt(sum); 279 } 280 281 @Override 282 public double distance(double[] a, double[] b) { 283 return Math.sqrt(distance2(a, b)); 284 } 285 286 @Override 287 public double distance2(final double[] a, final double[] b) { 288 checkLengths(a, b); 289 double sum = 0.0; 290 for (int i = 0; i < a.length; i++) { 291 double d = a[i] - b[i]; 292 sum = sum + d * d; 293 } 294 return sum; 295 } 296 297 @Override 298 public double distance(int[] a, int[] b) { 299 return Math.sqrt(distance2(a, b)); 300 } 301 302 @Override 303 public double distance2(final int[] a, final int[] b) { 304 checkLengths(a, b); 305 int sum = 0; 306 for (int i = 0; i < a.length; i++) { 307 int d = a[i] - b[i]; 308 sum = sum + d * d; 309 } 310 return sum; 311 } 312 313 @Override 314 public double distance(float[] a, float[] b) { 315 return Math.sqrt(distance2(a, b)); 316 } 317 318 @Override 319 public double distance2(float[] a, float[] b) { 320 checkLengths(a, b); 321 double sum = 0.0; 322 for (int i = 0; i < a.length; i++) { 323 double d = a[i] - b[i]; 324 sum = sum + d * d; 325 } 326 return sum; 327 } 328 329 @Override 330 public double getScale(int n) { 331 return Math.sqrt(1.0 / n); 332 } 333 334 } 335 336 // ------------------------------------------------------------------------------ 337 338 /** 339 * Implementation of the L-infinity vector norm (maximum norm/distance). This class defines no public constructor, 340 * use method {@link Linf#getInstance()} to retrieve the associated (singleton) instance. 341 */ 342 public static class Linf extends VectorNorm { 343 344 private static final Linf instance = new Linf(); 345 private Linf() {} 346 347 /** 348 * Returns an instance of this specific {@link VectorNorm} type. 349 * @return a {@link VectorNorm} instance 350 */ 351 public static Linf getInstance() { 352 return Linf.instance; 353 } 354 355 @Override 356 public double magnitude(double[] a) { 357 double dmax = 0.0; 358 for (int i = 0; i < a.length; i++) { 359 dmax = Math.max(dmax, Math.abs(a[i])); 360 } 361 return dmax; 362 } 363 364 @Override 365 public double magnitude(float[] a) { 366 float dmax = 0.0f; 367 for (int i = 0; i < a.length; i++) { 368 dmax = Math.max(dmax, Math.abs(a[i])); 369 } 370 return dmax; 371 } 372 373 @Override 374 public double magnitude(int[] a) { 375 int dmax = 0; 376 for (int i = 0; i < a.length; i++) { 377 dmax = Math.max(dmax, Math.abs(a[i])); 378 } 379 return dmax; 380 } 381 382 @Override 383 public double distance(double[] a, final double[] b) { 384 checkLengths(a, b); 385 double dmax = 0.0; 386 for (int i = 0; i < a.length; i++) { 387 double d = a[i] - b[i]; 388 dmax = Math.max(dmax, Math.abs(d)); 389 } 390 return dmax; 391 } 392 393 @Override 394 public double distance2(double[] a, double[] b) { 395 return sqr(distance(a, b)); 396 } 397 398 @Override 399 public double distance(int[] a, final int[] b) { 400 checkLengths(a, b); 401 int dmax = 0; 402 for (int i = 0; i < a.length; i++) { 403 int d = Math.abs(a[i] - b[i]); 404 dmax = Math.max(dmax, d); 405 } 406 return dmax; 407 } 408 409 @Override 410 public double distance2(int[] a, int[] b) { 411 double d = distance(a, b); 412 return d * d; 413 } 414 415 @Override 416 public double distance2(float[] a, float[] b) { 417 return sqr(distance(a, b)); 418 } 419 420 @Override 421 public double distance(float[] a, float[] b) { 422 checkLengths(a, b); 423 float dmax = 0; 424 for (int i = 0; i < a.length; i++) { 425 float d = Math.abs(a[i] - b[i]); 426 dmax = Math.max(dmax, d); 427 } 428 return dmax; 429 } 430 431 @Override 432 public double getScale(int n) { 433 return 1.0; 434 } 435 436 } 437 438} 439