IntersceneLma.java 73.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/**
 **
 ** IntersceneLma - Adjust camera egomotion with LMA
 **
 ** Copyright (C) 2020-2023 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
 **
 **  IntersceneLma.java is free software: you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License as published by
 **  the Free Software Foundation, either version 3 of the License, or
 **  (at your option) any later version.
 **
 **  This program is distributed in the hope that it will be useful,
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 **  GNU General Public License for more details.
 **
 **  You should have received a copy of the GNU General Public License
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ** -----------------------------------------------------------------------------**
 **
 */

25 26
package com.elphel.imagej.tileprocessor;

27 28 29 30 31 32
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35 36 37
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.DoubleAdder;

38 39
import javax.xml.bind.DatatypeConverter;

40 41
import com.elphel.imagej.common.ShowDoubleFloatArrays;

42
import Jama.Matrix;
Andrey Filippov's avatar
Andrey Filippov committed
43
import ij.ImagePlus;
44 45 46 47 48 49 50

public class IntersceneLma {
	QuadCLT [] scenesCLT =    null; // now will use just 2 - 0 -reference scene, 1 - scene.  
	private double []         last_rms =        null; // {rms, rms_pure}, matching this.vector
	private double []         good_or_bad_rms = null; // just for diagnostics, to read last (failed) rms
	private double []         initial_rms =     null; // {rms, rms_pure}, first-calcualted rms
	private double []         y_vector =        null; // sum of fx(initial parameters) and correlation offsets
51
	private double []         s_vector =        null; // strength component - just for debug images
52 53
	private double []         last_ymfx =       null;
	private double [][]       last_jt =         null;
Andrey Filippov's avatar
Andrey Filippov committed
54 55 56
	private double []         weights; // normalized so sum is 1.0 for all - samples and extra regularization
	private double            sum_weights =     0;
	private int               num_defined =     0;    
57 58 59
	private double            pure_weight; // weight of samples only
	private boolean []        par_mask =        null;
	private int []            par_indices =     null;
60 61
	private double  []        parameters_full = null; // full parameters vector for the currenl LMA run
	private double  []        backup_parameters_full = null; // full parameters vector before first LMA run
62
	private double  []        parameters_vector = null; 
63 64
	private double  []        parameters_pull = null; // for regularization - error is proportional to difference between
	//                                                   current vector and parameters_pull
65 66 67
	private double  [][]      macrotile_centers = null;  // (will be used to pull for regularization)
	private double            infinity_disparity = 0.1;  // treat lower as infinity
	private int               num_samples = 0;
68 69 70 71 72 73
	///////////////////////////////////////////////////////////
	// thread_invariant is needed for LMA, otherwise even with the same parameter vector RMS may be slightly different
	// keeping thread-variant where it is done once per LMA (during setup) - in normalizeWeights() and setSamplesWeights()
	// See original code (with all switching between variant/invariant) in pre 12/17/2023
	///////////////////////////////////////////////////////////
	
74
	private boolean           thread_invariant = true; // Do not use DoubleAdder, provide results not dependent on threads
75 76
	private int               num_components =   2;    // 2 for 2D matching only,3 - include disparity
	private double            disparity_weight = 1.0;  // relative weight of disparity errors
77 78
	
	private double [][][]     eig_trans = null;
79 80 81
	private int               tilesX = -1;
	private String            dbg_prefix = null;
	
82
	public IntersceneLma(
83 84
			boolean thread_invariant,
			double disparity_weight
85
			) {
86
		this.num_components =   (disparity_weight > 0) ? 3 : 2;
87
		this.disparity_weight = disparity_weight;
88
		this.thread_invariant=  thread_invariant;
89
	}
90
	
91 92 93
	public int getNumComponents() {
		return num_components;
	}
94 95 96
	public double [][]       getLastJT(){
		return last_jt;
	}
Andrey Filippov's avatar
Andrey Filippov committed
97 98 99 100 101 102 103 104
	
	public double getSumWeights() {
		return sum_weights;
	}
	
	public int getNumDefined() {
		return num_defined;
	}
105 106

	
107 108 109
	public double[] getLastRms() {
		return last_rms;
	}
110 111
	public double [] getSceneXYZ(boolean initial) {
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
112 113 114
		return new double[] {
				full_vector[ErsCorrection.DP_DSX],full_vector[ErsCorrection.DP_DSY],full_vector[ErsCorrection.DP_DSZ]};
	}
115 116
	public double [] getSceneATR(boolean initial) {
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
117 118 119
		return new double[] {
				full_vector[ErsCorrection.DP_DSAZ],full_vector[ErsCorrection.DP_DSTL],full_vector[ErsCorrection.DP_DSRL]};
	}
Andrey Filippov's avatar
Andrey Filippov committed
120 121 122 123 124 125 126
	public double [][] getSceneXYZATR(boolean initial) {
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
		return new double[][] {
				{full_vector[ErsCorrection.DP_DSX],full_vector[ErsCorrection.DP_DSY],full_vector[ErsCorrection.DP_DSZ]},
				{full_vector[ErsCorrection.DP_DSAZ],full_vector[ErsCorrection.DP_DSTL],full_vector[ErsCorrection.DP_DSRL]}};
	}
	
127 128
	public double [] getReferenceXYZ(boolean initial) {
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
129 130 131
		return new double[] {
				full_vector[ErsCorrection.DP_DX],full_vector[ErsCorrection.DP_DY],full_vector[ErsCorrection.DP_DZ]};
	}
132 133
	public double [] getReferenceATR(boolean initial) {
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
134 135 136
		return new double[] {
				full_vector[ErsCorrection.DP_DAZ],full_vector[ErsCorrection.DP_DTL],full_vector[ErsCorrection.DP_DRL]};
	}
Andrey Filippov's avatar
Andrey Filippov committed
137 138 139 140 141 142
	public double [][] getReferenceXYZATR(boolean initial) {
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
		return new double[][] {
				{full_vector[ErsCorrection.DP_DX],full_vector[ErsCorrection.DP_DY],full_vector[ErsCorrection.DP_DZ]},
				{full_vector[ErsCorrection.DP_DAZ],full_vector[ErsCorrection.DP_DTL],full_vector[ErsCorrection.DP_DRL]}};
	}
143

144
	public double [] getSceneERSXYZ(boolean initial) { // never used
145
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
146 147 148
		return new double[] {
				full_vector[ErsCorrection.DP_DSVX],full_vector[ErsCorrection.DP_DSVY],full_vector[ErsCorrection.DP_DSVZ]};
	}
149
	public double [] getSceneERSATR(boolean initial) { // never used
150
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
151 152 153
		return new double[] {
				full_vector[ErsCorrection.DP_DSVAZ],full_vector[ErsCorrection.DP_DSVTL],full_vector[ErsCorrection.DP_DSVRL]};
	}
154
	public double [] getReferenceERSXYZ(boolean initial) { // never used
155
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
156
		return new double[] {
Andrey Filippov's avatar
Andrey Filippov committed
157
				full_vector[ErsCorrection.DP_DVX],full_vector[ErsCorrection.DP_DVY],full_vector[ErsCorrection.DP_DVZ]};
158
	}
159
	public double [] getReferenceERSATR(boolean initial) { // never used
160
		double [] full_vector = initial? backup_parameters_full: getFullVector(parameters_vector);
161
		return new double[] {
Andrey Filippov's avatar
Andrey Filippov committed
162
				full_vector[ErsCorrection.DP_DVAZ],full_vector[ErsCorrection.DP_DVTL],full_vector[ErsCorrection.DP_DVRL]};
163 164
	}

165
	public String [] printOldNew(boolean allvectors) {
166
		return printOldNew(allvectors, 0);
167 168
	}

169 170 171 172
	public String [] printOldNew(boolean allvectors, int mode) {
		return printOldNew(allvectors, mode, 9, 6);
	}
	
173
	public String [] printOldNew(boolean allvectors, int w, int d) {
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
		return printOldNew(allvectors, 0, w, d);
	}

	public String [] printOldNew(boolean allvectors, int mode, int w, int d) {
		// mode: 0 - auto, 1 - force "was", 2 force "pull"
		
		String fmt1 = String.format("%%%d.%df", w+2,d+2); // more for the differences
		ArrayList<String> lines = new ArrayList<String>();
		for (int n = ErsCorrection.DP_DVAZ; n < ErsCorrection.DP_NUM_PARS; n+=3) {
			boolean adj = false;
			for (int i = 0; i <3; i++) adj |= par_mask[n+i];
			if (allvectors || adj) {
				String line = printNameV3(n, false, mode, w,d)+"  (" + getCompareType(mode)+
						" "+printNameV3(n, true, mode, w,d)+")";
				line += ", diff_last="+String.format(fmt1, getV3Diff(n)[0]);
				line += ", diff_first="+String.format(fmt1, getV3Diff(n)[1]);
				lines.add(line);
			}
		}
		return lines.toArray(new String[lines.size()]);
194 195
	}
	
196 197 198 199 200 201 202 203 204
	/**
	 * Calculate L2 for 3-vector difference between the adjusted values, this LMA start values
	 * and "backup" parameters - snapshot before the first adjustment (first calculation of 
	 * the motion vectors+LMA iteration  
	 * @param indx offset to the first element of the 3-vector in the full parameters array
	 * @return a pair of L2 differences {diff_with_this_LMA_start, diff_with_first_lma_start}
	 */
	public double [] getV3Diff(int indx) {
		double [] v_new = new double[3], v_backup = new double[3], v_start = new double[3];
205
		System.arraycopy(getFullVector(parameters_vector), indx, v_new, 0, 3);
206 207 208 209
		System.arraycopy(backup_parameters_full, indx, v_backup, 0, 3);
		System.arraycopy(parameters_full, indx, v_start, 0, 3);
		double l2_backup = 0;
		double l2_start = 0;
210
		for (int i = 0; i < 3; i++) {
211 212
			l2_backup += (v_new[i]-v_backup[i]) * (v_new[i]-v_backup[i]); 
			l2_start +=  (v_new[i]-v_start[i]) *  (v_new[i]-v_start[i]); 
213
		}
214
		return new double [] {Math.sqrt(l2_start), Math.sqrt(l2_backup)};
215 216
	}
	
217
	public String getCompareType() {
218 219 220 221 222 223
		return getCompareType(0);
//		return (parameters_pull != null)? "pull": "was";
	}

	public String getCompareType(int mode) {
		boolean is_pull = (mode == 0) ? (parameters_pull != null) : (mode > 1);  
224
		return is_pull? "pull": "was ";
225 226
	}
	
227
	public String printNameV3(int indx, boolean initial, int w, int d) {
228
		return printNameV3(indx, initial, 0, w, d);
229
	}
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

