Major cleanup of Utils class.
[trakem2.git] / SIFT_Test.java
blobea847c2042d4b33a592fff0da2630ede5e91edbe
1 //package mpi.fruitfly.registration;
3 import mpi.fruitfly.general.*;
4 import mpi.fruitfly.math.datastructures.*;
5 import mpi.fruitfly.math.*;
6 import mpi.fruitfly.registration.FloatArray2DSIFT;
7 import mpi.fruitfly.registration.FloatArray2DScaleOctave;
8 import mpi.fruitfly.registration.FloatArray2DScaleOctaveDoGDetector;
9 import mpi.fruitfly.registration.ImageFilter;
10 import mpi.fruitfly.registration.Feature;
12 import ij.plugin.*;
13 import ij.gui.*;
14 import ij.*;
15 import ij.process.*;
17 import java.util.Collections;
18 import java.util.Vector;
19 import java.awt.Color;
20 import java.awt.Polygon;
21 import java.awt.TextField;
22 import java.awt.event.KeyEvent;
23 import java.awt.event.KeyListener;
26 public class SIFT_Test implements PlugIn, KeyListener
28 // steps
29 private static int steps = 3;
30 // initial sigma
31 private static float initial_sigma = 1.6f;
32 // feature descriptor size
33 private static int fdsize = 8;
34 // feature descriptor orientation bins
35 private static int fdbins = 8;
36 // size restrictions for scale octaves, use octaves < max_size and > min_size only
37 private static int min_size = 64;
38 private static int max_size = 1024;
40 /**
41 * Set true to double the size of the image by linear interpolation to
42 * ( with * 2 + 1 ) * ( height * 2 + 1 ). Thus we can start identifying
43 * DoG extrema with $\sigma = INITIAL_SIGMA / 2$ like proposed by
44 * \citet{Lowe04}.
46 * This is useful for images scmaller than 1000px per side only.
47 */
48 private static boolean upscale = false;
49 private static float scale = 1.0f;
52 /**
53 * draws a rotated square with center point center, having size and orientation
55 static void drawSquare( ImageProcessor ip, double[] o, double scale, double orient )
57 scale /= 2;
59 double sin = Math.sin( orient );
60 double cos = Math.cos( orient );
62 int[] x = new int[ 6 ];
63 int[] y = new int[ 6 ];
66 x[ 0 ] = ( int )( o[ 0 ] + ( sin - cos ) * scale );
67 y[ 0 ] = ( int )( o[ 1 ] - ( sin + cos ) * scale );
69 x[ 1 ] = ( int )o[ 0 ];
70 y[ 1 ] = ( int )o[ 1 ];
72 x[ 2 ] = ( int )( o[ 0 ] + ( sin + cos ) * scale );
73 y[ 2 ] = ( int )( o[ 1 ] + ( sin - cos ) * scale );
74 x[ 3 ] = ( int )( o[ 0 ] - ( sin - cos ) * scale );
75 y[ 3 ] = ( int )( o[ 1 ] + ( sin + cos ) * scale );
76 x[ 4 ] = ( int )( o[ 0 ] - ( sin + cos ) * scale );
77 y[ 4 ] = ( int )( o[ 1 ] - ( sin - cos ) * scale );
78 x[ 5 ] = x[ 0 ];
79 y[ 5 ] = y[ 0 ];
81 ip.drawPolygon( new Polygon( x, y, x.length ) );
85 public void run( String args )
87 if ( IJ.versionLessThan( "1.37i" ) ) return;
89 final ImagePlus imp = WindowManager.getCurrentImage();
90 if ( imp == null ) { System.err.println( "There are no images open" ); return; }
92 final GenericDialog gd = new GenericDialog( "Test SIFT" );
94 gd.addNumericField( "steps_per_scale_octave :", steps, 0 );
95 gd.addNumericField( "initial_gaussian_blur :", initial_sigma, 2 );
96 gd.addNumericField( "feature_descriptor_size :", fdsize, 0 );
97 gd.addNumericField( "feature_descriptor_orientation_bins :", fdbins, 0 );
98 gd.addNumericField( "minimum_image_size :", min_size, 0 );
99 gd.addNumericField( "maximum_image_size :", max_size, 0 );
100 gd.addCheckbox( "upscale_image_first", upscale );
101 gd.showDialog();
102 if ( gd.wasCanceled() ) return;
103 steps = ( int )gd.getNextNumber();
104 initial_sigma = ( float )gd.getNextNumber();
105 fdsize = ( int )gd.getNextNumber();
106 fdbins = ( int )gd.getNextNumber();
107 min_size = ( int )gd.getNextNumber();
108 max_size = ( int )gd.getNextNumber();
109 upscale = gd.getNextBoolean();
110 if ( upscale ) scale = 2.0f;
113 ImageProcessor ip1 = imp.getProcessor().convertToFloat();
114 ImageProcessor ip2 = imp.getProcessor().duplicate().convertToRGB();
116 Vector< Feature > fs1;
118 FloatArray2DSIFT sift = new FloatArray2DSIFT( fdsize, fdbins );
120 FloatArray2D fa = ImageArrayConverter.ImageToFloatArray2D( ip1 );
121 ImageFilter.enhance( fa, 1.0f );
123 if ( upscale )
125 FloatArray2D fat = new FloatArray2D( fa.width * 2 - 1, fa.height * 2 - 1 );
126 FloatArray2DScaleOctave.upsample( fa, fat );
127 fa = fat;
128 fa = ImageFilter.computeGaussianFastMirror( fa, ( float )Math.sqrt( initial_sigma * initial_sigma - 1.0 ) );
130 else
131 fa = ImageFilter.computeGaussianFastMirror( fa, ( float )Math.sqrt( initial_sigma * initial_sigma - 0.25 ) );
133 long start_time = System.currentTimeMillis();
134 System.out.print( "processing SIFT ..." );
135 sift.init( fa, steps, initial_sigma, min_size, max_size );
136 fs1 = sift.run( max_size );
137 Collections.sort( fs1 );
138 System.out.println( " took " + ( System.currentTimeMillis() - start_time ) + "ms" );
140 System.out.println( fs1.size() + " features identified and processed" );
142 //#############################################################################
144 FloatArray2DScaleOctave[] sos = sift.getOctaves();
145 for ( int o = 0; o < sos.length; ++o )
147 FloatArray2DScaleOctave so = sos[ o ];
149 FloatArray2D[] l = so.getL();
150 FloatArray2D[] d = so.getD();
152 for ( int i = 0; i < steps; ++i )
154 FloatArray2D ls = l[ i ];
155 FloatArray2D ds = d[ i ];
156 int os;
157 for ( int oi = o; oi > 0; --oi )
159 os = ( int )Math.pow( 2, oi - 1 );
160 int w = imp.getWidth();
161 int h = imp.getHeight();
162 for ( os = oi; os > 1; --os )
164 w = w / 2 + w % 2;
165 h = h / 2 + h % 2;
167 //System.out.println( "o: " + o + ", w: " + w + ", h: " + h );
168 FloatArray2D ld = new FloatArray2D( w, h );
169 FloatArray2D dd = new FloatArray2D( w, h );
170 FloatArray2DScaleOctave.upsample( ls, ld );
171 FloatArray2DScaleOctave.upsample( ds, dd );
172 ls = ld;
173 ds = dd;
175 os = ( int )Math.pow( 2, o );
176 FloatProcessor fp = new FloatProcessor( ls.width, ls.height );
177 ImageArrayConverter.FloatArrayToFloatProcessor( fp, ls );
178 fp.setMinAndMax( 0.0, 1.0 );
179 //ImageProcessor ipl = fp.convertToRGB();
180 ImageProcessor ipl = fp.duplicate();
181 ImageArrayConverter.FloatArrayToFloatProcessor( fp, ds );
182 fp.setMinAndMax( -1.0, 1.0 );
183 ImageProcessor ipd = fp.convertToRGB();
185 // draw DoG detections
187 ipl.setLineWidth( 1 );
188 ipl.setColor( Color.red );
189 for ( Feature f : fs1 )
191 int ol = General.ldu( ( int )( f.scale / initial_sigma ) );
192 int sl = ( int )Math.round( steps * ( Math.log( f.scale / Math.pow( 2.0, ol ) / initial_sigma ) ) / Math.log( 2.0 ) );
193 if ( sl >= steps )
195 ++ol;
196 sl = sl % steps;
199 if ( ol <= o && sl <= i )
200 drawSquare( ipl, new double[]{ f.location[ 0 ] / scale, f.location[ 1 ] / scale }, fdsize * ( double )f.scale / scale, ( double )f.orientation );
204 FloatArray2D[] gradients = so.getL1( i );
205 ImageArrayConverter.FloatArrayToFloatProcessor( fp, gradients[ 0 ] );
206 stackGradientAmplitude.addSlice( null, fp );
207 ImageArrayConverter.FloatArrayToFloatProcessor( fp, gradients[ 1 ] );
208 stackGradientOrientation.addSlice( null, fp );
213 for ( int i = 0; i < d.length; ++i )
215 FloatProcessor fp = new FloatProcessor( d[ i ].width, d[ i ].height );
216 ImageArrayConverter.FloatArrayToFloatProcessor( fp, d[ i ] );
217 fp.setMinAndMax( -255.0, 255.0 );
218 ImageProcessor ipl = fp.convertToRGB();
220 // draw DoG detections
221 ipl.setLineWidth( 2 );
222 ipl.setColor( Color.green );
224 Vector< float[] > candidates = dog.getCandidates();
225 for ( float[] c : candidates )
227 if ( i == ( int )Math.round( c[ 2 ] ) )
228 ipl.drawDot( ( int )Math.round( c[ 0 ] ), ( int )Math.round( c[ 1 ] ) );
231 stackDoG.addSlice( null, ipl );
234 //stackDoG.addSlice( null, fp );
239 //#############################################################################
242 ip2.setLineWidth( 1 );
243 ip2.setColor( Color.red );
244 for ( Feature f : fs1 )
246 System.out.println( f.location[ 0 ] + " " + f.location[ 1 ] + " " + f.scale + " " + f.orientation );
247 drawSquare( ip2, new double[]{ f.location[ 0 ] / scale, f.location[ 1 ] / scale }, fdsize * ( double )f.scale / scale, ( double )f.orientation );
250 ImagePlus imp1 = new ImagePlus( imp.getTitle() + " Features ", ip2 );
251 imp1.show();
254 public void keyPressed(KeyEvent e)
256 if (
257 ( e.getKeyCode() == KeyEvent.VK_F1 ) &&
258 ( e.getSource() instanceof TextField) )
263 public void keyReleased(KeyEvent e) { }
265 public void keyTyped(KeyEvent e) { }