Commit f455f79f authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: Add getNadirDisparityMaps() and renderNadirSequence() for OpenMVS

New methods in OpticalFlow.java:
- getNadirDisparityMaps(): transforms SfM terrain disparity from the
  segment reference into each scene's own camera frame using
  Cuas.transformFromVirtual(). Returns double[][][nscene][ntiles][3].
- renderNadirSequence(): renders each scene from its own position
  (scene_xyz/atr=ZERO3, ref_scene=scene itself) using per-scene
  pXpYD from getNadirDisparityMaps(). ERS rolling-shutter velocity
  corrections are still applied. Output: <ts>-NADIR-MERGED.tiff.

Unlike renderSceneSequence() (TERRAIN-DISP), which warps all frames
to the reference for zero ground parallax, renderNadirSequence() produces
natural-parallax perspective images from each scene's own viewpoint —
the correct input format for OpenMVS/COLMAP dense reconstruction.

New parameter in IntersceneMatchParameters:
- nadir_gen (boolean, default false): checkbox under 'Flat ground' tab,
  before fgnd_gen_optho. Enables nadir rendering in the existing
  TERRAIN-DISP pipeline block.
Co-authored-by: 's avatarClaude <claude@elphel.com>
parent 5477b6bc
...@@ -1143,6 +1143,7 @@ min_str_neib_fpn 0.35 ...@@ -1143,6 +1143,7 @@ min_str_neib_fpn 0.35
public int fgnd_min_macro_tiles = 3; // Minimal number of macrotiles for high outliers. Minimal number of remaining macrotiles before removing high outpliers. public int fgnd_min_macro_tiles = 3; // Minimal number of macrotiles for high outliers. Minimal number of remaining macrotiles before removing high outpliers.
public double fgnd_normal_damping = 0.001; // Damping parameter for planes. Pull planes to horizontal when there is not enough data for tilts. public double fgnd_normal_damping = 0.001; // Damping parameter for planes. Pull planes to horizontal when there is not enough data for tilts.
public boolean nadir_gen = false; // generate per-scene nadir perspective images for OpenMVS input
public boolean fgnd_gen_optho = true; // generate orthogonal to the ground view public boolean fgnd_gen_optho = true; // generate orthogonal to the ground view
public boolean fgnd_gen_tilted = true; // generate tilted ground disparity view public boolean fgnd_gen_tilted = true; // generate tilted ground disparity view
public boolean fgnd_gen_scan = false; // generate "CT scan" views public boolean fgnd_gen_scan = false; // generate "CT scan" views
...@@ -3377,6 +3378,8 @@ min_str_neib_fpn 0.35 ...@@ -3377,6 +3378,8 @@ min_str_neib_fpn 0.35
gd.addNumericField("Damping parameter for planes", this.fgnd_normal_damping, 5,7,"", gd.addNumericField("Damping parameter for planes", this.fgnd_normal_damping, 5,7,"",
"Pull planes to horizontal when there is not enough data for tilts."); "Pull planes to horizontal when there is not enough data for tilts.");
gd.addMessage ("Output files generation related to ground planes"); gd.addMessage ("Output files generation related to ground planes");
gd.addCheckbox ("Generate nadir per-scene images for OpenMVS", this.nadir_gen,
"Render each scene from its own camera position (no terrain warp), for use as OpenMVS/COLMAP input.");
gd.addCheckbox ("Generate orthogonal to the ground view", this.fgnd_gen_optho, gd.addCheckbox ("Generate orthogonal to the ground view", this.fgnd_gen_optho,
"Generate relative to the ground plane view, minimizing anisotropic distortions."); "Generate relative to the ground plane view, minimizing anisotropic distortions.");
gd.addCheckbox ("Generate tilted-ground view", this.fgnd_gen_tilted, gd.addCheckbox ("Generate tilted-ground view", this.fgnd_gen_tilted,
...@@ -4813,6 +4816,7 @@ min_str_neib_fpn 0.35 ...@@ -4813,6 +4816,7 @@ min_str_neib_fpn 0.35
this.fgnd_min_macro_tiles=(int) gd.getNextNumber(); this.fgnd_min_macro_tiles=(int) gd.getNextNumber();
this.fgnd_normal_damping = gd.getNextNumber(); this.fgnd_normal_damping = gd.getNextNumber();
this.nadir_gen = gd.getNextBoolean();
this.fgnd_gen_optho = gd.getNextBoolean(); this.fgnd_gen_optho = gd.getNextBoolean();
this.fgnd_gen_tilted = gd.getNextBoolean(); this.fgnd_gen_tilted = gd.getNextBoolean();
this.fgnd_gen_scan = gd.getNextBoolean(); this.fgnd_gen_scan = gd.getNextBoolean();
...@@ -6108,6 +6112,7 @@ min_str_neib_fpn 0.35 ...@@ -6108,6 +6112,7 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"fgnd_min_macro_tiles", this.fgnd_min_macro_tiles+"");// int properties.setProperty(prefix+"fgnd_min_macro_tiles", this.fgnd_min_macro_tiles+"");// int
properties.setProperty(prefix+"fgnd_normal_damping", this.fgnd_normal_damping+""); // double properties.setProperty(prefix+"fgnd_normal_damping", this.fgnd_normal_damping+""); // double
properties.setProperty(prefix+"nadir_gen", this.nadir_gen+""); // boolean
properties.setProperty(prefix+"fgnd_gen_optho", this.fgnd_gen_optho+""); // boolean properties.setProperty(prefix+"fgnd_gen_optho", this.fgnd_gen_optho+""); // boolean
properties.setProperty(prefix+"fgnd_gen_tilted", this.fgnd_gen_tilted+""); // boolean properties.setProperty(prefix+"fgnd_gen_tilted", this.fgnd_gen_tilted+""); // boolean
properties.setProperty(prefix+"fgnd_gen_scan", this.fgnd_gen_scan+""); // boolean properties.setProperty(prefix+"fgnd_gen_scan", this.fgnd_gen_scan+""); // boolean
...@@ -7386,6 +7391,7 @@ min_str_neib_fpn 0.35 ...@@ -7386,6 +7391,7 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"fgnd_min_macro_tiles")!=null) this.fgnd_min_macro_tiles=Integer.parseInt(properties.getProperty(prefix+"fgnd_min_macro_tiles")); if (properties.getProperty(prefix+"fgnd_min_macro_tiles")!=null) this.fgnd_min_macro_tiles=Integer.parseInt(properties.getProperty(prefix+"fgnd_min_macro_tiles"));
if (properties.getProperty(prefix+"fgnd_normal_damping")!=null) this.fgnd_normal_damping=Double.parseDouble(properties.getProperty(prefix+"fgnd_normal_damping")); if (properties.getProperty(prefix+"fgnd_normal_damping")!=null) this.fgnd_normal_damping=Double.parseDouble(properties.getProperty(prefix+"fgnd_normal_damping"));
if (properties.getProperty(prefix+"nadir_gen")!=null) this.nadir_gen=Boolean.parseBoolean(properties.getProperty(prefix+"nadir_gen"));
if (properties.getProperty(prefix+"fgnd_gen_optho")!=null) this.fgnd_gen_optho=Boolean.parseBoolean(properties.getProperty(prefix+"fgnd_gen_optho")); if (properties.getProperty(prefix+"fgnd_gen_optho")!=null) this.fgnd_gen_optho=Boolean.parseBoolean(properties.getProperty(prefix+"fgnd_gen_optho"));
if (properties.getProperty(prefix+"fgnd_gen_tilted")!=null) this.fgnd_gen_tilted=Boolean.parseBoolean(properties.getProperty(prefix+"fgnd_gen_tilted")); if (properties.getProperty(prefix+"fgnd_gen_tilted")!=null) this.fgnd_gen_tilted=Boolean.parseBoolean(properties.getProperty(prefix+"fgnd_gen_tilted"));
if (properties.getProperty(prefix+"fgnd_gen_scan")!=null) this.fgnd_gen_scan=Boolean.parseBoolean(properties.getProperty(prefix+"fgnd_gen_scan")); if (properties.getProperty(prefix+"fgnd_gen_scan")!=null) this.fgnd_gen_scan=Boolean.parseBoolean(properties.getProperty(prefix+"fgnd_gen_scan"));
...@@ -8645,6 +8651,7 @@ min_str_neib_fpn 0.35 ...@@ -8645,6 +8651,7 @@ min_str_neib_fpn 0.35
imp.fgnd_min_macro_tiles = this.fgnd_min_macro_tiles; imp.fgnd_min_macro_tiles = this.fgnd_min_macro_tiles;
imp.fgnd_normal_damping = this.fgnd_normal_damping; imp.fgnd_normal_damping = this.fgnd_normal_damping;
imp.nadir_gen = this.nadir_gen;
imp.fgnd_gen_optho = this.fgnd_gen_optho; imp.fgnd_gen_optho = this.fgnd_gen_optho;
imp.fgnd_gen_tilted = this.fgnd_gen_tilted; imp.fgnd_gen_tilted = this.fgnd_gen_tilted;
imp.fgnd_gen_scan = this.fgnd_gen_scan; imp.fgnd_gen_scan = this.fgnd_gen_scan;
......
...@@ -8048,6 +8048,26 @@ java.lang.NullPointerException ...@@ -8048,6 +8048,26 @@ java.lang.NullPointerException
master_CLT.saveImagePlusInModelDirectory( master_CLT.saveImagePlusInModelDirectory(
null, // "GPU-SHIFTED-D"+clt_parameters.disparity, // String suffix, null, // "GPU-SHIFTED-D"+clt_parameters.disparity, // String suffix,
imp_terrain_disp); // imp_scenes); // ImagePlus imp) imp_terrain_disp); // imp_scenes); // ImagePlus imp)
// Nadir per-scene rendering for OpenMVS/COLMAP input
if (clt_parameters.imp.nadir_gen) {
double [][][] nadir_pXpYD = getNadirDisparityMaps(
clt_parameters, // CLTParameters clt_parameters,
terrain_disparity, // double [] terrain_disparity,
quadCLTs, // QuadCLT [] quadCLTs,
master_CLT, // QuadCLT ref_scene,
debugLevel); // int debugLevel
ImagePlus imp_nadir = renderNadirSequence(
clt_parameters, // CLTParameters clt_parameters,
nadir_pXpYD, // double [][][] nadir_pXpYD,
quadCLTs, // QuadCLT [] quadCLTs,
master_CLT, // QuadCLT ref_scene,
debugLevel); // int debugLevel
if (imp_nadir != null) {
master_CLT.saveImagePlusInModelDirectory(
null, // String suffix,
imp_nadir); // ImagePlus imp
}
}
} }
} }
} }
...@@ -10799,6 +10819,149 @@ java.lang.NullPointerException ...@@ -10799,6 +10819,149 @@ java.lang.NullPointerException
} }
/**
* Compute per-scene disparity maps in each scene's own camera frame,
* suitable for nadir rendering where each scene is rendered from its own
* position without a terrain-reference warp.
*
* Uses Cuas.transformFromVirtual() to project the segment reference's SfM
* terrain disparity into each scene's own frame. For the reference scene
* itself the transform is identity (ZERO3 pose).
*
* @param clt_parameters processing parameters
* @param terrain_disparity SfM terrain disparity in ref_scene's frame
* (COMBO_DSN_INDX_TERRAIN slice)
* @param quadCLTs all scenes in the segment (may contain nulls)
* @param ref_scene segment index/reference scene
* @param debugLevel
* @return per-scene pXpYD [nscene][ntiles][3]; null entries for scenes
* without registered poses
*/
public static double[][][] getNadirDisparityMaps(
CLTParameters clt_parameters,
double [] terrain_disparity,
QuadCLT [] quadCLTs,
QuadCLT ref_scene,
int debugLevel) {
QuadCLT[] selected_scenes = selectScenes(quadCLTs, ref_scene);
ErsCorrection ers_reference = ref_scene.getErsCorrection();
final int around = 2;
final double around_sigma = 4.0;
final int num_virtual_refines = 2;
double[][][] nadir_pXpYD = new double[selected_scenes.length][][];
for (int nscene = 0; nscene < selected_scenes.length; nscene++) {
String ts = selected_scenes[nscene].getImageName();
double[] scene_xyz = ZERO3;
double[] scene_atr = ZERO3;
if (selected_scenes[nscene] != ref_scene) {
scene_xyz = ers_reference.getSceneXYZ(ts);
scene_atr = ers_reference.getSceneATR(ts);
if ((scene_xyz == null) || (scene_atr == null)) {
if (debugLevel >= 0) {
System.out.println("getNadirDisparityMaps(): no pose for scene "+ts+", skipping");
}
continue;
}
}
if (debugLevel > 0) {
System.out.println("getNadirDisparityMaps(): scene "+nscene+"/"+selected_scenes.length+" "+ts);
}
nadir_pXpYD[nscene] = Cuas.transformFromVirtual(
clt_parameters, // CLTParameters clt_parameters,
terrain_disparity, // double [] disparity_ref,
scene_xyz, // final double [] scene_xyz,
scene_atr, // final double [] scene_atr,
ref_scene, // final QuadCLT reference_QuadClt,
around, // final int around,
around_sigma, // final double sigma,
num_virtual_refines, // final int num_refines,
null); // final String debugSuffix
}
return nadir_pXpYD;
}
/**
* Render each scene in the segment from its own camera position.
*
* Unlike renderSceneSequence() which warps all frames to the reference
* (terrain-referenced, zero parallax for flat ground), this method renders
* each scene with natural parallax from its own position — suitable as
* input for OpenMVS / COLMAP dense reconstruction.
*
* Each scene is rendered as its own reference (scene_xyz/atr = ZERO3,
* ref_scene = scene itself) using the per-scene pXpYD from
* getNadirDisparityMaps(). ERS rolling-shutter velocities are still
* applied for image quality.
*
* Output suffix: {@code <ref_ts>-NADIR-MERGED}
*
* @param clt_parameters processing parameters
* @param nadir_pXpYD per-scene pXpYD[nscene][ntiles][3], indexed by
* selectScenes() order; null entries are skipped
* @param quadCLTs all scenes in the segment (may contain nulls)
* @param ref_scene segment reference (used for ERS and scene selection)
* @param debugLevel
* @return ImagePlus multi-slice stack, one slice per scene, or null if no
* scenes could be rendered
*/
public static ImagePlus renderNadirSequence(
CLTParameters clt_parameters,
double [][][] nadir_pXpYD,
QuadCLT [] quadCLTs,
QuadCLT ref_scene,
int debugLevel) {
QuadCLT[] selected_scenes = selectScenes(quadCLTs, ref_scene);
if (selected_scenes.length == 0) return null;
ErsCorrection ers_reference = ref_scene.getErsCorrection();
boolean merge_all = true; // always produce single-channel merged output
boolean toRGB = false;
String suffix = ref_scene.getImageName() + "-NADIR-MERGED";
ImageStack stack_scenes = null;
for (int nscene = 0; nscene < selected_scenes.length; nscene++) {
if (nadir_pXpYD[nscene] == null) continue;
String ts = selected_scenes[nscene].getImageName();
// Apply ERS rolling-shutter velocity corrections for this scene
if (selected_scenes[nscene] != ref_scene) {
double[] scene_ers_xyz_dt = ers_reference.getSceneErsXYZ_dt(ts);
double[] scene_ers_atr_dt = ers_reference.getSceneErsATR_dt(ts);
selected_scenes[nscene].getErsCorrection().setErsDt(
scene_ers_xyz_dt, // double [] ers_xyz_dt
scene_ers_atr_dt);// double [] ers_atr_dt
}
// Render from scene's own position: ZERO3 offset, scene is its own reference
ImagePlus imp_scene = QuadCLT.renderGPUFromDSI(
-1, // final int sensor_mask (-1 = merge all)
merge_all, // final boolean merge_channels
null, // final Rectangle full_woi_in
clt_parameters, // CLTParameters clt_parameters
null, // double [] disparity_ref (use pXpYD)
nadir_pXpYD[nscene], // double [][] ref_pXpYD
ZERO3, // final double [] scene_xyz (own frame)
ZERO3, // final double [] scene_atr (own frame)
selected_scenes[nscene], // final QuadCLT scene
selected_scenes[nscene], // final QuadCLT ref_scene (self)
toRGB, // final boolean toRGB
clt_parameters.imp.show_mono_nan, // boolean show_nan
"", // String suffix
QuadCLT.THREADS_MAX, // int threadsMax
debugLevel); // int debugLevel
if (imp_scene == null) {
if (debugLevel >= 0) {
System.out.println("renderNadirSequence(): null result for scene "+ts);
}
continue;
}
if (stack_scenes == null) {
stack_scenes = new ImageStack(imp_scene.getWidth(), imp_scene.getHeight());
}
for (int i = 1; i <= imp_scene.getStackSize(); i++) {
stack_scenes.addSlice(ts, imp_scene.getStack().getPixels(i));
}
}
if (stack_scenes == null) return null;
return new ImagePlus(suffix, stack_scenes);
}
public static QuadCLT[] selectScenes( public static QuadCLT[] selectScenes(
QuadCLT[] quadCLTs, QuadCLT[] quadCLTs,
QuadCLT ref_scene) { QuadCLT ref_scene) {
......
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