3 Copyright (C) 2008 Verena Kaynig.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt )
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /* **************************************************************** *
20 * Representation of a non linear transform by explicit polynomial
24 * - make different kernels available
25 * - inverse transform for visualization
26 * - improve image interpolation
27 * - apply and applyInPlace should use precalculated transform?
28 * (What about out of image range pixels?)
30 * Author: Verena Kaynig
31 * Kontakt: verena.kaynig@inf.ethz.ch
33 * **************************************************************** */
35 package lenscorrection
;
40 import ij
.io
.FileSaver
;
41 import ij
.process
.ByteProcessor
;
42 import ij
.process
.ColorProcessor
;
43 import ij
.process
.FloatProcessor
;
44 import ij
.process
.ImageProcessor
;
46 import java
.awt
.Color
;
47 import java
.awt
.geom
.GeneralPath
;
48 import java
.io
.BufferedReader
;
49 import java
.io
.BufferedWriter
;
50 import java
.io
.FileNotFoundException
;
51 import java
.io
.FileOutputStream
;
52 import java
.io
.FileReader
;
53 import java
.io
.IOException
;
54 import java
.io
.OutputStreamWriter
;
57 public class NonLinearTransform
implements mpicbg
.trakem2
.transform
.CoordinateTransform
{
59 private double[][] beta
= null;
60 private double[] normMean
= null;
61 private double[] normVar
= null;
62 private double[][][] transField
= null;
63 private int dimension
= 0;
64 private int length
= 0;
65 private int width
= 0;
66 private int height
= 0;
68 public int getDimension(){ return dimension
; }
69 /** Deletes all dimension dependent properties */
70 public void setDimension( final int dimension
)
72 this.dimension
= dimension
;
73 length
= (dimension
+ 1)*(dimension
+ 2)/2;
75 beta
= new double[length
][2];
76 normMean
= new double[length
];
77 normVar
= new double[length
];
79 for (int i
=0; i
< length
; i
++){
84 precalculated
= false;
87 private boolean precalculated
= false;
89 public int getMinNumMatches()
95 public void fit( final double x
[][], final double y
[][], final double lambda
)
97 final double[][] expandedX
= kernelExpandMatrixNormalize( x
);
99 final Matrix phiX
= new Matrix( expandedX
, expandedX
.length
, length
);
100 final Matrix phiXTransp
= phiX
.transpose();
102 final Matrix phiXProduct
= phiXTransp
.times( phiX
);
104 final int l
= phiXProduct
.getRowDimension();
105 final double lambda2
= 2 * lambda
;
107 for (int i
= 0; i
< l
; ++i
)
108 phiXProduct
.set( i
, i
, phiXProduct
.get( i
, i
) + lambda2
);
110 final Matrix phiXPseudoInverse
= phiXProduct
.inverse();
111 final Matrix phiXProduct2
= phiXPseudoInverse
.times( phiXTransp
);
112 final Matrix betaMatrix
= phiXProduct2
.times( new Matrix( y
, y
.length
, 2 ) );
114 setBeta( betaMatrix
.getArray() );
117 public void estimateDistortion( final double hack1
[][], final double hack2
[][], final double transformParams
[][], final double lambda
, final int w
, final int h
)
119 beta
= new double[ length
][ 2 ];
120 normMean
= new double[ length
];
121 normVar
= new double[ length
];
123 for ( int i
= 0; i
< length
; i
++ )
132 /* TODO Find out how to keep some target points fixed (check fit method of NLT which is supposed to be exclusively forward) */
133 final double expandedX
[][] = kernelExpandMatrixNormalize( hack1
);
134 final double expandedY
[][] = kernelExpandMatrix( hack2
);
136 final int s
= expandedX
[ 0 ].length
;
137 Matrix S1
= new Matrix( 2 * s
, 2 * s
);
138 Matrix S2
= new Matrix( 2 * s
, 1 );
140 for ( int i
= 0; i
< expandedX
.length
; ++i
)
142 final Matrix xk_ij
= new Matrix( expandedX
[ i
], 1 );
143 final Matrix xk_ji
= new Matrix( expandedY
[ i
], 1 );
145 final Matrix yk1a
= xk_ij
.minus( xk_ji
.times( transformParams
[ i
][ 0 ] ) );
146 final Matrix yk1b
= xk_ij
.times( 0.0 ).minus( xk_ji
.times( -transformParams
[ i
][ 2 ] ) );
147 final Matrix yk2a
= xk_ij
.times( 0.0 ).minus( xk_ji
.times( -transformParams
[ i
][ 1 ] ) );
148 final Matrix yk2b
= xk_ij
.minus( xk_ji
.times( transformParams
[ i
][ 3 ] ) );
150 final Matrix y
= new Matrix( 2, 2 * s
);
151 y
.setMatrix( 0, 0, 0, s
- 1, yk1a
);
152 y
.setMatrix( 0, 0, s
, 2 * s
- 1, yk1b
);
153 y
.setMatrix( 1, 1, 0, s
- 1, yk2a
);
154 y
.setMatrix( 1, 1, s
, 2 * s
- 1, yk2b
);
156 final Matrix xk
= new Matrix( 2, 2 * expandedX
[ 0 ].length
);
157 xk
.setMatrix( 0, 0, 0, s
- 1, xk_ij
);
158 xk
.setMatrix( 1, 1, s
, 2 * s
- 1, xk_ij
);
160 final double[] vals
= { hack1
[ i
][ 0 ], hack1
[ i
][ 1 ] };
161 final Matrix c
= new Matrix( vals
, 2 );
163 final Matrix X
= xk
.transpose().times( xk
).times( lambda
);
164 final Matrix Y
= y
.transpose().times( y
);
166 S1
= S1
.plus( Y
.plus( X
) );
168 final double trans1
= ( transformParams
[ i
][ 2 ] * transformParams
[ i
][ 5 ] - transformParams
[ i
][ 0 ] * transformParams
[ i
][ 4 ] );
169 final double trans2
= ( transformParams
[ i
][ 1 ] * transformParams
[ i
][ 4 ] - transformParams
[ i
][ 3 ] * transformParams
[ i
][ 5 ] );
170 final double[] trans
= { trans1
, trans2
};
172 final Matrix translation
= new Matrix( trans
, 2 );
173 final Matrix YT
= y
.transpose().times( translation
);
174 final Matrix XC
= xk
.transpose().times( c
).times( lambda
);
176 S2
= S2
.plus( YT
.plus( XC
) );
178 final Matrix regularize
= Matrix
.identity( S1
.getRowDimension(), S1
.getColumnDimension() );
179 final Matrix beta
= new Matrix( S1
.plus( regularize
.times( 0.001 ) ).inverse().times( S2
).getColumnPackedCopy(), s
);
181 setBeta( beta
.getArray() );
184 public NonLinearTransform(final double[][] b
, final double[] nm
, final double[] nv
, final int d
, final int w
, final int h
){
189 length
= (dimension
+ 1)*(dimension
+ 2)/2;
194 public NonLinearTransform(final int d
, final int w
, final int h
){
196 length
= (dimension
+ 1)*(dimension
+ 2)/2;
198 beta
= new double[length
][2];
199 normMean
= new double[length
];
200 normVar
= new double[length
];
202 for (int i
=0; i
< length
; i
++){
211 public NonLinearTransform(){};
213 public NonLinearTransform(final String filename
){
217 public NonLinearTransform(final double[][] coeffMatrix
, final int w
, final int h
){
218 length
= coeffMatrix
.length
;
219 beta
= new double[length
][2];
220 normMean
= new double[length
];
221 normVar
= new double[length
];
224 dimension
= (int)(-1.5 + Math
.sqrt(0.25 + 2*length
));
226 for(int i
=0; i
<length
; i
++){
227 beta
[i
][0] = coeffMatrix
[0][i
];
228 beta
[i
][1] = coeffMatrix
[1][i
];
229 normMean
[i
] = coeffMatrix
[2][i
];
230 normVar
[i
] = coeffMatrix
[3][i
];
235 //implements mpicbg.trakem2
237 public void init( final String data
) throws NumberFormatException
{
238 final String
[] fields
= data
.split( " " );
241 dimension
= Integer
.parseInt(fields
[c
]); c
++;
242 length
= Integer
.parseInt(fields
[c
]); c
++;
244 beta
= new double[length
][2];
245 normMean
= new double[length
];
246 normVar
= new double[length
];
248 if ( fields
.length
== 4 + 4*length
)
250 for (int i
=0; i
< length
; i
++){
251 beta
[i
][0] = Double
.parseDouble(fields
[c
]); c
++;
252 beta
[i
][1] = Double
.parseDouble(fields
[c
]); c
++;
255 //System.out.println("c: " + c);
257 for (int i
=0; i
< length
; i
++){
258 normMean
[i
] = Double
.parseDouble(fields
[c
]); c
++;
261 //System.out.println("c: " + c);
263 for (int i
=0; i
< length
; i
++){
264 normVar
[i
] = Double
.parseDouble(fields
[c
]); c
++;
267 width
= Integer
.parseInt(fields
[c
]); c
++;
268 height
= Integer
.parseInt(fields
[c
]); c
++;
269 //System.out.println("c: " + c);
272 else throw new NumberFormatException( "Inappropriate parameters for " + this.getClass().getCanonicalName() );
278 public String
toXML(final String indent
){
279 return new StringBuilder(indent
).append("<ict_transform class=\"").append(this.getClass().getCanonicalName()).append("\" data=\"").append(toDataString()).append("\"/>").toString();
283 public String
toDataString(){
285 data
+= Integer
.toString(dimension
) + " ";
286 data
+= Integer
.toString(length
) + " ";
288 for (int i
=0; i
< length
; i
++){
289 data
+= Double
.toString(beta
[i
][0]) + " ";
290 data
+= Double
.toString(beta
[i
][1]) + " ";
293 for (int i
=0; i
< length
; i
++){
294 data
+= Double
.toString(normMean
[i
]) + " ";
297 for (int i
=0; i
< length
; i
++){
298 data
+= Double
.toString(normVar
[i
]) + " ";
300 data
+= Integer
.toString(width
) + " ";
301 data
+= Integer
.toString(height
) + " ";
309 public String
toString(){ return toDataString(); }
312 public float[] apply( final float[] location
){
314 final double[] position
= {(double) location
[0], (double) location
[1]};
315 final double[] featureVector
= kernelExpand(position
);
316 final double[] newPosition
= multiply(beta
, featureVector
);
318 final float[] newLocation
= new float[2];
319 newLocation
[0] = (float) newPosition
[0];
320 newLocation
[1] = (float) newPosition
[1];
326 public void applyInPlace( final float[] location
){
327 final double[] position
= {(double) location
[0], (double) location
[1]};
328 final double[] featureVector
= kernelExpand(position
);
329 final double[] newPosition
= multiply(beta
, featureVector
);
331 location
[0] = (float) newPosition
[0];
332 location
[1] = (float) newPosition
[1];
335 void precalculateTransfom(){
336 transField
= new double[width
][height
][2];
337 //double minX = width, minY = height, maxX = 0, maxY = 0;
339 for (int x
=0; x
<width
; x
++){
340 for (int y
=0; y
<height
; y
++){
341 final double[] position
= {x
,y
};
342 final double[] featureVector
= kernelExpand(position
);
343 final double[] newPosition
= multiply(beta
, featureVector
);
345 if ((newPosition
[0] < 0) || (newPosition
[0] >= width
) ||
346 (newPosition
[1] < 0) || (newPosition
[1] >= height
))
348 transField
[x
][y
][0] = -1;
349 transField
[x
][y
][1] = -1;
353 transField
[x
][y
][0] = newPosition
[0];
354 transField
[x
][y
][1] = newPosition
[1];
356 //minX = Math.min(minX, x);
357 //minY = Math.min(minY, y);
358 //maxX = Math.max(maxX, x);
359 //maxY = Math.max(maxY, y);
364 precalculated
= true;
367 public double[][] getCoefficients(){
368 final double[][] coeffMatrix
= new double[4][length
];
370 for(int i
=0; i
<length
; i
++){
371 coeffMatrix
[0][i
] = beta
[i
][0];
372 coeffMatrix
[1][i
] = beta
[i
][1];
373 coeffMatrix
[2][i
] = normMean
[i
];
374 coeffMatrix
[3][i
] = normVar
[i
];
380 public void setBeta(final double[][] b
){
382 //FIXME: test if normMean and normVar are still valid for this beta
386 System
.out
.println("beta:");
387 for (int i
=0; i
< beta
.length
; i
++){
388 for (int j
=0; j
< beta
[i
].length
; j
++){
389 System
.out
.print(beta
[i
][j
]);
390 System
.out
.print(" ");
392 System
.out
.println();
395 System
.out
.println("normMean:");
396 for (int i
=0; i
< normMean
.length
; i
++){
397 System
.out
.print(normMean
[i
]);
398 System
.out
.print(" ");
401 System
.out
.println("normVar:");
402 for (int i
=0; i
< normVar
.length
; i
++){
403 System
.out
.print(normVar
[i
]);
404 System
.out
.print(" ");
407 System
.out
.println("Image size:");
408 System
.out
.println("width: " + width
+ " height: " + height
);
410 System
.out
.println();
414 public void save( final String filename
)
417 final BufferedWriter out
= new BufferedWriter(
418 new OutputStreamWriter(
419 new FileOutputStream( filename
) ) );
421 out
.write("Kerneldimension");
423 out
.write(Integer
.toString(dimension
));
426 out
.write("number of rows");
428 out
.write(Integer
.toString(length
));
431 out
.write("Coefficients of the transform matrix:");
433 for (int i
=0; i
< length
; i
++){
434 String s
= Double
.toString(beta
[i
][0]);
436 s
+= Double
.toString(beta
[i
][1]);
441 out
.write("normMean:");
443 for (int i
=0; i
< length
; i
++){
444 out
.write(Double
.toString(normMean
[i
]));
448 out
.write("normVar: ");
450 for (int i
=0; i
< length
; i
++){
451 out
.write(Double
.toString(normVar
[i
]));
455 out
.write("image size: ");
457 out
.write(width
+ " " + height
);
460 catch(final IOException e
){System
.out
.println("IOException");}
462 catch(final FileNotFoundException e
){System
.out
.println("File not found!");}
465 public void load(final String filename
){
467 final BufferedReader in
= new BufferedReader(new FileReader(filename
));
469 String line
= in
.readLine(); //comment;
470 dimension
= Integer
.parseInt(in
.readLine());
471 line
= in
.readLine(); //comment;
472 line
= in
.readLine(); //comment;
473 length
= Integer
.parseInt(in
.readLine());
474 line
= in
.readLine(); //comment;
475 line
= in
.readLine(); //comment;
477 beta
= new double[length
][2];
479 for (int i
=0; i
< length
; i
++){
480 line
= in
.readLine();
481 final int ind
= line
.indexOf(" ");
482 beta
[i
][0] = Double
.parseDouble(line
.substring(0, ind
));
483 beta
[i
][1] = Double
.parseDouble(line
.substring(ind
+4));
486 line
= in
.readLine(); //comment;
487 line
= in
.readLine(); //comment;
489 normMean
= new double[length
];
491 for (int i
=0; i
< length
; i
++){
492 normMean
[i
]=Double
.parseDouble(in
.readLine());
495 line
= in
.readLine(); //comment;
496 line
= in
.readLine(); //comment;
498 normVar
= new double[length
];
500 for (int i
=0; i
< length
; i
++){
501 normVar
[i
]=Double
.parseDouble(in
.readLine());
503 line
= in
.readLine(); //comment;
504 line
= in
.readLine(); //comment;
505 line
= in
.readLine();
506 final int ind
= line
.indexOf(" ");
507 width
= Integer
.parseInt(line
.substring(0, ind
));
508 height
= Integer
.parseInt(line
.substring(ind
+4));
513 catch(final IOException e
){System
.out
.println("IOException");}
515 catch(final FileNotFoundException e
){System
.out
.println("File not found!");}
518 public ImageProcessor
[] transform(final ImageProcessor ip
){
520 this.precalculateTransfom();
522 final ImageProcessor newIp
= ip
.createProcessor(ip
.getWidth(), ip
.getHeight());
523 if (ip
instanceof ColorProcessor
) ip
.max(0);
524 final ImageProcessor maskIp
= new ByteProcessor(ip
.getWidth(),ip
.getHeight());
526 for (int x
=0; x
< width
; x
++){
527 for (int y
=0; y
< height
; y
++){
528 if (transField
[x
][y
][0] == -1){
531 newIp
.set(x
, y
, (int) ip
.getInterpolatedPixel((int)transField
[x
][y
][0],(int)transField
[x
][y
][1]));
535 return new ImageProcessor
[]{newIp
, maskIp
};
538 private double[] multiply(final double beta
[][], final double featureVector
[]){
539 final double[] result
= {0.0,0.0};
541 if (beta
.length
!= featureVector
.length
){
542 IJ
.log("Dimension of TransformMatrix and featureVector do not match!");
543 return new double[2];
546 for (int i
=0; i
<featureVector
.length
; i
++){
547 result
[0] = result
[0] + featureVector
[i
] * beta
[i
][0];
548 result
[1] = result
[1] + featureVector
[i
] * beta
[i
][1];
554 public double[] kernelExpand(final double position
[]){
555 final double expanded
[] = new double[length
];
558 for (int i
=1; i
<=dimension
; i
++){
559 for (double j
=i
; j
>=0; j
--){
560 final double val
= Math
.pow(position
[0],j
) * Math
.pow(position
[1],i
-j
);
561 expanded
[counter
] = val
;
566 for (int i
=0; i
<length
-1; i
++){
567 expanded
[i
] = expanded
[i
] - normMean
[i
];
568 expanded
[i
] = expanded
[i
] / normVar
[i
];
571 expanded
[length
-1] = 100;
577 public double[][] kernelExpandMatrixNormalize(final double positions
[][]){
578 normMean
= new double[length
];
579 normVar
= new double[length
];
581 for (int i
=0; i
< length
; i
++){
586 final double expanded
[][] = new double[positions
.length
][length
];
588 for (int i
=0; i
< positions
.length
; i
++){
589 expanded
[i
] = kernelExpand(positions
[i
]);
592 for (int i
=0; i
< length
; i
++){
595 for (int j
=0; j
< expanded
.length
; j
++){
596 mean
+= expanded
[j
][i
];
599 mean
/= expanded
.length
;
601 for (int j
=0; j
< expanded
.length
; j
++){
602 var
+= (expanded
[j
][i
] - mean
)*(expanded
[j
][i
] - mean
);
604 var
/= (expanded
.length
-1);
605 var
= Math
.sqrt(var
);
611 return kernelExpandMatrix(positions
);
615 //this function uses the parameters already stored
616 //in this object to normalize the positions given.
617 public double[][] kernelExpandMatrix(final double positions
[][]){
620 final double expanded
[][] = new double[positions
.length
][length
];
622 for (int i
=0; i
< positions
.length
; i
++){
623 expanded
[i
] = kernelExpand(positions
[i
]);
630 public void inverseTransform(final double range
[][]){
631 Matrix expanded
= new Matrix(kernelExpandMatrix(range
));
632 final Matrix b
= new Matrix(beta
);
634 final Matrix transformed
= expanded
.times(b
);
635 expanded
= new Matrix(kernelExpandMatrixNormalize(transformed
.getArray()));
637 final Matrix r
= new Matrix(range
);
638 final Matrix invBeta
= expanded
.transpose().times(expanded
).inverse().times(expanded
.transpose()).times(r
);
639 setBeta(invBeta
.getArray());
642 //FIXME this takes way too much memory
643 public void visualize(){
645 final int density
= Math
.max(width
,height
)/32;
646 final int border
= Math
.max(width
,height
)/8;
648 final double[][] orig
= new double[width
* height
][2];
649 final double[][] trans
= new double[height
* width
][2];
650 final double[][] gridOrigVert
= new double[width
*height
][2];
651 final double[][] gridTransVert
= new double[width
*height
][2];
652 final double[][] gridOrigHor
= new double[width
*height
][2];
653 final double[][] gridTransHor
= new double[width
*height
][2];
655 final FloatProcessor magnitude
= new FloatProcessor(width
, height
);
656 final FloatProcessor angle
= new FloatProcessor(width
, height
);
657 final ColorProcessor quiver
= new ColorProcessor(width
, height
);
658 final ByteProcessor empty
= new ByteProcessor(width
+2*border
, height
+2*border
);
659 quiver
.setLineWidth(1);
660 quiver
.setColor(Color
.green
);
662 final GeneralPath quiverField
= new GeneralPath();
664 float minM
= 1000, maxM
= 0;
665 float minArc
= 5, maxArc
= -6;
666 int countVert
= 0, countHor
= 0, countHorWhole
= 0;
668 for (int i
=0; i
< width
; i
++){
670 for (int j
=0; j
< height
; j
++){
671 final double[] position
= {(double) i
,(double) j
};
672 final double[] posExpanded
= kernelExpand(position
);
673 final double[] newPosition
= multiply(beta
, posExpanded
);
675 orig
[i
*j
][0] = position
[0];
676 orig
[i
*j
][1] = position
[1];
678 trans
[i
*j
][0] = newPosition
[0];
679 trans
[i
*j
][1] = newPosition
[1];
681 double m
= (position
[0] - newPosition
[0]) * (position
[0] - newPosition
[0]);
682 m
+= (position
[1] - newPosition
[1]) * (position
[1] - newPosition
[1]);
684 magnitude
.setf(i
,j
, (float) m
);
685 minM
= Math
.min(minM
, (float) m
);
686 maxM
= Math
.max(maxM
, (float) m
);
688 final double a
= Math
.atan2(position
[0] - newPosition
[0], position
[1] - newPosition
[1]);
689 minArc
= Math
.min(minArc
, (float) a
);
690 maxArc
= Math
.max(maxArc
, (float) a
);
691 angle
.setf(i
,j
, (float) a
);
693 if (i
%density
== 0 && j
%density
== 0)
694 drawQuiverField(quiverField
, position
[0], position
[1], newPosition
[0], newPosition
[1]);
696 gridOrigVert
[countVert
][0] = position
[0] + border
;
697 gridOrigVert
[countVert
][1] = position
[1] + border
;
698 gridTransVert
[countVert
][0] = newPosition
[0] + border
;
699 gridTransVert
[countVert
][1] = newPosition
[1] + border
;
703 gridOrigHor
[countHor
*width
+i
][0] = position
[0] + border
;
704 gridOrigHor
[countHor
*width
+i
][1] = position
[1] + border
;
705 gridTransHor
[countHor
*width
+i
][0] = newPosition
[0] + border
;
706 gridTransHor
[countHor
*width
+i
][1] = newPosition
[1] + border
;
713 magnitude
.setMinAndMax(minM
, maxM
);
714 angle
.setMinAndMax(minArc
, maxArc
);
715 //System.out.println(" " + minArc + " " + maxArc);
717 final ImagePlus magImg
= new ImagePlus("Magnitude of Distortion Field", magnitude
);
720 // ImagePlus angleImg = new ImagePlus("Angle of Distortion Field Vectors", angle);
723 final ImagePlus quiverImg
= new ImagePlus("Quiver Plot of Distortion Field", magnitude
);
725 quiverImg
.getCanvas().setDisplayList(quiverField
, Color
.green
, null );
726 quiverImg
.updateAndDraw();
728 // GeneralPath gridOrig = new GeneralPath();
729 // drawGrid(gridOrig, gridOrigVert, countVert, height);
730 // drawGrid(gridOrig, gridOrigHor, countHorWhole, width);
731 // ImagePlus gridImgOrig = new ImagePlus("Distortion Grid", empty);
732 // gridImgOrig.show();
733 // gridImgOrig.getCanvas().setDisplayList(gridOrig, Color.green, null );
734 // gridImgOrig.updateAndDraw();
736 final GeneralPath gridTrans
= new GeneralPath();
737 drawGrid(gridTrans
, gridTransVert
, countVert
, height
);
738 drawGrid(gridTrans
, gridTransHor
, countHorWhole
, width
);
739 final ImagePlus gridImgTrans
= new ImagePlus("Distortion Grid", empty
);
741 gridImgTrans
.getCanvas().setDisplayList(gridTrans
, Color
.green
, null );
742 gridImgTrans
.updateAndDraw();
744 //new FileSaver(quiverImg.getCanvas().imp).saveAsTiff("QuiverCanvas.tif");
745 new FileSaver(quiverImg
).saveAsTiff("QuiverImPs.tif");
747 System
.out
.println("FINISHED");
751 public void visualizeSmall(final double lambda
){
752 final int density
= Math
.max(width
,height
)/32;
754 final double[][] orig
= new double[2][width
* height
];
755 final double[][] trans
= new double[2][height
* width
];
757 final FloatProcessor magnitude
= new FloatProcessor(width
, height
);
759 final GeneralPath quiverField
= new GeneralPath();
761 float minM
= 1000, maxM
= 0;
762 final float minArc
= 5, maxArc
= -6;
763 final int countVert
= 0;
765 final int countHorWhole
= 0;
767 for (int i
=0; i
< width
; i
++){
769 for (int j
=0; j
< height
; j
++){
770 final double[] position
= {(double) i
,(double) j
};
771 final double[] posExpanded
= kernelExpand(position
);
772 final double[] newPosition
= multiply(beta
, posExpanded
);
774 orig
[0][i
*j
] = position
[0];
775 orig
[1][i
*j
] = position
[1];
777 trans
[0][i
*j
] = newPosition
[0];
778 trans
[1][i
*j
] = newPosition
[1];
780 double m
= (position
[0] - newPosition
[0]) * (position
[0] - newPosition
[0]);
781 m
+= (position
[1] - newPosition
[1]) * (position
[1] - newPosition
[1]);
783 magnitude
.setf(i
,j
, (float) m
);
784 minM
= Math
.min(minM
, (float) m
);
785 maxM
= Math
.max(maxM
, (float) m
);
787 if (i
%density
== 0 && j
%density
== 0)
788 drawQuiverField(quiverField
, position
[0], position
[1], newPosition
[0], newPosition
[1]);
792 magnitude
.setMinAndMax(minM
, maxM
);
793 final ImagePlus quiverImg
= new ImagePlus("Quiver Plot for lambda = "+lambda
, magnitude
);
795 quiverImg
.getCanvas().setDisplayList(quiverField
, Color
.green
, null );
796 quiverImg
.updateAndDraw();
798 System
.out
.println("FINISHED");
802 public static void drawGrid(final GeneralPath g
, final double[][] points
, final int count
, final int s
){
803 for (int i
=0; i
< count
- 1; i
++){
805 g
.moveTo((float)points
[i
][0], (float)points
[i
][1]);
806 g
.lineTo((float)points
[i
+1][0], (float)points
[i
+1][1]);
811 public static void drawQuiverField(final GeneralPath qf
, final double x1
, final double y1
, final double x2
, final double y2
)
813 qf
.moveTo((float)x1
, (float)y1
);
814 qf
.lineTo((float)x2
, (float)y2
);
817 public int getWidth(){
821 public int getHeight(){
826 * TODO Make this more efficient
829 final public NonLinearTransform
copy()
831 final NonLinearTransform t
= new NonLinearTransform();
832 t
.init( toDataString() );
836 public void set( final NonLinearTransform nlt
)
838 this.dimension
= nlt
.dimension
;
839 this.height
= nlt
.height
;
840 this.length
= nlt
.length
;
841 this.precalculated
= nlt
.precalculated
;
842 this.width
= nlt
.width
;
844 /* arrays by deep cloning */
845 this.beta
= new double[ nlt
.beta
.length
][];
846 for ( int i
= 0; i
< nlt
.beta
.length
; ++i
)
847 this.beta
[ i
] = nlt
.beta
[ i
].clone();
849 this.normMean
= nlt
.normMean
.clone();
850 this.normVar
= nlt
.normVar
.clone();
851 this.transField
= new double[ nlt
.transField
.length
][][];
853 for ( int a
= 0; a
< nlt
.transField
.length
; ++a
)
855 this.transField
[ a
] = new double[ nlt
.transField
[ a
].length
][];
856 for ( int b
= 0; b
< nlt
.transField
[ a
].length
; ++b
)
857 this.transField
[ a
][ b
] = nlt
.transField
[ a
][ b
].clone();