	public String printNameV3(int indx, boolean initial, int mode, int w, int d) {
		// mode: 0 - auto, 1 - was, 2 - pull 
		boolean use_pull = (mode == 0) ? (parameters_pull != null) : (mode > 1);  		
		double [] full_vector = initial? 
				(use_pull? getFullVector(parameters_pull) : backup_parameters_full):
			getFullVector(parameters_vector);
		double [] vector = new double[3];
		for (int i = 0; i <3; i++) {
			vector[i] = full_vector[indx + i];
		}
		String name = ErsCorrection.DP_VECTORS_NAMES[indx];
		return printNameV3(name, vector, w, d);
	}
	
245 246
	
	public static String printNameV3(String name, double[] vector) {
247
		return printNameV3(name, vector, 10, 6);
248 249 250 251 252 253 254 255 256 257 258 259 260 261
	}
	
	public static String printNameV3(String name, double[] vector, int w, int d) {
		return String.format("%14s: %s", name, printV3(vector, w, d));
	}

	
	public static String printV3(double[] vector) {
		return printV3(vector, 8, 5);
	}
	public static String printV3(double[] vector, int w, int d) {
		String fmt = String.format("[%%%d.%df, %%%d.%df, %%%d.%df]", w,d,w,d,w,d);
		return String.format(fmt, vector[0], vector[1], vector[2]);
	}
262

Andrey Filippov's avatar
Andrey Filippov committed
263 264 265 266 267 268 269 270 271
	public void prepareLMA(
			final double [][] scene_xyzatr0,     // camera center in world coordinates (or null to use instance)
			final double [][] scene_xyzatr_pull, // if both are not null, specify target values to pull to 
			final double [][] ref_xyzatr,        // 
			// reference atr, xyz are considered 0.0 - not anymore?
			final QuadCLT     scene_QuadClt,
			final QuadCLT     reference_QuadClt,
			final boolean[]   param_select,
			final double []   param_regweights,
272 273 274 275
			final double      eig_max_sqrt, //  6;    // for sqrt(lambda) - consider infinity (infinite linear feature, a line)
			final double      eig_min_sqrt, //  1;    // for sqrt(lambda) - consider infinity (infinite linear feature, a line)
			//if (eigen != null) normalize by eigenvalues, recalc derivatives to eigenvectors directions
			final double [][] eigen, // [tilesX*tilesY]{lamb0_x,lamb0_y, lamb0, lamb1} eigenvector0[x,y],lam0,lam1
Andrey Filippov's avatar
Andrey Filippov committed
276
			// now includes optional Disparity as the last element (for num_components==3)
Andrey Filippov's avatar
Andrey Filippov committed
277 278
			final double [][] vector_XYSDS,// optical flow X,Y, confidence obtained from the correlate2DIterate()
			final double [][] centers,     // macrotile centers (in pixels and average disparities
Andrey Filippov's avatar
Andrey Filippov committed
279
			final boolean     same_weights,
Andrey Filippov's avatar
Andrey Filippov committed
280
			boolean           first_run,
281
			String            dbg_prefix, // null or image name prefix
Andrey Filippov's avatar
Andrey Filippov committed
282
			final int         debug_level) {
283
		// before getFxDerivs
284 285 286 287
		eig_trans = setEigenTransform(
				eig_max_sqrt, // final double   eig_max_sqrt,
				eig_min_sqrt, // final double   eig_min_sqrt,
				eigen); // final double [][] eigen); // [tilesX*tilesY]{lamb0_x,lamb0_y, lamb0, lamb1} eigenvector0[x,y],lam0,lam1
288
		tilesX = reference_QuadClt.getTileProcessor().getTilesX(); // just for debug images
Andrey Filippov's avatar
Andrey Filippov committed
289 290 291 292
		scenesCLT = new QuadCLT [] {reference_QuadClt, scene_QuadClt};
		par_mask = param_select;
		macrotile_centers = centers;
		num_samples = num_components * centers.length;
293 294
		this.dbg_prefix = dbg_prefix;
		s_vector = (this.dbg_prefix != null) ? (new double[centers.length]): null; // original strength
Andrey Filippov's avatar
Andrey Filippov committed
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
		ErsCorrection ers_ref =   reference_QuadClt.getErsCorrection();
		ErsCorrection ers_scene = scene_QuadClt.getErsCorrection();
		final double []   scene_xyz = (scene_xyzatr0 != null) ? scene_xyzatr0[0] : ers_scene.camera_xyz;
		final double []   scene_atr = (scene_xyzatr0 != null) ? scene_xyzatr0[1] : ers_scene.camera_atr;
		final double []   reference_xyz = (ref_xyzatr != null)? ref_xyzatr[0]:     ers_ref.camera_xyz; // new double[3];
		final double []   reference_atr = (ref_xyzatr != null)? ref_xyzatr[1]:     ers_ref.camera_xyz; // new double[3];
		double [] full_parameters_vector = new double [] {
				0.0,                             0.0,                             0.0,
				ers_ref.ers_watr_center_dt[0],   ers_ref.ers_watr_center_dt[1],   ers_ref.ers_watr_center_dt[2],
				ers_ref.ers_wxyz_center_dt[0],   ers_ref.ers_wxyz_center_dt[1],   ers_ref.ers_wxyz_center_dt[2],
				reference_atr[0],                reference_atr[1],                reference_atr[2],
				reference_xyz[0],                reference_xyz[1],                reference_xyz[2],
				ers_scene.ers_watr_center_dt[0], ers_scene.ers_watr_center_dt[1], ers_scene.ers_watr_center_dt[2],
				ers_scene.ers_wxyz_center_dt[0], ers_scene.ers_wxyz_center_dt[1], ers_scene.ers_wxyz_center_dt[2],
				scene_atr[0],                    scene_atr[1],                    scene_atr[2],
				scene_xyz[0],                    scene_xyz[1],                    scene_xyz[2]};
		parameters_full = full_parameters_vector.clone();
		if ((vector_XYSDS != null) && (first_run || (backup_parameters_full == null))) {
			backup_parameters_full = full_parameters_vector.clone();
		}
		int num_pars = 0;
		for (int i = 0; i < par_mask.length; i++) if (par_mask[i]) num_pars++;
		par_indices = new int [num_pars];
		num_pars = 0;
		for (int i = 0; i < par_mask.length; i++) {
			if (par_mask[i]) par_indices[num_pars++] = i;
		}
		parameters_vector = new double [par_indices.length];
		for (int i = 0; i < par_indices.length; i++) {
			parameters_vector[i] = full_parameters_vector[par_indices[i]];
		}

		if ((scene_xyzatr_pull != null) && (scene_xyzatr_pull[0] != null) && (scene_xyzatr_pull[1] != null)) {
			double [] parameters_pull_full =  parameters_full.clone();
			for (int i = 0; i < 3; i++)	{
				parameters_pull_full[ErsCorrection.DP_DSX +  i] =  scene_xyzatr_pull[0][i]; 
				parameters_pull_full[ErsCorrection.DP_DSAZ +  i] = scene_xyzatr_pull[1][i]; 
				// 			parameters_pull = 
			}
			parameters_pull = new double [par_indices.length];
			for (int i = 0; i < par_indices.length; i++) {
				parameters_pull[i] = parameters_pull_full[par_indices[i]];
			}
		}
		
		if (vector_XYSDS != null) {// skip when used for the motion blur vectors, not LMA
Andrey Filippov's avatar
Andrey Filippov committed
341 342 343
			setSamplesWeights(vector_XYSDS,  // not regularized yet ! // 3d updated
				same_weights); // final boolean same_weights) // same weight if > 0

Andrey Filippov's avatar
Andrey Filippov committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
		} else {
			weights = null; // new double[2 * centers.length];
		}

		last_jt = new double [parameters_vector.length][];
		if (debug_level > 1) {
			System.out.println("prepareLMA() 1");
		}
		double [] fx = getFxDerivs(
				parameters_vector, // double []         vector,
				last_jt,           // final double [][] jt, // should be null or initialized with [vector.length][]
				scenesCLT[1],      // final QuadCLT     scene_QuadClt,
				scenesCLT[0],      // final QuadCLT     reference_QuadClt,
				debug_level);      // final int         debug_level)
		if (vector_XYSDS == null) {
			return; // for MB vectors (noLMA)
		}
		
		double [][] wjtj = getWJtJlambda( // USED in lwir all NAN
				0.0,               // final double      lambda,
				last_jt);               // final double [][] jt) all 0???
		for (int i = 0; i < parameters_vector.length; i++) {
			int indx = num_samples + i;
			if (wjtj[i][i] == 0) {  // why is it zero (leading to NaN)
				weights[indx] = 0;
			} else {
				weights[indx] = param_regweights[par_indices[i]]/Math.sqrt(wjtj[i][i]);
			}
		}
		normalizeWeights(); // make full weight == 1.0; pure_weight <= 1.0;
		// remeasure fx - now with regularization terms.
		if (debug_level > 1) {
			System.out.println("prepareLMA() 2");
		}
		fx = getFxDerivs(
				parameters_vector, // double []         vector,
				last_jt,                // final double [][] jt, // should be null or initialized with [vector.length][]
				scene_QuadClt,     // final QuadCLT     scene_QuadClt,
				reference_QuadClt, // final QuadCLT     reference_QuadClt,
				debug_level);      // final int         debug_level)
		// Why y_vector starts with initial value of fx??? 
		y_vector = fx.clone();
		for (int i = 0; i < vector_XYSDS.length; i++) {
			if (vector_XYSDS[i] != null){
				y_vector[num_components * i + 0] += vector_XYSDS[i][0];
				y_vector[num_components * i + 1] += vector_XYSDS[i][1];
390 391 392 393 394
				if (num_components > 2) { // ****************************** [3] - disparity? Was BUG: [2] !
					y_vector[num_components * i + 2] += vector_XYSDS[i][3]; // vector_XYSDS[i][2]; 
				}
				if (s_vector != null) {
					s_vector[i] = vector_XYSDS[i][2];
Andrey Filippov's avatar
Andrey Filippov committed
395 396 397
				}
			}
		}
398
			
Andrey Filippov's avatar
Andrey Filippov committed
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
		if (parameters_pull != null){
			for (int i = 0; i < par_indices.length; i++) {
				y_vector [i + num_components * macrotile_centers.length] = parameters_pull[i]; // - parameters_initial[i]; // scale will be combined with weights
			}			
		}
		
		last_rms = new double [2];
		last_ymfx = getYminusFxWeighted(
				fx, // final double []   fx,
				last_rms); // final double []   rms_fp // null or [2]
		initial_rms = last_rms.clone();
		good_or_bad_rms = this.last_rms.clone();
			
	}
	
	
	
416 417 418
	public void prepareLMA(
			final double []   scene_xyz0,     // camera center in world coordinates (or null to use instance)
			final double []   scene_atr0,     // camera orientation relative to world frame (or null to use instance)
419 420
			final double []   scene_xyz_pull, // if both are not null, specify target values to pull to 
			final double []   scene_atr_pull, // 
421
			// reference atr, xyz are considered 0.0 - not anymore?
422 423 424 425
			final QuadCLT     scene_QuadClt,
			final QuadCLT     reference_QuadClt,
			final boolean[]   param_select,
			final double []   param_regweights,
426 427 428 429
//			final double [][] vector_XYS,  // optical flow X,Y, confidence obtained from the correlate2DIterate()
			// now includes optional Disparity as the last element (for num_components==3) 
			final double [][] vector_XYSDS,// optical flow X,Y, confidence obtained from the correlate2DIterate()
			final double [][] centers,     // macrotile centers (in pixels and average disparities
Andrey Filippov's avatar
Andrey Filippov committed
430
			final boolean     same_weights,
431
			boolean           first_run,
432 433 434 435 436
			final int         debug_level)
	{
		scenesCLT = new QuadCLT [] {reference_QuadClt, scene_QuadClt};
		par_mask = param_select;
		macrotile_centers = centers;
437
		num_samples = num_components * centers.length;
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
		ErsCorrection ers_ref =   reference_QuadClt.getErsCorrection();
		ErsCorrection ers_scene = scene_QuadClt.getErsCorrection();
		final double []   scene_xyz = (scene_xyz0 != null) ? scene_xyz0 : ers_scene.camera_xyz;
		final double []   scene_atr = (scene_atr0 != null) ? scene_atr0 : ers_scene.camera_atr;
		final double []   reference_xyz = new double[3];
		final double []   reference_atr = new double[3];
		double [] full_parameters_vector = new double [] {
				0.0,                             0.0,                             0.0,
				ers_ref.ers_watr_center_dt[0],   ers_ref.ers_watr_center_dt[1],   ers_ref.ers_watr_center_dt[2],
				ers_ref.ers_wxyz_center_dt[0],   ers_ref.ers_wxyz_center_dt[1],   ers_ref.ers_wxyz_center_dt[2],
				reference_atr[0],                reference_atr[1],                reference_atr[2],
				reference_xyz[0],                reference_xyz[1],                reference_xyz[2],
				ers_scene.ers_watr_center_dt[0], ers_scene.ers_watr_center_dt[1], ers_scene.ers_watr_center_dt[2],
				ers_scene.ers_wxyz_center_dt[0], ers_scene.ers_wxyz_center_dt[1], ers_scene.ers_wxyz_center_dt[2],
				scene_atr[0],                    scene_atr[1],                    scene_atr[2],
				scene_xyz[0],                    scene_xyz[1],                    scene_xyz[2]};
454
		parameters_full = full_parameters_vector.clone();
455
		if ((vector_XYSDS != null) && (first_run || (backup_parameters_full == null))) {
456 457
			backup_parameters_full = full_parameters_vector.clone();
		}
458 459 460
		int num_pars = 0;
		for (int i = 0; i < par_mask.length; i++) if (par_mask[i]) num_pars++;
		par_indices = new int [num_pars];
461
		num_pars = 0;
462 463 464
		for (int i = 0; i < par_mask.length; i++) {
			if (par_mask[i]) par_indices[num_pars++] = i;
		}
465
		parameters_vector = new double [par_indices.length];
466 467 468
		for (int i = 0; i < par_indices.length; i++) {
			parameters_vector[i] = full_parameters_vector[par_indices[i]];
		}
469

470 471 472 473 474 475 476 477 478 479 480 481 482 483
		if ((scene_xyz_pull != null) && (scene_atr_pull != null)) {
			double [] parameters_pull_full =  parameters_full.clone();
			for (int i = 0; i < 3; i++)	{
				parameters_pull_full[ErsCorrection.DP_DSX +  i] =  scene_xyz_pull[i]; 
				parameters_pull_full[ErsCorrection.DP_DSAZ +  i] = scene_atr_pull[i]; 
				// 			parameters_pull = 
			}
			parameters_pull = new double [par_indices.length];
			for (int i = 0; i < par_indices.length; i++) {
				parameters_pull[i] = parameters_pull_full[par_indices[i]];
			}
		}
		
		if (vector_XYSDS != null) {// skip when used for the motion blur vectors, not LMA
Andrey Filippov's avatar
Andrey Filippov committed
484 485
			setSamplesWeights(vector_XYSDS,  // not regularized yet ! // 3d updated
					same_weights); // final boolean same_weights) // same weight if > 0
486 487 488
		} else {
			weights = null; // new double[2 * centers.length];
		}
489 490

		last_jt = new double [parameters_vector.length][];
491 492 493
		if (debug_level > 1) {
			System.out.println("prepareLMA() 1");
		}
494 495 496 497 498 499
		double [] fx = getFxDerivs(
				parameters_vector, // double []         vector,
				last_jt,           // final double [][] jt, // should be null or initialized with [vector.length][]
				scenesCLT[1],      // final QuadCLT     scene_QuadClt,
				scenesCLT[0],      // final QuadCLT     reference_QuadClt,
				debug_level);      // final int         debug_level)
500
		if (vector_XYSDS == null) {
501 502 503
			return; // for MB vectors (noLMA)
		}
		
Andrey Filippov's avatar
Andrey Filippov committed
504
		double [][] wjtj = getWJtJlambda( // USED in lwir all NAN
505
				0.0,               // final double      lambda,
506
				last_jt);               // final double [][] jt) all 0???
507 508
		for (int i = 0; i < parameters_vector.length; i++) {
			int indx = num_samples + i;
509 510 511 512 513
			if (wjtj[i][i] == 0) {  // why is it zero (leading to NaN)
				weights[indx] = 0;
			} else {
				weights[indx] = param_regweights[par_indices[i]]/Math.sqrt(wjtj[i][i]);
			}
514 515 516
		}
		normalizeWeights(); // make full weight == 1.0; pure_weight <= 1.0;
		// remeasure fx - now with regularization terms.
517 518 519 520

		if (debug_level > 1) {
			System.out.println("prepareLMA() 2");
		}
521 522 523 524 525 526
		fx = getFxDerivs(
				parameters_vector, // double []         vector,
				last_jt,                // final double [][] jt, // should be null or initialized with [vector.length][]
				scene_QuadClt,     // final QuadCLT     scene_QuadClt,
				reference_QuadClt, // final QuadCLT     reference_QuadClt,
				debug_level);      // final int         debug_level)
527
		// Why y_vector starts with initial value of fx??? 
528
		y_vector = fx.clone();
529 530 531 532 533 534 535 536
		for (int i = 0; i < vector_XYSDS.length; i++) {
			if (vector_XYSDS[i] != null){
				y_vector[num_components * i + 0] += vector_XYSDS[i][0];
				y_vector[num_components * i + 1] += vector_XYSDS[i][1];
				if (num_components > 2) {
					y_vector[num_components * i + 2] += vector_XYSDS[i][2];
				}
				
537 538
			}
		}
539 540 541 542 543 544 545
		if (parameters_pull != null){
			for (int i = 0; i < par_indices.length; i++) {
//				y_vector [i + num_components * macrotile_centers.length] += parameters_pull[i]; // - parameters_initial[i]; // scale will be combined with weights
				y_vector [i + num_components * macrotile_centers.length] = parameters_pull[i]; // - parameters_initial[i]; // scale will be combined with weights
			}			
		}
		
546 547 548 549 550 551 552 553
		last_rms = new double [2];
		last_ymfx = getYminusFxWeighted(
				fx, // final double []   fx,
				last_rms); // final double []   rms_fp // null or [2]
		initial_rms = last_rms.clone();
		good_or_bad_rms = this.last_rms.clone();
	}
	
554
	public int runLma( // <0 - failed, >=0 iteration number (1 - immediately)
555 556 557 558 559 560
			double lambda,           // 0.1
			double lambda_scale_good,// 0.5
			double lambda_scale_bad, // 8.0
			double lambda_max,       // 100
			double rms_diff,         // 0.001
			int    num_iter,         // 20
561
			boolean last_run,
562 563 564 565 566 567 568 569 570 571 572
			int    debug_level)
	{
		boolean [] rslt = {false,false};
		this.last_rms = null; // remove?
		int iter = 0;
		for (iter = 0; iter < num_iter; iter++) {
			rslt =  lmaStep(
					lambda,
					rms_diff,
					debug_level);
			if (rslt == null) {
573
				return -1; // false; // need to check
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
			}
			if (debug_level > 1) {
				System.out.println("LMA step "+iter+": {"+rslt[0]+","+rslt[1]+"} full RMS= "+good_or_bad_rms[0]+
						" ("+initial_rms[0]+"), pure RMS="+good_or_bad_rms[1]+" ("+initial_rms[1]+") + lambda="+lambda);
			}
			if (rslt[1]) {
				break;
			}
			if (rslt[0]) { // good
				lambda *= lambda_scale_good;
			} else {
				lambda *= lambda_scale_bad;
				if (lambda > lambda_max) {
					break; // not used in lwir
				}
			}
590 591 592 593
			if (dbg_prefix != null) {
				showDebugImage(dbg_prefix+"-"+iter+(rslt[0]?"-GOOD":"-BAD"));
			}

594 595 596
		}
		if (rslt[0]) { // better
			if (iter >= num_iter) { // better, but num tries exceeded
597
				if (debug_level > 1) System.out.println("Step "+iter+": Improved, but number of steps exceeded maximal");
598
			} else {
599
				if (debug_level > 1) System.out.println("Step "+iter+": LMA: Success");
600 601 602
			}

		} else { // improved over initial ?
Andrey Filippov's avatar
Andrey Filippov committed
603
			if (last_rms[0] < initial_rms[0]) { // NaN
604
				rslt[0] = true;
605
				if (debug_level > 1) System.out.println("Step "+iter+": Failed to converge, but result improved over initial");
606
			} else {
607
				if (debug_level > 1) System.out.println("Step "+iter+": Failed to converge");
608 609
			}
		}
610 611 612
		if (dbg_prefix != null) {
			showDebugImage(dbg_prefix+"-FINAL");
		}
613 614
		boolean show_intermediate = true;
		if (show_intermediate && (debug_level > 0)) {
615 616
			System.out.println("LMA: full RMS="+last_rms[0]+" ("+initial_rms[0]+"), pure RMS="+last_rms[1]+" ("+initial_rms[1]+") + lambda="+lambda);
		}
617 618 619 620 621 622
		if (debug_level > 2){ 
			String [] lines1 = printOldNew(false); // boolean allvectors)
			System.out.println("iteration="+iter);
			for (String line : lines1) {
				System.out.println(line);
			}
623
		}
624
		if (debug_level > 0) {
625
			if ((debug_level > 1) ||  last_run) { // (iter == 1) || last_run) {
626
				if (!show_intermediate) {
627
					System.out.println("LMA: iter="+iter+",   full RMS="+last_rms[0]+" ("+initial_rms[0]+"), pure RMS="+last_rms[1]+" ("+initial_rms[1]+") + lambda="+lambda);
628
				}
629 630 631 632 633 634
				String [] lines = printOldNew(false); // boolean allvectors)
				for (String line : lines) {
					System.out.println(line);
				}
			}
		}
Andrey Filippov's avatar
Andrey Filippov committed
635 636 637 638 639 640 641 642 643 644
		if ((debug_level > -2) && !rslt[0]) { // failed
			if ((debug_level > 1) || (iter == 1) || last_run) {
				System.out.println("LMA failed on iteration = "+iter);
				String [] lines = printOldNew(true); // boolean allvectors)
				for (String line : lines) {
					System.out.println(line);
				}
			}
			System.out.println();
		}
645 646

		return rslt[0]? iter : -1;
647 648 649 650 651 652 653 654 655 656
	}
	
