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
;
37 import ij
.process
.ByteProcessor
;
38 import ij
.process
.ColorProcessor
;
39 import ij
.process
.FloatProcessor
;
40 import ij
.process
.ImageProcessor
;
43 import ij
.io
.FileSaver
;
45 import java
.awt
.Color
;
46 import java
.awt
.geom
.GeneralPath
;
47 import java
.io
.BufferedWriter
;
48 import java
.lang
.Math
;
55 public class NonLinearTransform
implements mpicbg
.trakem2
.transform
.CoordinateTransform
{
57 private double[][] beta
= null;
58 private double[] normMean
= null;
59 private double[] normVar
= null;
60 private double[][][] transField
= null;
61 private int dimension
= 0;
62 private int length
= 0;
63 private int width
= 0;
64 private int height
= 0;
66 public int getDimension(){ return dimension
; }
67 /** Deletes all dimension dependent properties */
68 public void setDimension( final int dimension
)
70 this.dimension
= dimension
;
71 length
= (dimension
+ 1)*(dimension
+ 2)/2;
73 beta
= new double[length
][2];
74 normMean
= new double[length
];
75 normVar
= new double[length
];
77 for (int i
=0; i
< length
; i
++){
82 precalculated
= false;
85 private boolean precalculated
= false;
87 public int getMinNumMatches()
93 public void fit( final double x
[][], final double y
[][], final double lambda
)
95 final double[][] expandedX
= kernelExpandMatrixNormalize( x
);
97 final Matrix phiX
= new Matrix( expandedX
, expandedX
.length
, length
);
98 final Matrix phiXTransp
= phiX
.transpose();
100 final Matrix phiXProduct
= phiXTransp
.times( phiX
);
102 final int l
= phiXProduct
.getRowDimension();
103 final double lambda2
= 2 * lambda
;
105 for (int i
= 0; i
< l
; ++i
)
106 phiXProduct
.set( i
, i
, phiXProduct
.get( i
, i
) + lambda2
);
108 final Matrix phiXPseudoInverse
= phiXProduct
.inverse();
109 final Matrix phiXProduct2
= phiXPseudoInverse
.times( phiXTransp
);
110 final Matrix betaMatrix
= phiXProduct2
.times( new Matrix( y
, y
.length
, 2 ) );
112 setBeta( betaMatrix
.getArray() );
115 public void estimateDistortion( double hack1
[][], double hack2
[][], double transformParams
[][], double lambda
, int w
, int h
)
117 beta
= new double[ length
][ 2 ];
118 normMean
= new double[ length
];
119 normVar
= new double[ length
];
121 for ( int i
= 0; i
< length
; i
++ )
130 final double expandedX
[][] = kernelExpandMatrixNormalize( hack1
);
131 final double expandedY
[][] = kernelExpandMatrix( hack2
);
133 int s
= expandedX
[ 0 ].length
;
134 Matrix S1
= new Matrix( 2 * s
, 2 * s
);
135 Matrix S2
= new Matrix( 2 * s
, 1 );
137 for ( int i
= 0; i
< expandedX
.length
; ++i
)
139 Matrix xk_ij
= new Matrix( expandedX
[ i
], 1 );
140 Matrix xk_ji
= new Matrix( expandedY
[ i
], 1 );
142 Matrix yk1a
= xk_ij
.minus( xk_ji
.times( transformParams
[ i
][ 0 ] ) );
143 Matrix yk1b
= xk_ij
.times( 0.0 ).minus( xk_ji
.times( -transformParams
[ i
][ 2 ] ) );
144 Matrix yk2a
= xk_ij
.times( 0.0 ).minus( xk_ji
.times( -transformParams
[ i
][ 1 ] ) );
145 Matrix yk2b
= xk_ij
.minus( xk_ji
.times( transformParams
[ i
][ 3 ] ) );
147 Matrix y
= new Matrix( 2, 2 * s
);
148 y
.setMatrix( 0, 0, 0, s
- 1, yk1a
);
149 y
.setMatrix( 0, 0, s
, 2 * s
- 1, yk1b
);
150 y
.setMatrix( 1, 1, 0, s
- 1, yk2a
);
151 y
.setMatrix( 1, 1, s
, 2 * s
- 1, yk2b
);
153 Matrix xk
= new Matrix( 2, 2 * expandedX
[ 0 ].length
);
154 xk
.setMatrix( 0, 0, 0, s
- 1, xk_ij
);
155 xk
.setMatrix( 1, 1, s
, 2 * s
- 1, xk_ij
);
157 double[] vals
= { hack1
[ i
][ 0 ], hack1
[ i
][ 1 ] };
158 Matrix c
= new Matrix( vals
, 2 );
160 Matrix X
= xk
.transpose().times( xk
).times( lambda
);
161 Matrix Y
= y
.transpose().times( y
);
163 S1
= S1
.plus( Y
.plus( X
) );
165 double trans1
= ( transformParams
[ i
][ 2 ] * transformParams
[ i
][ 5 ] - transformParams
[ i
][ 0 ] * transformParams
[ i
][ 4 ] );
166 double trans2
= ( transformParams
[ i
][ 1 ] * transformParams
[ i
][ 4 ] - transformParams
[ i
][ 3 ] * transformParams
[ i
][ 5 ] );
167 double[] trans
= { trans1
, trans2
};
169 Matrix translation
= new Matrix( trans
, 2 );
170 Matrix YT
= y
.transpose().times( translation
);
171 Matrix XC
= xk
.transpose().times( c
).times( lambda
);
173 S2
= S2
.plus( YT
.plus( XC
) );
175 Matrix regularize
= Matrix
.identity( S1
.getRowDimension(), S1
.getColumnDimension() );
176 Matrix beta
= new Matrix( S1
.plus( regularize
.times( 0.001 ) ).inverse().times( S2
).getColumnPackedCopy(), s
);
178 setBeta( beta
.getArray() );
181 public NonLinearTransform(double[][] b
, double[] nm
, double[] nv
, int d
, int w
, int h
){
186 length
= (dimension
+ 1)*(dimension
+ 2)/2;
191 public NonLinearTransform(int d
, int w
, int h
){
193 length
= (dimension
+ 1)*(dimension
+ 2)/2;
195 beta
= new double[length
][2];
196 normMean
= new double[length
];
197 normVar
= new double[length
];
199 for (int i
=0; i
< length
; i
++){
208 public NonLinearTransform(){};
210 public NonLinearTransform(String filename
){
214 public NonLinearTransform(double[][] coeffMatrix
, int w
, int h
){
215 length
= coeffMatrix
.length
;
216 beta
= new double[length
][2];
217 normMean
= new double[length
];
218 normVar
= new double[length
];
221 dimension
= (int)(-1.5 + Math
.sqrt(0.25 + 2*length
));
223 for(int i
=0; i
<length
; i
++){
224 beta
[i
][0] = coeffMatrix
[0][i
];
225 beta
[i
][1] = coeffMatrix
[1][i
];
226 normMean
[i
] = coeffMatrix
[2][i
];
227 normVar
[i
] = coeffMatrix
[3][i
];
232 //implements mpicbg.trakem2
233 public void init( String data
) throws NumberFormatException
{
234 final String
[] fields
= data
.split( " " );
237 dimension
= Integer
.parseInt(fields
[c
]); c
++;
238 length
= Integer
.parseInt(fields
[c
]); c
++;
240 beta
= new double[length
][2];
241 normMean
= new double[length
];
242 normVar
= new double[length
];
244 if ( fields
.length
== 4 + 4*length
)
246 for (int i
=0; i
< length
; i
++){
247 beta
[i
][0] = Double
.parseDouble(fields
[c
]); c
++;
248 beta
[i
][1] = Double
.parseDouble(fields
[c
]); c
++;
251 //System.out.println("c: " + c);
253 for (int i
=0; i
< length
; i
++){
254 normMean
[i
] = Double
.parseDouble(fields
[c
]); c
++;
257 //System.out.println("c: " + c);
259 for (int i
=0; i
< length
; i
++){
260 normVar
[i
] = Double
.parseDouble(fields
[c
]); c
++;
263 width
= Integer
.parseInt(fields
[c
]); c
++;
264 height
= Integer
.parseInt(fields
[c
]); c
++;
265 //System.out.println("c: " + c);
268 else throw new NumberFormatException( "Inappropriate parameters for " + this.getClass().getCanonicalName() );
273 public String
toXML(final String indent
){
274 return new StringBuilder(indent
).append("<ict_transform class=\"").append(this.getClass().getCanonicalName()).append("\" data=\"").append(toDataString()).append("\"/>").toString();
277 public String
toDataString(){
279 data
+= Integer
.toString(dimension
) + " ";
280 data
+= Integer
.toString(length
) + " ";
282 for (int i
=0; i
< length
; i
++){
283 data
+= Double
.toString(beta
[i
][0]) + " ";
284 data
+= Double
.toString(beta
[i
][1]) + " ";
287 for (int i
=0; i
< length
; i
++){
288 data
+= Double
.toString(normMean
[i
]) + " ";
291 for (int i
=0; i
< length
; i
++){
292 data
+= Double
.toString(normVar
[i
]) + " ";
294 data
+= Integer
.toString(width
) + " ";
295 data
+= Integer
.toString(height
) + " ";
302 public String
toString(){ return toDataString(); }
304 public float[] apply( float[] location
){
306 double[] position
= {(double) location
[0], (double) location
[1]};
307 double[] featureVector
= kernelExpand(position
);
308 double[] newPosition
= multiply(beta
, featureVector
);
310 float[] newLocation
= new float[2];
311 newLocation
[0] = (float) newPosition
[0];
312 newLocation
[1] = (float) newPosition
[1];
317 public void applyInPlace( float[] location
){
318 double[] position
= {(double) location
[0], (double) location
[1]};
319 double[] featureVector
= kernelExpand(position
);
320 double[] newPosition
= multiply(beta
, featureVector
);
322 location
[0] = (float) newPosition
[0];
323 location
[1] = (float) newPosition
[1];
326 void precalculateTransfom(){
327 transField
= new double[width
][height
][2];
328 //double minX = width, minY = height, maxX = 0, maxY = 0;
330 for (int x
=0; x
<width
; x
++){
331 for (int y
=0; y
<height
; y
++){
332 double[] position
= {x
,y
};
333 double[] featureVector
= kernelExpand(position
);
334 double[] newPosition
= multiply(beta
, featureVector
);
336 if ((newPosition
[0] < 0) || (newPosition
[0] >= width
) ||
337 (newPosition
[1] < 0) || (newPosition
[1] >= height
))
339 transField
[x
][y
][0] = -1;
340 transField
[x
][y
][1] = -1;
344 transField
[x
][y
][0] = newPosition
[0];
345 transField
[x
][y
][1] = newPosition
[1];
347 //minX = Math.min(minX, x);
348 //minY = Math.min(minY, y);
349 //maxX = Math.max(maxX, x);
350 //maxY = Math.max(maxY, y);
355 precalculated
= true;
358 public double[][] getCoefficients(){
359 double[][] coeffMatrix
= new double[4][length
];
361 for(int i
=0; i
<length
; i
++){
362 coeffMatrix
[0][i
] = beta
[i
][0];
363 coeffMatrix
[1][i
] = beta
[i
][1];
364 coeffMatrix
[2][i
] = normMean
[i
];
365 coeffMatrix
[3][i
] = normVar
[i
];
371 public void setBeta(double[][] b
){
373 //FIXME: test if normMean and normVar are still valid for this beta
377 System
.out
.println("beta:");
378 for (int i
=0; i
< beta
.length
; i
++){
379 for (int j
=0; j
< beta
[i
].length
; j
++){
380 System
.out
.print(beta
[i
][j
]);
381 System
.out
.print(" ");
383 System
.out
.println();
386 System
.out
.println("normMean:");
387 for (int i
=0; i
< normMean
.length
; i
++){
388 System
.out
.print(normMean
[i
]);
389 System
.out
.print(" ");
392 System
.out
.println("normVar:");
393 for (int i
=0; i
< normVar
.length
; i
++){
394 System
.out
.print(normVar
[i
]);
395 System
.out
.print(" ");
398 System
.out
.println("Image size:");
399 System
.out
.println("width: " + width
+ " height: " + height
);
401 System
.out
.println();
405 public void save( final String filename
)
408 BufferedWriter out
= new BufferedWriter(
409 new OutputStreamWriter(
410 new FileOutputStream( filename
) ) );
412 out
.write("Kerneldimension");
414 out
.write(Integer
.toString(dimension
));
417 out
.write("number of rows");
419 out
.write(Integer
.toString(length
));
422 out
.write("Coefficients of the transform matrix:");
424 for (int i
=0; i
< length
; i
++){
425 String s
= Double
.toString(beta
[i
][0]);
427 s
+= Double
.toString(beta
[i
][1]);
432 out
.write("normMean:");
434 for (int i
=0; i
< length
; i
++){
435 out
.write(Double
.toString(normMean
[i
]));
439 out
.write("normVar: ");
441 for (int i
=0; i
< length
; i
++){
442 out
.write(Double
.toString(normVar
[i
]));
446 out
.write("image size: ");
448 out
.write(width
+ " " + height
);
451 catch(IOException e
){System
.out
.println("IOException");}
453 catch(FileNotFoundException e
){System
.out
.println("File not found!");}
456 public void load(String filename
){
458 BufferedReader in
= new BufferedReader(new FileReader(filename
));
460 String line
= in
.readLine(); //comment;
461 dimension
= Integer
.parseInt(in
.readLine());
462 line
= in
.readLine(); //comment;
463 line
= in
.readLine(); //comment;
464 length
= Integer
.parseInt(in
.readLine());
465 line
= in
.readLine(); //comment;
466 line
= in
.readLine(); //comment;
468 beta
= new double[length
][2];
470 for (int i
=0; i
< length
; i
++){
471 line
= in
.readLine();
472 int ind
= line
.indexOf(" ");
473 beta
[i
][0] = Double
.parseDouble(line
.substring(0, ind
));
474 beta
[i
][1] = Double
.parseDouble(line
.substring(ind
+4));
477 line
= in
.readLine(); //comment;
478 line
= in
.readLine(); //comment;
480 normMean
= new double[length
];
482 for (int i
=0; i
< length
; i
++){
483 normMean
[i
]=Double
.parseDouble(in
.readLine());
486 line
= in
.readLine(); //comment;
487 line
= in
.readLine(); //comment;
489 normVar
= new double[length
];
491 for (int i
=0; i
< length
; i
++){
492 normVar
[i
]=Double
.parseDouble(in
.readLine());
494 line
= in
.readLine(); //comment;
495 line
= in
.readLine(); //comment;
496 line
= in
.readLine();
497 int ind
= line
.indexOf(" ");
498 width
= Integer
.parseInt(line
.substring(0, ind
));
499 height
= Integer
.parseInt(line
.substring(ind
+4));
504 catch(IOException e
){System
.out
.println("IOException");}
506 catch(FileNotFoundException e
){System
.out
.println("File not found!");}
509 public ImageProcessor
[] transform(ImageProcessor ip
){
511 this.precalculateTransfom();
513 ImageProcessor newIp
= ip
.createProcessor(ip
.getWidth(), ip
.getHeight());
514 if (ip
instanceof ColorProcessor
) ip
.max(0);
515 ImageProcessor maskIp
= new ByteProcessor(ip
.getWidth(),ip
.getHeight());
517 for (int x
=0; x
< width
; x
++){
518 for (int y
=0; y
< height
; y
++){
519 if (transField
[x
][y
][0] == -1){
522 newIp
.set(x
, y
, (int) ip
.getInterpolatedPixel((int)transField
[x
][y
][0],(int)transField
[x
][y
][1]));
526 return new ImageProcessor
[]{newIp
, maskIp
};
529 private double[] multiply(double beta
[][], double featureVector
[]){
530 double[] result
= {0.0,0.0};
532 if (beta
.length
!= featureVector
.length
){
533 IJ
.log("Dimension of TransformMatrix and featureVector do not match!");
534 return new double[2];
537 for (int i
=0; i
<featureVector
.length
; i
++){
538 result
[0] = result
[0] + featureVector
[i
] * beta
[i
][0];
539 result
[1] = result
[1] + featureVector
[i
] * beta
[i
][1];
545 public double[] kernelExpand(double position
[]){
546 double expanded
[] = new double[length
];
549 for (int i
=1; i
<=dimension
; i
++){
550 for (double j
=i
; j
>=0; j
--){
551 double val
= Math
.pow(position
[0],j
) * Math
.pow(position
[1],i
-j
);
552 expanded
[counter
] = val
;
557 for (int i
=0; i
<length
-1; i
++){
558 expanded
[i
] = expanded
[i
] - normMean
[i
];
559 expanded
[i
] = expanded
[i
] / normVar
[i
];
562 expanded
[length
-1] = 100;
568 public double[][] kernelExpandMatrixNormalize(double positions
[][]){
569 normMean
= new double[length
];
570 normVar
= new double[length
];
572 for (int i
=0; i
< length
; i
++){
577 double expanded
[][] = new double[positions
.length
][length
];
579 for (int i
=0; i
< positions
.length
; i
++){
580 expanded
[i
] = kernelExpand(positions
[i
]);
583 for (int i
=0; i
< length
; i
++){
586 for (int j
=0; j
< expanded
.length
; j
++){
587 mean
+= expanded
[j
][i
];
590 mean
/= expanded
.length
;
592 for (int j
=0; j
< expanded
.length
; j
++){
593 var
+= (expanded
[j
][i
] - mean
)*(expanded
[j
][i
] - mean
);
595 var
/= (expanded
.length
-1);
596 var
= Math
.sqrt(var
);
602 return kernelExpandMatrix(positions
);
606 //this function uses the parameters already stored
607 //in this object to normalize the positions given.
608 public double[][] kernelExpandMatrix(double positions
[][]){
611 double expanded
[][] = new double[positions
.length
][length
];
613 for (int i
=0; i
< positions
.length
; i
++){
614 expanded
[i
] = kernelExpand(positions
[i
]);
621 public void inverseTransform(double range
[][]){
622 Matrix expanded
= new Matrix(kernelExpandMatrix(range
));
623 Matrix b
= new Matrix(beta
);
625 Matrix transformed
= expanded
.times(b
);
626 expanded
= new Matrix(kernelExpandMatrixNormalize(transformed
.getArray()));
628 Matrix r
= new Matrix(range
);
629 Matrix invBeta
= expanded
.transpose().times(expanded
).inverse().times(expanded
.transpose()).times(r
);
630 setBeta(invBeta
.getArray());
633 //FIXME this takes way too much memory
634 public void visualize(){
636 int density
= Math
.max(width
,height
)/32;
637 int border
= Math
.max(width
,height
)/8;
639 double[][] orig
= new double[width
* height
][2];
640 double[][] trans
= new double[height
* width
][2];
641 double[][] gridOrigVert
= new double[width
*height
][2];
642 double[][] gridTransVert
= new double[width
*height
][2];
643 double[][] gridOrigHor
= new double[width
*height
][2];
644 double[][] gridTransHor
= new double[width
*height
][2];
646 FloatProcessor magnitude
= new FloatProcessor(width
, height
);
647 FloatProcessor angle
= new FloatProcessor(width
, height
);
648 ColorProcessor quiver
= new ColorProcessor(width
, height
);
649 ByteProcessor empty
= new ByteProcessor(width
+2*border
, height
+2*border
);
650 quiver
.setLineWidth(1);
651 quiver
.setColor(Color
.green
);
653 GeneralPath quiverField
= new GeneralPath();
655 float minM
= 1000, maxM
= 0;
656 float minArc
= 5, maxArc
= -6;
657 int countVert
= 0, countHor
= 0, countHorWhole
= 0;
659 for (int i
=0; i
< width
; i
++){
661 for (int j
=0; j
< height
; j
++){
662 double[] position
= {(double) i
,(double) j
};
663 double[] posExpanded
= kernelExpand(position
);
664 double[] newPosition
= multiply(beta
, posExpanded
);
666 orig
[i
*j
][0] = position
[0];
667 orig
[i
*j
][1] = position
[1];
669 trans
[i
*j
][0] = newPosition
[0];
670 trans
[i
*j
][1] = newPosition
[1];
672 double m
= (position
[0] - newPosition
[0]) * (position
[0] - newPosition
[0]);
673 m
+= (position
[1] - newPosition
[1]) * (position
[1] - newPosition
[1]);
675 magnitude
.setf(i
,j
, (float) m
);
676 minM
= Math
.min(minM
, (float) m
);
677 maxM
= Math
.max(maxM
, (float) m
);
679 double a
= Math
.atan2(position
[0] - newPosition
[0], position
[1] - newPosition
[1]);
680 minArc
= Math
.min(minArc
, (float) a
);
681 maxArc
= Math
.max(maxArc
, (float) a
);
682 angle
.setf(i
,j
, (float) a
);
684 if (i
%density
== 0 && j
%density
== 0)
685 drawQuiverField(quiverField
, position
[0], position
[1], newPosition
[0], newPosition
[1]);
687 gridOrigVert
[countVert
][0] = position
[0] + border
;
688 gridOrigVert
[countVert
][1] = position
[1] + border
;
689 gridTransVert
[countVert
][0] = newPosition
[0] + border
;
690 gridTransVert
[countVert
][1] = newPosition
[1] + border
;
694 gridOrigHor
[countHor
*width
+i
][0] = position
[0] + border
;
695 gridOrigHor
[countHor
*width
+i
][1] = position
[1] + border
;
696 gridTransHor
[countHor
*width
+i
][0] = newPosition
[0] + border
;
697 gridTransHor
[countHor
*width
+i
][1] = newPosition
[1] + border
;
704 magnitude
.setMinAndMax(minM
, maxM
);
705 angle
.setMinAndMax(minArc
, maxArc
);
706 //System.out.println(" " + minArc + " " + maxArc);
708 ImagePlus magImg
= new ImagePlus("Magnitude of Distortion Field", magnitude
);
711 // ImagePlus angleImg = new ImagePlus("Angle of Distortion Field Vectors", angle);
714 ImagePlus quiverImg
= new ImagePlus("Quiver Plot of Distortion Field", magnitude
);
716 quiverImg
.getCanvas().setDisplayList(quiverField
, Color
.green
, null );
717 quiverImg
.updateAndDraw();
719 // GeneralPath gridOrig = new GeneralPath();
720 // drawGrid(gridOrig, gridOrigVert, countVert, height);
721 // drawGrid(gridOrig, gridOrigHor, countHorWhole, width);
722 // ImagePlus gridImgOrig = new ImagePlus("Distortion Grid", empty);
723 // gridImgOrig.show();
724 // gridImgOrig.getCanvas().setDisplayList(gridOrig, Color.green, null );
725 // gridImgOrig.updateAndDraw();
727 GeneralPath gridTrans
= new GeneralPath();
728 drawGrid(gridTrans
, gridTransVert
, countVert
, height
);
729 drawGrid(gridTrans
, gridTransHor
, countHorWhole
, width
);
730 ImagePlus gridImgTrans
= new ImagePlus("Distortion Grid", empty
);
732 gridImgTrans
.getCanvas().setDisplayList(gridTrans
, Color
.green
, null );
733 gridImgTrans
.updateAndDraw();
735 //new FileSaver(quiverImg.getCanvas().imp).saveAsTiff("QuiverCanvas.tif");
736 new FileSaver(quiverImg
).saveAsTiff("QuiverImPs.tif");
738 System
.out
.println("FINISHED");
742 public void visualizeSmall(double lambda
){
743 int density
= Math
.max(width
,height
)/32;
745 double[][] orig
= new double[2][width
* height
];
746 double[][] trans
= new double[2][height
* width
];
748 FloatProcessor magnitude
= new FloatProcessor(width
, height
);
750 GeneralPath quiverField
= new GeneralPath();
752 float minM
= 1000, maxM
= 0;
753 float minArc
= 5, maxArc
= -6;
754 int countVert
= 0, countHor
= 0, countHorWhole
= 0;
756 for (int i
=0; i
< width
; i
++){
758 for (int j
=0; j
< height
; j
++){
759 double[] position
= {(double) i
,(double) j
};
760 double[] posExpanded
= kernelExpand(position
);
761 double[] newPosition
= multiply(beta
, posExpanded
);
763 orig
[0][i
*j
] = position
[0];
764 orig
[1][i
*j
] = position
[1];
766 trans
[0][i
*j
] = newPosition
[0];
767 trans
[1][i
*j
] = newPosition
[1];
769 double m
= (position
[0] - newPosition
[0]) * (position
[0] - newPosition
[0]);
770 m
+= (position
[1] - newPosition
[1]) * (position
[1] - newPosition
[1]);
772 magnitude
.setf(i
,j
, (float) m
);
773 minM
= Math
.min(minM
, (float) m
);
774 maxM
= Math
.max(maxM
, (float) m
);
776 if (i
%density
== 0 && j
%density
== 0)
777 drawQuiverField(quiverField
, position
[0], position
[1], newPosition
[0], newPosition
[1]);
781 magnitude
.setMinAndMax(minM
, maxM
);
782 ImagePlus quiverImg
= new ImagePlus("Quiver Plot for lambda = "+lambda
, magnitude
);
784 quiverImg
.getCanvas().setDisplayList(quiverField
, Color
.green
, null );
785 quiverImg
.updateAndDraw();
787 System
.out
.println("FINISHED");
791 public static void drawGrid(GeneralPath g
, double[][] points
, int count
, int s
){
792 for (int i
=0; i
< count
- 1; i
++){
794 g
.moveTo((float)points
[i
][0], (float)points
[i
][1]);
795 g
.lineTo((float)points
[i
+1][0], (float)points
[i
+1][1]);
800 public static void drawQuiverField(GeneralPath qf
, double x1
, double y1
, double x2
, double y2
)
802 qf
.moveTo((float)x1
, (float)y1
);
803 qf
.lineTo((float)x2
, (float)y2
);
806 public int getWidth(){
810 public int getHeight(){
816 * TODO Make this more efficient
818 final public NonLinearTransform
copy()
820 final NonLinearTransform t
= new NonLinearTransform();
821 t
.init( toDataString() );
825 public void set( final NonLinearTransform nlt
)
827 this.dimension
= nlt
.dimension
;
828 this.height
= nlt
.height
;
829 this.length
= nlt
.length
;
830 this.precalculated
= nlt
.precalculated
;
831 this.width
= nlt
.width
;
833 /* arrays by deep cloning */
834 this.beta
= new double[ nlt
.beta
.length
][];
835 for ( int i
= 0; i
< nlt
.beta
.length
; ++i
)
836 this.beta
[ i
] = nlt
.beta
[ i
].clone();
838 this.normMean
= nlt
.normMean
.clone();
839 this.normVar
= nlt
.normVar
.clone();
840 this.transField
= new double[ nlt
.transField
.length
][][];
842 for ( int a
= 0; a
< nlt
.transField
.length
; ++a
)
844 this.transField
[ a
] = new double[ nlt
.transField
[ a
].length
][];
845 for ( int b
= 0; b
< nlt
.transField
[ a
].length
; ++b
)
846 this.transField
[ a
][ b
] = nlt
.transField
[ a
][ b
].clone();