Commit 6f3b31c5 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

matching tilts with affines

parent 83ce74fe
Loading
Loading
Loading
Loading
+74 −7
Original line number Original line Diff line number Diff line
@@ -54,10 +54,13 @@ public class ERSTiltLMA {
	private double []         last_ymfx =       null;
	private double []         last_ymfx =       null;
	private double [][]       last_jt =         null;
	private double [][]       last_jt =         null;
	
	
	public  double [][][]     aff_pairs_nosr =  null;
	public  double [][][]     aff_pairs_inosr = null; // inverted pairs affines w/o scale and rotation
	public  double [][][][]   aff_tilts =       null;
	public  double [][][][]   aff_tilts =       null;
	public  boolean           invert_q2a =      false;
	public  boolean           invert_q2a =      false;
	// debug
	// debug
	public  double [][][]     aff_pairs =       null; // pairwise image-based affines
	public  double [][]       diff_tilts =      null; // pairwise differential tilts
	
	public boolean            last3only =       false;  // true; // debug feature
	public boolean            last3only =       false;  // true; // debug feature
	public double             scale_pairs =     1e3; // 1e4; // increase fX and derivatives for pairs
	public double             scale_pairs =     1e3; // 1e4; // increase fX and derivatives for pairs
	public double             delta=            1e-7;
	public double             delta=            1e-7;
@@ -99,7 +102,16 @@ public class ERSTiltLMA {
		return svd;
		return svd;
	}
	}
	
	
	public void printResults(boolean degrees) {
	/**
	 * Get differential tilts between the second and the first scenes in each pair
	 * @return [pair]{tiltX,tiltY}
	 */
	public double [][] getDiffTilts(){
		return diff_tilts;
	}
	
	
	public void printSceneResults(boolean degrees, boolean percents) {
		double [][] pseudo_xy = getPseudoXY();
		double [][] pseudo_xy = getPseudoXY();
		double [][][] ers_affines = getERSAffines();
		double [][][] ers_affines = getERSAffines();
		SingularValueDecomposition [] svd = getSVD();
		SingularValueDecomposition [] svd = getSVD();
@@ -116,8 +128,59 @@ public class ERSTiltLMA {
		}
		}
		return;
		return;
	}
	}
	public void printPairsResults(boolean degrees, boolean percents) {
		double sd = degrees? 180/Math.PI : 1.0;
		double sp = percents? 100 : 1;
		String svd_title = SingularValueDecomposition.titleString(degrees);
		double [] fx = getFxDerivs(
				parameters_vector, // double []         vector,
				null,              // final double [][] jt, // should be null or initialized with [vector.length][]
				0);                // final int         debug_level)
		
		String tab_title_rad =      String.format(
				"%4s\t%4s\t%4s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%s",
				"#","scn0","scn1","tiltX","tiltY","tilt","tilt-dir","elevation","pair_\u0394w","residual",svd_title);
		String tab_title_deg =      String.format(
				"%4s\t%4s\t%4s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%s",
				"#","scn0","scn1","tiltX","tiltY","tilt","tilt-dir\u00B0","elevation\u00B0","pair_\u0394w","residual",svd_title);
		String tab_title_rad_perc = String.format(
				"%4s\t%4s\t%4s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%s",
				"#","scn0","scn1","tiltX%","tiltY%","tilt%","tilt-dir","elevation","pair_\u0394w%","residual%",svd_title);
		String tab_title_deg_perc = String.format(
				"%4s\t%4s\t%4s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%11s\t%s",
				"#","scn0","scn1","tiltX%","tiltY%","tilt%","tilt-dir\u00B0","elevation\u00B0","pair_\u0394w%","residual%",svd_title);
		String title =degrees ? (percents?tab_title_deg_perc:tab_title_deg) : (percents?tab_title_rad_perc:tab_title_rad);
		
		String fmt_rad=     "%4d\t%4d\t%4d\t%11.8f\t%11.8f\t%11.8f\t%11.8f\t%11.8f\t%11.8f\t%11.8f\t%s";
		String fmt_deg=     "%4d\t%4d\t%4d\t%11.8f\t%11.8f\t%11.8f\t%11.6f\t%11.6f\t%11.8f\t%11.8f\t%s";
		String fmt_rad_perc="%4d\t%4d\t%4d\t%11.6f%%\t%11.6f%%\t%11.6f%%\t%11.8f\t%11.8f\t%11.6f%%\t%11.6f%%\t%s";
		String fmt_deg_perc="%4d\t%4d\t%4d\t%11.6f%%\t%11.6f%%\t%11.6f%%\t%11.6f\t%11.6f\t%11.6f%%\t%11.6f%%\t%s";
		String fmt =degrees ? (percents?fmt_deg_perc:fmt_deg) : (percents?fmt_rad_perc:fmt_rad);
		
		System.out.println(title);

		double [] fit_err = new double [num_pairs]; 
		for (int npair=0; npair < num_pairs; npair++) {
			int [] pscenes = {indices[cpairs[npair][0]], indices[cpairs[npair][1]]};
			double [] dtilt_xy = diff_tilts[npair];
			double dtilt = Math.sqrt(dtilt_xy[0]*dtilt_xy[0]+dtilt_xy[1]*dtilt_xy[1]);
			double tilt_dir = Math.atan2(dtilt_xy[1],dtilt_xy[0]);
			double tilt_ang = Math.atan(dtilt);
			double [][] aff_pair = aff_pairs[npair]; // image-based affine for a pair
			SingularValueDecomposition svd_aff_pair = SingularValueDecomposition.singularValueDecompose(aff_pair);
			// just to see - which is zeroed - beta or gamma? gamma changes, beta stays
			String ssvd = svd_aff_pair.toString(degrees, 1);
			double pair_dw = svd_aff_pair.getDW();
			fit_err[npair] = fx[npair] / scale_pairs; // dW -> %
			System.out.println(String.format(fmt,
					npair, pscenes[0], pscenes[1], sp*dtilt_xy[0], sp*dtilt_xy[1], sp*dtilt, sd*tilt_dir, sd*tilt_ang,
					sp*pair_dw, sp*fit_err[npair], ssvd));
			
			


		}
		return;
	
	}	
	
	
	/*
	/*
	 * Starting with tilts0 and tilt1 = tilt0+tilt_diff (differential
	 * Starting with tilts0 and tilt1 = tilt0+tilt_diff (differential
@@ -155,9 +218,13 @@ public class ERSTiltLMA {
		this.cpairs = cpairs;
		this.cpairs = cpairs;
		num_scenes = indices.length;
		num_scenes = indices.length;
		num_pairs = cpairs.length;
		num_pairs = cpairs.length;
		aff_pairs_nosr = new double [num_pairs][][];
		aff_pairs = new double [num_pairs][][]; // preserving for stats, not used in processing
		diff_tilts= new double [num_pairs][];
		aff_pairs_inosr = new double [num_pairs][][];
		aff_tilts =      new double  [num_pairs][2][][];
		aff_tilts =      new double  [num_pairs][2][][];
		for (int npair = 0; npair < num_pairs; npair++) {
		for (int npair = 0; npair < num_pairs; npair++) {
			aff_pairs[npair] =  affine_pairs[npair]; // preserving for stats
			diff_tilts[npair] = new double [] {tilts[npair][1][0]-tilts[npair][0][0],tilts[npair][1][1]-tilts[npair][0][1]};
			double [][] affine_pair_nors = SingularValueDecomposition.removeTiltRotScale(
			double [][] affine_pair_nors = SingularValueDecomposition.removeTiltRotScale(
					affine_pairs[npair], // double [][] A,
					affine_pairs[npair], // double [][] A,
	    			false,               // boolean removeTilt,
	    			false,               // boolean removeTilt,
@@ -165,7 +232,7 @@ public class ERSTiltLMA {
	    			true,                // boolean removeScale,
	    			true,                // boolean removeScale,
	    			false,               // boolean removeOffset,
	    			false,               // boolean removeOffset,
	    			false);              // boolean max_is_scale);
	    			false);              // boolean max_is_scale);
			aff_pairs_nosr[npair] = QuatUtils.matInverse2x2(affine_pair_nors); // maybe reverse order and do not use inversion?
			aff_pairs_inosr[npair] = QuatUtils.matInverse2x2(affine_pair_nors); // maybe reverse order and do not use inversion?
			for (int i = 0; i < 2; i++) {
			for (int i = 0; i < 2; i++) {
				aff_tilts[npair][i] = QuatUtils.tiltToAffine( // convert tilts to affines as they will not be modified later
				aff_tilts[npair][i] = QuatUtils.tiltToAffine( // convert tilts to affines as they will not be modified later
						tilts[npair][i]);        // double [] tilt,
						tilts[npair][i]);        // double [] tilt,
@@ -223,7 +290,7 @@ public class ERSTiltLMA {
						double [][][] aff_err = QuatUtils.pseudoAffineDiffAndDerivatives( //affineDiffAndDerivatives(
						double [][][] aff_err = QuatUtils.pseudoAffineDiffAndDerivatives( //affineDiffAndDerivatives(
								pseudo_xy,                   // double [][]   txy,   // [scene][direction]
								pseudo_xy,                   // double [][]   txy,   // [scene][direction]
								aff_tilts[npair],      // double [][][] a_tilts,
								aff_tilts[npair],      // double [][][] a_tilts,
								aff_pairs_nosr[npair], //  double [][]   iaff_pair, // affine pair inversed
								aff_pairs_inosr[npair], //  double [][]   iaff_pair, // affine pair inversed
								invert_q2a); // boolean       invert_q2a)  // invert result affines (to match "usual")
								invert_q2a); // boolean       invert_q2a)  // invert result affines (to match "usual")
						if (jt == null) {
						if (jt == null) {
							aff_err = new double [][][] {aff_err[0]}; //
							aff_err = new double [][][] {aff_err[0]}; //
@@ -248,7 +315,7 @@ public class ERSTiltLMA {
		for (int ithread = 0; ithread < threads.length; ithread++) {
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
			threads[ithread] = new Thread() {
				public void run() {
				public void run() {
					for (int nscene = ai.getAndIncrement(); nscene < num_pairs; nscene = ai.getAndIncrement()) {
					for (int nscene = ai.getAndIncrement(); nscene < num_scenes; nscene = ai.getAndIncrement()) {
						int pindx = num_pairs + 2*nscene;
						int pindx = num_pairs + 2*nscene;
						for (int j = 0; j < 2; j++) {
						for (int j = 0; j < 2; j++) {
							fX[pindx+j] =  vector[2*nscene + j];
							fX[pindx+j] =  vector[2*nscene + j];
+7 −2
Original line number Original line Diff line number Diff line
@@ -61,6 +61,8 @@ public class OrthoAltitudeMatch {
		boolean test_quat0 = false;
		boolean test_quat0 = false;
		boolean test_quat2=  false; // true;
		boolean test_quat2=  false; // true;
        boolean use_degrees = true;
        boolean use_degrees = true;
        boolean use_percents = true;
        
        boolean debug_tilts = true;
        boolean debug_tilts = true;
        
        
		boolean invert_order= false; // print them
		boolean invert_order= false; // print them
@@ -160,6 +162,7 @@ public class OrthoAltitudeMatch {
			int [] ipair = {indices[cpair[0]], indices[cpair[1]]};
			int [] ipair = {indices[cpair[0]], indices[cpair[1]]};
			if (updateStatus) {
			if (updateStatus) {
				IJ.showStatus("Processing pair "+npair+" of "+condensed_pairs.length+" "+ipair[0]+"->"+ipair[1]);
				IJ.showStatus("Processing pair "+npair+" of "+condensed_pairs.length+" "+ipair[0]+"->"+ipair[1]);
				IJ.showProgress(1.0*npair/condensed_pairs.length-1);
			}
			}
			PairwiseOrthoMatch pairwiseOrthoMatch = ortho_maps[ipair[0]].getMatch(ortho_maps[ipair[1]].getName(), true); // ?
			PairwiseOrthoMatch pairwiseOrthoMatch = ortho_maps[ipair[0]].getMatch(ortho_maps[ipair[1]].getName(), true); // ?
    		if (pairwiseOrthoMatch == null) {
    		if (pairwiseOrthoMatch == null) {
@@ -914,7 +917,9 @@ public class OrthoAltitudeMatch {
		System.out.println("LMA -> "+lma_rslt);
		System.out.println("LMA -> "+lma_rslt);
		if (lma_rslt >= 0) {
		if (lma_rslt >= 0) {
			if (debugLevel > -3) {
			if (debugLevel > -3) {
				ersTiltLMA.printResults(use_degrees);
				ersTiltLMA.printSceneResults(use_degrees, use_percents);
				
				ersTiltLMA.printPairsResults(use_degrees, use_percents);				
			}
			}
		}
		}
		System.out.println();
		System.out.println();
@@ -924,7 +929,7 @@ public class OrthoAltitudeMatch {
				QuatUtils.testPseudoAffineDiffAndDerivatives(
				QuatUtils.testPseudoAffineDiffAndDerivatives(
						pseudo_xy, // double [][]   xy,   // [scene][direction]
						pseudo_xy, // double [][]   xy,   // [scene][direction]
						ersTiltLMA.aff_tilts[npair], // double [][][] a_tilts,
						ersTiltLMA.aff_tilts[npair], // double [][][] a_tilts,
						ersTiltLMA.aff_pairs_nosr[npair], // double [][]   iaff_pair, // affine pair inversed
						ersTiltLMA.aff_pairs_inosr[npair], // double [][]   iaff_pair, // affine pair inversed
						invert_q2a); // boolean       invert_q2a){  // invert result affines (to match "usual")
						invert_q2a); // boolean       invert_q2a){  // invert result affines (to match "usual")
				System.out.println();
				System.out.println();
			}
			}
+42 −3
Original line number Original line Diff line number Diff line
@@ -6567,6 +6567,9 @@ public class OrthoMapsCollection implements Serializable{
		boolean flt_show_rms =       true;  // clt_parameters.imp.flt_show_rms;      //  true;
		boolean flt_show_rms =       true;  // clt_parameters.imp.flt_show_rms;      //  true;
		boolean flt_show_zoom =      true;  // clt_parameters.imp.flt_show_zoom;     //  true;
		boolean flt_show_zoom =      true;  // clt_parameters.imp.flt_show_zoom;     //  true;
		boolean flt_show_alt =       true;  // clt_parameters.imp.flt_show_alt;     //  true;
		boolean flt_show_alt =       true;  // clt_parameters.imp.flt_show_alt;     //  true;
		boolean flt_show_svd =       true;
		boolean flt_show_degrees =   true;
		


		boolean alt_overwrite =      clt_parameters.imp.alt_overwrite; // false; // overwrite existing altitude match pairs
		boolean alt_overwrite =      clt_parameters.imp.alt_overwrite; // false; // overwrite existing altitude match pairs
		boolean alt_pairwise =       clt_parameters.imp.alt_pairwise; // false; // overwrite existing altitude match pairs
		boolean alt_pairwise =       clt_parameters.imp.alt_pairwise; // false; // overwrite existing altitude match pairs
@@ -6671,7 +6674,10 @@ public class OrthoMapsCollection implements Serializable{
				flt_show_zoom,     // boolean          show_zoom,
				flt_show_zoom,     // boolean          show_zoom,
				flt_show_alt,      // boolean          show_alt,
				flt_show_alt,      // boolean          show_alt,
				use_tab,           // boolean          use_tab,
				use_tab,           // boolean          use_tab,
				null);             // String           extra_line)
				null,              // String           extra_line)
				flt_show_svd,      // boolean          show_svd,
				flt_show_degrees); // boolean          use_degrees);
			
		{
		{
			System.out.println("Selected\t"+available_pairs.length+"\tscene pairs for matching");
			System.out.println("Selected\t"+available_pairs.length+"\tscene pairs for matching");
			if (use_tab) {
			if (use_tab) {
@@ -6682,6 +6688,10 @@ public class OrthoMapsCollection implements Serializable{
				if (flt_show_zoom)     System.out.print(String.format("\t%4s", "Zoom"));
				if (flt_show_zoom)     System.out.print(String.format("\t%4s", "Zoom"));
				if (flt_show_alt)      System.out.print(String.format("\t%7s\t%7s\t%7s", "tiltX","tiltY","offs"));
				if (flt_show_alt)      System.out.print(String.format("\t%7s\t%7s\t%7s", "tiltX","tiltY","offs"));
				if (flt_show_sfm)      System.out.print(String.format("\t%5s\t%5s", "SfM0","SfM1"));
				if (flt_show_sfm)      System.out.print(String.format("\t%5s\t%5s", "SfM0","SfM1"));
				if (flt_show_svd) {
					String svd_title=SingularValueDecomposition.titleString(flt_show_degrees);
					System.out.print("\t"+ svd_title);
				}
				System.out.println();
				System.out.println();
			}
			}
			for (int i = 0; i < available_pairs.length; i++) {
			for (int i = 0; i < available_pairs.length; i++) {
@@ -7535,6 +7545,30 @@ public class OrthoMapsCollection implements Serializable{
			boolean          show_alt,
			boolean          show_alt,
			boolean          use_tab,
			boolean          use_tab,
			String           extra_line) {
			String           extra_line) {
		return 	textPairs (
				plist, // int [][] plist,
				show_names, // boolean          show_names,
				show_overlap, // boolean          show_overlap,
				show_rms, // boolean          show_rms,
				show_zoom, // boolean          show_zoom,
				show_alt, // boolean          show_alt,
				use_tab, // boolean          use_tab,
				extra_line, // String           extra_line,
				false, // boolean          show_svd,
				false); // boolean          use_degrees);

	}	
	public String [] textPairs (
			int [][] plist,
			boolean          show_names,
			boolean          show_overlap,
			boolean          show_rms,
			boolean          show_zoom,
			boolean          show_alt,
			boolean          use_tab,
			String           extra_line,
			boolean          show_svd,
			boolean          use_degrees) {
		boolean show_sfm = show_alt;
		boolean show_sfm = show_alt;


		// TODO: show SfM of each scene
		// TODO: show SfM of each scene
@@ -7563,6 +7597,11 @@ public class OrthoMapsCollection implements Serializable{
					}
					}
				}
				}
				if (show_sfm) text_pairs[i] +=  String.format(use_tab?"\t%5.1f\t%5.1f":" S %5.1f %5.1f", sfm_gain[0],sfm_gain[1]);
				if (show_sfm) text_pairs[i] +=  String.format(use_tab?"\t%5.1f\t%5.1f":" S %5.1f %5.1f", sfm_gain[0],sfm_gain[1]);
				if (show_svd && use_tab && (pairwiseOrthoMatch.getAffine()!=null)) { // now only for tab
					SingularValueDecomposition svd = SingularValueDecomposition.singularValueDecompose(pairwiseOrthoMatch.getAffine());
					String ssvd = svd.toString(use_degrees, 1);
					text_pairs[i] +=  "\t"+ssvd;
				}
			}
			}
		}
		}
		if (extra_line !=null) {
		if (extra_line !=null) {
+36 −13
Original line number Original line Diff line number Diff line
@@ -1466,13 +1466,36 @@ q11 - q22 = c3
			double [][][] a_tilts,
			double [][][] a_tilts,
			double [][]   iaff_pair, // affine pair inversed
			double [][]   iaff_pair, // affine pair inversed
			boolean       invert_q2a){  // invert result affines (to match "usual")
			boolean       invert_q2a){  // invert result affines (to match "usual")
		double        delta= 1e-6;
		double        delta= 1e-8;
		/*
		xy = new double [][] {
		xy = new double [][] {
			{xy[0][0]-0.1,xy[0][1]+0.1},
			{xy[1][0]+0.1,xy[1][1]+0.1}
		};

		a_tilts = new double[][][] {
			{
				{a_tilts[0][0][0],     a_tilts[0][0][1]-0.01},
				{a_tilts[0][1][0]-0.01,a_tilts[0][1][1]}
			},
			{
				{a_tilts[1][0][0],     a_tilts[1][0][1]-0.1},
				{a_tilts[1][1][0]-0.1, a_tilts[1][1][1]}
			}
		};

		iaff_pair = new double [][]  {
			{iaff_pair[0][0],    iaff_pair[0][1]+0.1},
			{iaff_pair[1][0]+0.1,iaff_pair[1][1]}
		};

		 */
		double [][] xy_m = new double [][] {
			{xy[0][0],xy[0][1]},
			{xy[0][0],xy[0][1]},
			{xy[1][0],xy[1][1]}
			{xy[1][0],xy[1][1]}
		};
		};


		a_tilts = new double[][][] {
		double [][][] a_tilts_m= new double[][][] {
			{
			{
				{a_tilts[0][0][0],a_tilts[0][0][1]},
				{a_tilts[0][0][0],a_tilts[0][0][1]},
				{a_tilts[0][1][0],a_tilts[0][1][1]}
				{a_tilts[0][1][0],a_tilts[0][1][1]}
@@ -1483,14 +1506,14 @@ q11 - q22 = c3
			}
			}
		};
		};


		iaff_pair = new double [][]  {
		double [][] iaff_pair_m = new double [][]  {
			{iaff_pair[0][0],iaff_pair[0][1]},
			{iaff_pair[0][0],iaff_pair[0][1]},
			{iaff_pair[1][0],iaff_pair[1][1]}
			{iaff_pair[1][0],iaff_pair[1][1]}
		};
		};
		testPseudoAffineDiffAndDerivatives(
		testPseudoAffineDiffAndDerivatives(
				xy,          // double [][]   xy,   // [scene][direction]
				xy_m,          // double [][]   xy,   // [scene][direction]
				a_tilts,     // double [][][] a_tilts,
				a_tilts_m,     // double [][][] a_tilts,
				iaff_pair,   // double [][]   iaff_pair, // affine pair inversed
				iaff_pair_m,   // double [][]   iaff_pair, // affine pair inversed
				invert_q2a,    // boolean       invert_q2a,  // invert result affines (to match "usual")
				invert_q2a,    // boolean       invert_q2a,  // invert result affines (to match "usual")
				delta);        // double        delta);
				delta);        // double        delta);
	}
	}