	private boolean [] lmaStep(
			double lambda,
			double rms_diff,
			int debug_level) {
		boolean [] rslt = {false,false};
		// maybe the following if() branch is not needed - already done in prepareLMA !
		if (this.last_rms == null) { //first time, need to calculate all (vector is valid)
			last_rms = new double[2];
657 658 659
			if (debug_level > 1) {
				System.out.println("lmaStep(): first step");
			}
660 661 662 663 664 665 666 667 668 669 670
			double [] fx = getFxDerivs(
					parameters_vector, // double []         vector,
					last_jt,           // final double [][] jt, // should be null or initialized with [vector.length][]
					scenesCLT[1],      // final QuadCLT     scene_QuadClt,
					scenesCLT[0],      // final QuadCLT     reference_QuadClt,
					debug_level);      // final int         debug_level)
			last_ymfx = getYminusFxWeighted(
					fx, // final double []   fx,
					last_rms); // final double []   rms_fp // null or [2]
			this.initial_rms = this.last_rms.clone();
			this.good_or_bad_rms = this.last_rms.clone();
Andrey Filippov's avatar
Andrey Filippov committed
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
			if (dbg_prefix != null) { // -1) { // temporary
				String      dbg_title= scenesCLT[0].getImageName()+"-"+scenesCLT[1].getImageName()+"-FxDerivs";
				int         dbg_num_rows = 3;
				boolean     dbg_show_reg = true;
				boolean     dbg_show =     true;
				showFxDerivs(
						fx,           // double []   fX,
						last_jt,      // double [][] jt,
						0,            // int         num_rows, // <=0 - stack 3?
						dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
						dbg_show,     // boolean     show,
						dbg_title);   // String      title);
				showFxDerivs(
						fx,           // double []   fX,
						last_jt,      // double [][] jt,
						dbg_num_rows, // int         num_rows, // <=0 - stack 3?
						dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
						dbg_show, // boolean     show,
						dbg_title); // String      title);
				
				double      debug_delta = 1e-4;
				boolean     show_img = true;
/*				debugDerivs(
						parameters_vector, // double []         vector,
						scenesCLT[1],      // final QuadCLT     scene_QuadClt,
						scenesCLT[0],      // final QuadCLT     reference_QuadClt,
						debug_delta,       // final double      delta,
						show_img,          // final boolean     show_img,
						debug_level);      // final int         debugLevel) */
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
				/*
				dbgYminusFxWeight(
						this.last_ymfx,
						this.weights,
						"Initial_y-fX_after_moving_objects");
                */
			}
			if (last_ymfx == null) {
				return null; // need to re-init/restart LMA
			}
			// TODO: Restore/implement
			if (debug_level > 3) {
				/*
				 dbgJacobians(
							corr_vector, // GeometryCorrection.CorrVector corr_vector,
							1E-5, // double delta,
							true); //boolean graphic)
				*/
			}
719 720 721
			if (dbg_prefix != null) {
				showDebugImage(dbg_prefix+"-INIT");
			}
722 723 724 725 726 727
		}
		Matrix y_minus_fx_weighted = new Matrix(this.last_ymfx, this.last_ymfx.length);

		Matrix wjtjlambda = new Matrix(getWJtJlambda(
				lambda, // *10, // temporary
				this.last_jt)); // double [][] jt)
728
		
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
		if (debug_level>2) {
			System.out.println("JtJ + lambda*diag(JtJ");
			wjtjlambda.print(18, 6);
		}
		Matrix jtjl_inv = null;
		try {
			jtjl_inv = wjtjlambda.inverse(); // check for errors
		} catch (RuntimeException e) {
			rslt[1] = true;
			if (debug_level > 0) {
				System.out.println("Singular Matrix!");
			}

			return rslt;
		}
		if (debug_level>2) {
			System.out.println("(JtJ + lambda*diag(JtJ).inv()");
			jtjl_inv.print(18, 6);
		}
//last_jt has NaNs
		Matrix jty = (new Matrix(this.last_jt)).times(y_minus_fx_weighted);
		if (debug_level>2) {
			System.out.println("Jt * (y-fx)");
			jty.print(18, 6);
		}
754 755
		
		
756 757 758
		Matrix mdelta = jtjl_inv.times(jty);
		if (debug_level>2) {
			System.out.println("mdelta");
759
			mdelta.print(18, 10);
760 761 762 763 764 765 766 767
		}

		double scale = 1.0;
		double []  delta =      mdelta.getColumnPackedCopy();
		double []  new_vector = parameters_vector.clone();
		for (int i = 0; i < parameters_vector.length; i++) {
			new_vector[i] += scale * delta[i];
		}
768
		
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
		double [] fx = getFxDerivs(
				new_vector, // double []         vector,
				last_jt,           // final double [][] jt, // should be null or initialized with [vector.length][]
				scenesCLT[1],      // final QuadCLT     scene_QuadClt,
				scenesCLT[0],      // final QuadCLT     reference_QuadClt,
				debug_level);      // final int         debug_level)
		double [] rms = new double[2];
		last_ymfx = getYminusFxWeighted(
//				vector_XYS, // final double [][] vector_XYS,
				fx, // final double []   fx,
				rms); // final double []   rms_fp // null or [2]
		if (debug_level > 2) {
			/*
			dbgYminusFx(this.last_ymfx, "next y-fX");
			dbgXY(new_vector, "XY-correction");
			*/
		}

		if (last_ymfx == null) {
			return null; // need to re-init/restart LMA
		}

		this.good_or_bad_rms = rms.clone();
		if (rms[0] < this.last_rms[0]) { // improved
			rslt[0] = true;
			rslt[1] = rms[0] >=(this.last_rms[0] * (1.0 - rms_diff));
			this.last_rms = rms.clone();

			this.parameters_vector = new_vector.clone();
			if (debug_level > 2) {
				// print vectors in some format
				/*
				System.out.print("delta: "+corr_delta.toString()+"\n");
				System.out.print("New vector: "+new_vector.toString()+"\n");
				System.out.println();
				*/
			}
		} else { // worsened
			rslt[0] = false;
			rslt[1] = false; // do not know, caller will decide
			// restore state
			fx = getFxDerivs(
					parameters_vector, // double []         vector,
					last_jt,           // final double [][] jt, // should be null or initialized with [vector.length][]
					scenesCLT[1],      // final QuadCLT     scene_QuadClt,
					scenesCLT[0],      // final QuadCLT     reference_QuadClt,
					debug_level);      // final int         debug_level)
			last_ymfx = getYminusFxWeighted(
					fx, // final double []   fx,
					this.last_rms); // final double []   rms_fp // null or [2]
			if (last_ymfx == null) {
				return null; // need to re-init/restart LMA
			}
			if (debug_level > 2) {
				/*
				 dbgJacobians(
							corr_vector, // GeometryCorrection.CorrVector corr_vector,
							1E-5, // double delta,
							true); //boolean graphic)
							*/
			}
		}
		return rslt;
	}
	
834 835 836 837
	private static double [][][] setEigenTransform(
			final double   eig_max_sqrt,
			final double   eig_min_sqrt,
			final double [][] eigen){ // [tilesX*tilesY]{lamb0_x,lamb0_y, lamb0, lamb1} eigenvector0[x,y],lam0,lam1
838 839 840
		if (eigen == null) {
			return null;
		}
841
		final double [][][] transform = new double[eigen.length][][];
842 843 844 845 846 847 848 849 850
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
		final AtomicInteger ai = new AtomicInteger(0);
		final double k0 = 1.0/eig_max_sqrt;
		
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int iTile = ai.getAndIncrement(); iTile < eigen.length; iTile = ai.getAndIncrement()) if (eigen[iTile] != null){
						double [][] am = {{eigen[iTile][0],eigen[iTile][1]},{eigen[iTile][1],-eigen[iTile][0]}};
851 852 853 854 855 856 857 858
						if (!Double.isNaN(am[0][0]) && !Double.isNaN(am[0][1])) {
							transform[iTile] = new double [2][2];
							for (int i = 0; i < 2; i++) {
								double k = Math.max(0, 1/Math.max(eig_min_sqrt, Math.sqrt(eigen[iTile][2+i]))-k0);
								for (int j = 0; j < 2; j++) {
									transform[iTile][i][j] = k* am[i][j];  
								}		
							}
859 860 861 862 863 864 865 866
						}
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		return transform;
	}
867 868
	
