Commit ba9466e1 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Improving matching stability, added parameters

parent f468c5ba
Loading
Loading
Loading
Loading
+55 −42
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ public class ComboMatch {
		int zoom_lev = -3; // 0; // +1 - zoom in twice, -1 - zoom out twice
//		boolean show_map_stats =      false;      
		boolean show_combo =          false; // true;
		
		boolean create_overlaps =     false;
//		boolean show_combo_mask =     false; // generate image mas (where it is defined)_
//		boolean use_alt =             false;
//		boolean show_centers =        true;
@@ -182,7 +182,7 @@ public class ComboMatch {
		}
		
		
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,900);
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,600);
		gd.addChoice      ("Files list/data path (w/o extension):", files_lists_paths, files_lists_paths[default_list_choice]);
		gd.addCheckbox    ("Use saved maps collection", use_saved_collection, "If false - use files list.");
		gd.addCheckbox    ("Save maps collection", save_collection, "Save maps collection to be able to restore.");
@@ -219,6 +219,7 @@ public class ComboMatch {
//		gd.addCheckbox    ("Show transformation centers",      show_centers, "Mark verticals from the UAS on the ground.");
//		gd.addCheckbox    ("Show statistics for ortho images", show_map_stats, "Generate and show statistics for ortho maps.");
		gd.addCheckbox    ("Show combo maps/stats",            show_combo, "Generate/save combo maps and stats.");
		gd.addCheckbox    ("Create overlap pairs",             create_overlaps, "Create scene pairs overlaps.");
//		gd.addCheckbox    ("Show combo image mask",            show_combo_mask, "Display combo binary image.");
//		gd.addCheckbox    ("Show altitude combo image", use_alt, "Load and process altitude maps.");
		gd.addNumericField("Remove fraction of worst matches",   frac_remove,  3,7,"",	"When fitting scenes remove this fraction of worst match.");
@@ -270,14 +271,8 @@ public class ComboMatch {

		OrthoMap.setGPUWidthHeight(gpu_width,gpu_height);
		
//		show_centers =              gd.getNextBoolean();
//		show_map_stats =            gd.getNextBoolean();
		show_combo =                gd.getNextBoolean();
//		show_combo_mask =           gd.getNextBoolean();
//		use_alt =                   gd.getNextBoolean();

//		gpu_spair[0] =              gd.getNextString();
//		gpu_spair[1] =              gd.getNextString();
		create_overlaps =           gd.getNextBoolean();
		frac_remove =               gd.getNextNumber();
		metric_error=               gd.getNextNumber();
		if (use_marked_image ) { // will only be used if found and asked
@@ -770,6 +765,10 @@ public class ComboMatch {
			maps_collection.processComboMap(debugLevel);
			return true;
		}
		if (create_overlaps) {
			boolean ok =maps_collection.getIntersectedPairs(debugLevel);
			if (!ok) return false;
		}
        if (process_correlation || render_match || pattern_match) {
//        	int [] gpu_pair;
        	if (gpu_spair == null) {
@@ -792,7 +791,7 @@ public class ComboMatch {
				String [] choices_all = new String[choices.length+1];
				System.arraycopy(choices, 0, choices_all, 0, choices.length);
				choices_all[choices_all.length-1] = "--- select a single image ---";
				GenericJTabbedDialog gdc = new GenericJTabbedDialog("Select image pair",1200,400);
				GenericJTabbedDialog gdc = new GenericJTabbedDialog("Select image pair",1200,100);
				int num_choice_lines = 50;
				gdc.addChoice("Image pair:",
						choices_all,
@@ -804,25 +803,23 @@ public class ComboMatch {
				if (pair >= choices.length) {
					int default_choice = 0;
					int num_scene_lines = 50;
					String scene_name = 	maps_collection.selectOneScene(
							0, // int num_scene,
							default_choice, // int default_choice,
							num_scene_lines); // int num_choice_lines)
					if (scene_name == null) {
						return false;
					}
					if (process_correlation) { // select a second image to match
						// select a second image and set gpu_spair
						int default_choice1 = 0;
						String scene_name1 = 	maps_collection.selectOneScene(
								1, // int num_scene,
						gpu_spair = maps_collection.selectTwoScenes(
								default_choice1, // int default_choice,
								num_scene_lines); // int num_choice_lines)
						if (scene_name1 == null) {
						if (gpu_spair == null) {
							return false;
						}
					} else {
						String scene_name = 	maps_collection.selectOneScene(
								0, // int num_scene,
								default_choice, // int default_choice,
								num_scene_lines); // int num_choice_lines)
						if (scene_name == null) {
							return false;
						}
						gpu_spair = new String[] {scene_name, scene_name1};
					} else { // pattern match - single image
						gpu_spair = new String[] {scene_name};
					}
				} else {
@@ -913,7 +910,7 @@ public class ComboMatch {
        				num_tries_fit = 0;
        				update_match = false;
        			}
        			debugLevel = 0;
 //       			debugLevel = 0;
        			boolean  batch_mode = true; // false; //  true;
        			boolean ignore_prev_rms = true;
        			Rectangle woi = new Rectangle(); // used to return actual woi from correlateOrthoPair()
@@ -976,6 +973,9 @@ public class ComboMatch {
        						System.out.println("adjusted affines[1] for a pair: "+gpu_spair[0]+"/"+gpu_spair[1]);
        						System.out.println("[["+affines[1][0][0]+","+affines[1][0][1]+","+affines[1][0][2]+"],");
        						System.out.println(" ["+affines[1][1][0]+","+affines[1][1][1]+","+affines[1][1][2]+"]]");
        						if (pmatch != null) {
            						System.out.println("RMSE="+pmatch.rms);
        						}
        						System.out.println();
        					}
        				}
@@ -1040,45 +1040,57 @@ public class ComboMatch {

		PairwiseOrthoMatch pairwiseOrthoMatch = maps_collection.ortho_maps[gpu_pair[0]].getMatch(
				maps_collection.ortho_maps[gpu_pair[1]].getName());
//		boolean has_match = pairwiseOrthoMatch != null;
		PairwiseOrthoMatch inv_match =  maps_collection.ortho_maps[gpu_pair[1]].getMatch(
				maps_collection.ortho_maps[gpu_pair[0]].getName());
		
		// dialog - ask parameters and if has_match -ask if to use it (then just return true)
		// if has inv - ask and, if yes, = create inverted as initial
		boolean use_exixting_pair =    false;
		boolean invert_exixting_pair = false;
		double search_step =           8.0; // pix
		double search_range =         50.0; // pix
		double maximal_rms =           0.25; //
		int    min_overlap =          3000; // do not try to match if there is too small overlap (scaled pixels)
		int    num_iter_lma =          5;
		boolean use_existing_pair =    clt_parameters.imp.ospir_existing; // false
		boolean invert_exixting_pair = clt_parameters.imp.ospir_invert;   // false
		double search_step =           clt_parameters.imp.ospir_step;     // 8.0; // pix
		double search_range =          clt_parameters.imp.ospir_range;    // 50.0; // pix
		double good_rms =              clt_parameters.imp.ospir_good_rms; // 0.27; //
		double max_rms =               clt_parameters.imp.ospir_max_rms;  // 0.35; //
		int    min_overlap =           clt_parameters.imp.ospir_overlap;  // 3000; // do not try to match if there is too small overlap (scaled pixels)
		int    num_iter_lma =          clt_parameters.imp.ospir_num_iter; // 5;
		boolean ignore_rms =           clt_parameters.imp.ospir_ignore_rms; // false
		int    spiral_debug =          clt_parameters.imp.ospir_debug;    // -3;
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Setup SpiralMatch",1200,300);
		if (pairwiseOrthoMatch != null) {
			gd.addCheckbox    ("Use existing image pair",  use_exixting_pair, "Use existing affine settings for this pair, do not use spiral search.");
			gd.addCheckbox    ("Use existing image pair",  use_existing_pair, "Use existing affine settings for this pair, do not use spiral search.");
		} else {
			use_existing_pair = false;
		}
		if (inv_match != null) {
			gd.addCheckbox    ("Invert existing image pair", invert_exixting_pair, "Invert existing image pair affine transform, do not use spiral search.");
		} else {
			invert_exixting_pair = false;
		}
		gd.addNumericField("Spiral search step",     search_step,  3,7,"scaled pix",	"Distance between spiral search probes, in scaled pixels.");
		gd.addNumericField("Spiral search radius",   search_range, 3,7,"scaled pix",	"Maximal radius of the spiral search, in scaled pixels.");
		gd.addNumericField("Maximal RMSE",           maximal_rms,  3,7,"scaled pix",	"Maximal RMSE to consider match, in scaled pixels.");
		gd.addNumericField("RMSE to end search",     good_rms,  3,7,"scaled pix",	"Maximal RMSE to consider match, in scaled pixels.");
		gd.addNumericField("Satisfactory RMSE",      max_rms,  3,7,"scaled pix",	"Maximal RMSE to consider match, in scaled pixels.");
		gd.addNumericField("Minimal overlap",        min_overlap,  0,4,"scaled pix ^ 2","Minimal overlap area in square scaled pixels.");
		gd.addNumericField("LMA iterations",         num_iter_lma, 0,2,"",              "Number of LMA iterations.");
		gd.addCheckbox    ("Ignore worsening RMSE",  ignore_rms, "Ignore worsening/not improving RMSE during spiral search.");
		gd.addNumericField("Spiral search debug level",spiral_debug, 0,3,"","Debug level during Spiral search.");
		
		gd.showDialog();
		if (gd.wasCanceled()) return null;
		if (pairwiseOrthoMatch != null) {
			use_exixting_pair =    gd.getNextBoolean();
			use_existing_pair =    gd.getNextBoolean();
		}
		if (inv_match != null) {
			invert_exixting_pair = gd.getNextBoolean();
		}
		search_step=               gd.getNextNumber();
		search_range=              gd.getNextNumber();
		maximal_rms =              gd.getNextNumber();
		good_rms =                 gd.getNextNumber();
		max_rms =                  gd.getNextNumber();
		min_overlap =        (int) gd.getNextNumber();
		num_iter_lma =       (int) gd.getNextNumber();
		if (use_exixting_pair) {
		ignore_rms =               gd.getNextBoolean();
		spiral_debug =       (int) gd.getNextNumber();
		if (use_existing_pair) {
			if (invert_exixting_pair) {
				System.out.println("Both direct and inverted matches are selected, using direct match");
			}
@@ -1095,7 +1107,6 @@ public class ComboMatch {

		pairwiseOrthoMatch = maps_collection.SpiralMatch (
				clt_parameters,  // CLTParameters    clt_parameters,
//				PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics, may be null if not needed
				frac_remove,     // double           frac_remove, //  =        0.25
				metric_error,    // double           metric_error,
				gpu_pair,        // int []           gpu_pair,
@@ -1103,10 +1114,12 @@ public class ComboMatch {
				initial_zoom,    // int              zoom_lev,
				search_step,     // double           pix_step,
				search_range,    // double           pix_range,
				maximal_rms,     // double           need_rms,
				good_rms,        // double           good_rms,
				max_rms,         // 			double           max_rms,
				num_iter_lma,    // int              num_tries, //  = 5
				min_overlap,     // int              min_overlap, // 3000
				debugLevel);    // int              debugLevel){
				ignore_rms,      // boolean          ignore_rms,
				spiral_debug);     // int              debugLevel){
		return pairwiseOrthoMatch;
	}
	
+217 −13
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@@ -987,7 +988,6 @@ public class OrthoMapsCollection implements Serializable{
    
	public PairwiseOrthoMatch SpiralMatch (
			CLTParameters    clt_parameters,
//			PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics, may be null if not needed
			double           frac_remove, //  =        0.25
			double           metric_error,
			int []           gpu_pair,
@@ -995,15 +995,16 @@ public class OrthoMapsCollection implements Serializable{
			int              zoom_lev,
			double           pix_step,
			double           pix_range,
			double           need_rms,
			double           good_rms,
			double           max_rms,
			int              num_tries, //  = 5
			int              min_overlap, //  = 5
			boolean          ignore_rms,
			int              debugLevel){
		double [][] affine1 = new double [][] {affines_init[1][0].clone(),affines_init[1][1].clone()};
		double [][][] affines = new double [][][] {affines_init[0],affine1};
		boolean  show_vf = false;
		boolean  batch_mode = true;
		boolean  ignore_prev_rms = false; // true;
		double [][] ground_planes = null; // null or double[2] - will return ground planes:
		double pix_size = OrthoMap.getPixelSizeMeters (zoom_lev);
		int nx = 0, ny=0; // number of steps (pix_step size) in hor and vert directions (both pos and neg)
@@ -1015,7 +1016,8 @@ public class OrthoMapsCollection implements Serializable{
				zoom_lev); // int zoom_lev); 
		double           max_std =     0.5;      // maximal standard deviation to limit center area  
		double           min_std_rad = 2.0;  // minimal radius of the central area (if less - fail)

		int best_nx = -1, best_ny = -1;
		PairwiseOrthoMatch best_pom = null;
		while ((Math.abs(nx) <= nabs) && (Math.abs(ny) <= nabs)) {
			for (int i = 0; i < affines_init.length; i++) {
				System.arraycopy(affines_init[1][i], 0, affine1[i], 0, affine1[i].length);
@@ -1032,7 +1034,7 @@ public class OrthoMapsCollection implements Serializable{
					min_std_rad,     // double           min_std_rad,  // minimal radius of the central area (if less - fail)
					frac_remove,     // double           frac_remove, //  =        0.25
					metric_error,    // 			double           metric_error,
					ignore_prev_rms, // boolean ignore_prev_rms,
					ignore_rms,      // boolean ignore_prev_rms,
					num_tries,       //  = 5int              num_tries, //  = 5
					false,           // boolean          calc_warp, (will return null if false)
					batch_mode,      // boolean          batch_mode,
@@ -1042,15 +1044,20 @@ public class OrthoMapsCollection implements Serializable{
					zoom_lev,        // int              zoom_lev,
					show_vf,         // boolean show_vf,
					ground_planes,   // double [][]      ground_planes, // null or double[2] - will return ground planes
					debugLevel);     // final int        debugLevel)
					debugLevel-4);     // final int        debugLevel)
			pairwiseOrthoMatch.affine = affines[1]; // modified by correlateOrthoPair
			if (debugLevel > -4) {
				System.out.println(String.format("SpiralMatch(): nx = %3d, ny=%3d, RMSE=%8.6f",
						nx,ny,pairwiseOrthoMatch.rms));
			}
			if (pairwiseOrthoMatch.rms < need_rms) {
			if (pairwiseOrthoMatch.rms < good_rms) {
				break;
			}
			if (!Double.isNaN(pairwiseOrthoMatch.rms) && ((best_pom == null) || !(best_pom.rms <= pairwiseOrthoMatch.rms))) {
				best_pom = pairwiseOrthoMatch.clone();
				best_nx = nx;
				best_ny = ny;
			}
			// update nx, ny
			if ((nx >   ny) && (nx > -ny)){
				ny++;
@@ -1062,11 +1069,22 @@ public class OrthoMapsCollection implements Serializable{
				nx++;
			}
		}
		if (!(pairwiseOrthoMatch.rms < need_rms)) { // failed
			return null;
		}
		if (pairwiseOrthoMatch.rms < good_rms) { // failed
			return pairwiseOrthoMatch; // pairwiseOrthoMatch.affine will have adjusted affine[1]
		}
		if ((best_pom != null) && (best_pom.rms <= max_rms)) {
			if (debugLevel > -4) {
				System.out.println("SpiralMatch(): best RMSE="+best_pom.rms+" < "+max_rms+
						" for nx = "+best_nx+", ny="+best_ny+", using it.");
			}
			return best_pom;
		}
		if (debugLevel > -4) {
			System.out.println("SpiralMatch(): Failed to find a good match candidate. Best RMSE="+
			((best_pom != null)? best_pom.rms:"N/A")+", max_rms= "+max_rms+"");
		}
		return null; // pairwiseOrthoMatch.affine will have adjusted affine[1]
	}
	
	
	
@@ -1132,6 +1150,7 @@ public class OrthoMapsCollection implements Serializable{
			boolean          show_vf,
			double [][]      ground_planes, // null or double[2] - will return ground planes:
			int              debugLevel){
		double center_radius_change = 1.5; // if increases by more than this, disregard RMSE worsening
		boolean show_lma_dbg = !batch_mode && (debugLevel > 1); 
		if (woi == null) {
			woi = new Rectangle();
@@ -1268,6 +1287,7 @@ public class OrthoMapsCollection implements Serializable{
		double [][] jtj = null;
		double rms = Double.NaN;
		double last_center_radius = 0;
		double previous_center_radius = 1.0;
		for (int ntry = 0; ntry < num_tries; ntry++) {
			if (!batch_mode) {
				if (debugLevel>-3) {
@@ -1508,6 +1528,13 @@ public class OrthoMapsCollection implements Serializable{

					debugLevel);     // final int     debug_level)
			last_center_radius = orthoPairLMA.getCenterRadius();
			double center_radius_increase = 
					Double.isInfinite(previous_center_radius)?
							(Double.isInfinite(last_center_radius)?1:0):
								last_center_radius/previous_center_radius;
			if ((ntry == 0) && Double.isInfinite(last_center_radius)) {
				center_radius_increase = 1.0; // if starts with infinity - no increase  
			}
			if ((min_std_rad >0) && (last_center_radius < 1)) {
				if (debugLevel>-3) {
					System.out.println("correlateOrthoPair(): center_radius="+
@@ -1559,10 +1586,18 @@ public class OrthoMapsCollection implements Serializable{
					if (debugLevel > -3) {
						System.out.println("Will continue, as ignore_prev_rms is set");
					}					
				} else {
					if (center_radius_increase > center_radius_change) {
						if (debugLevel > -3) {
							System.out.println("Will continue, as center_radius increased from "+
									previous_center_radius+" to "+	last_center_radius +" (more than "+
									center_radius_change+"x).");
						}
					} else {
						break;
					}
				}
			}
			affines_gpu[1]=OrthoMap.combineAffine(affines_gpu[1], orthoPairLMA.getAffine());
			jtj = orthoPairLMA.getLastJtJ();
			if ((prev_rms - rms)/prev_rms < rel_improve) {
@@ -1573,11 +1608,32 @@ public class OrthoMapsCollection implements Serializable{
					if (debugLevel > -3) {
						System.out.println("Will continue, as ignore_prev_rms is set");
					}					
				} else {
					if (center_radius_increase > center_radius_change) {
						if (debugLevel > -3) {
							System.out.println("Will continue, as center_radius increased from "+
									previous_center_radius+" to "+	last_center_radius +" (more than "+
									center_radius_change+"x).");
						}
					} else {
						break;
					}
				}
			}

			if (center_radius_increase > center_radius_change) {
				num_tries ++;
				if (debugLevel > -2) {
					System.out.println("Increasing num_tries to "+num_tries+", as center_radius increased from "+
							previous_center_radius+" to "+	last_center_radius +" (more than "+
							center_radius_change+"x).");
				}
			}
			
			
			prev_rms=rms;
			previous_center_radius = last_center_radius;
			
		} // for (int ntry = 0; ntry < num_tries; ntry++) {
		
		if ((min_std_rad > 0) && (last_center_radius < min_std_rad)) {
@@ -3728,6 +3784,42 @@ public class OrthoMapsCollection implements Serializable{
		return ortho_maps[scene_number].getName();
	}

	public String[] selectTwoScenes(
			int default_choice,
			int num_choice_lines) {
		String [] fs = {"first","second"};
		String [] lines = new String [ortho_maps.length];
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss.SS zzz");// may be VV instead of zzz
		for (int indx = 0; indx < ortho_maps.length; indx++) {
			OrthoMap map = ortho_maps[indx];
			LocalDateTime ldt = map.getLocalDateTime();
			ZonedDateTime zonedUTC = ldt.atZone(ZoneId.of("UTC")); // that time is UTC
			ZonedDateTime zonedDateTime = zonedUTC.withZoneSameInstant(ZoneId.of("Europe/Kyiv"));
			String sdt = zonedDateTime.format(formatter);
			String name = map.getName();
			double agl = map.getAGL();
			lines[indx]=String.format(
					"%3d %17s %26s %6.2f",indx, name, sdt, agl);
		}
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Select two image scenes",1200,150);
		for (int num_scene = 0; num_scene < 2; num_scene++) {
			gd.addChoice(fs[num_scene]+" image:",
					lines,
					lines[default_choice],
					"Select "+fs[num_scene]+" scene", num_choice_lines);
		}
		gd.showDialog();
		if (gd.wasCanceled()) return null;
		String [] names = new String[2];
		for (int num_scene = 0; num_scene < 2; num_scene++) {
			int scene_number= gd.getNextChoiceIndex();
			names[num_scene] = ortho_maps[scene_number].getName();
		}		
		return names;
	}

	
	
	public String [] getScenesList() {
		String [] lines = new String [ortho_maps.length];
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss.SS zzz");// may be VV instead of zzz
@@ -3806,6 +3898,84 @@ public class OrthoMapsCollection implements Serializable{
		return indices;
	}
	
	public boolean getIntersectedPairs(
			int debugLevel) {
		int [] indices = getScenesSelection(
				null, // boolean select_all,
				" to find intersects"); // String purpose)
		if (indices == null) {
			return false;
		}
		int     zoom_lev = -5;
		double  min_overlap = 0.25;
		boolean bounds_to_indices = true;
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Combo map/stats generation",1200,1000);
		gd.addNumericField("Zoom level",                 zoom_lev,  0,4,"",
				"Zoom level: +1 - zoom in twice, -1 - zoom out twice");
		gd.addNumericField("Minimal overlap",                min_overlap,    3,7,"",
				"Minimal overlap as a fraction of the smaller image.");
		gd.showDialog();
		if (gd.wasCanceled()) return false;
		zoom_lev =     (int) gd.getNextNumber();
		min_overlap =        gd.getNextNumber();
		
		int [] wh =     new int[2];
		int [] origin = new int[2];
		double [][] centers =new double [indices.length][];			
		double [][] dmulti = renderMultiDouble (
				null, // double [][]   ground_planes, // null - images, non-null altitudes. use new double[2][3] for old way alt
				indices,    // int []        indices, // null or which indices to use (normally just 2 for pairwise comparison)
				bounds_to_indices, // boolean       bounds_to_indices,
				null, // affines,    // double [][][] affines, // null or [indices.length][2][3]
				null, // warp,       // FineXYCorr    warp,,
				zoom_lev, // int         zoom_level,
				wh,         // int []      wh,
				origin,     // int []      origin){ // maps[0] as a reference
				centers);   // double [][] centers)
		
		double [] overlaps = getFracOverlaps(
				dmulti); // final double [][] dmulti) {
		int num_overlaps_all = 0, num_overlaps_sel = 0;
		boolean [][] intersects = new boolean [dmulti.length][dmulti.length];
		for (int i = 0; i < overlaps.length; i++) if (!Double.isNaN(overlaps[i])){
			num_overlaps_all++;
			if (overlaps[i] >= min_overlap) {
				num_overlaps_sel++;
				int row = i / dmulti.length;
				int col = i % dmulti.length;
				intersects[row][col] = true;
			}
		}
		int [] groups = new int [dmulti.length];
		for (int i = 0; i < groups.length; i++) {
			groups[i] = i;
		}
		for (int i = 0; i< (groups.length-1); i++) {
			for (int j = i+1; j < groups.length; j++) if (groups[j] != groups[i]){
				int g0 =  groups[i];
				int g1 =  groups[j];
				for (int k = 0; k < groups.length; k++) {
					if (groups[k] == g1) {
						groups[k] = g0;
					}
				}
			}
		}
		HashSet<Integer> hs = new HashSet<Integer>();
		for (int i:groups) {
			hs.add(i);
		}
		System.out.println("getIntersectedPairs(): num_overlaps_all="+num_overlaps_all+
				", num_overlaps_sel="+num_overlaps_sel+", number of disconnected groups="+hs.size());
		if (debugLevel > 0) {
			ShowDoubleFloatArrays.showArrays( 
					overlaps,
					"Overlaps");
		}
		return true;
	}
	
	
	public boolean processComboMap(
			int debugLevel) {
		int [] indices = getScenesSelection(
@@ -4331,4 +4501,38 @@ public class OrthoMapsCollection implements Serializable{
		}
	}
	
	public static double [] getFracOverlaps(
			final double [][] dmulti) {
		final double [] overlaps = new double [dmulti.length*dmulti.length];

		final Thread[] threads = ImageDtt.newThreadArray();
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int nscene = ai.getAndIncrement(); nscene < (dmulti.length-1); nscene = ai.getAndIncrement()) {
						double [] data0 = dmulti[nscene];
						int num0 = 0;
						for (int i = 0; i < data0.length; i++) if (!Double.isNaN(data0[i])) {
							num0++;
						}

						for (int nscene1 = nscene+1; nscene1 < dmulti.length; nscene1++) {
							double [] data1 = dmulti[nscene1];
							int num1 = 0, num_intersect=0; 
							for (int i = 0; i < data0.length; i++) if (!Double.isNaN(data1[i])) {
								num1++;
								if (!Double.isNaN(data0[i])) {
									num_intersect++;
								}
							}
							overlaps[nscene * dmulti.length  + nscene1] = (1.0 * num_intersect)/ Math.min(num0, num1);
						}
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		return overlaps;
	}
}
+13 −1
Original line number Diff line number Diff line
@@ -23,7 +23,19 @@ public class PairwiseOrthoMatch implements Serializable {
		this.jtj = jtj;
		this.zoom_lev=zoom_lev;
	}
	
	public PairwiseOrthoMatch clone() {
		double [][] affine = {this.affine[0].clone(),this.affine[1].clone()};
		double [][] jtj = new double [this.jtj.length][];
		for (int i = 0; i < this.jtj.length; i++) {
			jtj[i] = this.jtj[i].clone();
		}
		PairwiseOrthoMatch pom = new PairwiseOrthoMatch(
				affine,
				jtj,
				this.rms,
				this.zoom_lev);
		return pom;
	}
	public PairwiseOrthoMatch getInverse(double [] rd) {
		double [][] affine = OrthoMap.invertAffine(getAffine());
		PairwiseOrthoMatch inverted_match = new PairwiseOrthoMatch(