@@ -1544,11 +1567,11 @@ q11 - q22 = c3
			System.out.println(String.format("%5s\t%20s\t%20s\t%20s\t%20s",
			System.out.println(String.format("%5s\t%20s\t%20s\t%20s\t%20s",
					"mode#", "dx0", "dy0", "dx1", "dy1"));
					"mode#", "dx0", "dy0", "dx1", "dy1"));
			System.out.println(String.format("%5s\t%20.12f\t%20.12f\t%20.12f\t%20.12f",
			System.out.println(String.format("%5s\t%20.12f\t%20.12f\t%20.12f\t%20.12f",
					"deriv", s*dWdW[0], s*dWdW[1], s*dWdW[2], s*dWdW[3]));
					"deriv", s*dWdW[1], s*dWdW[2], s*dWdW[3], s*dWdW[4]));
			System.out.println(String.format("%5s\t%20.12f\t%20.12f\t%20.12f\t%20.12f",
			System.out.println(String.format("%5s\t%20.12f\t%20.12f\t%20.12f\t%20.12f",
					"delta", s*dWdW_delta[0], s*dWdW_delta[1],s*dWdW_delta[2],s*dWdW_delta[3]));
					"delta", s*dWdW_delta[1], s*dWdW_delta[2],s*dWdW_delta[3],s*dWdW_delta[4]));
			System.out.println(String.format("%5s\t%20.12f\t%20.12f\t%20.12f\t%20.12f",
			System.out.println(String.format("%5s\t%20.12f\t%20.12f\t%20.12f\t%20.12f",
					"diff", s*(dWdW_delta[0]-dWdW[0]), s*(dWdW_delta[1]-dWdW[1]), s*(dWdW_delta[2]-dWdW[2]), s*(dWdW_delta[3]-dWdW[3])));
					"diff", s*(dWdW_delta[1]-dWdW[1]), s*(dWdW_delta[2]-dWdW[2]), s*(dWdW_delta[3]-dWdW[3]), s*(dWdW_delta[4]-dWdW[4])));
			System.out.println ("Change xy[0][0] >= 1.0 to exit");
			System.out.println ("Change xy[0][0] >= 1.0 to exit");
			System.out.println ();
			System.out.println ();
		}
		}