	private void setSamplesWeights(
Andrey Filippov's avatar
Andrey Filippov committed
869 870
			final double [][] vector_XYSDS,  // not regularized yet
			final boolean same_weights) // same weight if > 0
871
	{
872
		//num_components 2 - old, 3 - with disparity
873 874
		this.weights = new double [num_samples + parameters_vector.length];
		
875
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
876
		final AtomicInteger ai = new AtomicInteger(0);
877
		final AtomicInteger ati = new AtomicInteger(0);
Andrey Filippov's avatar
Andrey Filippov committed
878
		final AtomicInteger anum_defined = new AtomicInteger(0);
879
		final double [] sw_arr = new double [threads.length];
880
		double sum_weights;
881 882 883 884 885 886 887
		final int num_types = (num_components > 2) ? 2 : 1;
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					int thread_num = ati.getAndIncrement();
					for (int iMTile = ai.getAndIncrement(); iMTile < vector_XYSDS.length; iMTile = ai.getAndIncrement()) if (vector_XYSDS[iMTile] != null){
						double w = vector_XYSDS[iMTile][2];
888 889 890 891
						if ((eig_trans != null) && (eig_trans[iMTile] == null)) {
							w = 0;
							continue;
						}
892 893
						if (Double.isNaN(w)) {
							w = 0;
894
							continue;
895
						}
Andrey Filippov's avatar
Andrey Filippov committed
896
						if (w > 0) {
Andrey Filippov's avatar
Andrey Filippov committed
897 898 899
							if (same_weights) {
								w = 1.0;
							}
Andrey Filippov's avatar
Andrey Filippov committed
900 901 902 903 904 905 906 907 908 909 910 911
							anum_defined.getAndIncrement();
							weights[num_components  * iMTile] = w;
							sw_arr[thread_num] += 2*w;
							//disparity_weight
							if (num_types > 1) {
								w = vector_XYSDS[iMTile][4] * disparity_weight;
								if (Double.isNaN(w) || Double.isNaN(vector_XYSDS[iMTile][3])) {
									w = 0;
									vector_XYSDS[iMTile][3] = 0.0; // disparity
								}
								weights[num_components * iMTile + 2] = w;
								sw_arr[thread_num] += w;
912
							}
913 914
						}
					}
915 916 917 918 919 920 921
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		sum_weights = 0.0;
		for (double w:sw_arr) {
			sum_weights += w;
922
		}
Andrey Filippov's avatar
Andrey Filippov committed
923 924 925
		num_defined = anum_defined.get();
		this.sum_weights = sum_weights;
		
926 927 928
		if (sum_weights <= 1E-8) {
			System.out.println("!!!!!! setSamplesWeights(): sum_weights=="+sum_weights+" <= 1E-8");
		}
929
		ai.set(0);
930
		final double s = 1.0/sum_weights; // Was 0.5 - already taken care of
931 932 933
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
934 935 936
					for (int iMTile = ai.getAndIncrement(); iMTile < vector_XYSDS.length; iMTile = ai.getAndIncrement()) if (vector_XYSDS[iMTile] != null){
						weights[num_components * iMTile] *= s;
						weights[num_components * iMTile + 1] = weights[num_components * iMTile];
937
						if (num_components > 2) {
938
							weights[num_components * iMTile + 2] *= s;
939
						}
940 941 942 943 944 945 946 947
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		pure_weight = 1.0;
	}

948 949
	private void normalizeWeights()
	{
950
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
951 952 953 954 955 956 957 958 959 960 961 962
		final AtomicInteger ai =    new AtomicInteger(0);
		final AtomicInteger ati =    new AtomicInteger(0);
		final double [] sum_weight = new double [threads.length];
		ati.set(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					int thread_num = ati.getAndIncrement();
					for (int i = ai.getAndIncrement(); i < num_samples; i = ai.getAndIncrement()){
						if (Double.isNaN(weights[i])) {
							System.out.println("normalizeWeights(): weights["+i+"== NaN: 2");
							weights[i] = 0;
963
						}
964
						sum_weight[thread_num] += weights[i];
965
					}
966
				}
967 968 969 970 971 972 973 974 975 976 977
			};
		}		      
		ImageDtt.startAndJoin(threads);
		double sum_weight_pure = 0;
		for (double sw:sum_weight)	sum_weight_pure += sw;
		double full_weight = sum_weight_pure;
		for (int i = 0; i < par_indices.length; i++) {
			int indx =  num_samples + i;
			if (Double.isNaN(weights[indx])) {
				System.out.println("normalizeWeights(): weights["+indx+"] == NaN: 1.5, i="+i);
				weights[indx] = 0;
978
			}
979
			full_weight += weights[indx];
980 981 982 983
		}
		pure_weight = sum_weight_pure/full_weight;
		final double s = 1.0/full_weight;
		if (Double.isNaN(s)) {
984
			System.out.println("normalizeWeights(): s == NaN  : 2");
985 986 987 988 989 990 991 992 993 994 995 996 997
		}
		ai.set(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int i = ai.getAndIncrement(); i < weights.length; i = ai.getAndIncrement()){
						weights[i] *= s;
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
	}
998 999
	
	
1000 1001 1002 1003 1004
	/**
	 * Combine unmodified parameters with these ones, using parameters mask
	 * @param vector variable-length adjustable vector, corresponding to a parameter mask
	 * @return full parameters vector combining adjusted and fixed parameters
	 */
1005
	private double [] getFullVector(double [] vector) {
1006
		double [] full_vector = parameters_full.clone();
1007 1008 1009 1010 1011 1012
		for (int i = 0; i < par_indices.length; i++) {
			full_vector[par_indices[i]] = vector[i];
		}
		return full_vector;
	}
	
1013
	
Andrey Filippov's avatar
Andrey Filippov committed
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
	// if eig_trans != null, transform derivatives, keep Fx
	
