Commit c3505d27 authored by Andrey Filippov's avatar Andrey Filippov

Working snapshot,single-connected pairs

parent d8f3ec21
......@@ -1303,6 +1303,8 @@ public class ComboMatch {
System.out.println("This can happen if files have different resolution for new run.");
System.out.println("Verify path, then modify filenames[i], break at line above: 'maps_collection.ortho_maps[i].setFileName(filenames[i])'.");
System.out.println("Reduce i by 1 and continue");
} else {
maps_collection.ortho_maps[i] = new OrthoMap(path);
}
}
return true;
......
......@@ -913,6 +913,10 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
int swidth = getWidth();
int sheight = getHeight();
final float [] spix = orig_image.data;
if (swidth*sheight != spix.length) {
System.out.println ("downScaleForGPU(): swidth="+ swidth+", sheight="+sheight+", swidth*sheight="+(swidth*sheight)+", spix.length="+spix.length);
System.out.println ();
}
final int width = (swidth+frscale-1)/frscale;
final int height = (sheight+frscale-1)/frscale;
final int tiles = width * height;
......@@ -939,17 +943,28 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
for (int py = 0; py < tileH; py++) {
int ls = (tileY*frscale + py)*swidth;
for (int px = 0; px < tileW; px++) {
double d = spix[ls + tileX*frscale+px];
if (!Double.isNaN(d)) {
double w = wnd[py][px];
sw += w;
swd += w*d;
}
if (sw > 0) {
opix[tileY * width + tileX] = (float) (swd/sw);
int indx = ls + tileX*frscale+px;
if ((indx >=0) && (indx < spix.length)) {
double d = spix[ls + tileX*frscale+px]; //java.lang.ArrayIndexOutOfBoundsException: Index 3892800 out of bounds for length 3892680
if (!Double.isNaN(d)) {
double w = wnd[py][px];
sw += w;
swd += w*d;
}
} else {
System.out.println("downScaleForGPU(): indx = "+indx+" ("+spix.length+"), tileX= "+
tileX+", tileY="+tileY+", px="+px+", py="+py+", ls="+ls);
}
// if (sw > 0) {
// opix[tileY * width + tileX] = (float) (swd/sw);
// }
}
}
if (sw > 0) {
opix[tileY * width + tileX] = (float) (swd/sw);
}
}
}
};
......
......@@ -55,6 +55,7 @@ public class OrthoMapsCollection implements Serializable{
public static final int MODE_ALT = 1;
public static final int MODE_MASK = 2;
/*
public static final int PAIR_NONE = 0;
public static final int PAIR_DEFINED = 1;
public static final int PAIR_UNDEFINED = 2;
......@@ -63,7 +64,8 @@ public class OrthoMapsCollection implements Serializable{
public static final int HEUR_LAST_SEQ = 1; // use last of connected following this
public static final int HEUR_DIV_LONG = 2; // divide long connected series
public static final int HEUR_MIN_DIA = 4; // minimal diameter increase (or no increase)
public static final int HEUR_SAME_DIA = 8; // minimal diameter increase (or no increase)
public static final int HEUR_SAME_DIA = 8; // minimal diameter increase (or no increase)
*/
public static final String [] KEY_DIRS= {"rootDirectory", // from EyesisCorrectionParameters
"sourceDirectory","linkedModels","videoDirectory","x3dDirectory","resultsDirectory","scenesDirectory",
......@@ -4867,7 +4869,8 @@ public class OrthoMapsCollection implements Serializable{
sb.append(String.format("%4d\t%4d\t%s\t%s\t%6.4f\t%3d\tSKIP\t\t\t%6.4f\t%3d\n",
ipair[0], ipair[1],
ortho_maps[ipair[0]].getName(), ortho_maps[ipair[1]].getName(),
overlaps[overlap_indx], initial_zoom,
overlaps[overlap_indx],
initial_zoom,
direct_match.rms,
direct_match.zoom_lev));
CalibrationFileManagement.saveStringToFile (
......@@ -5066,20 +5069,10 @@ public class OrthoMapsCollection implements Serializable{
return false;
}
// gen number of pairs:
// int num_scenes = indices.length;
int [][] pair_state = new int [indices.length][indices.length];
double [][] overlaps = new double [indices.length][indices.length];
double [] timestamps = new double [indices.length];
int [] groups = new int [indices.length];
int [][] dist = new int [indices.length][indices.length];
for (int i = 0; i < indices.length; i++) {
groups[i] = i;
timestamps[i] = ortho_maps[indices[i]].getTimeStamp();
}
// int num_pairs = 0;
int num_defined = 0;
int num_undefined = 0;
......@@ -5089,34 +5082,10 @@ public class OrthoMapsCollection implements Serializable{
PairwiseOrthoMatch match = ortho_maps[indices[i]].getMatch(name2,true);
if (match != null) {
if (match.isDefined()) {
pair_state[i][j] = PAIR_DEFINED;
num_defined++;
/*
// update groups
if (groups[i] != groups[j]) {
int g0 = Math.min(groups[i], groups[j]);
int g1 = Math.max(groups[i], groups[j]);
for (int k = 0; k < groups.length; k++) {
if (groups[k] == g1) {
groups[k] = g0;
}
}
}
updateDistance(
new int [] {i,j}, // final int [] pair,
dist); // final int [][] dist)
*/
recordPair(
new int [] {i,j}, // int [] pair,
true, // boolean success,
pair_state, //int [][] pair_state,// = new int [indices.length][indices.length];
groups, // int [] groups, // = new int [indices.length];
dist); //int [][] dist) // = new int [indices.length];
} else {
pair_state[i][j] = PAIR_UNDEFINED;
num_undefined++;
}
overlaps[i][j] = match.getOverlap();
}
}
}
......@@ -5126,21 +5095,24 @@ public class OrthoMapsCollection implements Serializable{
}
boolean dry_run = false;
boolean skip_exist = clt_parameters.imp.pwise_skip_exist; //
boolean refine_exist = clt_parameters.imp.pwise_refine_exist; // if false, start from scratch, true - start from previous
boolean delete_failed = clt_parameters.imp.pwise_delete_fail; // delete existing match if now failed
boolean gen_inverse = clt_parameters.imp.pwise_gen_inverse; // generate inverse matches
/// boolean skip_exist = clt_parameters.imp.pwise_skip_exist; //
/// boolean refine_exist = clt_parameters.imp.pwise_refine_exist; // if false, start from scratch, true - start from previous
/// boolean delete_failed = clt_parameters.imp.pwise_delete_fail; // delete existing match if now failed
/// boolean gen_inverse = clt_parameters.imp.pwise_gen_inverse; // generate inverse matches
boolean save_each = clt_parameters.imp.pwise_save_each; // save state file after each match
boolean log_append = clt_parameters.imp.pwise_log_append; //
String log_path = clt_parameters.imp.pwise_log_path; //
int debugLevel = clt_parameters.imp.pwise_debug; //
double min_overlap_frac = clt_parameters.imp.pwise_overlap; // 0.25;
//Initial spiral search for image matching
double search_step = clt_parameters.imp.ospir_step; // 8.0; // pix
double search_range = clt_parameters.imp.ospir_range; // 50.0; // pix
double double_threshold = clt_parameters.imp.ospir_double; //
double good_rms = clt_parameters.imp.ospir_good_rms; // 0.27; //
double max_rms = clt_parameters.imp.ospir_max_rms; // 0.35; //
double max_rms_refine = clt_parameters.imp.pwise_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;
double [] max_rms_iter = clt_parameters.imp.ospir_rms_iter; // {1.0, 0.6};//
......@@ -5161,32 +5133,35 @@ public class OrthoMapsCollection implements Serializable{
double fill_fraction = clt_parameters.imp.pmtch_cent_fill; // should be populated not less than this
double fill_fraction_final = clt_parameters.imp.pmtch_cent_final; // should be populated not less than this during final pass
double ease_nosfm = clt_parameters.imp.pmtch_ease_nosfm; // ease metric_error when no SfM gain == 0;
// double max_rmse_reuse = 0.35;
boolean use_multi = true;
int heur = 15;
int min_scene = 0;
GenericJTabbedDialog gd = new GenericJTabbedDialog("Pairwise Match Parameters",1200,1000);
gd.addMessage("Number of scenes - "+indices.length+
", number of defined pairs - "+num_defined+
", number of undefined pairs - "+num_undefined+
", number of disconnected groups - "+hs.size());
", number of undefined pairs - "+num_undefined);
// +", number of disconnected groups - "+hs.size());
//
gd.addCheckbox ("Dry run", dry_run, "Create pairs, do not adjust.");
gd.addCheckbox ("Skip existing", skip_exist, "Do not regenerate if match with same or higher resolution exists.");
gd.addCheckbox ("Refine existing", refine_exist, "Refine existing matches (false - start from scratch with spiral search).");
gd.addCheckbox ("Delete failed", delete_failed, "Delete previous matches if it failed now.");
gd.addCheckbox ("Generate inverse matches", gen_inverse, "Generate (refine if exist and enabled) inverse matches.");
/// gd.addCheckbox ("Skip existing", skip_exist, "Do not regenerate if match with same or higher resolution exists.");
/// gd.addCheckbox ("Refine existing", refine_exist, "Refine existing matches (false - start from scratch with spiral search).");
/// gd.addCheckbox ("Delete failed", delete_failed, "Delete previous matches if it failed now.");
/// gd.addCheckbox ("Generate inverse matches", gen_inverse, "Generate (refine if exist and enabled) inverse matches.");
gd.addCheckbox ("Save state after each match", save_each, "Update state file after each match generation to mitigate possible crashes.");
gd.addCheckbox ("Write log file", log_append, "Enable writing log file with matching results.");
gd.addStringField ("Log file full path", log_path, 150, "Path of the log file to be appended.");
gd.addNumericField("Pairwise match debug level", debugLevel, 0,3,"","Debug level during Spiral search.");
gd.addNumericField("Minimal overlap fraction", min_overlap_frac, 3,7,"", "Minimal overlap fraction.");
gd.addMessage ("Initial spiral search for image matching");
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("Mitigate small overlap", double_threshold, 3,7,"","For small overlaps increase zoom by 1 and range - twice.");
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("Satisfactory RMSE, spiral", max_rms, 3,7,"scaled pix", "Maximal RMSE to consider match, in scaled pixels, during spiral.");
gd.addNumericField("Satisfactory RMSE, final", max_rms_refine,3,7,"scaled pix", "Maximal RMSE to consider match, in scaled pixels, during refine.");
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 during spiral search.");
gd.addNumericField("RMSE at first iteration", max_rms_iter[0], 3,7,"scaled pix","Maximal RMSE at first iteration.");
......@@ -5216,20 +5191,21 @@ public class OrthoMapsCollection implements Serializable{
gd.showDialog();
if (gd.wasCanceled()) return false;
dry_run = gd.getNextBoolean();
skip_exist = gd.getNextBoolean();
refine_exist = gd.getNextBoolean();
delete_failed = gd.getNextBoolean();
gen_inverse = gd.getNextBoolean();
/// skip_exist = gd.getNextBoolean();
/// refine_exist = gd.getNextBoolean();
/// delete_failed = gd.getNextBoolean();
/// gen_inverse = gd.getNextBoolean();
save_each = gd.getNextBoolean();
log_append = gd.getNextBoolean();
log_path = gd.getNextString();
debugLevel = (int) gd.getNextNumber();
min_overlap_frac = gd.getNextNumber();
search_step = gd.getNextNumber();
search_range = gd.getNextNumber();
double_threshold = gd.getNextNumber();
good_rms = gd.getNextNumber();
max_rms = gd.getNextNumber();
max_rms_refine = gd.getNextNumber();
min_overlap = (int) gd.getNextNumber();
num_iter_lma = (int) gd.getNextNumber();
max_rms_iter[0] = gd.getNextNumber();
......@@ -5253,114 +5229,50 @@ public class OrthoMapsCollection implements Serializable{
min_scene = (int) gd.getNextNumber();
heur = (int) gd.getNextNumber();
use_multi = gd.getNextBoolean();
double max_rmse_reuse= max_rms_refine;
PairsGraph pairsGraph = new PairsGraph(
this, // OrthoMapsCollection orthoMapsCollection,
indices, // int [] indices,
min_overlap_frac, // double min_overlap_frac,
max_rmse_reuse, // double max_rmse_reuse,
use_multi, // boolean multi,
debugLevel); // int debugLevel);
if (dry_run) {
PairsGraph pairsGraph = new PairsGraph(
this, // OrthoMapsCollection orthoMapsCollection,
indices, // int [] indices,
use_multi, // boolean multi,
debugLevel); // int debugLevel);
return pairsGraph.dryRun(
heur, // int heur,
debugLevel); // int debugLevel)
/*
int [][] pairs = getPairsIndices( // maybe update sometimes?
pair_state, // final int [][] pair_state,
groups); // final int [] groups);
*
int num_compact = 10; // compact after each 10 runs
int num_pairs = 0;
int ok_dist = 1;
int [] start_ij = {0,0};
int [] next_pair;
do {
next_pair = suggestPairSingle( // single-connected, no cycles
// add some parameters
heur, // int heur,
pairs, // int [][] pairs,
pair_state, // int [][] pair_state, // = new int [indices.length][indices.length];
overlaps, // double [][] overlaps, // = new double [indices.length][indices.length];
timestamps, // double [] timestamps, // = new double [indices.length];
groups, // int [] groups, // = new int [indices.length];
dist, // int [][] dist) { // = new int [indices.length];
ok_dist, // int ok_dist)
start_ij); // int [] start_ij) // = new int [indices.length];
if (next_pair == null) {
break;
}
if (next_pair[2] > HEUR_LAST_SEQ) {
heur &= ~HEUR_LAST_SEQ;
}
if (next_pair[2] > HEUR_DIV_LONG) {
heur &= ~HEUR_DIV_LONG;
}
if (next_pair.length > 3) {
ok_dist = next_pair[3];
start_ij[0] = next_pair[0];
start_ij[1] = next_pair[1];
System.out.println(String.format("%3d: %3d-%3d %2d (%3d)", num_pairs,next_pair[0], next_pair[1],next_pair[2],next_pair[3]));
} else {
System.out.println(String.format("%3d: %3d-%3d %2d", num_pairs,next_pair[0], next_pair[1],next_pair[2]));
}
recordPair(
next_pair, // int [] pair,
true, // boolean success,
pair_state, // int [][] pair_state,// = new int [indices.length][indices.length];
groups, // int [] groups, // = new int [indices.length];
dist); // int [][] dist) // = new int [indices.length];
*/
/*
if ((num_pairs % num_compact) == 0) {
pairs = updatePairsIndices(
true, // final boolean compact,
pairs, // final int [][] pairs,
groups); // final int [] groups)
} else {
updatePairsIndices(
false, // final boolean compact,
pairs, // final int [][] pairs,
groups); // final int [] groups)
}
*/
/*
num_pairs++;
} while (true);
String [] titles = {"overlap", "state", "dist"};
double [][] dbg_img = new double [titles.length][indices.length*indices.length];
for (int i = 0; i < indices.length; i++) {
for (int j = 0; j < indices.length; j++) {
int indx = i * indices.length+ j;
dbg_img[0][indx] = overlaps[i][j];
dbg_img[1][indx] = pair_state[i][j];
dbg_img[2][indx] = dist[i][j];
} else {
if (log_append && (log_path != null)) { // assuming directory exists
StringBuffer sb = new StringBuffer();
sb.append(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime())+"\n");
sb.append("num_scenes\t"+ indices.length+"\n");
sb.append("num_defined\t"+ num_defined+"\n");
sb.append("num_undefined\t"+ num_undefined+"\n");
sb.append("num_groups\t"+ pairsGraph.getNumberOfGroups()+"\n");
sb.append(String.format("%4s\t%4s\t%17s\t%17s\t%6s\t%3s\t%4s,\t%4s\t%6s\t%6s\t%7s\n",
"scn1","scn2","timestamp1","timestamp2","ovrlp","zl","nx","ny","RMS-sp","RMSfin","fzl","removed"));
CalibrationFileManagement.saveStringToFile (
log_path, //String path,
sb.toString(), // data,
true); // boolean append)
if (debugLevel>-3) {
System.out.print(sb.toString());
}
}
ShowDoubleFloatArrays.showArrays(
dbg_img,
indices.length,
indices.length,
true,
"dry_run.tiff",
titles);
*/
// return true;
}
/*
return generatePairwiseMatches(
return generatePairwiseAffines(
clt_parameters, // CLTParameters clt_parameters,
min_overlap_frac, // double min_overlap_frac,
indices, // int [] indices,
overlaps, // double [] overlaps,
skip_exist, // boolean skip_existing,
refine_exist, // boolean refine_existing, // if false, start from scratch, true - start from previous
delete_failed, // boolean delete_failed, // if false, start from scratch, true - start from previous
gen_inverse, // boolean gen_inverse, // generate inverse matches
pairsGraph, // PairsGraph pairsGraph,
heur, // int heur,
min_overlap_frac, // double min_overlap_frac,
// indices, // int [] indices,
// overlaps, // double [] overlaps,
// skip_exist, // boolean skip_existing,
// refine_exist, // boolean refine_existing, // if false, start from scratch, true - start from previous
// delete_failed, // boolean delete_failed, // if false, start from scratch, true - start from previous
// gen_inverse, // boolean gen_inverse, // generate inverse matches
save_each, // boolean save_each, // save state file after each match
log_append, // boolean log_append, //
log_path, // String log_path,
......@@ -5369,6 +5281,7 @@ public class OrthoMapsCollection implements Serializable{
search_range, // double search_range,
good_rms, // double good_rms,
max_rms, // double max_rms,
max_rms_refine, // double max_rms_refine,
min_overlap, // int min_overlap,
num_iter_lma, // int num_iter_lma,
spiral_ignore_rms, // boolean ignore_rms,
......@@ -5389,339 +5302,286 @@ public class OrthoMapsCollection implements Serializable{
max_rms_iter, // double [] max_rms_iter,
min_scene, // int min_scene,
debugLevel); // int debugLevel
*/
return true;
}
}
public static int [] suggestPairSingle( // single-connected, no cycles
// add some parameters
final int heur,
final int [][] pairs,
final int [][] pair_state, // = new int [indices.length][indices.length];
final double [][] overlaps, // = new double [indices.length][indices.length];
final double [] timestamps, // = new double [indices.length];
final int [] groups, // = new int [indices.length];
final int [][] dist,
final int ok_dist,
final int [] start_ij) { // = new int [indices.length];
int i0 = 1;
single: {
int g0 = groups[0];
for (; i0 < groups.length; i0++) if (groups[i0] !=g0){
break single;
}
return null; // already single-connected
}
int i = i0-1;
// groups[i] - last same group as group[0]
if ((heur & HEUR_LAST_SEQ) != 0) {// try last in connected sequence - it should not yet be the same group
for (; i < (groups.length-1); i++) {
if (groups[i+1] != groups[i]) {
if ((pair_state[i][i+1] != 0) && ((i == 0) || (pair_state[i-1][i] == 0))) { // next is somehow connected, but previous is not
int j = i+1;
for (; (j < groups.length) && (pair_state[i][j] != 0); j++);
j--; // now j - last connected. Go backward if last connected failed
for (; j > i; j--) {
if (pair_state[i][j] != PAIR_FAILED) {
if (groups[j] != groups[i]) {
return new int [] {i,j,HEUR_LAST_SEQ};
}
break; // for (; j > i; j--) { : already connected
}
}
}
}
public boolean generatePairwiseAffines(
CLTParameters clt_parameters,
PairsGraph pairsGraph,
int heur,
double min_overlap_frac,
// int [] indices,
// double [] overlaps,
// boolean skip_existing,
// boolean refine_existing, // if false, start from scratch, true - start from previous
// boolean delete_failed, // if false, start from scratch, true - start from previous
// boolean gen_inverse, // generate inverse matches
boolean save_each, // save state file after each match
boolean log_append, //
String log_path,
String orthoMapsCollection_path,
double search_step,
double search_range_in,
double good_rms,
double max_rms,
double max_rms_refine,
int min_overlap,
int num_iter_lma,
boolean ignore_rms,
int spiral_debug,
double frac_remove,
double metric_error,
boolean pmtch_use_affine,
double max_std,
double min_std_rad,
boolean ignore_prev_rms,
int num_tries,
double rad_fraction,
double max_tile_rad,
double fill_fraction,
double fill_fraction_final,
double ease_nosfm,
double double_threshold,
double [] max_rms_iter,
int min_scene,
int debugLevel) {
int [] indices = pairsGraph.getIndices();
boolean batch_mode = true;
// int num_scenes = indices.length;
int num_pairs = 0;
ArrayList<Point> failed_pairs = new ArrayList<Point>();
int ok_dist = 1;
int [] start_ij = {0,0};
int [] next_pair;
while (!pairsGraph.isSingleConnected()) {
next_pair = pairsGraph.suggestPairSingle( // single-connected, no cycles
// add some parameters
heur, // int heur,
ok_dist, // int ok_dist)
start_ij, // int [] start_ij) // = new int [indices.length];
pairsGraph.useMultiThreaded(), // multi,
debugLevel);
if (next_pair == null) {
System.out.println("No pairs suggested, isSingleConnected()="+pairsGraph.isSingleConnected());
break;
}
}
if ((heur & HEUR_DIV_LONG) != 0) {// Try middle of the long connected series
i = i0-1;
for (; i < (groups.length-1); i++) {
if (groups[i+1] != groups[i]) {
// if (pair_state[i][i+1] != 0) { // next is somehow connected
if ((pair_state[i][i+1] != 0) && ((i == 0) || (pair_state[i-1][i] == 0))) { // next is somehow connected, but previous is not
int j = i+1;
int num_cand=0;
for (; (j < groups.length) && (pair_state[i][j] != 0) && (groups[j] != groups[i]); j++) {
if (pair_state[i][j] == PAIR_UNDEFINED) num_cand++;
}
if (num_cand > 0) {
j--; // now j - last connected. Go backward if last connected failed
// find the middle
int kbest = -1;
double best = -1;
for (int k = i+1; k <= j; k++) if (pair_state[i][k] == PAIR_UNDEFINED){
double d = Math.min(timestamps[k]-timestamps[i], timestamps[j]-timestamps[k]);
if (d > best) {
kbest = k;
best = d;
}
}
return new int [] {i,kbest,HEUR_DIV_LONG};
}
}
}
if (next_pair[2] > PairsGraph.HEUR_LAST_SEQ) {
heur &= ~PairsGraph.HEUR_LAST_SEQ;
}
}
if ((heur & (HEUR_MIN_DIA | HEUR_SAME_DIA)) != 0) { // minimal diameter increase (or no increase)
// use pairs, make multithreaded (separate method)
final boolean [] tried = new boolean [pairs.length];
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
// final AtomicInteger astart= new AtomicInteger(0);
final AtomicInteger abest_dia= new AtomicInteger(pair_state.length);
final AtomicBoolean ago = new AtomicBoolean(true);
final int [][] best_row_col= new int [pair_state.length+1][];
final boolean use_min_dia = (heur & HEUR_MIN_DIA) != 0;
final boolean use_same_dia = (heur & HEUR_SAME_DIA) != 0;
final int [] same_row_col = {-1,-1};
// find minimal diameter or first that does not increase it
for (int pass = 0; pass <2; pass++) {
if (pass == 0) {
for (int n = 0; n < pairs.length; n++) if ((pairs[n] != null) && (pairs[n][0]>=start_ij[0])){
if ((pairs[n][0] >start_ij[0]) || (pairs[n][1] > start_ij[1])) {
ai.set(n);
break;
}
}
} else {
ai.set(0); // start from the very beginning on pass 1
if (next_pair[2] > PairsGraph.HEUR_DIV_LONG) {
heur &= ~PairsGraph.HEUR_DIV_LONG;
}
if (next_pair.length > 3) {
ok_dist = next_pair[3];
start_ij[0] = next_pair[0];
start_ij[1] = next_pair[1];
if (debugLevel > 0) {
System.out.println(String.format("%3d: %3d-%3d %2d (%3d)", num_pairs,next_pair[0], next_pair[1],next_pair[2],next_pair[3]));
}
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int n = ai.getAndIncrement(); n < pairs.length; n = ai.getAndIncrement()) if (ago.get() && (pairs[n] != null) && !tried[n]){
tried[n] = true; // for the second pass
int row = pairs[n][0];
int col = pairs[n][1];
if ((pair_state[row][col] == PAIR_UNDEFINED) && (groups[row] != groups[col])) {
int [] dias = newDiameter( // or return a pair - new/old?
pairs[n], // final int [] pair,
dist); // final int [][] dist)
int d = dias[0];
if (use_min_dia && (d <= ok_dist)) {
ago.set(false); // got it, other threads may finish
}
int was_min = abest_dia.getAndAccumulate(dias[0], Math::min);
if (was_min > d) { // I set it
best_row_col[d] = pairs[n];
}
if (use_same_dia && (dias[0] <= dias[1])) {
boolean i_stopped = ago.getAndSet(false);
if (i_stopped) {
same_row_col[0] = pairs[n][0];
same_row_col[1] = pairs[n][1];
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
if (!ago.get()) { // was stopped after condition met (on any pass)
if (same_row_col[0] >= 0) {
return new int [] {same_row_col[0],same_row_col[1], HEUR_SAME_DIA};
} else {
int [] row_col = best_row_col[abest_dia.get()];
return new int [] {row_col[0],row_col[1], HEUR_MIN_DIA, ok_dist}; // keep same distance
}
} else {
if (debugLevel > 0) {
System.out.println(String.format("%3d: %3d-%3d %2d", num_pairs,next_pair[0], next_pair[1],next_pair[2]));
}
} // for (int pass = 0; pass <2; pass++)
if (use_min_dia) {
int [] row_col = best_row_col[abest_dia.get()];
return new int [] {row_col[0],row_col[1], HEUR_MIN_DIA, abest_dia.get()}; // update (increase) best distance
}
}
// just any? Or it is not needed after (heur & HEUR_MIN_DIA)?
return null;
}
public static int [][] updatePairsIndices(
final boolean compact,
final int [][] pairs,
final int [] groups){
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger aindx = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int n = ai.getAndIncrement(); n < pairs.length; n = ai.getAndIncrement())if (pairs[n] != null){
if (groups[pairs[n][0]] == groups[pairs[n][1]]) {
pairs[n] = null;
aindx.getAndIncrement();
}
}
int [] ipair = {indices[next_pair[0]], indices[next_pair[1]]};
if (ipair[0] < min_scene) {
System.out.println ("Skipping "+ipair[0]+":"+ipair[1]+" until "+min_scene);
continue;
}
boolean direct = ipair[0] < ipair[0]; // always?
int min_zoom_lev = ortho_maps[ipair[0]].getOriginalZoomLevel();
int max_zoom_lev = ortho_maps[ipair[0]].getOriginalZoomLevel();
double max_agl = ortho_maps[ipair[0]].getAGL();
for (int i = 0; i < ipair.length; i++) {
max_agl = Math.max(max_agl, ortho_maps[ipair[i]].getAGL());
min_zoom_lev = Math.min(min_zoom_lev, ortho_maps[ipair[i]].getOriginalZoomLevel());
max_zoom_lev = Math.max(max_zoom_lev, ortho_maps[ipair[i]].getOriginalZoomLevel());
}
double agl_ratio = max_agl/50.0;
double metric_error_adj = metric_error * agl_ratio * agl_ratio; // metric_error settings is good for 50m. Increase for higher Maybe squared?
int initial_zoom = max_zoom_lev - 4; // another algorithm?
// overlaps
double overlap_frac = pairsGraph.getOverlap(next_pair);
double overlap_frac_mod = overlap_frac;
double search_range = search_range_in;
while (overlap_frac_mod < double_threshold) {
overlap_frac_mod *= 2;
initial_zoom += 1;
search_range *= 2;
}
// unityAffine()
double [][] affine0 = pmtch_use_affine?ortho_maps[ipair[0]].getAffine():unityAffine(); // {{1,0,0},{0,1,0}}; // will always stay the same
double [][] affine1 = pmtch_use_affine?ortho_maps[ipair[0]].getAffine():unityAffine(); // {{1,0,0},{0,1,0}}; // here (manual mode) start from the center, may use prediction in auto
double [][][] affines = new double[][][] {affine0,affine1};
double spiral_rms = Double.NaN;
// now always unity, but after partial adjustment may be non-unity
// TODO: Not yet tested with intermediate adjustment.
PairwiseOrthoMatch pairwiseOrthoMatch = SpiralMatch (
clt_parameters, // CLTParameters clt_parameters,
frac_remove, // double frac_remove, // = 0.25
metric_error_adj,// double metric_error,
pmtch_use_affine, // boolean pmtch_use_affine,
max_std, // double max_std, // maximal standard deviation to limit center area
min_std_rad, // double min_std_rad, // minimal radius of the central area (if less - fail)
rad_fraction, // double rad_fraction,
max_tile_rad, // double max_tile_rad, // = 30;
fill_fraction, // double fill_fraction,
fill_fraction_final, // double fill_fraction_final,
ease_nosfm, // double ease_nosfm,
ipair, // int [] gpu_pair,
affines, // double [][][] affines_init, // here in meters, relative to vertical points
initial_zoom, // int zoom_lev,
search_step, // double pix_step,
search_range, // double pix_range,
good_rms, // double good_rms,
max_rms, // double max_rms,
num_iter_lma, // int num_tries, // = 5
min_overlap, // int min_overlap, // 3000
ignore_rms, // boolean ignore_rms,
max_rms_iter, // double [] max_rms_iter, // = {1.0, 0.6};//
overlap_frac, // double overlap, // OR IS IT overlap_frac_mod ?
spiral_debug); // int debugLevel)
Point pair = new Point(next_pair[0],next_pair[1]);
boolean success = (pairwiseOrthoMatch != null) && !Double.isNaN(pairwiseOrthoMatch.rms);
if (!success) { // not yet add to pairsGraph until verified with high-res
String str_failed = "%4d\t%4d\t%s\t%s\t%6.4f\t%3d\tFAILED\n";
if (log_append && (log_path != null)) { // assuming directory exists
StringBuffer sb = new StringBuffer();
sb.append(String.format(str_failed,
ipair[0], ipair[1], ortho_maps[ipair[0]].getName(), ortho_maps[ipair[1]].getName(),
overlap_frac,
initial_zoom));
CalibrationFileManagement.saveStringToFile (
log_path, //String path,
sb.toString(), // data,
true); // boolean append)
}
};
}
ImageDtt.startAndJoin(threads);
if (compact) {
final int [][] pairs_compact = new int [pairs.length - aindx.get()][];
ai.set(0);
aindx.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int n = ai.getAndIncrement(); n < pairs.length; n = ai.getAndIncrement()) if (pairs[n] != null){
pairs_compact[aindx.getAndIncrement()] = pairs[n];
failed_pairs.add(pair);
// continue;
} else { // success!
spiral_rms = pairwiseOrthoMatch.rms;
// new_pairs.add(pair); // adjusted with spiral
// refine match with high resolution
affines[1] = pairwiseOrthoMatch.getAffine();
affines[1][0] = affines[1][0].clone();
affines[1][1] = affines[1][1].clone();
Rectangle woi = new Rectangle(); // used to return actual woi from correlateOrthoPair()
correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
pairwiseOrthoMatch, //PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
0, // int min_overlap,
max_std, // double max_std, // maximal standard deviation to limit center area
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_adj,// double metric_error,
ignore_prev_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,
ipair, // String [] gpu_spair,
affines, // double [][][] affines, // on top of GPS offsets
woi, // Rectangle woi,
min_zoom_lev, // int zoom_lev,
false, // show_vf, // boolean show_vf,
null, // ground_planes, // double [][] ground_planes, // null or double[2] - will return ground planes
rad_fraction, // double rad_fraction,
max_tile_rad, // double max_tile_rad, // = 30;
fill_fraction, // double fill_fraction,
fill_fraction_final, // double fill_fraction_final,
ease_nosfm, // double ease_nosfm,
null, // double [] max_rms_iter, // = {1.0, 0.6};//
debugLevel-4); // final int debugLevel)
boolean failed_refine = Double.isNaN(pairwiseOrthoMatch.rms) || (pairwiseOrthoMatch.rms > max_rms_refine);
// Create log line and write it
StringBuffer sb = new StringBuffer();
sb.append(String.format("%4d\t%4d\t%s\t%s\t%6.4f\t%3d",
ipair[0], ipair[1], ortho_maps[ipair[0]].getName(), ortho_maps[ipair[1]].getName(),
overlap_frac, initial_zoom));
sb.append(String.format("\t%3d\t%3d\t%6.4f",
pairwiseOrthoMatch.nxy[0],pairwiseOrthoMatch.nxy[1],spiral_rms));
if (failed_refine) {
String str_failed = String.format("\t%6.4f\tFAILED\n",pairwiseOrthoMatch.rms);
failed_pairs.add(pair);
sb.append(String.format(str_failed));
if (debugLevel > -4) System.out.print("Final adjustment"+str_failed);
} else {
pairwiseOrthoMatch.overlap = overlap_frac; // needed here if refining old/manual w/o overlap
sb.append(String.format("\t%6.4f\t%3d\n",pairwiseOrthoMatch.rms,pairwiseOrthoMatch.zoom_lev));
if (debugLevel > -4) System.out.println("Final adjustment RMSE="+pairwiseOrthoMatch.rms+
", overlap = "+pairwiseOrthoMatch.overlap);
ortho_maps[ipair[0]].setMatch(ortho_maps[ipair[1]].getName(),pairwiseOrthoMatch);
if (save_each && (orthoMapsCollection_path != null)) {
try {
writeOrthoMapsCollection(orthoMapsCollection_path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}
ImageDtt.startAndJoin(threads);
return pairs_compact;
}
return pairs;
}
public static int [][] getPairsIndices(
final int [][] pair_state,
final int [] groups){
final int n = pair_state.length;
final int n2 = n * n;
final int [][] pairs0 = new int[n * (n-1) / 2][];
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger aindx = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int i = ai.getAndIncrement(); i < n2; i = ai.getAndIncrement()){
int row = i / n;
int col = i % n;
if ((col > row ) && (groups[col] != groups[row]) && (pair_state[row][col] == PAIR_UNDEFINED)) {
int indx = aindx.getAndIncrement();
pairs0[indx] = new int[] {row,col};
if (debugLevel > -4) {
System.out.println("Saved data to "+ orthoMapsCollection_path);
}
}
}
};
}
ImageDtt.startAndJoin(threads);
ai.set(0);
final int [][] pairs = new int [aindx.get()][2];
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int i = ai.getAndIncrement(); i < pairs.length; i = ai.getAndIncrement()){
pairs[i][0] = pairs0[i][0];
pairs[i][1] = pairs0[i][1];
}
if (log_append && (log_path != null)) { // assuming directory exists
CalibrationFileManagement.saveStringToFile (
log_path, //String path,
sb.toString(), // data,
true); // boolean append)
}
};
}
ImageDtt.startAndJoin(threads);
return pairs;
}
public static void recordPair(
int [] pair,
boolean success,
int [][] pair_state,// = new int [indices.length][indices.length];
int [] groups, // = new int [indices.length];
int [][] dist) { // = new int [indices.length];
int i = pair[0], j = pair[1];
if (success) {
pair_state[i][j] = PAIR_DEFINED;
// merge groups
if (groups[i] != groups[j]) {
int g0 = Math.min(groups[i], groups[j]);
int g1 = Math.max(groups[i], groups[j]);
for (int k = 0; k < groups.length; k++) {
if (groups[k] == g1) {
groups[k] = g0;
}
success &= !failed_refine;
}
pairsGraph.recordPair(
next_pair, // int [] pair,
success, // boolean success,
pairsGraph.useMultiThreaded());
if (success) {
num_pairs++;
}
} // next pair
if (log_append && (log_path != null)) { // assuming directory exists
StringBuffer sb = new StringBuffer();
sb.append("\nSUMMARY\n");
sb.append("new\t"+ num_pairs+"\n");
// sb.append("new\t"+ new_pairs.size()+"\n");
sb.append("failed\t"+failed_pairs.size()+"\n");
if (!failed_pairs.isEmpty()) {
for (int i = 0; i < failed_pairs.size(); i++) {
int [] ipair = {indices[failed_pairs.get(i).x], indices[failed_pairs.get(i).y]};
sb.append(String.format("%4d\t%4d\t%s\t%s\n",
ipair[0], ipair[1], ortho_maps[ipair[0]].getName(), ortho_maps[ipair[1]].getName()));
}
}
updateDistance(
pair, // final int [] pair,
dist); // final int [][] dist)
} else {
pair_state[i][j] = PAIR_FAILED;
CalibrationFileManagement.saveStringToFile (
log_path, //String path,
sb.toString(), // data,
true); // boolean append)
if (debugLevel > -4) {
System.out.println("Appended log file "+ log_path);
}
}
}
public static void updateDistance(
final int [] pair,
final int [][] dist) { // symmetrical
final int i = pair[0], j = pair[1];
final int [][] dist2 = {dist[i].clone(),dist[j].clone()};
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() {
// pair should be disconnected, so n from one thread != m from the other
for (int n = ai.getAndIncrement(); n < dist.length; n = ai.getAndIncrement()) if ((dist2[0][n] > 0) || (n == i)){
int d1 = dist2[0][n]+1;
for (int m = 0; m < dist.length; m++) if ((dist2[1][m] > 0) || ((m == j) && (n != i))){
int d = d1+ dist2[1][m];
dist[n][m] = d;
dist[m][n] = d;
}
}
}
};
}
ImageDtt.startAndJoin(threads);
dist[i][j] = 1;
dist[j][i] = 1;
return;
}
public static int [] newDiameter( // or return a pair - new/old?
final int [] pair,
final int [][] dist) { // symmetrical
final int i = pair[0], j = pair[1];
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger amax_new = new AtomicInteger(0);
final AtomicInteger amax_old = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int n = ai.getAndIncrement(); n < dist.length; n = ai.getAndIncrement()) if ((dist[i][n] > 0) || (n==i)){
int d1 = dist[i][n]+1;
amax_new.getAndAccumulate(d1, Math::max);
int mx = d1-1;
for (int m = 0; m < dist.length; m++) if (dist[j][m] > 0){
int d = d1+ dist[j][m];
amax_new.getAndAccumulate(d, Math::max);
mx = Math.max(mx, dist[j][m]);
}
amax_old.getAndAccumulate(mx, Math::max);
}
}
};
}
ImageDtt.startAndJoin(threads);
return new int [] {amax_new.get(),amax_old.get()};
}
public static int [] newDiameterSingleThread( // or return a pair - new/old?
final int [] pair,
final int [][] dist) { // symmetrical
final int i = pair[0], j = pair[1];
int max_new = 0, max_old = 0;
for (int n = 0; n < dist.length; n++) if ((dist[i][n] > 0) || (n==i)){
int d1 = dist[i][n]+1;
max_new = Math.max(max_new, d1);
max_old = Math.max(max_old, d1-1);
for (int m = 0; m < dist.length; m++) if (dist[j][m] > 0){
int d = d1+ dist[j][m];
max_new = Math.max(max_new, d);
max_old = Math.max(max_old, dist[j][m]);
}
if (orthoMapsCollection_path != null) {
try {
writeOrthoMapsCollection(orthoMapsCollection_path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (debugLevel > -4) {
System.out.println("Saved data to "+ orthoMapsCollection_path);
}
}
return new int [] {max_new,max_old};
return true;
}
public boolean processComboMap(
CLTParameters clt_parameters,
int debugLevel) {
......@@ -5740,6 +5600,7 @@ public class OrthoMapsCollection implements Serializable{
}
return true;
}
public boolean processComboSelection(
CLTParameters clt_parameters,
int [] indices,
......
......@@ -29,6 +29,8 @@ import java.awt.Point;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import com.elphel.imagej.cameras.CLTParameters;
......@@ -218,6 +220,7 @@ public class OrthoMultiLMA {
OrthoMapsCollection maps_collection,
String orthoMapsCollection_path
) {
boolean all_pairs = true;
boolean move_only = clt_parameters.imp.pmap_move_only; // false;
boolean ignore_affines = clt_parameters.imp.pmap_ignore_affines; // false;
boolean use_inv = clt_parameters.imp.pmap_use_inv; // false;
......@@ -232,22 +235,23 @@ public class OrthoMultiLMA {
int debugLevel = clt_parameters.imp.pmap_debugLevel; // 2;
GenericJTabbedDialog gd = new GenericJTabbedDialog("Pairwise Match Parameters",1200,400);
gd.addCheckbox ("Use all available pairs", all_pairs, "Use all available pairs.");
gd.addCheckbox ("Moves only", move_only, "Moves only, no affine transform.");
gd.addCheckbox ("Ignore existing affines", ignore_affines, "Start from unity matrices, ignore saved affines.");
gd.addCheckbox ("Use reversed pairs", use_inv, "Use reversed (late-early timestamps) pairs.");
gd.addNumericField("Skew pull", skew_pull, 7,10,"", "Intention to have axes perpendicular.");
gd.addNumericField("Tilt pull", tilt_pull, 7,10,"", "Intention to have axes same length.");
gd.addNumericField("Scale pull", scale_pull, 7,10,"", "Intention to have average scale of images = 1.0.");
gd.addNumericField("Position pull", position_pull,7,10,"", "Intension to match IMS (GNSS) coordinates.");
gd.addNumericField("Skew pull", skew_pull, 7,11,"", "Intention to have axes perpendicular.");
gd.addNumericField("Tilt pull", tilt_pull, 7,11,"", "Intention to have axes same length.");
gd.addNumericField("Scale pull", scale_pull, 7,11,"", "Intention to have average scale of images = 1.0.");
gd.addNumericField("Position pull", position_pull,7,11,"", "Intension to match IMS (GNSS) coordinates.");
gd.addNumericField("Overlap inportance", overlap_pow, 3,7,"", "Raise overlap fraction (of the smaller image) to this power before using as weight.");
gd.addNumericField("RMSE relative improvement",rms_diff, 8,10,"", "Relative RMSE improvement to exit LMA.");
gd.addNumericField("RMSE relative improvement",rms_diff, 8,11,"", "Relative RMSE improvement to exit LMA.");
gd.addNumericField("LMA iterations", num_iter, 0,3,"",".Maximal number of the LMA iterations.");
gd.addCheckbox ("Show result image", show_result, ".");
gd.addNumericField("Debug level for maps", debugLevel, 0,3,"","Debug building for LMA building maps.");
gd.showDialog();
if (gd.wasCanceled()) return -1;
all_pairs = gd.getNextBoolean();
move_only = gd.getNextBoolean();
ignore_affines = gd.getNextBoolean();
use_inv = gd.getNextBoolean();
......@@ -265,6 +269,7 @@ public class OrthoMultiLMA {
clt_parameters, // CLTParameters clt_parameters,
maps_collection, // OrthoMapsCollection maps_collection,
orthoMapsCollection_path, // String orthoMapsCollection_path,
all_pairs, // boolean all_pairs,
move_only, // boolean move_only,
ignore_affines, // boolean ignore_affines,
use_inv, // boolean use_inv,
......@@ -282,6 +287,7 @@ public class OrthoMultiLMA {
CLTParameters clt_parameters,
OrthoMapsCollection maps_collection,
String orthoMapsCollection_path,
boolean all_pairs,
boolean move_only,
boolean ignore_affines,
boolean use_inv,
......@@ -296,9 +302,37 @@ public class OrthoMultiLMA {
int debugLevel) {
double [] val_coord = null; // 1 - valid, 0 - invalid, minimize coordinates errors
boolean corr_avg= (skew_pull > 0) || (tilt_pull > 0) || (scale_pull > 0);
int [] indices = maps_collection.getScenesSelection(
null, // boolean select_all,
" to build a map"); // String purpose)
int [] indices = null;
if (all_pairs) {
boolean [] used_scenes = new boolean [maps_collection.ortho_maps.length];
for (int scene0 = 0; scene0 < (used_scenes.length-1); scene0++) {
Set<String> match_names = maps_collection.ortho_maps[scene0].pairwise_matches.keySet();
for (String scene1_name:match_names) {
PairwiseOrthoMatch match = maps_collection.ortho_maps[scene0].getMatch(scene1_name); // defined only
if (match != null) {
int scene1 = maps_collection.getIndex(scene1_name);
used_scenes[scene0] = true;
used_scenes[scene1] = true;
}
}
}
int num_scenes = 0;
for (int i = 0; i < used_scenes.length; i++) if (used_scenes[i]){
num_scenes++;
}
indices = new int [num_scenes];
int indx = 0;
for (int i = 0; i < used_scenes.length; i++) if (used_scenes[i]){
indices[indx++] = i;
}
if (debugLevel > -1) {
System.out.println("buildOrthoMap(): got "+indices.length+" scenes with pairs");
}
} else {
indices = maps_collection.getScenesSelection(
null, // boolean select_all,
" to build a map with LMA from pair-wise matches"); // String purpose)
}
OrthoMultiLMA oml = new OrthoMultiLMA(
corr_avg,
move_only);
......
......@@ -57,6 +57,8 @@ public class PairsGraph {
public PairsGraph (
OrthoMapsCollection orthoMapsCollection,
int [] indices,
double min_overlap_frac,
double max_rmse_reuse,
boolean multi,
int debugLevel) {
this.orthoMapsCollection = orthoMapsCollection;
......@@ -75,40 +77,70 @@ public class PairsGraph {
}
int num_defined = 0;
int num_undefined = 0;
int num_bad = 0;
int num_low_overlap = 0;
for (int i = 0; i < indices.length-1; i++) {
for (int j = i+1; j < indices.length; j++){
String name2 = ortho_maps[indices[j]].getName();
PairwiseOrthoMatch match = ortho_maps[indices[i]].getMatch(name2,true);
if (match != null) {
if (match.isDefined()) {
pair_state[i][j] = PAIR_DEFINED;
num_defined++;
recordPair(
new int [] {i,j}, // int [] pair,
true, // boolean success,
multi);
if (match.getOverlap() < min_overlap_frac){
num_low_overlap++;
} else {
pair_state[i][j] = PAIR_UNDEFINED;
num_undefined++;
if (match.isDefined()) {
if ((match.getOverlap() < min_overlap_frac) || ((max_rmse_reuse > 0) && !(match.getRMS() <= max_rmse_reuse))) {
pair_state[i][j] = PAIR_UNDEFINED;
num_undefined++;
num_bad++;
} else {
pair_state[i][j] = PAIR_DEFINED;
num_defined++;
recordPair(
new int [] {i,j}, // int [] pair,
true, // boolean success,
multi);
}
} else {
pair_state[i][j] = PAIR_UNDEFINED;
num_undefined++;
}
overlaps[i][j] = match.getOverlap();
}
overlaps[i][j] = match.getOverlap();
}
}
}
HashSet<Integer> hs = new HashSet<Integer>();
for (int i:groups) {
hs.add(i);
}
pairs = multi? getPairsIndicesMulti():getPairsIndicesSingle();
if (debugLevel > 0) {
if (debugLevel > -1) {
System.out.println("Number of scenes - "+indices.length);
System.out.println("Number of defined pairs - "+num_defined);
System.out.println("Number of undefined pairs - "+num_undefined);
System.out.println("Number of disconnected groups - "+hs.size());
System.out.println("Number of low overlap pairs ("+min_overlap_frac+") - "+num_low_overlap);
System.out.println("Number of bad rms pairs ("+max_rmse_reuse+") - "+num_bad);
System.out.println("Number of disconnected groups - "+getNumberOfGroups());
}
}
public int getNumberOfGroups() {
HashSet<Integer> hs = new HashSet<Integer>();
for (int i:groups) {
hs.add(i);
}
return hs.size();
}
public int [] getIndices() {
return indices;
}
public boolean useMultiThreaded() {
return multi;
}
public double getOverlap(
int [] pair) {
return overlaps[Math.min(pair[0],pair[1])][Math.max(pair[0],pair[1])];
}
public boolean dryRun(
int heur,
int debugLevel) {
......
......@@ -37,6 +37,9 @@ public class PairwiseOrthoMatch implements Serializable {
this.rms = rms;
this.overlap = overlap;
}
public double getRMS() {
return this.rms;
}
public boolean isDefined() {
return affine != null;
......
......@@ -143,6 +143,7 @@ public class IntersceneMatchParameters {
// pairwise match parameters
public int pwise_zoom = -5;
public double pwise_overlap = 0.25;
public double pwise_max_rms = 0.6; // maximal acceptable LMA RMS - best during refine
public boolean pwise_skip_exist = true;
public boolean pwise_refine_exist = true; // if false, start from scratch, true - start from previous
public boolean pwise_delete_fail = true; // delete existing match if now failed
......@@ -795,7 +796,7 @@ public class IntersceneMatchParameters {
gd.addNumericField("Spiral search radius", this.ospir_range, 3,7,"scaled pix", "Maximal radius of the spiral search, in scaled pixels.");
gd.addNumericField("Mitigate small overlap", this.ospir_double, 3,7,"","For small overlaps increase zoom by 1 and range - twice.");
gd.addNumericField("RMSE to end search", this.ospir_good_rms, 3,7,"scaled pix", "Maximal RMSE to consider match, in scaled pixels.");
gd.addNumericField("Satisfactory RMSE", this.ospir_max_rms, 3,7,"scaled pix", "Maximal RMSE to consider match, in scaled pixels.");
gd.addNumericField("Satisfactory RMSE, spiral", this.ospir_max_rms, 3,7,"scaled pix", "Maximal RMSE to consider match, in scaled pixels, during spiral.");
gd.addNumericField("Minimal overlap", this.ospir_overlap, 0,4,"scaled pix ^ 2","Minimal overlap area in square scaled pixels.");
gd.addNumericField("LMA iterations", this.ospir_num_iter, 0,2,"", "Number of LMA iterations during spiral search.");
gd.addNumericField("RMSE at first iteration", this.ospir_rms_iter[0], 3,7,"scaled pix","Maximal RMSE at first iteration.");
......@@ -806,6 +807,7 @@ public class IntersceneMatchParameters {
gd.addMessage ("Pairwise image matching");
gd.addNumericField("Zoom level", this.pwise_zoom, 0,3,"","Low-res images to determine overlaps.");
gd.addNumericField("Minimal overlap fraction", this.pwise_overlap, 3,7,"", "Minimal overlap area as a fraction of the smaller of the two images.");
gd.addNumericField("Satisfactory RMSE, refine", this.pwise_max_rms, 3,7,"scaled pix", "Maximal RMSE to consider match, in scaled pixels, during refine (high res).");
gd.addCheckbox ("Skip existing", this.pwise_skip_exist, "Do not regenerate if match with same or higher resolution exists.");
gd.addCheckbox ("Refine existing", this.pwise_refine_exist, "Refine existing matches (false - start from scratch with spiral search).");
gd.addCheckbox ("Delete failed", this.pwise_delete_fail, "Delete previous matches if it failed now.");
......@@ -819,13 +821,13 @@ public class IntersceneMatchParameters {
gd.addCheckbox ("Moves only", this.pmap_move_only, "Moves only, no affine transform.");
gd.addCheckbox ("Ignore existing affines", this.pmap_ignore_affines, "Start from unity matrices, ignore saved affines.");
gd.addCheckbox ("Use reversed pairs", this.pmap_use_inv, "Use reversed (late-early timestamps) pairs.");
gd.addNumericField("Skew pull", this.pmap_skew_pull, 3,7,"", "Intention to have axes perpendicular.");
gd.addNumericField("Tilt pull", this.pmap_tilt_pull, 3,7,"", "Intention to have axes same length.");
gd.addNumericField("Scale pull", this.pmap_scale_pull, 3,7,"", "Intention to have average scale of images = 1.0.");
gd.addNumericField("Position pull", this.pmap_position_pull, 3,7,"", "Intension to match IMS (GNSS) coordinates.");
gd.addNumericField("Skew pull", this.pmap_skew_pull, 7,11,"", "Intention to have axes perpendicular.");
gd.addNumericField("Tilt pull", this.pmap_tilt_pull, 7,11,"", "Intention to have axes same length.");
gd.addNumericField("Scale pull", this.pmap_scale_pull, 7,11,"", "Intention to have average scale of images = 1.0.");
gd.addNumericField("Position pull", this.pmap_position_pull,7,11,"", "Intension to match IMS (GNSS) coordinates.");
gd.addNumericField("Overlap inportance", this.pmap_overlap_pow, 3,7,"", "Raise overlap fraction (of the smaller image) to this power before using as weight.");
gd.addNumericField("RMSE relative improvement", this.pmap_rms_diff, 3,7,"", "Relative RMSE improvement to exit LMA.");
gd.addNumericField("LMA iterations", this.pmap_num_iter, 0,3,"",".Maximal number of the LMA iterations.");
gd.addNumericField("RMSE relative improvement", this.pmap_rms_diff, 8,11,"", "Relative RMSE improvement to exit LMA.");
gd.addNumericField("LMA iterations", this.pmap_num_iter, 0,3,"",".Maximal number of the LMA iterations.");
gd.addCheckbox ("Show result image", this.pmap_show_result, ".");
gd.addNumericField("Debug level for maps", this.pmap_debugLevel, 0,3,"","Debug building for LMA building maps.");
......@@ -1721,6 +1723,7 @@ public class IntersceneMatchParameters {
this.pwise_zoom = (int) gd.getNextNumber();
this.pwise_overlap = gd.getNextNumber();
this.pwise_max_rms = gd.getNextNumber();
this.pwise_skip_exist = gd.getNextBoolean();
this.pwise_refine_exist = gd.getNextBoolean();
this.pwise_delete_fail = gd.getNextBoolean();
......@@ -2249,6 +2252,8 @@ public class IntersceneMatchParameters {
properties.setProperty(prefix+"pwise_zoom", this.pwise_zoom + ""); // int
properties.setProperty(prefix+"pwise_overlap", this.pwise_overlap + ""); // double
properties.setProperty(prefix+"pwise_max_rms", this.pwise_max_rms + ""); // double
properties.setProperty(prefix+"pwise_skip_exist", this.pwise_skip_exist + ""); // boolean
properties.setProperty(prefix+"pwise_refine_exist", this.pwise_refine_exist + ""); // boolean
properties.setProperty(prefix+"pwise_delete_fail", this.pwise_delete_fail + ""); // boolean
......@@ -2740,6 +2745,8 @@ public class IntersceneMatchParameters {
if (properties.getProperty(prefix+"pwise_zoom")!=null) this.pwise_zoom=Integer.parseInt(properties.getProperty(prefix+ "pwise_zoom"));
if (properties.getProperty(prefix+"pwise_overlap")!=null) this.pwise_overlap=Double.parseDouble(properties.getProperty(prefix+ "pwise_overlap"));
if (properties.getProperty(prefix+"pwise_max_rms")!=null) this.pwise_max_rms=Double.parseDouble(properties.getProperty(prefix+ "pwise_max_rms"));
if (properties.getProperty(prefix+"pwise_skip_exist")!=null) this.pwise_skip_exist=Boolean.parseBoolean(properties.getProperty(prefix+ "pwise_skip_exist"));
if (properties.getProperty(prefix+"pwise_refine_exist")!=null) this.pwise_refine_exist=Boolean.parseBoolean(properties.getProperty(prefix+"pwise_refine_exist"));
if (properties.getProperty(prefix+"pwise_delete_fail")!=null) this.pwise_delete_fail=Boolean.parseBoolean(properties.getProperty(prefix+ "pwise_delete_fail"));
......@@ -3257,6 +3264,7 @@ public class IntersceneMatchParameters {
imp.pwise_zoom = this.pwise_zoom;
imp.pwise_overlap = this.pwise_overlap;
imp.pwise_max_rms = this.pwise_max_rms;
imp.pwise_skip_exist = this.pwise_skip_exist;
imp.pwise_refine_exist = this.pwise_refine_exist;
imp.pwise_delete_fail = this.pwise_delete_fail;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment