separated CoordinateTransform parts of lenscorrection.NonLinearTransform
[trakem2.git] / mpicbg-trakem2 / src / main / java / mpicbg / trakem2 / transform / NonLinearCoordinateTransform.java
blobbf4b2e9c3d4ff103066433c3b3fc68accb537259
1 /**
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
21 * kernel expansion.
23 * TODO:
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 mpicbg.trakem2.transform;
37 public class NonLinearCoordinateTransform implements mpicbg.trakem2.transform.CoordinateTransform
39 protected double[][] beta = null;
40 protected double[] normMean = null;
41 protected double[] normVar = null;
42 protected int dimension = 0;
43 protected int length = 0;
44 protected int width = 0;
45 protected int height = 0;
47 public NonLinearCoordinateTransform(){};
49 @Override
50 public void init( final String data ) throws NumberFormatException{
51 final String[] fields = data.split( " " );
52 int c = 0;
54 dimension = Integer.parseInt(fields[c]); c++;
55 length = Integer.parseInt(fields[c]); c++;
57 beta = new double[length][2];
58 normMean = new double[length];
59 normVar = new double[length];
61 if ( fields.length == 4 + 4*length )
63 for (int i=0; i < length; i++){
64 beta[i][0] = Double.parseDouble(fields[c]); c++;
65 beta[i][1] = Double.parseDouble(fields[c]); c++;
68 for (int i=0; i < length; i++){
69 normMean[i] = Double.parseDouble(fields[c]); c++;
72 for (int i=0; i < length; i++){
73 normVar[i] = Double.parseDouble(fields[c]); c++;
76 width = Integer.parseInt(fields[c]); c++;
77 height = Integer.parseInt(fields[c]); c++;
80 else throw new NumberFormatException( "Inappropriate parameters for " + this.getClass().getCanonicalName() );
83 @Override
84 public String toXML(final String indent){
85 return new StringBuilder(indent).append("<ict_transform class=\"").append(this.getClass().getCanonicalName()).append("\" data=\"").append(toDataString()).append("\"/>").toString();
88 @Override
89 public String toDataString(){
90 String data = "";
91 data += Integer.toString(dimension) + " ";
92 data += Integer.toString(length) + " ";
94 for (int i=0; i < length; i++){
95 data += Double.toString(beta[i][0]) + " ";
96 data += Double.toString(beta[i][1]) + " ";
99 for (int i=0; i < length; i++){
100 data += Double.toString(normMean[i]) + " ";
103 for (int i=0; i < length; i++){
104 data += Double.toString(normVar[i]) + " ";
106 data += Integer.toString(width) + " ";
107 data += Integer.toString(height) + " ";
109 return data;
113 @Override
114 public String toString(){ return toDataString(); }
116 @Override
117 public float[] apply(final float[] location) {
119 final double[] position = { (double) location[0], (double) location[1] };
120 final double[] featureVector = kernelExpand(position);
121 final double[] newPosition = multiply(beta, featureVector);
123 final float[] newLocation = new float[2];
124 newLocation[0] = (float) newPosition[0];
125 newLocation[1] = (float) newPosition[1];
127 return newLocation;
130 @Override
131 public void applyInPlace(final float[] location) {
132 final double[] position = { (double) location[0], (double) location[1] };
133 final double[] featureVector = kernelExpand(position);
134 final double[] newPosition = multiply(beta, featureVector);
136 location[0] = (float) newPosition[0];
137 location[1] = (float) newPosition[1];
141 static protected double[] multiply(final double beta[][], final double featureVector[]) {
142 final double[] result = { 0.0, 0.0 };
144 if (beta.length != featureVector.length)
146 return new double[2];
149 for (int i = 0; i < featureVector.length; ++i)
151 result[0] = result[0] + featureVector[i] * beta[i][0];
152 result[1] = result[1] + featureVector[i] * beta[i][1];
155 return result;
158 public double[] kernelExpand( final double position[] ) {
159 final double expanded[] = new double[length];
161 int counter = 0;
162 for (int i = 1; i <= dimension; i++) {
163 for (double j = i; j >= 0; j--) {
164 final double val = Math.pow(position[0], j)
165 * Math.pow(position[1], i - j);
166 expanded[counter] = val;
167 ++counter;
171 for (int i = 0; i < length - 1; i++) {
172 expanded[i] = expanded[i] - normMean[i];
173 expanded[i] = expanded[i] / normVar[i];
176 expanded[length - 1] = 100;
178 return expanded;
182 * TODO Make this more efficient
184 @Override
185 public NonLinearCoordinateTransform copy()
187 final NonLinearCoordinateTransform t = new NonLinearCoordinateTransform();
188 t.init(toDataString());
189 return t;