Commit d8f3ec21 authored by Andrey Filippov's avatar Andrey Filippov

Optimizing pairs generation

parent 1cc8ef8f
......@@ -216,9 +216,33 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
pairwise_matches.remove(name);
}
public PairwiseOrthoMatch getMatch(
String name,
boolean with_undefined) {
PairwiseOrthoMatch match = pairwise_matches.get(name);
if (match == null) return null;
if (with_undefined || match.isDefined()) return match;
return null;
}
public PairwiseOrthoMatch getMatch(String name) {
return pairwise_matches.get(name);
return getMatch(name, false); // old - do not count undefined
// return pairwise_matches.get(name);
}
public void unsetMatches(boolean undefined_only) {
if (undefined_only) {
String [] matches = pairwise_matches.keySet().toArray(new String[0]);
for (String match:matches) {
if (!getMatch(match).isDefined()) {
unsetMatch(match);
}
}
} else {
pairwise_matches = new HashMap<String, PairwiseOrthoMatch>();
}
}
public int getOriginalZoomLevel() {
......@@ -480,7 +504,9 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
averageImagePixel = Double.NaN; // average image pixel value (to combine with raw)
}
public double getTimeStamp() {
return ts;
}
public LocalDateTime getLocalDateTime() {
return dt;
}
......@@ -5244,6 +5270,71 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
return pattern;
}
/**
* Decomposing linear transform into rotation
* R1={{cos(beta),sin(beta)},{-sin(beta), cos(beta)}} ,
* non-uniform scale transform W={{w1,0}{0,w2}}, and rotation
* R2={{cos(gamma),sin(gamma)},{-sin(gamma), cos(gamma)}}
* A=R1*W*R2 using singular value decomposition
* https://math.stackexchange.com/questions/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation
* @param A - input 2x2 matrix
* @return {s,beta,w,gamma,beta+gamma}
* A = B + C
* b00= b11; c00=-c01
* b10=-b01; c10= c01
*/
public static double [] singularValueDecompose(
double [][] A) {
double a00=A[0][0],a01=A[0][1],a10=A[1][0],a11=A[1][1];
double b00=(a00+a11)/2; // , b11 = b00;
double c00=(a00-a11)/2; //, c11 =-c00;
double b01=(a01-a10)/2; //, b10 =-b01;
double c01=(a01+a10)/2; //, c10 = c01;
double w1_p_w2_2= Math.sqrt(b00*b00+b01*b01);
double w1_m_w2_2= Math.sqrt(c00*c00+c01*c01);
double w1 = w1_p_w2_2 + w1_m_w2_2;
double w2 = w1_p_w2_2 - w1_m_w2_2;
double g_p_b = Math.atan2(b01, b00);
double g_m_b = Math.atan2(c01, c00);
double gamma = (g_p_b + g_m_b)/2;
double beta = (g_p_b - g_m_b)/2;
return new double [] {beta,w1,w2,gamma,g_p_b};
}
/**
* Use singular value decomposition and then split scaling {{w1,0},{0,w1}}
* into overall scaling caused by zoom != 1.0 because of altitude error
* and unidirectional scaling caused by tilted projection plane. As the
* input linear transformation matrix converts ground coordinates to source
* image coordinates, the scale in the tilt direction is > than scale in the
* perpendicular direction (tilt axis).
* Matrix R1 is additionally rotated by PI/2 if needed so W={{w1,0},{0,w2}}
* has w2>=w1 and W={{s,0},{0,s/t}}, where t <= 1.0 and equals to cos(tilt)
*
* @param A - linear transformation matrix from rectified ground coordinates
* to source image coordinates. OK to use 2x3 affine matrix,extra
* components will be ignored.
* @return {beta, s, t, beta+gamma}, beta+gamma - total rotation
*/
public static double [] singularValueDecomposeScaleTilt(
double [][] A) {
double [] svd=singularValueDecompose(A);
double w1 = svd[1], w2 = svd[2], beta=svd[0], g_p_b=svd[4];
// considering tilt in y direction, it should have higher scale
// (and source image coordinates), while X should correspond to
// the axis of rotation, and scale is just scale caused by error in
// altitude.
double s = Math.min(w1, w2);
double t = w1/w2; // <=1.0, ==cos(tilt)
if (w1 > w2) { // rotate tilt by PI/2
t = w2/w1;
beta += Math.PI/2;
if (beta > Math.PI) {
beta -= 2* Math.PI;
}
}
return new double [] {beta, s,t, g_p_b};
}
......
......@@ -311,7 +311,7 @@ public class OrthoMultiLMA {
clt_parameters, // CLTParameters clt_parameters,
maps_collection, // OrthoMapsCollection maps_collection,
indices, // int [] indices,
ignore_affines, // boolean ignore_affines,
ignore_affines, // boolean ignore_affines,
val_coord, // double [] val_coord, // 1 - valid, 0 - invalid, minimize coordinates errors
position_pull, // double position_pull,
skew_pull, // double skew_pull,
......
This diff is collapsed.
......@@ -9,7 +9,7 @@ import Jama.Matrix;
public class PairwiseOrthoMatch implements Serializable {
private static final long serialVersionUID = 1L;
public double [][] affine = new double[2][3];
private double [][] affine = new double[2][3];
public transient double [][] jtj = new double [6][6];
public int zoom_lev;
public double rms = Double.NaN;
......@@ -17,12 +17,14 @@ public class PairwiseOrthoMatch implements Serializable {
public transient double overlap = 0.0;
public transient double [] equalize1to0 = {1,0}; // value1 = equalize2to1[0]*value2+equalize2to1[1]
public PairwiseOrthoMatch() {
}
// public PairwiseOrthoMatch() {}
public double getOverlap() {
return overlap;
}
public void setOverlap(double overlap) {
this.overlap =overlap;
}
public PairwiseOrthoMatch(
double [][] affine,
double [][] jtj,
......@@ -36,6 +38,9 @@ public class PairwiseOrthoMatch implements Serializable {
this.overlap = overlap;
}
public boolean isDefined() {
return affine != null;
}
public double [] getEqualize2to1() {
return equalize1to0;
}
......@@ -52,7 +57,7 @@ public class PairwiseOrthoMatch implements Serializable {
}
public PairwiseOrthoMatch clone() {
double [][] affine = {this.affine[0].clone(),this.affine[1].clone()};
double [][] affine = (this.affine==null) ? null: (new double [][] {this.affine[0].clone(),this.affine[1].clone()});
double [][] jtj = new double [this.jtj.length][];
for (int i = 0; i < this.jtj.length; i++) {
jtj[i] = this.jtj[i].clone();
......@@ -221,9 +226,16 @@ public class PairwiseOrthoMatch implements Serializable {
}
public double [][] getAffine(){
if (affine == null) {
return new double [][] {{1,0,0},{0,1,0}};
}
return affine;
}
public void setAffine(double [][] affine) {
this.affine= affine;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
for (int i = 0; i < jtj.length; i++) {
......
......@@ -609,6 +609,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
}
public static Properties getTiffMeta(String path) throws IOException {
// System.out.println("getTiffMeta(): "+path);
Properties properties = new Properties();
File file = new File(path);
String extension = getFileExtension(file);
......@@ -620,7 +621,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
ImageReader reader = readers.next();
stream = ImageIO.createImageInputStream(file);
reader.setInput(stream, true);
IIOMetadata metadata = reader.getImageMetadata(0);
IIOMetadata metadata = reader.getImageMetadata(0); //java.lang.IllegalStateException: Input not set!
TIFFDirectory ifd = TIFFDirectory.createFromMetadata(metadata);
TIFFField [] tfs = ifd.getTIFFFields();
for (TIFFField tf: tfs) {
......
......@@ -11639,6 +11639,7 @@ public class ImageDttCPU {
*/
public static void startAndJoin(Thread[] threads) // USED in lwir
{
// System.out.println("startAndJoin()");
for (int ithread = 0; ithread < threads.length; ++ithread)
{
threads[ithread].setPriority(Thread.NORM_PRIORITY);
......
......@@ -29,6 +29,7 @@ import java.util.Properties;
import java.util.StringTokenizer;
import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.orthomosaic.ComboMatch;
public class IntersceneMatchParameters {
public static String [] MODES3D = {"RAW", "INF", "FG", "BG"}; // RAW:-1
......@@ -93,7 +94,10 @@ public class IntersceneMatchParameters {
public boolean sfm_show_corr_ind = false; // Show SfM for each pairs group, each refinement run
public boolean sfm_show_corr = false; // Show combined SfM for each refinement run
// rectilinear matching parameters
// rectilinear matching parameters
public String omtch_img_set = ComboMatch.FILES_LISTS_PATHS[0]; // image s
public int rln_gpu_width = 4096; // horizontal GPU image size (applied during init)
public int rln_gpu_height = 4096; // vertical GPU image size (applied during init)
......@@ -172,6 +176,8 @@ public class IntersceneMatchParameters {
public int pequ_num_iter = 100; // 50;
public int pequ_debugLevel = 2;
public String patt_save_top = "/media/elphel/NVME/lwir16-proc/ortho_videos/debug/sept12-13/pattern_match/";
public String patt_save_subdir = "combo_maps";
public double [] getImsMountATR() {
......@@ -737,11 +743,16 @@ public class IntersceneMatchParameters {
"Show combined SfM for each refinement run.");
gd.addTab ("Mosaic", "Combining scene series into a composite map map");
gd.addChoice ("Files list/data path (w/o extension):", ComboMatch.FILES_LISTS_PATHS, omtch_img_set);
gd.addNumericField("GPU window width", this.rln_gpu_width, 0,5,"pix",
"Horizontal GPU image size (applied during init.)");
gd.addNumericField("GPU window height", this.rln_gpu_height, 0,5,"pix",
"Vertical GPU image size (applied during init).");
gd.addMessage ("Rectilinear image matching");
gd.addNumericField("Phase correlation fat zero", this.rln_fat_zero, 5,8,"",
"Phase correlation fat zero - was set to 10000.");
......@@ -829,6 +840,10 @@ public class IntersceneMatchParameters {
gd.addNumericField("RMSE relative improvement", this.pequ_rms_diff, 3,7,"", "Relative RMSE improvement to exit LMA.");
gd.addNumericField("LMA iterations", this.pequ_num_iter, 0,3,"",".Maximal number of the LMA iterations.");
gd.addNumericField("Debug level for equalization",this.pequ_debugLevel, 0,3,"","Debug level for global (LMA-based) intensity equalization.");
gd.addMessage ("Pattern match parameters");
gd.addStringField ("Pattern match save directory",this.patt_save_top, 120, "Top directory to save combo maps");
gd.addStringField ("Save subdirectory", this.patt_save_subdir, 80, "Subdirectory for versions of the same scene/pair of scenes");
//
......@@ -1663,6 +1678,8 @@ public class IntersceneMatchParameters {
this.sfm_show_corr_ind = gd.getNextBoolean();
this.sfm_show_corr = gd.getNextBoolean();
this.omtch_img_set = ComboMatch.FILES_LISTS_PATHS[gd.getNextChoiceIndex()];
this.rln_gpu_width = (int) gd.getNextNumber();
this.rln_gpu_height = (int) gd.getNextNumber();
this.rln_fat_zero = gd.getNextNumber();
......@@ -1737,6 +1754,9 @@ public class IntersceneMatchParameters {
this.pequ_num_iter = (int) gd.getNextNumber();
this.pequ_debugLevel = (int) gd.getNextNumber();
this.patt_save_top= gd.getNextString();
this.patt_save_subdir = gd.getNextString();
this.center_reference = gd.getNextBoolean();
this.overlap_sequences = gd.getNextBoolean();
this.reset_photometric = gd.getNextBoolean();
......@@ -2185,6 +2205,7 @@ public class IntersceneMatchParameters {
properties.setProperty(prefix+"sfm_show_seq", this.sfm_show_seq + ""); // boolean
properties.setProperty(prefix+"sfm_show_corr_ind", this.sfm_show_corr_ind + ""); // boolean
properties.setProperty(prefix+"sfm_show_corr", this.sfm_show_corr + ""); // boolean
properties.setProperty(prefix+"omtch_img_set", this.omtch_img_set + ""); // String
properties.setProperty(prefix+"rln_gpu_width", this.rln_gpu_width+""); // int
properties.setProperty(prefix+"rln_gpu_height", this.rln_gpu_height+""); // int
......@@ -2261,6 +2282,9 @@ public class IntersceneMatchParameters {
properties.setProperty(prefix+"pequ_num_iter", this.pequ_num_iter + ""); // int
properties.setProperty(prefix+"pequ_debugLevel", this.pequ_debugLevel + ""); // int
properties.setProperty(prefix+"patt_save_top", this.patt_save_top + ""); // String
properties.setProperty(prefix+"patt_save_subdir", this.patt_save_subdir + ""); // String
properties.setProperty(prefix+"center_reference", this.center_reference + ""); // boolean
properties.setProperty(prefix+"overlap_sequences", this.overlap_sequences + ""); // boolean
properties.setProperty(prefix+"reset_photometric", this.reset_photometric + ""); // boolean
......@@ -2671,7 +2695,9 @@ public class IntersceneMatchParameters {
if (properties.getProperty(prefix+"sfm_save_seq")!=null) this.sfm_save_seq=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_save_seq"));
if (properties.getProperty(prefix+"sfm_show_seq")!=null) this.sfm_show_seq=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_show_seq"));
if (properties.getProperty(prefix+"sfm_show_corr_ind")!=null) this.sfm_show_corr_ind=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_show_corr_ind"));
if (properties.getProperty(prefix+"sfm_show_corr")!=null) this.sfm_show_corr=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_show_corr"));
if (properties.getProperty(prefix+"sfm_show_corr")!=null) this.sfm_show_corr=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_show_corr"));
if (properties.getProperty(prefix+"omtch_img_set")!=null) this.omtch_img_set=(String) properties.getProperty(prefix+ "omtch_img_set");
if (properties.getProperty(prefix+"rln_gpu_width")!=null) this.rln_gpu_width=Integer.parseInt(properties.getProperty(prefix+"rln_gpu_width"));
if (properties.getProperty(prefix+"rln_gpu_height")!=null) this.rln_gpu_height=Integer.parseInt(properties.getProperty(prefix+"rln_gpu_height"));
......@@ -2747,6 +2773,9 @@ public class IntersceneMatchParameters {
if (properties.getProperty(prefix+"pequ_num_iter")!=null) this.pequ_num_iter=Integer.parseInt(properties.getProperty(prefix+ "pequ_num_iter"));
if (properties.getProperty(prefix+"pequ_debugLevel")!=null) this.pequ_debugLevel=Integer.parseInt(properties.getProperty(prefix+ "pequ_debugLevel"));
if (properties.getProperty(prefix+"patt_save_top")!=null) this.patt_save_top=(String) properties.getProperty(prefix+ "patt_save_top");
if (properties.getProperty(prefix+"patt_save_subdir")!=null) this.patt_save_subdir=(String) properties.getProperty(prefix+ "patt_save_subdir");
if (properties.getProperty(prefix+"center_reference")!=null) this.center_reference=Boolean.parseBoolean(properties.getProperty(prefix+"center_reference"));
if (properties.getProperty(prefix+"overlap_sequences")!=null) this.overlap_sequences=Boolean.parseBoolean(properties.getProperty(prefix+"overlap_sequences"));
if (properties.getProperty(prefix+"reset_photometric")!=null) this.reset_photometric=Boolean.parseBoolean(properties.getProperty(prefix+"reset_photometric"));
......@@ -3185,6 +3214,7 @@ public class IntersceneMatchParameters {
imp.sfm_show_seq = this.sfm_show_seq;
imp.sfm_show_corr_ind = this.sfm_show_corr_ind;
imp.sfm_show_corr = this.sfm_show_corr;
imp.omtch_img_set = this.omtch_img_set;
imp.rln_gpu_width = this.rln_gpu_width;
imp.rln_gpu_height = this.rln_gpu_height;
......@@ -3260,6 +3290,9 @@ public class IntersceneMatchParameters {
imp.pequ_num_iter = this.pequ_num_iter;
imp.pequ_debugLevel = this.pequ_debugLevel;
imp.patt_save_top = this.patt_save_top;
imp.patt_save_subdir = this.patt_save_subdir;
imp.center_reference = this.center_reference;
imp.overlap_sequences = this.overlap_sequences;
imp.reset_photometric = this.reset_photometric;
......
......@@ -222,17 +222,7 @@ public class QuadCLTCPU {
enu_corr_metric = corr;
}
@Deprecated
public double [][] getPimuOffsets() {
return pimu_offsets;
}
@Deprecated
public void setPimuOffsets(double[][] offsets) { // never
pimu_offsets = offsets;
}
// find best rotation between IMU XYZ and camera XYZ
/**
* Refine scene poses (now only linear) from currently adjusted poses
......
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