	public ImagePlus showFxDerivs(
			double []   fX,
			double [][] jt,
			int         num_rows, // <=0 - stack
			boolean     show_reg,  // extra row for regularization parameters
			boolean     show,
			String      title) {
		int gap =    1;
		double [][][] scales = {
				{{320,320}, {256,256} ,{0,1}},	//y                      *
				{{320,320}, {256,256} ,{0,1}},	//fX                     *
				{{ 0, 2.5},  { 0, 2.5} , {0,1}},	//y-fX                   *
				{{0,   75},  { 0, 75},  {0,1}},  //hor *
				{{0,   75},  { 0, 75},  {0,1}},  //vert *
				{{ 0,100},  { 0,100},  {0,1}},  //"pX",      // (pix)     0
				{{ 0,100},  { 0,100},  {0,1}},  //"pY",            // (pix)     1
				{{0,100},   { 0,100},  {0,1}},  //"disp",          // (pix)     2
				{{0,100},   { 0,100},  {0,1}},  //"ers_vaz_ref",   // (rad/sec) 3
				{{0,100},   { 0,100},  {0,1}},  //"ers_vtl_ref",   // (rad/sec) 4
				{{0,100},   { 0,100},  {0,1}},	//"ers_vrl_ref",   // (rad/sec) 5
				{{0,100},   { 0,100},  {0,1}}, //"ers_dvx_ref",   // (m/s)     6
				{{0,100},   { 0,100},  {0,1}}, //"ers_dvy_ref",   // (m/s)     7
				{{0,100},   { 0,100},  {0,1}}, //"ers_dvz_ref",   // (m/s)     8
				{{-1120,20},{ 70,50},  {0,1}}, //"azimuth_ref",   // (rad)     9 *
				{{-70,  50},{-1120,20},{0,1}}, //"tilt_ref",      // (rad)    10 *
				{{0,500},   { 0,500},  {0,1}}, //"roll_ref",      // (rad)    11 *
				{{ 25,2.5}, {-1.5,0.5},{0,1}}, //"X_ref",         // (m)      12 *
				{{-1.5,0.5},{-25,2.5}, {0,1}}, //"Y_ref",         // (m)	  13 *
				{{ 0, 7.5}, { 0, 7.5}, {0,1}}, //"Z_ref",         // (m)      14 *
				{{0,100},   { 0,100},  {0,1}}, //"ers_vaz_scene", // (rad/sec)15
				{{0,100},   { 0,100},  {0,1}}, //"ers_vtl_scene", // (rad/sec)16
				{{0,100},   { 0,100},  {0,1}}, //"ers_vrl_scene", // (rad/sec)17
				{{0,100},   { 0,100},  {0,1}}, //"ers_dvx_scene", // (m/s)    18
				{{0,100},   { 0,100},  {0,1}}, //"ers_dvy_scene", // (m/s)    19
				{{0,100},   { 0,100},  {0,1}}, //"ers_dvz_scene", // (m/s)    20
				{{1120,20}, { -70,50}, {0,1}}, //"azimuth_scene", // (rad)    21 *
				{{70,  50}, {1120,20}, {0,1}}, //"tilt_scene",   // (rad)    22 *
				{{0,500},   { 0,500},  {0,1}}, //"Roll_scene",    // (rad)    23 *
				{{-25, 2.5},{ 1.5,0.5},{0,1}}, //"X_scene",       // (m)      24 *
				{{ 1.5,0.5},{25, 2.5}, {0,1}}, //"Y_scene",       // (m)	  25 *
				{{ 0, 7.5}, { 0, 7.5},  {0,1}}  //"Z_scene"        // (m)      26 *
		};

		String [] titles_pre = {"y", "fx", "y-fx", "hor", "vert"};
		int num_pre = titles_pre.length;
		int length = num_samples/num_components;
		int width =  tilesX;
		int height0 = length/width;
		int height = height0 + (show_reg? 1 : 0);
		int num_pars0 =  jt.length;
		
		int num_pars1 =  jt.length+num_pre;
		double [][] jt_ext = new double [num_pars1][];
		jt_ext[0] = y_vector;
		jt_ext[1] = fX;
		jt_ext[2] = y_vector.clone();
		for (int i = 0; i < jt_ext[2].length; i++) {
			jt_ext[2][i] -= jt_ext[1][i];
		}
		double [][][] img_stack = new double [num_components][num_pars1][width*height];
		String [] titles = new String [num_pars1];
		for (int i = 0; i < num_pre; i++) {
			titles[i] = titles_pre[i];
		}
		
		for (int i = 0; i < par_indices.length; i++) {
			titles[i+num_pre] = ErsCorrection.DP_DERIV_NAMES[par_indices[i]];
			jt_ext[i+num_pre] = jt[i];
		}
		// combine rotate and translate 
		// See if both azimuth_scene and X_scene are present
		int [][] hor_vert_indices = {{-1,-1},{-1,-1}}; 
		for (int i = 0; i < par_indices.length; i++) {
			if (par_indices[i] ==ErsCorrection.DP_DSAZ) hor_vert_indices[0][0] = i;
			if (par_indices[i] ==ErsCorrection.DP_DSX)  hor_vert_indices[0][1] = i;
			if (par_indices[i] ==ErsCorrection.DP_DSTL) hor_vert_indices[1][0] = i;
			if (par_indices[i] ==ErsCorrection.DP_DSY)  hor_vert_indices[1][1] = i;
		}
		for (int vnh = 0; vnh < hor_vert_indices.length; vnh++) if (( hor_vert_indices[vnh][0] >=0 ) && (hor_vert_indices[vnh][1] >= 0)){
			double [] sw = new double[2],swd = new double[2];
			for (int n = 0; n < hor_vert_indices[vnh].length; n++) {
				for (int i = 0; i < length; i++) {
					int indx = num_components * i + vnh;
					double w = weights[indx];
					double d = jt[hor_vert_indices[vnh][n]][indx];
					sw [n]+=w;
					swd[n]+=w*d;
				}
				swd[n] /= sw[n];
			}
			double mult_second = swd[0] / swd[1];
			int jindex = 3 + vnh; 
			jt_ext[jindex] = new double [weights.length];
			for (int i = 0; i < weights.length; i++) {
				jt_ext[jindex][i] = jt[hor_vert_indices[vnh][0]][i] - mult_second * jt[hor_vert_indices[vnh][1]][i];
			}
		}
		String [] titles_top = new String [num_components];
		titles_top[0] = "pX";
		titles_top[1] = "pY";
		if (num_components > 2) {
			titles_top[2] = "Disp";
		}
		for (int np = 0; np < num_pars1; np++){
			for (int nc = 0; nc < num_components; nc++) {
				Arrays.fill(img_stack[nc][np], Double.NaN);
				if (jt_ext[np] != null) {
					for (int npix = 0; npix < length; npix++) {
						int sindx = nc+num_components*npix;
						if (weights[sindx] > 0) {
							if ((img_stack[nc]== null) || (img_stack[nc][np]== null) ||
									(jt_ext[np]== null)) {
								System.out.println("showFxDerivs(): Null pointer");

							}
							img_stack[nc][np][npix] = jt_ext[np][sindx]; // null pointer
						}
					}
					if (show_reg) {
						for (int i = 0; i < num_pars0; i++) {
							img_stack[nc][np][length+i] = jt_ext[np][num_samples+i]; 
						}
					}
				}
			}
		}
		if (num_rows <= 0) {
			ImagePlus imp_stack = ShowDoubleFloatArrays.showArraysHyperstack(
					img_stack,  // double[][][] pixels, 
					width,      // int          width, 
					title,      // "terrain_vegetation_render.tiff", // String       title, "time_derivs-rt"+diff_time_rt+"-rxy"+diff_time_rxy,
					titles,     // String []    titles, // all slices*frames titles or just slice titles or null
					titles_top, // String []    frame_titles, // frame titles or null
					show);      // boolean      show)
			return imp_stack;

		}
		// TODO: add translate+rotate combo and scale factors to see all tiles simultaneously (as static members?)
		int num_cols = (int) Math.ceil(1.0*num_pars1/num_rows); 
		int full_width =  num_cols * (width +  gap) - gap;
		int full_height = num_rows * (height + gap) - gap;
		double [][] tiled_stack = new double [num_components][full_width*full_height];
		for (int nc = 0; nc < tiled_stack.length; nc++) {
			Arrays.fill (tiled_stack[nc], Double.NaN);
		}
		for (int ntile = 0; ntile < num_pars1; ntile++) {
			int tile_row = ntile / num_cols; 
			int tile_col = ntile % num_cols;
			int tl_index = tile_row * (height + gap) * full_width + tile_col * (width + gap); 
			for (int nc = 0; nc < tiled_stack.length; nc++) {
				int scale_index = (ntile<num_pre)? ntile: (par_indices[ntile-num_pre] + num_pre);
				double offs = scales[scale_index][nc][0];
				double div =  scales[scale_index][nc][1];
				for (int nrow = 0; nrow < height; nrow++) {
					System.arraycopy(
							img_stack[nc][ntile],
							nrow * width,
							tiled_stack[nc],
							tl_index + nrow * full_width,
							width);
					if (nrow < height0) {
						for (int i = 0; i < width; i++) {
							int indx = tl_index + nrow * full_width + i;
							tiled_stack[nc][indx]= (tiled_stack[nc][indx]- offs)/div;
						}
					}
				}
			}			
		}
		ImagePlus imp_stack = ShowDoubleFloatArrays.makeArrays(
				tiled_stack, // double[][] pixels,
				full_width,  //int width,
				full_height, // int height,
				title+"_tiled",       // String title,
				titles_top); // String [] titles)
    	imp_stack.getProcessor().resetMinAndMax();
		if (show) {
			imp_stack.show();
		}
		return imp_stack;
	}
	
	public double [][] getFxDerivsDelta(
			double []         vector,
			final double[]    deltas, // same length as vector, or [1] - then use for all
			final QuadCLT     scene_QuadClt,
			final QuadCLT     reference_QuadClt,
			final int         debug_level) {
		int dbg_n = -2256; // 1698; // -2486;
		final boolean mb_mode = (weights == null); // mb_mode should have num_components==2 !
		final int weights_length = mb_mode ?  (2 * macrotile_centers.length) : weights.length; // OK to keep 2
		double [][] jt =  new double [vector.length][weights_length];
		for (int nv = 0; nv < vector.length; nv++) {
			double delta = (nv < deltas.length) ? deltas[nv] : deltas[deltas.length -1];
			if (nv == dbg_n) {
				System.out.println("getFxDerivsDelta(): nv="+nv);
			}
			double [] vpm = vector.clone();
			vpm[nv]+= 0.5*delta;
			double [] fx_p =  getFxDerivs(
					vpm,
					null,              // final double [][] jt, // should be null or initialized with [vector.length][]
					scene_QuadClt,     // final QuadCLT     scene_QuadClt,
					reference_QuadClt, // final QuadCLT     reference_QuadClt,
					debug_level);
			vpm[nv]-= delta;
			double [] fx_m =  getFxDerivs(
					vpm,
					null, // final double [][] jt, // should be null or initialized with [vector.length][]
					scene_QuadClt,     // final QuadCLT     scene_QuadClt,
					reference_QuadClt, // final QuadCLT     reference_QuadClt,
					debug_level);
			for (int i = 0; i <weights_length; i++) if ((weights==null) ||  (weights[i] > 0)) {
				jt[nv][i] = (fx_p[i]-fx_m[i])/delta;
			}
		}
		return jt;
	}
	
