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.sift.scalespace; 011 012import ij.IJ; 013 014public abstract class HierarchicalScaleSpace { 015 016 final int P; // number of octaves 017 final int Q; // number of levels per octave 018 final double sigma_s; // absolute scale of original image 019 final double sigma_0; // absolute base scale of first octave (level 0,0) 020 final int botLevel, topLevel; // bottom and top level index in each octave 021 final ScaleOctave[] octaves; 022 023 HierarchicalScaleSpace(int P, int Q, double sigma_s, double sigma_0, int botLevel, int topLevel) { 024 this.Q = Q; 025 this.P = P; 026 this.sigma_s = sigma_s; 027 this.sigma_0 = sigma_0; 028 this.botLevel = botLevel; 029 this.topLevel = topLevel; 030 octaves = new ScaleOctave[P]; 031 } 032 033 public int getP() { 034 return P; 035 } 036 037 public int getQ() { 038 return Q; 039 } 040 041 public double getSigma_s() { 042 return sigma_s; 043 } 044 045 public double getSigma_0() { 046 return sigma_0; 047 } 048 049 public ScaleOctave getOctave(int p) { 050 return octaves[p]; 051 } 052 053 public ScaleLevel getScaleLevel(int p, int q) { 054 return getOctave(p).getLevel(q); 055 } 056 057// public float getValue(int p, int q, int u, int v) { 058// ScaleLevel level = getLevel(p,q); 059// return level.getf(u, v); 060// } 061 062 public int getScaleIndex(int p, int q) { 063 int m = Q * p + q; 064 return m; 065 } 066 067 public float getScaleIndexFloat(float p, float q) { 068 float m = Q * p + q; 069 return m; 070 } 071 072 public double getAbsoluteScale(int p, float q) { 073 double m = Q * p + q; 074 return sigma_0 * Math.pow(2, m/Q); 075 } 076 077 public double getRelativeScale(double scaleA, double scaleB) { // scaleA <= scaleB 078 if (scaleA > scaleB) { 079 throw new IllegalArgumentException("getRelativeScale(): scaleA > scaleB"); 080 } 081 return Math.sqrt(scaleB*scaleB - scaleA*scaleA); 082 } 083 084 public double getRealX(int p, double xp) { 085 return Math.pow(2, p) * xp; // TODO: optimize (precalculate Math.pow(p, 2)) 086 } 087 088 public double getRealY(int p, double yp) { 089 return Math.pow(2, p) * yp; 090 } 091 092 public void show() { 093 show(""); 094 } 095 096 public void show(String title) { 097 if (!title.isEmpty()) { 098 title = title + ": "; 099 } 100 for (int p = 0; p < P; p++) { 101 octaves[p].showAsStack(title + "Octave " + p); 102 } 103 } 104 105 public void print() { 106 IJ.log("Hierarchical Scale Space (" + this.getClass().toString() + ")"); 107 for (ScaleOctave oct : octaves) { 108 oct.print(); 109 } 110 111 } 112}