Commit c48eb737 authored by Andrey Filippov's avatar Andrey Filippov

improving matching from the center to mitigate scale/rotations

parent 5e03168f
...@@ -1299,7 +1299,7 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341 ...@@ -1299,7 +1299,7 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
int nSlices = stack_scenes.getSize(); int nSlices = stack_scenes.getSize();
String [] scene_names = new String [nSlices]; String [] scene_names = new String [nSlices];
for (int n = 0; n < scene_names.length; n++) { for (int n = 0; n < scene_names.length; n++) {
scene_names[n] = stack_scenes.getSliceLabel(n+1).substring(0,17); scene_names[n] = stack_scenes.getSliceLabel(n+1).substring(0,17); // wrong image opened-> StringIndexOutOfBoundsException: begin 0, end 17, length 8
} }
if (all_scenes != null) { if (all_scenes != null) {
all_scenes[0] = scene_names; all_scenes[0] = scene_names;
......
...@@ -1013,13 +1013,17 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -1013,13 +1013,17 @@ public class OrthoMapsCollection implements Serializable{
null, // double [][] jtj, null, // double [][] jtj,
Double.NaN, // double rms, Double.NaN, // double rms,
zoom_lev); // int zoom_lev); zoom_lev); // int zoom_lev);
double max_std = 1.5; // maximal standard deviation to limit center area 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) double min_std_rad = 2.0; // minimal radius of the central area (if less - fail)
while ((Math.abs(nx) <= nabs) && (Math.abs(ny) <= nabs)) { while ((Math.abs(nx) <= nabs) && (Math.abs(ny) <= nabs)) {
affine1[0][2] = affines_init[1][0][2] + pix_step * pix_size * nx; for (int i = 0; i < affines_init.length; i++) {
affine1[1][2] = affines_init[1][1][2] + pix_step * pix_size * ny; System.arraycopy(affines_init[1][i], 0, affine1[i], 0, affine1[i].length);
}
affine1[0][2] += pix_step * pix_size * nx;
affine1[1][2] += pix_step * pix_size * ny;
pairwiseOrthoMatch.rms = Double.NaN; pairwiseOrthoMatch.rms = Double.NaN;
correlateOrthoPair( correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters, clt_parameters, // CLTParameters clt_parameters,
pairwiseOrthoMatch, //PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics pairwiseOrthoMatch, //PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
...@@ -1262,6 +1266,7 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -1262,6 +1266,7 @@ public class OrthoMapsCollection implements Serializable{
double frac_below = 0.1; double frac_below = 0.1;
double [][] jtj = null; double [][] jtj = null;
double rms = Double.NaN; double rms = Double.NaN;
double last_center_radius = 0;
for (int ntry = 0; ntry < num_tries; ntry++) { for (int ntry = 0; ntry < num_tries; ntry++) {
if (!batch_mode) { if (!batch_mode) {
if (debugLevel>-3) { if (debugLevel>-3) {
...@@ -1500,6 +1505,15 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -1500,6 +1505,15 @@ public class OrthoMapsCollection implements Serializable{
min_std_rad, // double min_std_rad, // minimal radius of the central area (if less - fail) min_std_rad, // double min_std_rad, // minimal radius of the central area (if less - fail)
debugLevel); // final int debug_level) debugLevel); // final int debug_level)
last_center_radius = orthoPairLMA.getCenterRadius();
if ((min_std_rad >0) && (last_center_radius < 1)) {
if (debugLevel>-3) {
System.out.println("correlateOrthoPair(): center_radius="+
orthoPairLMA.getCenterRadius()+" < "+ 1);
}
return null;
}
if (num_good_tiles < min_good_tiles) { if (num_good_tiles < min_good_tiles) {
if (debugLevel>-4) { if (debugLevel>-4) {
System.out.println("correlateOrthoPair(): num_good_tiles="+ System.out.println("correlateOrthoPair(): num_good_tiles="+
...@@ -1563,6 +1577,14 @@ public class OrthoMapsCollection implements Serializable{ ...@@ -1563,6 +1577,14 @@ public class OrthoMapsCollection implements Serializable{
prev_rms=rms; prev_rms=rms;
} // for (int ntry = 0; ntry < num_tries; ntry++) { } // for (int ntry = 0; ntry < num_tries; ntry++) {
if ((min_std_rad > 0) && (last_center_radius < min_std_rad)) {
if (debugLevel>-3) {
System.out.println("correlateOrthoPair(): center_radius="+
last_center_radius+" < "+ min_std_rad);
}
return null;
}
......
...@@ -37,8 +37,8 @@ import Jama.Matrix; ...@@ -37,8 +37,8 @@ import Jama.Matrix;
public class OrthoPairLMA { public class OrthoPairLMA {
private boolean thread_invariant= true; private boolean thread_invariant= true;
private int N = 0; private int N = 0; // number of tiles in WOI: woi.width * woi.height
private Rectangle woi = null; private Rectangle woi = null; // in tiles
private int width; private int width;
private double [] last_rms = null; // {rms, rms_pure}, matching this.vector private double [] last_rms = null; // {rms, rms_pure}, matching this.vector
private double [] good_or_bad_rms = null; // just for diagnostics, to read last (failed) rms private double [] good_or_bad_rms = null; // just for diagnostics, to read last (failed) rms
...@@ -53,11 +53,15 @@ public class OrthoPairLMA { ...@@ -53,11 +53,15 @@ public class OrthoPairLMA {
private double [] last_ymfx = null; private double [] last_ymfx = null;
private double [][] last_jt = null; private double [][] last_jt = null;
private boolean origin_center = false; // true - origin in overlap center, false - top left corner (as it was) 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 private double [] origin = null; // in pixels either {0,0} for top-left or center of the woi
private double center_radius = 0; // center zone radius (in tiles) that has limited standard deviation
public int num_good_tiles = 0; public int num_good_tiles = 0;
public OrthoPairLMA (boolean origin_center) { public OrthoPairLMA (boolean origin_center) {
this.origin_center = origin_center; this.origin_center = origin_center;
} }
public double getCenterRadius() {
return center_radius;
}
public int prepareLMA( public int prepareLMA(
// will always calculate relative affine, starting with unity // will always calculate relative affine, starting with unity
int width, // tilesX int width, // tilesX
...@@ -95,6 +99,24 @@ public class OrthoPairLMA { ...@@ -95,6 +99,24 @@ public class OrthoPairLMA {
} }
N = woi.width * woi.height; N = woi.width * woi.height;
parameters_vector = new double [] {1,0,0,1,0,0}; parameters_vector = new double [] {1,0,0,1,0,0};
if (min_std_rad > 0) {
int min_tiles = 4;
getCenterRadius(
max_std, // final double max_std, // maximal standard deviation to limit center area
min_tiles, // final int min_tiles,
vector_XYS, // final double [][] vector_XYS,
weights_extra, // final double [] weights_extra, // null or additional weights (such as elevation-based)
centers); // final double [][] centers)
// if (getCenterRadius() < min_std_rad) { // only after last pass of LMA!
// num_good_tiles = 0;
// return num_good_tiles;
// }
weights_extra = applyRadialWeights( // uses this.center_radius;
vector_XYS, // final double [][] vector_XYS,
weights_extra, // final double [] weights_extra,
centers); // final double [][] centers)
}
setSamplesWeightsYCenters( setSamplesWeightsYCenters(
vector_XYS, vector_XYS,
weights_extra, // null or additional weights (such as elevation-based) weights_extra, // null or additional weights (such as elevation-based)
...@@ -136,6 +158,175 @@ public class OrthoPairLMA { ...@@ -136,6 +158,175 @@ public class OrthoPairLMA {
//getWJtJlambda( //getWJtJlambda(
// lambda, // *10, // temporary // lambda, // *10, // temporary
// this.last_jt) // this.last_jt)
private double [] applyRadialWeights( // uses this.center_radius;
final double [][] vector_XYS,
final double [] weights_extra,
final double [][] centers) { // null or additional weights (such as elevation-based)
return applyRadialWeights(
center_radius, // final double radius_tiles,
vector_XYS, // final double [][] vector_XYS,
weights_extra, // final double [] weights_extra, // null or additional weights (such as elevation-based)
centers); // final double [][] centers);
}
private double [] applyRadialWeights(
final double radius_tiles,
final double [][] vector_XYS,
final double [] weights_extra, // null or additional weights (such as elevation-based)
final double [][] centers) {
if (Double.isInfinite(radius_tiles)) {
return weights_extra; // may be null - should be OK
}
final double radius_pix = radius_tiles * GPUTileProcessor.DTT_SIZE;
final double radius_pix2 = radius_pix*radius_pix;
final double [] weights = new double [vector_XYS.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 iTile = ai.getAndIncrement(); iTile < N; iTile = ai.getAndIncrement()) {
int tileX = iTile % woi.width + woi.x;
int tileY = iTile / woi.width + woi.y;
int aTile = tileY * width + tileX;
if ((vector_XYS[aTile] != null) && (centers[aTile] != null)) {
double w = vector_XYS[aTile][2];
if (weights_extra != null) w *= weights_extra[aTile];
if (Double.isNaN(w)) w = 0;
double dx = centers[aTile][0] - origin[0];
double dy = centers[aTile][1] - origin[1];
double r_pix2 = dx*dx+dy*dy; // radius in pixels, squared
if (r_pix2 < 4*radius_pix2) {
double r_pix = Math.sqrt(r_pix2); // radius in pixels
double wr = 0.5*(1.0 + Math.cos(0.5*Math.PI*r_pix/radius_pix));
weights[aTile] = w*wr;
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return weights;
}
/**
* Calculate center radius (in tiles) to use for LMA when initial rotation or
* scaling is inaccurate so the peripheral areas do not fit into correlation range.
* In that case try to adjust only the central area first, then increase that area
* in next iterations.
* @param max_std maximal standard deviation (average for X and Y) inside center area
* @param min_tiles minimal tiles in the center zone
* @param vector_XYS 2D correlation-measured X,Y, and strength
* @param weights_extra null or optional additional weights of the samples
* @param centers per tile (matching vector_XYS and weights_extra) tile centers in pixels
* @return maximal radius from the center (in pixels) where standard deviation of the inside samples is
* below max_std. Returns Double.POSITIVE_INFINITY if std is not reached
*/
private double getCenterRadius(
final double max_std, // maximal standard deviation to limit center area
// final double min_std_rad, // minimal radius of the central area (if less - fail)
final int min_tiles,
final double [][] vector_XYS,
final double [] weights_extra, // null or additional weights (such as elevation-based)
final double [][] centers) {
final int rad_max = Math.max(woi.width,woi.height)/2 +1;
final int rad_length = rad_max +1;
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger ati = new AtomicInteger(0);
final double [][] s0_arr = new double [threads.length][rad_length];
final double [][] sx_arr = new double [threads.length][rad_length];
final double [][] sx2_arr = new double [threads.length][rad_length];
final double [][] sy_arr = new double [threads.length][rad_length];
final double [][] sy2_arr = new double [threads.length][rad_length];
final int [][] sn_arr = new int [threads.length][rad_length];
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int thread_num = ati.getAndIncrement();
for (int iTile = ai.getAndIncrement(); iTile < N; iTile = ai.getAndIncrement()) {
int tileX = iTile % woi.width + woi.x;
int tileY = iTile / woi.width + woi.y;
int aTile = tileY * width + tileX;
if ((vector_XYS[aTile] != null) && (centers[aTile] != null)) {
double w = vector_XYS[aTile][2];
if (weights_extra != null) w *= weights_extra[aTile];
if (Double.isNaN(w)) w = 0;
double dx = centers[aTile][0] - origin[0];
double dy = centers[aTile][1] - origin[1];
double r_t = Math.sqrt(dx*dx+dy*dy)/GPUTileProcessor.DTT_SIZE; // radius in tiles
int irt = (int) Math.round(r_t);
if (irt < rad_length) {
double fx = vector_XYS[aTile][0];
double fy = vector_XYS[aTile][1];
sn_arr [thread_num][irt] += 1;
s0_arr [thread_num][irt] += w;
sx_arr [thread_num][irt] += w * fx;
sx2_arr[thread_num][irt] += w * fx*fx;
sy_arr [thread_num][irt] += w * fy;
sy2_arr[thread_num][irt] += w * fy * fy;
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
final double [] s0 = new double [rad_length];
final double [] sx = new double [rad_length];
final double [] sx2 = new double [rad_length];
final double [] sy = new double [rad_length];
final double [] sy2 = new double [rad_length];
final int [] sn = new int [rad_length];
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int iRad = ai.getAndIncrement(); iRad < rad_length; iRad = ai.getAndIncrement()) {
for (int i = 0; i < threads.length; i++) {
s0 [iRad]+=s0_arr [i][iRad];
sx [iRad]+=sx_arr [i][iRad];
sx2[iRad]+=sx2_arr[i][iRad];
sy [iRad]+=sy_arr [i][iRad];
sy2[iRad]+=sy2_arr[i][iRad];
sn [iRad]+=sn_arr [i][iRad];
}
}
}
};
}
ImageDtt.startAndJoin(threads);
double sc0=0, scx=0,scx2=0,scy=0,scy2=0,std_prev=0, std=0;
int scn=0;
center_radius = Double.POSITIVE_INFINITY;
for (int iRad=0; iRad < rad_length; iRad++) {
sc0+= s0 [iRad];
scx+= sx [iRad];
scx2+=sx2[iRad];
scy+= sy [iRad];
scy2+=sy2[iRad];
scn+= sn [iRad];
if ((scn > min_tiles) && (sc0 > 0)) {// for one tile gets scrt() of a small negative error
std = Math.sqrt((scx2*sc0 - scx*scx + scy2*sc0 - scy*scy)/2)/sc0;
}
if ((scn >= min_tiles) && (std >= max_std)) {
if (iRad==0) {
center_radius = 0;
break; // probably can not happen
}
center_radius = iRad - (std - max_std) / (std - std_prev);
break;
}
std_prev = std;
}
return center_radius;
}
private void setSamplesWeightsYCenters( private void setSamplesWeightsYCenters(
final double [][] vector_XYS, final double [][] vector_XYS,
......
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