Commit 5e03168f authored by Andrey Filippov's avatar Andrey Filippov

Fixed affine inversion

parent 0da53711
......@@ -805,12 +805,26 @@ public class ComboMatch {
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;
}
gpu_spair = new String[] {scene_name};
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,
default_choice1, // int default_choice,
num_scene_lines); // int num_choice_lines)
if (scene_name1 == null) {
return false;
}
gpu_spair = new String[] {scene_name, scene_name1};
} else { // pattern match - single image
gpu_spair = new String[] {scene_name};
}
} else {
gpu_spair = new String[] {
maps_collection.ortho_maps[available_pairs[pair][0]].getName(),
......@@ -818,15 +832,19 @@ public class ComboMatch {
}
}
int [] gpu_pair = new int[gpu_spair.length];
for (int i = 0; i < gpu_pair.length; i++) {
gpu_pair[i] = maps_collection.getIndex(gpu_spair[i]);
}
int min_zoom_lev = maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel();
int max_zoom_lev = maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel();
double max_agl = maps_collection.ortho_maps[gpu_pair[0]].getAGL();
for (int i = 0; i < gpu_pair.length; i++) {
gpu_pair[i] = maps_collection.getIndex(gpu_spair[i]);
max_agl = Math.max(max_agl, maps_collection.ortho_maps[gpu_pair[i]].getAGL());
min_zoom_lev = Math.min(min_zoom_lev, maps_collection.ortho_maps[gpu_pair[i]].getOriginalZoomLevel());
max_zoom_lev = Math.max(max_zoom_lev, maps_collection.ortho_maps[gpu_pair[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?
System.out.println("Setting up GPU");
......@@ -849,7 +867,7 @@ public class ComboMatch {
double [][] affine1 = null;
if (gpu_spair.length < 2) {
System.out.println("Selected a single image");
System.out.println("Selected a single image, not a pair");
double [][][] affines = {affine0}; // or use affine1 = null as second?
if (pattern_match) {
ImagePlus imp_pat_match = maps_collection.patternMatchDualWrap (
......@@ -861,8 +879,22 @@ public class ComboMatch {
}
} else {
pairwiseOrthoMatch = maps_collection.ortho_maps[gpu_pair[0]].getMatch(
maps_collection.ortho_maps[gpu_pair[1]].getName());
if (process_correlation && !use_marked_image) { // match may or may not exist
// if match exists - ask if use it. If not - open dialog and start spiral
pairwiseOrthoMatch = initialPairAdjust(
clt_parameters, // CLTParameters clt_parameters,
maps_collection, // OrthoMapsCollection maps_collection,
frac_remove, // double frac_remove, // = 0.25
metric_error_adj,// double metric_error,
gpu_spair, // String[] gpu_spair,
debugLevel); // int debugLevel)
if (pairwiseOrthoMatch == null) { // if OK - either match existed or created by SpiralMatch()
return false;
}
} else {
pairwiseOrthoMatch = maps_collection.ortho_maps[gpu_pair[0]].getMatch(
maps_collection.ortho_maps[gpu_pair[1]].getName());
}
if (pairwiseOrthoMatch == null) {
System.out.println("No correlation data is available for pairs "+gpu_spair[0]+
" - "+gpu_spair[1]+" need to implement/search reverse, a spiral search or restart command");
......@@ -874,8 +906,10 @@ public class ComboMatch {
int [] zooms = {initial_zoom, min_zoom_lev, 1000,1000}; // make automatic
double scale = 2.0; // scale vectors when warping;
// int num_tries = 5; // make configurable
if (!process_correlation) {
if (!process_correlation || !use_marked_image) { // skip low-res
zooms = new int[] {min_zoom_lev, 1000};
}
if (!process_correlation) { // 0 LMA adjustments
num_tries_fit = 0;
update_match = false;
}
......@@ -884,24 +918,31 @@ public class ComboMatch {
boolean ignore_prev_rms = true;
Rectangle woi = new Rectangle(); // used to return actual woi from correlateOrthoPair()
double [][] ground_planes = null;
double max_std = 1.5; // maximal standard deviation to limit center area
double min_std_rad = 2.0; // minimal radius of the central area (if less - fail)
for (int zi = 0; zi < zooms.length; zi++) {
zoom_lev = zooms[zi];
if (zoom_lev >=1000) {
break;
}
boolean show_vf = render_match || pattern_match;
boolean show_vf = false; // render_match || pattern_match;
if (render_match || pattern_match) {
ground_planes = new double [gpu_pair.length][];
}
// will modify affines[1], later add jtj, weight, smth. else?
PairwiseOrthoMatch pmatch = process_correlation? pairwiseOrthoMatch: null;
FineXYCorr warp = maps_collection.correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
(process_correlation? pairwiseOrthoMatch: null), //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, // double metric_error,
metric_error_adj,// double metric_error,
ignore_prev_rms, // boolean ignore_prev_rms,
num_tries_fit, // = 5int num_tries, // = 5
true, // boolean calc_warp,
true, // boolean calc_warp, (will return null if false)
batch_mode, // boolean batch_mode,
gpu_pair, // String [] gpu_spair,
affines, // double [][][] affines, // on top of GPS offsets
......@@ -910,7 +951,7 @@ public class ComboMatch {
show_vf, // boolean show_vf,
ground_planes, // double [][] ground_planes, // null or double[2] - will return ground planes
debugLevel); // final int debugLevel)
if (warp == null) {
if ((warp == null) || ((pmatch != null) && Double.isNaN(pmatch.rms))) {
System.out.println("Failed correlateOrthoPair()");
return false;
}
......@@ -948,10 +989,10 @@ public class ComboMatch {
// imp_pat_match.show();
}
if (render_match) {
String title=String.format("multi_%03d-%03d_%s-%s_zoom%d_%d",gpu_pair[0],gpu_pair[1],gpu_spair[0],gpu_spair[1],min_zoom_lev,zoom_lev);
ImagePlus imp_img_pair = maps_collection.renderMulti (
//_zoom<integer> is needed for opening with "Extract Objects" command
"multi_"+gpu_spair[0]+"-"+gpu_spair[1]+"_zoom"+min_zoom_lev+"_"+zoom_lev, // String title,
// false, // boolean use_alt,
title, // String title,
OrthoMapsCollection.MODE_IMAGE, // int mode, // 0 - regular image, 1 - altitudes, 2 - black/white mask // boolean use_alt,
gpu_pair, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
bounds_to_indices, // boolean bounds_to_indices,
......@@ -978,6 +1019,98 @@ public class ComboMatch {
}
return true;
}
public static PairwiseOrthoMatch initialPairAdjust(
CLTParameters clt_parameters,
OrthoMapsCollection maps_collection,
double frac_remove, // = 0.25
double metric_error,
String[] gpu_spair,
int debugLevel) {
int [] gpu_pair = new int[gpu_spair.length];
gpu_pair[0] = maps_collection.getIndex(gpu_spair[0]);
int min_zoom_lev = maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel();
int max_zoom_lev = maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel();
for (int i = 0; i < gpu_pair.length; i++) {
gpu_pair[i] = maps_collection.getIndex(gpu_spair[i]);
min_zoom_lev = Math.min(min_zoom_lev, maps_collection.ortho_maps[gpu_pair[i]].getOriginalZoomLevel());
max_zoom_lev = Math.max(max_zoom_lev, maps_collection.ortho_maps[gpu_pair[i]].getOriginalZoomLevel());
}
int initial_zoom = max_zoom_lev - 4; // another algorithm?
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;
GenericJTabbedDialog gd = new GenericJTabbedDialog("Setup SpiralMatch",1200,900);
if (pairwiseOrthoMatch != null) {
gd.addCheckbox ("Use existing image pair", use_exixting_pair, "Use existing affine settings for this pair, do not use spiral search.");
}
if (inv_match != null) {
gd.addCheckbox ("Invert existing image pair", invert_exixting_pair, "Invert existing image pair affine transform, do not use spiral search.");
}
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("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.showDialog();
if (gd.wasCanceled()) return null;
if (pairwiseOrthoMatch != null) {
use_exixting_pair = gd.getNextBoolean();
}
if (inv_match != null) {
invert_exixting_pair = gd.getNextBoolean();
}
search_step= gd.getNextNumber();
search_range= gd.getNextNumber();
maximal_rms = gd.getNextNumber();
min_overlap = (int) gd.getNextNumber();
num_iter_lma = (int) gd.getNextNumber();
if (use_exixting_pair) {
if (invert_exixting_pair) {
System.out.println("Both direct and inverted matches are selected, using direct match");
}
return pairwiseOrthoMatch;
} else if (invert_exixting_pair) {
double [] enuOffset = maps_collection.ortho_maps[gpu_pair[0]].enuOffsetTo(maps_collection.ortho_maps[gpu_pair[1]]);
double [] rd = {enuOffset[0], -enuOffset[1]}; // {right,down} of the image
// create inverted pairwiseOrthoMatch - move to PairwiseOrthoMatch
return inv_match.getInverse(rd);
}
double [][] affine0 = {{1,0,0},{0,1,0}}; // will always stay the same
double [][] affine1 = {{1,0,0},{0,1,0}}; // here (manual mode) start from the center, may use prediction in auto
double [][][] affines = new double[][][] {affine0,affine1};
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,
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,
maximal_rms, // double need_rms,
num_iter_lma, // int num_tries, // = 5
min_overlap, // int min_overlap, // 3000
debugLevel); // int debugLevel){
return pairwiseOrthoMatch;
}
public static boolean updateBlBcFileNames(
String suffix,
......@@ -1375,7 +1508,9 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
// get TD interscene correlation of 2 scenes, use only combo (all channels) data
TDCorrTile [] corr_tiles = TDCorrTile.getFromGpu(
GPU_QUAD_AFFINE);
double neib_radius = clt_parameters.imp.rln_neib_radius;;
// depends on zoom level
double neib_radius = clt_parameters.imp.rln_neib_radius;
boolean rln_neibs_fill = clt_parameters.imp.rln_neibs_fill;
double rln_fat_zero = clt_parameters.imp.rln_fat_zero;
boolean rln_use_neibs = clt_parameters.imp.rln_use_neibs;
......@@ -1384,6 +1519,14 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
double rln_sngl_rstr = clt_parameters.imp.rln_sngl_rstr;
double rln_neib_rstr = clt_parameters.imp.rln_neib_rstr;
double max_neib_radius = Math.min(woi.width, woi.height)/GPUTileProcessor.DTT_SIZE * clt_parameters.imp.rln_radius_frac;
if (neib_radius > max_neib_radius) {
neib_radius = max_neib_radius;
}
double [][][] corr_tiles_pd = new double [(neib_radius>0)? 2: 1][][];
// use TDCorrTile.calcNeibs() here to get 8-neighbors
corr_tiles_pd[0] = TDCorrTile.convertTDtoPD(
......
......@@ -3005,6 +3005,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
}
return true;
}
public static double [][] combineAffine(
double [][] ref_affine,
double [][] other_affine){
......@@ -3021,6 +3022,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
{A.get(1,0),A.get(1,1),B.get(1,0)}};
return affine;
}
/**
......
......@@ -985,6 +985,86 @@ public class OrthoMapsCollection implements Serializable{
return null;
} */
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,
double [][][] affines_init, // here in meters, relative to vertical points
int zoom_lev,
double pix_step,
double pix_range,
double need_rms,
int num_tries, // = 5
int min_overlap, // = 5
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)
int nabs = (int) Math.ceil(pix_range/pix_step);
PairwiseOrthoMatch pairwiseOrthoMatch = new PairwiseOrthoMatch(
affines[1], // double [][] affine,
null, // double [][] jtj,
Double.NaN, // double rms,
zoom_lev); // int zoom_lev);
double max_std = 1.5; // maximal standard deviation to limit center area
double min_std_rad = 2.0; // minimal radius of the central area (if less - fail)
while ((Math.abs(nx) <= nabs) && (Math.abs(ny) <= nabs)) {
affine1[0][2] = affines_init[1][0][2] + pix_step * pix_size * nx;
affine1[1][2] = affines_init[1][1][2] + pix_step * pix_size * ny;
pairwiseOrthoMatch.rms = Double.NaN;
correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
pairwiseOrthoMatch, //PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
min_overlap, // 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, // 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,
gpu_pair, // String [] gpu_spair,
affines, // double [][][] affines, // on top of GPS offsets
null, // woi, // Rectangle woi,
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)
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) {
break;
}
// update nx, ny
if ((nx > ny) && (nx > -ny)){
ny++;
} else if ((nx <= ny) && (nx > -ny)){
nx--;
} else if ((ny <= -nx) && (ny > nx)){
ny--;
} else {
nx++;
}
}
if (!(pairwiseOrthoMatch.rms < need_rms)) { // failed
return null;
}
return pairwiseOrthoMatch; // pairwiseOrthoMatch.affine will have adjusted affine[1]
}
public FineXYCorr correlateOrthoPair( // not used
CLTParameters clt_parameters,
......@@ -1006,9 +1086,14 @@ public class OrthoMapsCollection implements Serializable{
for (int i = 0; i < gpu_pair.length; i++) {
gpu_pair[i] = getIndex(gpu_spair[i]);
}
double max_std = 1.5; // maximal standard deviation to limit center area
double min_std_rad = 2.0; // minimal radius of the central area (if less - fail)
return 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, // double metric_error,
ignore_prev_rms, // boolean ignore_prev_rms,
......@@ -1027,6 +1112,9 @@ public class OrthoMapsCollection implements Serializable{
public FineXYCorr correlateOrthoPair(
CLTParameters clt_parameters,
PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics, may be null if not needed
int min_overlap,
double max_std, // maximal standard deviation to limit center area
double min_std_rad, // minimal radius of the central area (if less - fail)
double frac_remove, // = 0.25
double metric_error,
boolean ignore_prev_rms,
......@@ -1043,6 +1131,10 @@ public class OrthoMapsCollection implements Serializable{
if (woi == null) {
woi = new Rectangle();
}
int min_tiles_overlap = min_overlap/GPUTileProcessor.DTT_SIZE/GPUTileProcessor.DTT_SIZE;
if (pairwiseOrthoMatch != null) {
pairwiseOrthoMatch.rms = Double.NaN; // mark as failed
}
boolean show_gpu_img = true; // (debugLevel > 1);
boolean show_tile_centers = false; // true; // (debugLevel > 1);
if (!batch_mode) {
......@@ -1058,8 +1150,8 @@ public class OrthoMapsCollection implements Serializable{
affines[0], // double [][] ref_affine,
affines[1]); // double [][] other_affine
if (bounds_overlap_meters == null) {
if (debugLevel > -3) {
if ((bounds_overlap_meters == null) || (bounds_overlap_meters[0] == null) || (bounds_overlap_meters[1] == null)) {
if (debugLevel > -4) {
System.out.println("correlateOrthoPair(): no overlap");
return null;
}
......@@ -1109,6 +1201,9 @@ public class OrthoMapsCollection implements Serializable{
gpu_pair_img[n] = ortho_maps[gpu_pair[n]].getPaddedGPU (zoom_lev); // int zoom_level,
}
boolean invert_second = (debugLevel > 1000);
if (debugLevel > 10) {
return null;
}
if (invert_second) {
for (int i = 0; i < gpu_pair_img[1].length; i++) {
gpu_pair_img[1][i]= -gpu_pair_img[1][i];
......@@ -1127,6 +1222,13 @@ public class OrthoMapsCollection implements Serializable{
}
woi.width = overlap_wh_pixel[0];
woi.height = overlap_wh_pixel[1]; // = new Rectangle(0, 0, overlap_wh_pixel[0], overlap_wh_pixel[1]);
if (woi.width * woi.height < min_overlap) {
if (debugLevel > -4) {
System.out.println("correlateOrthoPair(): too small overlap: "+
woi.width+" * "+ woi.height+" = "+(woi.width * woi.height)+" < "+min_overlap+"");
}
return null;
}
if (woi.width > OrthoMap.gpu_width) {
if (debugLevel > -3) {
System.out.println("correlateOrthoPair() correlation woi.width="+woi.width+" > gpu_width="+OrthoMap.gpu_width+". Truncating.");
......@@ -1178,6 +1280,17 @@ public class OrthoMapsCollection implements Serializable{
batch_mode, // final boolean batch_mode,
dbg_suffix, // final String dbg_suffix, // for image_names
debugLevel); // final int debugLevel);
if (tp_tasks[0].length < min_tiles_overlap) {
if (pairwiseOrthoMatch != null) {
pairwiseOrthoMatch.rms = Double.NaN; // mark as failed
}
if (debugLevel > -4) {
System.out.println("correlateOrthoPair(): too small non-null overlap: "+
tp_tasks[0].length +" < "+min_tiles_overlap+"");
}
return null;
}
// get elevations
int zoom_lev_tiles = zoom_lev-3;
double [] ground_planes_weight = null;
......@@ -1216,13 +1329,27 @@ public class OrthoMapsCollection implements Serializable{
ground_planes_weight[i] = 1.0;
}
}
System.out.println("correlateOrthoPair(): left "+num_left+" tiles (was "+tp_tasks[0].length+" before filtering). metric_error="+metric_error);
System.out.println();
if (debugLevel > -3) {
System.out.println("correlateOrthoPair(): left "+num_left+" tiles (was "+tp_tasks[0].length+" before filtering). metric_error="+metric_error);
System.out.println();
}
if (num_left < tp_tasks[0].length/4) {
num_elevations--;
System.out.println("too few tiles remain, try again. metric_error="+metric_error);
pairwiseOrthoMatch.rms = Double.NaN; // failed
return null;
}
if (num_left < min_tiles_overlap) {
if (pairwiseOrthoMatch != null) {
pairwiseOrthoMatch.rms = Double.NaN; // mark as failed
}
if (debugLevel > -4) {
System.out.println("correlateOrthoPair(): too small non-null, filtered by elevations overlap: "+
num_left +" < "+min_tiles_overlap+"");
}
return null;
}
}
double max_err= 7.0;
......@@ -1357,14 +1484,32 @@ public class OrthoMapsCollection implements Serializable{
double rms_diff = 0.001;
int num_iter = 20;
boolean last_run = false;
orthoPairLMA.prepareLMA(
int min_good_tiles = min_tiles_overlap/2;
int num_good_tiles = orthoPairLMA.prepareLMA(
// will always calculate relative affine, starting with unity
tilesX, // int width,
tilesX, // int width,
vector_field[1], // double [][] vector_XYS, // optical flow X,Y, confidence obtained from the correlate2DIterate()
tile_centers, // double [][] centers, // tile centers (in pixels)
null, // double [] weights_extra, // optional, may be null
true, // boolean first_run,
debugLevel); // final int debug_level)
tile_centers, // double [][] centers, // tile centers (in pixels)
null, // double [] weights_extra, // optional, may be null
true, // boolean first_run,
min_good_tiles, // int min_good_tiles,
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)
debugLevel); // final int debug_level)
if (num_good_tiles < min_good_tiles) {
if (debugLevel>-4) {
System.out.println("correlateOrthoPair(): num_good_tiles="+
num_good_tiles+ " < "+min_good_tiles);
}
if (pairwiseOrthoMatch != null) {
pairwiseOrthoMatch.rms = Double.NaN; // mark as failed
}
return null;
}
int lma_rslt = orthoPairLMA.runLma( // <0 - failed, >=0 iteration number (1 - immediately)
lambda, // double lambda, // 0.1
lambda_scale_good, // double lambda_scale_good,// 0.5
......@@ -3529,7 +3674,11 @@ public class OrthoMapsCollection implements Serializable{
}
public String selectOneScene(int default_choice, int num_choice_lines) {
public String selectOneScene(
int num_scene,
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++) {
......@@ -3543,11 +3692,11 @@ public class OrthoMapsCollection implements Serializable{
lines[indx]=String.format(
"%3d %17s %26s %6.2f",indx, name, sdt, agl);
}
GenericJTabbedDialog gd = new GenericJTabbedDialog("Select Image from the list ",1200,1000);
gd.addChoice("Image pair:",
GenericJTabbedDialog gd = new GenericJTabbedDialog("Select the "+fs[num_scene]+" image from the list ",1200,1000);
gd.addChoice(fs[num_scene]+" image:",
lines,
lines[default_choice],
"Select scene", num_choice_lines);
"Select "+fs[num_scene]+" scene", num_choice_lines);
gd.showDialog();
if (gd.wasCanceled()) return null;
int scene_number= gd.getNextChoiceIndex();
......
......@@ -54,21 +54,26 @@ public class OrthoPairLMA {
private double [][] last_jt = null;
private boolean origin_center = false; // true - origin in overlap center, false - top left corner (as it was)
private double [] origin = null; // either {0,0} for top-left or center of the woi
public int num_good_tiles = 0;
public OrthoPairLMA (boolean origin_center) {
this.origin_center = origin_center;
}
public void prepareLMA(
public int prepareLMA(
// will always calculate relative affine, starting with unity
int width, // tilesX
double [][] vector_XYS, // optical flow X,Y, confidence obtained from the correlate2DIterate()
double [][] centers, // tile centers (in pixels)
double [] weights_extra, // optional, may be null
boolean first_run,
int min_good_tiles,
double max_std, // maximal standard deviation to limit center area
double min_std_rad, // minimal radius of the central area (if less - fail)
final int debug_level) {
tile_centers = centers;
this.width = width;
int height = vector_XYS.length / width;
int min_x = width, min_y=height, max_x = -1, max_y=-1;
num_good_tiles = 0;
for (int tile = 0; tile < vector_XYS.length; tile++) if ((vector_XYS[tile] !=null)) {
int tileX = tile % width;
int tileY = tile / width;
......@@ -76,8 +81,12 @@ public class OrthoPairLMA {
if (tileX > max_x) max_x = tileX;
if (tileY < min_y) min_y = tileY;
if (tileY > max_y) max_y = tileY;
num_good_tiles++;
}
woi = new Rectangle (min_x, min_y, max_x - min_x + 1, max_y - min_y + 1);
if (num_good_tiles < min_good_tiles) {
return num_good_tiles;
}
origin = new double[2];
if (origin_center) {
origin = new double [] {
......@@ -98,7 +107,7 @@ public class OrthoPairLMA {
last_rms = new double [2];
initial_rms = last_rms.clone();
good_or_bad_rms = this.last_rms.clone();
return num_good_tiles;
}
public double [][] getAffine(){
......
......@@ -14,10 +14,40 @@ public class PairwiseOrthoMatch implements Serializable {
public PairwiseOrthoMatch() {
}
public PairwiseOrthoMatch(double [][] affine, double [][] jtj, double rms, int zoom_lev) {
public PairwiseOrthoMatch(
double [][] affine,
double [][] jtj,
double rms,
int zoom_lev) {
this.affine = affine;
this.jtj = jtj;
this.zoom_lev=zoom_lev;
}
public PairwiseOrthoMatch getInverse(double [] rd) {
double [][] affine = OrthoMap.invertAffine(getAffine());
PairwiseOrthoMatch inverted_match = new PairwiseOrthoMatch(
affine, // double [][] affine,
null, // double [][] jtj,
rms, // double rms,
zoom_lev); // int zoom_lev)
double [] corr = {
rd[0] * (affine[0][0]-1.0)+ rd[1]*affine[0][1],
rd[0] * affine[1][0]+ rd[1]*(affine[1][1]-1.0)};
affine[0][2] += corr[0];
affine[1][2] += corr[1];
return inverted_match;
}
public PairwiseOrthoMatch getInverse() {
PairwiseOrthoMatch inverted_match = new PairwiseOrthoMatch(
OrthoMap.invertAffine(getAffine()), // double [][] affine,
null, // double [][] jtj,
rms, // double rms,
zoom_lev); // int zoom_lev)
return inverted_match;
}
public double [][] getAffine(){
return affine;
}
......
......@@ -100,11 +100,12 @@ public class IntersceneMatchParameters {
public double rln_fat_zero = 10000.0; // phase correlation fat zero
public boolean rln_use_neibs = true; // calculate TD neighbors in phase correlation
public boolean rln_neibs_fill = false; // fill empty neighbors centers
public double rln_neib_radius = 2.9; // neighbors radius (tiles)
public double rln_neib_radius = 5.9; // neighbors radius (tiles)
public double rln_radius_frac = 0.1; // rln_neib_radius not less than this fraction of woi width/height
public double rln_cent_radius = 4.0; // centroids center radius
public int rln_n_recenter = 2; // when cosine window, re-center window these many times
public double rln_sngl_rstr = 0.3; // minimal single-tile phase correlation maximums relative to max str
public double rln_neib_rstr = 0.5; // minimal neighbors phase correlation maximums relative to max str
public double rln_neib_rstr = 0.4; // minimal neighbors phase correlation maximums relative to max str
public double [] getImsMountATR() {
return new double [] {
......@@ -683,6 +684,8 @@ public class IntersceneMatchParameters {
"Fill empty neighbors centers (false - only non-empty).");
gd.addNumericField("Neighbors radius", this.rln_neib_radius, 5,8,"tiles",
"Use these tiles around the center one.");
gd.addNumericField("Neighbors radius fraction woi", this.rln_radius_frac, 5,8,"",
"Naighbors radius not less than this fraction of tiles WOI.");
gd.addNumericField("Centroids radius", this.rln_cent_radius, 5,8,"",
"Centroids radius for maximums isolation.");
gd.addNumericField("Recenter centroid", this.rln_n_recenter, 0,3,"",
......@@ -1526,6 +1529,7 @@ public class IntersceneMatchParameters {