	public void debugDerivs(
			double []         vector,
			final QuadCLT     scene_QuadClt,
			final QuadCLT     reference_QuadClt,
			final double      delta,
			final boolean     show_img,
			final int         debugLevel) {
        double [] delta_scale ={
				1.0,  //"pX",            // (pix)     0
				1.0,  //"pY",            // (pix)     1
				1.0,  //"disp",          // (pix)     2
				1.0,  //"ers_vaz_ref",   // (rad/sec) 3
				1.0,  //"ers_vtl_ref",   // (rad/sec) 4
				1.0,  //"ers_vrl_ref",   // (rad/sec) 5
				1.0,  //"ers_dvx_ref",   // (m/s)     6
				1.0,  //"ers_dvy_ref",   // (m/s)     7
				1.0,  //"ers_dvz_ref",   // (m/s)     8
				1.0,  //"azimuth_ref",   // (rad)     9 *
				1.0,  //"tilt_ref",      // (rad)    10 *
				1.0,  //"roll_ref",      // (rad)    11 *
				1.0,  //"X_ref",         // (m)      12 *
				1.0,  //"Y_ref",         // (m)	  13 *
				1.0,  //"Z_ref",         // (m)      14 *
				1.0,  //"ers_vaz_scene", // (rad/sec)15
				1.0,  //"ers_vtl_scene", // (rad/sec)16
				1.0,  //"ers_vrl_scene", // (rad/sec)17
				1.0,  //"ers_dvx_scene", // (m/s)    18
				1.0,  //"ers_dvy_scene", // (m/s)    19
				1.0,  //"ers_dvz_scene", // (m/s)    20
				1.0,  //"azimuth_scene", // (rad)    21 *
				1.0,  //"tilt_scene",   // (rad)    22 *
				1.0,  //"Roll_scene",    // (rad)    23 *
				1.0,  //"X_scene",       // (m)      24 *
				1.0,  //"Y_scene",       // (m)	  25 *
				1.0   //"Z_scene"        // (m)      26 *
		};
//		int length = num_samples/num_components;
//		int width =  tilesX;
//		int height0 = length/width;
		double [] deltas = new double [vector.length];
		String [] par_names = new String[vector.length];
		for (int i = 0; i < deltas.length; i++) {
			deltas[i] = delta * delta_scale[par_indices[i]];
			par_names[i] =  ErsCorrection.DP_DERIV_NAMES[par_indices[i]];
		}
		String [] comp_names = {"dx", "dy","ddisp"};
		double [][] jt = new double [vector.length][];
		double [] fX = getFxDerivs(
				vector,            // final double []   vector,
				jt,                // final double [][] jt, // should be null or initialized with [vector.length][]
				scene_QuadClt,     // final QuadCLT     scene_QuadClt,
				reference_QuadClt, // final QuadCLT     reference_QuadClt,
				debugLevel);       // final int         debug_level)
		double  [][] jt_delta =  getFxDerivsDelta (
				vector,            // final double []   vector,
				deltas,            // final double[]    deltas, // same length as vector, or [1] - then use for all
				scene_QuadClt,     // final QuadCLT     scene_QuadClt,
				reference_QuadClt, // final QuadCLT     reference_QuadClt,
				debugLevel-10);    // final int         debug_level)
		double [][] jt_diff = new double [jt_delta.length][jt_delta[0].length];
		double max_err=0;
		double min_bad = 0.01;
		for (int n = 0; n < jt_diff.length; n++) {
			for (int w = 0; w < jt_diff[0].length; w++) if (weights[w] > 0){ // skip zero weights
				jt_diff[n][w] = jt[n][w] - jt_delta[n][w];
//				int [] ti = par_rindex[n];
				int ntile = w/num_components;
				int ncomp = w % num_components;
				if (Math.abs(jt_diff[n][w]) > max_err) {
					System.out.println("debugDerivs(): n="+n+" ("+par_names[n]+"), ntile = "+ntile +", comp="+comp_names[ncomp] +", diff="+jt_diff[n][w]+" jt="+jt[n][w]+" jt_delta="+jt_delta[n][w]);
				} else if (Math.abs(jt_diff[n][w]) > min_bad) {
					System.out.println("debugDerivs(): n="+n+" ("+par_names[n]+"), ntile = "+ntile +", comp="+comp_names[ncomp] +", diff="+jt_diff[n][w]+" jt="+jt[n][w]+" jt_delta="+jt_delta[n][w]);
				}
				max_err = Math.max(max_err, Math.abs(jt_diff[n][w]));
			}
		}
		System.out.println("delta = "+delta+", max_err = "+max_err);
		if (show_img) {
			String      dbg_title= scenesCLT[0].getImageName()+"-"+scenesCLT[1].getImageName();
			int         dbg_num_rows = 3;
			boolean     dbg_show_reg = true;
			boolean     dbg_show =     true;
			showFxDerivs(
					fX,           // double []   fX,
					jt,           // double [][] jt,
					0,            // int         num_rows, // <=0 - stack 3?
					dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
					dbg_show,     // boolean     show,
					dbg_title+"-jt");   // String      title);
			showFxDerivs(
					fX,           // double []   fX,
					jt,           // double [][] jt,
					dbg_num_rows, // int         num_rows, // <=0 - stack 3?
					dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
					dbg_show, // boolean     show,
					dbg_title+"-jt"); // String      title);
			
			showFxDerivs(
					fX,           // double []   fX,
					jt_delta,     // double [][] jt,
					0,            // int         num_rows, // <=0 - stack 3?
					dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
					dbg_show,     // boolean     show,
					dbg_title+"-jt_delta_"+delta);   // String      title);
			showFxDerivs(
					fX,           // double []   fX,
					jt_delta,     // double [][] jt,
					dbg_num_rows, // int         num_rows, // <=0 - stack 3?
					dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
					dbg_show, // boolean     show,
					dbg_title+"-jt_delta_"+delta); // String      title);
			
			showFxDerivs(
					fX,           // double []   fX,
					jt_diff,      // double [][] jt,
					0,            // int         num_rows, // <=0 - stack 3?
					dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
					dbg_show,     // boolean     show,
					dbg_title+"-jt_diff_"+delta);   // String      title);
			showFxDerivs(
					fX,           // double []   fX,
					jt_diff,      // double [][] jt,
					dbg_num_rows, // int         num_rows, // <=0 - stack 3?
					dbg_show_reg, // boolean     show_reg,  // extra row for regularization parameters
					dbg_show, // boolean     show,
					dbg_title+"-jt_diff_"+delta); // String      title);
		}
		return;
	}
	
1365
	
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
	private double [] getFxDerivs(
			double []         vector,
			final double [][] jt, // should be null or initialized with [vector.length][]
			final QuadCLT     scene_QuadClt,
			final QuadCLT     reference_QuadClt,
			final int         debug_level)
	{
		final double [] full_vector = getFullVector(vector);
		final ErsCorrection ers_ref =   reference_QuadClt.getErsCorrection();
		final ErsCorrection ers_scene = scene_QuadClt.getErsCorrection();
1376
		final double [] scene_xyz =     new double[3];
1377 1378 1379
		final double [] scene_atr  =    new double[3];
		final double [] reference_xyz = new double[3]; // will stay 0
		final double [] reference_atr = new double[3]; // will stay 0
1380 1381 1382
		final boolean mb_mode = (weights == null); // mb_mode should have num_components==2 !
		final int weights_length = mb_mode ?  (2 * macrotile_centers.length) : weights.length; // OK to keep 2
		final double [] fx =       mb_mode ? null : (new double [weights_length]); // weights.length]; : weights.length :
1383 1384
		if (jt != null) {
			for (int i = 0; i < jt.length; i++) {
1385
				jt[i] = new double [weights_length]; // weights.length];
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
			}
		}
		
		for (int i = 0; i <3; i++) {
			ers_ref.ers_watr_center_dt[i] =   full_vector[ErsCorrection.DP_DVAZ +  i];
			ers_ref.ers_wxyz_center_dt[i] =   full_vector[ErsCorrection.DP_DVX +   i];
			ers_scene.ers_watr_center_dt[i] = full_vector[ErsCorrection.DP_DSVAZ + i];
			ers_scene.ers_wxyz_center_dt[i] = full_vector[ErsCorrection.DP_DSVX +  i];
			reference_atr[i] = full_vector[ErsCorrection.DP_DAZ +  i];
			reference_xyz[i] = full_vector[ErsCorrection.DP_DX +  i];
			scene_atr[i] =     full_vector[ErsCorrection.DP_DSAZ +  i];
			scene_xyz[i] =     full_vector[ErsCorrection.DP_DSX +  i];
		}
1399 1400 1401 1402
		if (Double.isNaN(scene_xyz[0])) {
			System.out.println("getFxDerivs(): scene_xyz[0]=NaN");
			System.out.println();
		}
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
		ers_scene.setupERS();
		ers_ref.setupERS();
		final Matrix [] reference_matrices_inverse = ErsCorrection.getInterRotDeriveMatrices(
				reference_atr, // double [] atr);
				true);         // boolean invert));

		final Matrix [] scene_matrices_inverse = ErsCorrection.getInterRotDeriveMatrices(
				scene_atr, // double [] atr);
				true);         // boolean invert));

		final Matrix  scene_rot_matrix = ErsCorrection.getInterRotDeriveMatrices(
				scene_atr, // double [] atr);
				false)[0]; // boolean invert));
		
1417
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
1418 1419 1420 1421 1422
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int iMTile = ai.getAndIncrement(); iMTile < macrotile_centers.length; iMTile = ai.getAndIncrement()) {
1423
						if ((macrotile_centers[iMTile]!=null) && (mb_mode || (weights[2*iMTile] > 0.0))){  // was: weights[iMTile]?
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
							//infinity_disparity
							boolean is_infinity = macrotile_centers[iMTile][2] < infinity_disparity;
							double [][] deriv_params = ers_ref.getDPxSceneDParameters(
									ers_scene,                   // ErsCorrection    ers_scene,
									true,                        // boolean correctDistortions,
									is_infinity,                 // boolean is_infinity,
									macrotile_centers[iMTile],   // double [] pXpYD_reference,
									reference_xyz,               // double [] reference_xyz, // reference (this) camera center in world coordinates
									scene_xyz,                   // double [] scene_xyz,    // (other, ers_scene) camera center in world coordinates
									reference_matrices_inverse,  // Matrix [] reference_matrices_inverse,
									scene_matrices_inverse,      // Matrix [] scene_matrices_inverse,
									scene_rot_matrix,            // Matrix    scene_rot_matrix,        // single rotation (direct) matrix for the scene
									debug_level);                // int debug_level);
							if (deriv_params!= null) {
Andrey Filippov's avatar
Andrey Filippov committed
1438 1439
								boolean bad_tile = false;
								if (!bad_tile) {
1440
									if (!mb_mode) {
1441 1442 1443 1444 1445
										fx[num_components * iMTile + 0] = deriv_params[0][0]; // pX
										fx[num_components * iMTile + 1] = deriv_params[0][1]; // pY
										if (num_components > 2) {
											fx[num_components * iMTile + 2] = deriv_params[0][2]; // D
										}
1446
									}
Andrey Filippov's avatar
Andrey Filippov committed
1447 1448 1449
									if (jt != null) {
										for (int i = 0; i < par_indices.length; i++) {
											int indx = par_indices[i] + 1;
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
											if (eig_trans != null) {
												//********************************
												// apply eig_trans here:
												for (int j = 0; j < 2; j++) {
													jt[i][num_components * iMTile + j] =
															eig_trans[iMTile][j][0] * deriv_params[indx][0] +
															eig_trans[iMTile][j][1] * deriv_params[indx][1];	
												}
											} else {
												jt[i][num_components * iMTile + 0] = deriv_params[indx][0]; // pX
												jt[i][num_components * iMTile + 1] = deriv_params[indx][1]; // pY (disparity is not used)
											}
1462 1463 1464
											if (num_components > 2) {
												jt[i][num_components * iMTile + 2] = deriv_params[indx][2]; // pY (disparity is used)
											}
Andrey Filippov's avatar
Andrey Filippov committed
1465
										}
1466 1467 1468
										if (Double.isNaN(jt[0][num_components * iMTile + 0])) {
											System.out.println("getFxDerivs(): NaN, iMTile="+iMTile);
										}
1469 1470
									}
								}
1471
							} else if (mb_mode) {
1472 1473 1474 1475 1476
								if (jt != null) {
									for (int i = 0; i < par_indices.length; i++) {
										jt[i][2 * iMTile + 0] = Double.NaN; // pX
										jt[i][2 * iMTile + 1] = Double.NaN; // ; // pY (disparity is not used)
									}
1477
								}
1478 1479 1480 1481 1482 1483 1484
							}
						}
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
1485 1486 1487
		if (mb_mode) {
			return null;
		}
1488 1489
		// pull to the initial parameter values
		for (int i = 0; i < par_indices.length; i++) {
1490
			fx [i + num_samples] = vector[i]; // - parameters_initial[i]; // scale will be combined with weights
1491 1492 1493
			if (jt != null) { 
				jt[i][i + num_samples] = 1.0; // scale will be combined with weights
			}
1494 1495 1496 1497 1498 1499
		}
///		if (parameters_pull != null){
///			for (int i = 0; i < par_indices.length; i++) {
///				fx [i + num_samples] -= parameters_pull[i]; // - parameters_initial[i]; // scale will be combined with weights
///			}			
///		}
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
		return fx;
	}
	
	private double [][] getWJtJlambda( // USED in lwir
			final double      lambda,
			final double [][] jt)
	{
		final int num_pars = jt.length;
		final int num_pars2 = num_pars * num_pars;
		final int nup_points = jt[0].length;
		final double [][] wjtjl = new double [num_pars][num_pars];
1511
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int indx = ai.getAndIncrement(); indx < num_pars2; indx = ai.getAndIncrement()) {
						int i = indx / num_pars;
						int j = indx % num_pars;
						if (j >= i) {
							double d = 0.0;
							for (int k = 0; k < nup_points; k++) {
1522
								if (jt[i][k] != 0) {
1523
									d+=0; // ???
1524
								}
1525
								d += weights[k]*jt[i][k]*jt[j][k];
1526 1527 1528 1529
								if (Double.isNaN(d)) {
									System.out.println("getWJtJlambda(): NAN i="+i+", j="+j+", k="+k);
								}
								
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
							}
							wjtjl[i][j] = d;
							if (i == j) {
								wjtjl[i][j] += d * lambda;
							} else {
								wjtjl[j][i] = d;
							}
						}
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		return wjtjl;
	}
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
    	