+11 −5
Original line number Original line Diff line number Diff line
@@ -49,6 +49,11 @@ public class SingularValueDecomposition {
	public double getMinScale() {return Math.min(w1,w2);}
	public double getMinScale() {return Math.min(w1,w2);}
	public double getMaxScale() {return Math.max(w1,w2);}
	public double getMaxScale() {return Math.max(w1,w2);}
	
	
	// Measure of tilt - difference between singular values (they both are assumed to be ~= 1.0)
	public double getDW() {
		return Math.abs(w1-w2);
	}
	
	public static String titleString(boolean degrees) {
	public static String titleString(boolean degrees) {
		SingularValueDecomposition svd= new SingularValueDecomposition(0,0,0,0,0);
		SingularValueDecomposition svd= new SingularValueDecomposition(0,0,0,0,0);
		return svd.toString(degrees, 2);
		return svd.toString(degrees, 2);
@@ -67,20 +72,21 @@ public class SingularValueDecomposition {
//System.out.println("svd_affine_pair=    ["+svd_affine_pair.scale+  ","+svd_affine_pair.getTiltAngle()+ ","+svd_affine_pair.gamma+ ","+svd_affine_pair.rot+
//System.out.println("svd_affine_pair=    ["+svd_affine_pair.scale+  ","+svd_affine_pair.getTiltAngle()+ ","+svd_affine_pair.gamma+ ","+svd_affine_pair.rot+
// "] tilt="+(svd_affine_pair.getTiltAngle()*180/Math.PI)+ "\u00B0, dir="+(svd_affine_pair.gamma*180/Math.PI)+"\u00B0");
// "] tilt="+(svd_affine_pair.getTiltAngle()*180/Math.PI)+ "\u00B0, dir="+(svd_affine_pair.gamma*180/Math.PI)+"\u00B0");
		String tab_title_rad = String.format("%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s",
		String tab_title_rad = String.format("%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s",
				"scale","tilt","gamma","beta","rot", "w1", "w2", "ratio");
				"scale","tilt","gamma","beta","rot", "w1", "w2", "\u0394w"); // ratio");
		String tab_title_deg = String.format("%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s",
		String tab_title_deg = String.format("%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s",
				"scale","tilt\u00B0","gamma\u00B0","beta\u00B0","rot\u00B0", "w1", "w2", "ratio");
				"scale","tilt\u00B0","gamma\u00B0","beta\u00B0","rot\u00B0", "w1", "w2", "\u0394w"); // ratio");
		String tab_fmt_rad = "%10.8f\t%10.7f\t%10.7f\t%10.7f\t%10.7f\t%10.8f\t%10.8f\t%10.8f";
		String tab_fmt_rad = "%10.8f\t%10.7f\t%10.7f\t%10.7f\t%10.7f\t%10.8f\t%10.8f\t%10.8f";
		String tab_fmt_deg = "%10.8f\t%10.5f\t%10.5f\t%10.5f\t%10.5f\t%10.8f\t%10.8f\t%10.8f";
		String tab_fmt_deg = "%10.8f\t%10.5f\t%10.5f\t%10.5f\t%10.5f\t%10.8f\t%10.8f\t%10.8f";
		String fmt_rad = " scale=%10.8f,tilt= %10.7f, gamma=%10.7f, beta=%10.7f, rot=%10.7f, w1=%10.8f, w2=%10.8f, ratio=%10.8f";
		String fmt_rad = " scale=%10.8f,tilt= %10.7f, gamma=%10.7f, beta=%10.7f, rot=%10.7f, w1=%10.8f, w2=%10.8f, \u0394w=%10.8f"; // ratio=%10.8f";
		String fmt_deg = " scale=%10.8f,tilt= %10.5f\u00B0, gamma=%10.5f\u00B0, beta=%10.5f\u00B0, rot=%10.5f\u00B0, w1=%10.8f, w2=%10.8f, ratio=%10.8f";
		String fmt_deg = " scale=%10.8f,tilt= %10.5f\u00B0, gamma=%10.5f\u00B0, beta=%10.5f\u00B0, rot=%10.5f\u00B0, w1=%10.8f, w2=%10.8f, \u0394w=%10.8f"; // ratio=%10.8f\";
		if (tab_mode==2) {
		if (tab_mode==2) {
			return degrees?tab_title_deg:tab_title_rad;
			return degrees?tab_title_deg:tab_title_rad;
		}
		}
		String fmt = (tab_mode==1)?(degrees ? tab_fmt_deg : tab_fmt_rad):(degrees ? fmt_deg : fmt_rad);
		String fmt = (tab_mode==1)?(degrees ? tab_fmt_deg : tab_fmt_rad):(degrees ? fmt_deg : fmt_rad);
		double s = degrees ? (180/Math.PI):1;
		double s = degrees ? (180/Math.PI):1;
//		String fmt=degrees ? fmt_deg : fmt_rad;
//		String fmt=degrees ? fmt_deg : fmt_rad;
		return String.format(fmt, scale, s*getTiltAngle(), s*gamma, s*beta, s*rot, w1, w2, ratio);
//		return String.format(fmt, scale, s*getTiltAngle(), s*gamma, s*beta, s*rot, w1, w2, ratio);
		return String.format(fmt, scale, s*getTiltAngle(), s*gamma, s*beta, s*rot, w1, w2, Math.abs(w1-w2));
	}
	}