	public void showDebugImage(	String dbg_title ) { // includes "_iteration_number" or "_final"
		if (s_vector == null) {
			return;
		}
		int tilesY =  s_vector.length / tilesX;
		String [] titles = {"dx","dy","dr", "str", "e0", "e1", "e"};
		double [][] dbg_img = new double [titles.length][tilesX*tilesY];
		for (int l = 0; l < dbg_img.length; l++) {
			Arrays.fill(dbg_img[l], Double.NaN);
		}
		double [] fx = getFxDerivs(
				parameters_vector, // double []         vector,
				null,              // final double [][] jt, // should be null or initialized with [vector.length][]
				scenesCLT[1],      // final QuadCLT     scene_QuadClt,
				scenesCLT[0],      // final QuadCLT     reference_QuadClt,
				-1);               // debug_level);      // final int         debug_level)
		double [] ymfxw_m = getYminusFxWeighted(
				fx,     // final double []   fx,
				null,   // final double []   rms_fp // null or [2]
				true);//final boolean     force_metric // when true, ignore transform with eig_trans and use linear dx, dy in pixels
        double [] ymfxw_e = null;
        if (eig_trans != null) {
        	ymfxw_e = getYminusFxWeighted(
    				fx,     // final double []   fx,
    				null,   // final double []   rms_fp // null or [2]
    				false);//final boolean     force_metric // when true, ignore transform with eig_trans and use linear dx, dy in pixels
        }
        for (int nTile = 0; nTile < s_vector.length; nTile++) {
        	int indx = num_components * nTile;
        	double w = weights[num_components * nTile];
        	if ((weights[indx] > 0) && (weights[indx+1] > 0)) {
        		for (int i = 0; i < 2; i++) {
        			ymfxw_m[indx + i] /= weights[indx + i];
        			if (ymfxw_e != null) {
            			ymfxw_e[indx + i] /= weights[indx + i];
        			}
        		}
        		double dx = ymfxw_m[indx + 0]; 
        		double dy = ymfxw_m[indx + 1]; 
        		dbg_img[0][nTile] = dx; 
        		dbg_img[1][nTile] = dy;
        		dbg_img[2][nTile] = Math.sqrt(dx*dx+dy*dy);
        		dbg_img[3][nTile] = s_vector[nTile];
    			if (ymfxw_e != null) {
            		double d0 = ymfxw_e[indx + 0]; 
            		double d1 = ymfxw_e[indx + 1]; 
            		dbg_img[4][nTile] = d0; 
            		dbg_img[5][nTile] = d1;
            		dbg_img[6][nTile] = Math.sqrt(d0*d0+d1*d1);
    			}        	
        	}
        }
		if (ymfxw_e == null) {
			dbg_img[4]=null;
			dbg_img[5]=null;
			dbg_img[6]=null;
		}
		ShowDoubleFloatArrays.showArrays( // out of boundary 15
				dbg_img,
				tilesX,
				tilesY,
				true,
				dbg_title,
				titles);
		
	}
	
1613
	
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
	public boolean isEigenNormalized() {
		return (eig_trans != null);
	}
	public double [] calcRMS (boolean metric) {
		double [] rms_fp = new double [2];
		double [] fx = getFxDerivs(
				parameters_vector, // double []         vector,
				null,              // final double [][] jt, // should be null or initialized with [vector.length][]
				scenesCLT[1],      // final QuadCLT     scene_QuadClt,
				scenesCLT[0],      // final QuadCLT     reference_QuadClt,
				-1);               // debug_level);      // final int         debug_level)
		last_ymfx = getYminusFxWeighted(
				fx,     // final double []   fx,
				rms_fp, // final double []   rms_fp // null or [2]
				metric);//final boolean     force_metric // when true, ignore transform with eig_trans and use linear dx, dy in pixels
		return rms_fp;
	}
	
	
	private double [] getYminusFxWeighted(
			final double []   fx,
			final double []   rms_fp) { // null or [2]
		return getYminusFxWeighted(
				fx,     // final double []   fx,
				rms_fp, // final double []   rms_fp, // null or [2]
				false); // final boolean     force_metric)			

	}

1643 1644
	private double [] getYminusFxWeighted(
			final double []   fx,
1645 1646
			final double []   rms_fp, // null or [2]
			final boolean     force_metric // when true, ignore transform with eig_trans and use linear dx, dy in pixels			
1647
			) {
1648
		double [] ymfxw;
1649
		if (thread_invariant) {
1650
			 ymfxw =  getYminusFxWeightedInvariant(fx,rms_fp, force_metric); // null or [2]
1651
		} else {
1652
			 ymfxw = getYminusFxWeightedFast      (fx,rms_fp, force_metric); // null or [2]
1653
		}
1654 1655 1656 1657 1658 1659
		return ymfxw; 
	}
	
	
	// TODO: modify these 2 methods to iterate through pairs, and transform pair if (eig_trans != null)
	
1660 1661
	private double [] getYminusFxWeightedInvariant(
			final double []   fx,
1662 1663
			final double []   rms_fp, // null or [2]
			final boolean     force_metric // when true, ignore transform with eig_trans and use linear dx, dy in pixels			
1664
			) {
1665
		final Thread[]      threads =     ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
1666 1667 1668
		final AtomicInteger ai =          new AtomicInteger(0);
		final double []     wymfw =       new double [fx.length];
		double s_rms; 
1669
		final double [] l2_arr = new double [num_samples]; 
1670
		if (!force_metric && (eig_trans != null)) {
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
					public void run() {
						for (int nTile = ai.getAndIncrement(); nTile < macrotile_centers.length; nTile = ai.getAndIncrement()) {
							int ix = num_components * nTile;
							if (weights[ix] > 0) {
								int iy = ix+1;
								double dx = y_vector[ix] - fx[ix];
								double dy = y_vector[iy] - fx[iy];
								double d0 = eig_trans[nTile][0][0] * dx + eig_trans[nTile][0][1] * dy;
								double d1 = eig_trans[nTile][1][0] * dx + eig_trans[nTile][1][1] * dy;
								double wd0 = d0 * weights[ix];
								double wd1 = d1 * weights[ix];
								if (Double.isNaN(wd0) || Double.isNaN(wd1)) {
									System.out.println("getYminusFxWeighted(): weights["+ix+"]="+weights[ix]+", wd0="+wd0+
											", y_vector[ix]="+y_vector[ix]+", fx[ix]="+fx[ix]);
									System.out.println("getYminusFxWeighted(): weights["+iy+"]="+weights[iy]+", wd1="+wd1+
											", y_vector[iy]="+y_vector[iy]+", fx[iy]="+fx[iy]);
								}
								l2_arr[ix] = d0 * wd0;
								wymfw[ix] = wd0;
								l2_arr[iy] = d1 * wd1;
								wymfw[iy] = wd1;
								for (int j = 2; j < num_components; j++) {
									int i = ix+j;
									double d = y_vector[i] - fx[i];
									double wd = d * weights[i];
									if (Double.isNaN(wd)) {
										System.out.println("getYminusFxWeighted(): weights["+i+"]="+weights[i]+", wd="+wd+
												", y_vector[i]="+y_vector[i]+", fx[i]="+fx[i]);
									}
									//double l2 = d * wd;
									l2_arr[i] = d * wd;
									wymfw[i] = wd;
								}
							}
1707
						}
1708
					}
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
				};
			}		      
			ImageDtt.startAndJoin(threads);
		} else {
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
					public void run() {
						for (int i = ai.getAndIncrement(); i < num_samples; i = ai.getAndIncrement()) if (weights[i] > 0) {
							double d = y_vector[i] - fx[i];
							double wd = d * weights[i];
							if (Double.isNaN(wd)) {
								System.out.println("getYminusFxWeighted(): weights["+i+"]="+weights[i]+", wd="+wd+
										", y_vector[i]="+y_vector[i]+", fx[i]="+fx[i]);
							}
							//double l2 = d * wd;
							l2_arr[i] = d * wd;
							wymfw[i] = wd;
						}
					}
				};
			}		      
			ImageDtt.startAndJoin(threads);
		} 
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
		s_rms = 0.0;
		for (double l2:l2_arr) {
			s_rms += l2;
		}
		double rms_pure = Math.sqrt(s_rms/pure_weight);
		for (int i = 0; i < par_indices.length; i++) {
			int indx = i + num_samples;
			double d = y_vector[indx] - fx[indx]; // fx[indx] == vector[i]
			double wd = d * weights[indx];
			s_rms += d * wd;
			wymfw[indx] =   wd;
		}
		double rms = Math.sqrt(s_rms); // assuming sum_weights == 1.0; /pure_weight); shey should be re-normalized after adding regularization
		if (rms_fp != null) {
			rms_fp[0] = rms;
			rms_fp[1] = rms_pure;
		}
		return wymfw;
	}

	
	
1754
	private double [] getYminusFxWeightedFast( // problems. at least with eigen?
1755
			final double []   fx,
1756 1757
			final double []   rms_fp, // null or [2]
			final boolean     force_metric // when true, ignore transform with eig_trans and use linear dx, dy in pixels			
1758 1759 1760 1761 1762 1763
			) {
		final Thread[]      threads =     ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
		final AtomicInteger ai =          new AtomicInteger(0);
		final double []     wymfw =       new double [fx.length];
		final AtomicInteger ati = new AtomicInteger(0);
		final double [] l2_arr = new double [threads.length];
1764
		if (!force_metric && (eig_trans != null)) {
1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
					public void run() {
						int thread_num = ati.getAndIncrement();
						for (int nTile = ai.getAndIncrement(); nTile < macrotile_centers.length; nTile = ai.getAndIncrement()) {
							int ix = num_components * nTile;
							if (weights[ix] > 0) {
								int iy = ix+1;
								double dx = y_vector[ix] - fx[ix];
								double dy = y_vector[iy] - fx[iy];
								double d0 = eig_trans[nTile][0][0] * dx + eig_trans[nTile][0][1] * dy;
								double d1 = eig_trans[nTile][1][0] * dx + eig_trans[nTile][1][1] * dy;
								double wd0 = d0 * weights[ix];
								double wd1 = d1 * weights[ix];
								if (Double.isNaN(wd0) || Double.isNaN(wd1)) {
									System.out.println("getYminusFxWeighted(): weights["+ix+"]="+weights[ix]+", wd0="+wd0+
											", y_vector[ix]="+y_vector[ix]+", fx[ix]="+fx[ix]);
									System.out.println("getYminusFxWeighted(): weights["+iy+"]="+weights[iy]+", wd1="+wd1+
											", y_vector[iy]="+y_vector[iy]+", fx[iy]="+fx[iy]);
								}
								l2_arr[thread_num] += d0 * wd0;
								wymfw[ix] = wd0;
								l2_arr[thread_num] += d1 * wd1;
								wymfw[iy] = wd1;
								for (int j = 2; j < num_components; j++) {
									int i = ix+j;
									double d = y_vector[i] - fx[i];
									double wd = d * weights[i];
									if (Double.isNaN(wd)) {
										System.out.println("getYminusFxWeighted(): weights["+i+"]="+weights[i]+", wd="+wd+
												", y_vector[i]="+y_vector[i]+", fx[i]="+fx[i]);
									}
									//double l2 = d * wd;
									l2_arr[thread_num] += d * wd;
									wymfw[i] = wd;
								}
							}
1802 1803
						}
					}
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
				};
			}		      
			ImageDtt.startAndJoin(threads);
		} else {
			for (int ithread = 0; ithread < threads.length; ithread++) {
				threads[ithread] = new Thread() {
					public void run() {
						int thread_num = ati.getAndIncrement();
						for (int i = ai.getAndIncrement(); i < num_samples; i = ai.getAndIncrement()) if (weights[i] > 0) {
							double d = y_vector[i] - fx[i];
							double wd = d * weights[i];
							if (Double.isNaN(wd)) {
								System.out.println("getYminusFxWeighted(): weights["+i+"]="+weights[i]+", wd="+wd+
										", y_vector[i]="+y_vector[i]+", fx[i]="+fx[i]);
							}
							l2_arr[thread_num] += d * wd;
							wymfw[i] = wd;
						}
					}
				};
			}		      
			ImageDtt.startAndJoin(threads);
		}
1827 1828 1829
		double s_rms = 0.0;
		for (double l2:l2_arr) {
			s_rms += l2;
1830
		}
1831 1832 1833 1834 1835 1836 1837 1838
		double rms_pure = Math.sqrt(s_rms/pure_weight);
		for (int i = 0; i < par_indices.length; i++) {
			int indx = i + num_samples;
			double d = y_vector[indx] - fx[indx]; // fx[indx] == vector[i]
			double wd = d * weights[indx];
			s_rms += d * wd;
			wymfw[indx] =   wd;
		}
1839
		double rms = Math.sqrt(s_rms); // assuming sum_weights == 1.0; /pure_weight); they should be re-normalized after adding regularization
1840 1841 1842 1843 1844 1845 1846
		if (rms_fp != null) {
			rms_fp[0] = rms;
			rms_fp[1] = rms_pure;
		}
		return wymfw;
	}
	
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
	public static String getChecksum(Serializable object) throws IOException, NoSuchAlgorithmException {
	    ByteArrayOutputStream baos = null;
	    ObjectOutputStream oos = null;
	    try {
	        baos = new ByteArrayOutputStream();
	        oos = new ObjectOutputStream(baos);
	        oos.writeObject(object);
	        MessageDigest md = MessageDigest.getInstance("MD5");
	        byte[] thedigest = md.digest(baos.toByteArray());
	        return DatatypeConverter.printHexBinary(thedigest);
	    } finally {
	        oos.close();
	        baos.close();
	    }
	}
1862
}