Commit a01a6381 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: lean pose DEBUG: -POSE-RT-COMPOSITE hyperstack (real x virtual renders)

Per Andrey (no blind fixes - see what is going on): save the composite
(TD-averaged, grid-transformed) scenes actually correlated against the
virtual center, WITH the virtual render for comparison:

- curt.pose_img_save (checkbox "Pose test save composite scenes"):
  -POSE-RT-COMPOSITE.tiff hyperstack [t: real, virtual][z: scene] - the
  virtual-center render repeated for every scene so the component slider
  blink-compares at any z. z aligned with -POSE-RT-HYPER/-CORR2D.
- leanMeasure img_out holder: when requested, re-runs execConvertDirect
  with erase_clt=1 (NaN outside task tiles - the standard interCorrTD
  erase=-1 leaves the previous scene's tiles as ghosts in a render;
  correlation itself unaffected), then imclt renders sensor slot 0 = the
  consolidated average (last LMA cycle, converged pose).
- Virtual component = imclt of the reference buffer (what the conj-multiply
  actually sees), not a re-render from prepared data.

Observability only - processing unchanged, roll-bias symptom preserved.
Verified: mvn -DskipTests clean package OK.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent a6a8ad3d
......@@ -254,6 +254,9 @@ public class CuasPoseRT {
* By Claude on 07/05/2026, from Andrey's design.
* @param corr_pd_out null or length-1 holder - filled with the pixel-domain
* correlation tiles ([tile][15*15], dense grid index) for debug rendering
* @param img_out null or length-1 holder - filled with the imclt render of the
* consolidated composite scene ([width*height], NaN outside task tiles);
* requesting it adds an erased re-convert + an imclt pass (debug only)
* @return [3][num_pix][] {centers pXpYD, vector_XYS {dx,dy,strength}, eigen
* {e0x,e0y,l0,l1}} - the coord_motion contract of interCorrPair - or null
*/
......@@ -269,6 +272,7 @@ public class CuasPoseRT {
final double [] scene_atr,
final int margin,
final double [][][] corr_pd_out, // By Claude on 07/04/2026
final float [][] img_out, // By Claude on 07/04/2026
final int debugLevel) {
final GpuQuad gpuQuad = center_CLT.getGPUQuad();
final int num_pix = pXpYD_center.length;
......@@ -308,6 +312,13 @@ public class CuasPoseRT {
0, // sensor_mask_inter = 0: convert only, return before correlate
ImageDtt.THREADS_MAX,
debugLevel);
// DEBUG (img_out): re-convert with erase_clt=1 so non-task tiles are NaN (interCorrTD
// converts with erase=-1, leaving the PREVIOUS scene's tiles outside the selection -
// harmless for correlation, ghosts in a render). Same LPFs/tasks/offsets - identical
// task-tile content, only the background differs. By Claude on 07/04/2026.
if (img_out != null) {
gpuQuad.execConvertDirect(false, null, 1);
}
// 3. the CPU consolidation bridge (future clt_average_sensors kernel)
final float [][] fclt16 = gpuQuad.getCltData(false);
final float [] avg_td = CuasTD.consolidateSensorsTD(fclt16, null);
......@@ -333,6 +344,12 @@ public class CuasPoseRT {
return null;
}
if (corr_pd_out != null) corr_pd_out[0] = corr_pd; // debug rendering (-POSE-RT-CORR2D) // By Claude on 07/04/2026
// DEBUG (img_out): render the composite actually correlated - sensor slot 0 holds the
// consolidated TD average (setCltData above); correlation did not modify the CLT buffer.
// By Claude on 07/04/2026.
if (img_out != null) {
img_out[0] = com.elphel.imagej.cuas.CuasMotion.perSensorImagesFromTD(gpuQuad, false)[0];
}
// 6. peak + eigen per tile (the GPU argmax+eigen kernel's Java oracle)
final int corr_width = 2 * GPUTileProcessorDttSize() - 1;
final double [][] centers = new double [num_pix][];
......@@ -393,6 +410,7 @@ public class CuasPoseRT {
final double [] lma_rms, // out
final double [][][] coord_motion_rslt, // out [3][][]
final double [][][] corr_pd_out, // null or len-1: last-cycle PD correlations // By Claude on 07/04/2026
final float [][] img_out, // null or len-1: last-cycle composite render // By Claude on 07/04/2026
final int debugLevel) {
final IntersceneLma intersceneLma = new IntersceneLma(
clt_parameters.ilp.ilma_thread_invariant,
......@@ -404,7 +422,7 @@ public class CuasPoseRT {
cm = leanMeasure(
clt_parameters, image_dtt, center_CLT, scene,
center_disparity, pXpYD_center, selection,
scene_xyzatr0[0], scene_xyzatr0[1], margin, corr_pd_out, debugLevel);
scene_xyzatr0[0], scene_xyzatr0[1], margin, corr_pd_out, img_out, debugLevel);
if (cm == null) return null;
final double [][] eigen_masked = clt_parameters.imp.eig_xy_lma ? null : cm[2];
intersceneLma.prepareLMA(
......@@ -659,6 +677,24 @@ public class CuasPoseRT {
final double [][][] corr_pd_holder = corr_save ? new double [1][][] : null;
final float [] corr_nan_slice = corr_save ? new float [tilesX*(corr_size+1)*tilesY*(corr_size+1)] : null;
if (corr_nan_slice != null) Arrays.fill(corr_nan_slice, Float.NaN);
// DEBUG (pose_img_save): the composite (TD-averaged, grid-transformed) scenes actually
// correlated against the virtual center + the center reference render itself.
// By Claude on 07/04/2026, per Andrey's debug approach.
final boolean img_save = clt_parameters.curt.pose_img_save && clt_parameters.curt.pose_lean;
if (clt_parameters.curt.pose_img_save && !clt_parameters.curt.pose_lean) {
System.out.println("CuasPoseRT.testPoseSequence(): pose_img_save is only implemented "+
"for the LEAN engine (pose_lean) - ignored");
}
final int img_width = center_CLT.getGPUQuad().getImageWidth();
final int img_height = center_CLT.getGPUQuad().getImageHeight();
final ArrayList<float []> img_scenes = img_save ? new ArrayList<float []>() : null;
final float [][] img_holder = img_save ? new float [1][] : null;
final float [] img_nan_slice = img_save ? new float [img_width*img_height] : null;
if (img_nan_slice != null) Arrays.fill(img_nan_slice, Float.NaN);
// the virtual-center reference render (what every scene correlates against) - becomes
// the second component of the -POSE-RT-COMPOSITE hyperstack, repeated for every scene
final float [] ref_render = img_save ? com.elphel.imagej.cuas.CuasMotion.perSensorImagesFromTD(
center_CLT.getGPUQuad(), true)[0] : null; // reference buffer, all slots = center
final double [][][] fitted = new double [quadCLTs.length][][];
final int [] fail_reason = new int [1];
final StringBuffer sb = new StringBuffer();
......@@ -708,6 +744,7 @@ public class CuasPoseRT {
hyper_scenes.add(nan_comps);
hyper_ts.add(ts_name);
if (stack_corr != null) stack_corr.addSlice(ts_name, corr_nan_slice.clone()); // keep z aligned // By Claude on 07/04/2026
if (img_scenes != null) img_scenes.add(img_nan_slice.clone()); // By Claude on 07/04/2026
sb.append(nscene+", "+ts_name);
for (int j = 0; j < 12; j++) sb.append(", NaN");
sb.append(", NaN, 0.0, 0, -1\n");
......@@ -737,6 +774,7 @@ public class CuasPoseRT {
fail_reason[0] = 0;
final double [][][] coord_motion_rslt = new double [3][][]; // [centers, vector_XYS, eigen] of the last LMA cycle
if (corr_pd_holder != null) corr_pd_holder[0] = null; // no stale slices on failure // By Claude on 07/04/2026
if (img_holder != null) img_holder[0] = null; // By Claude on 07/04/2026
double [][] pose;
if (clt_parameters.curt.pose_lean) {
pose = leanFitScene(
......@@ -754,6 +792,7 @@ public class CuasPoseRT {
lma_rms, // double [] lma_rms (out),
coord_motion_rslt, // double [][][] coord_motion_rslt (out),
corr_pd_holder, // double [][][] corr_pd_out (last-cycle PD correlations) // By Claude on 07/04/2026
img_holder, // float [][] img_out (last-cycle composite render) // By Claude on 07/04/2026
debugLevel - 2); // int debug_level
if (pose == null) fail_reason[0] = 1; // measurement/LMA
} else {
......@@ -843,6 +882,10 @@ public class CuasPoseRT {
stack_corr.addSlice(ts_name, corr_nan_slice.clone());
}
}
// DEBUG: the composite scene render for -POSE-RT-COMPOSITE // By Claude on 07/04/2026
if (img_scenes != null) {
img_scenes.add((img_holder[0] != null) ? img_holder[0] : img_nan_slice.clone());
}
// CSV row + comparison stats
final double [] st = (stored[nscene] != null) ? stored[nscene][1] : null;
sb.append(nscene+", "+ts_name);
......@@ -940,6 +983,25 @@ public class CuasPoseRT {
imp_corr.getProcessor().resetMinAndMax();
center_CLT.saveImagePlusInModelDirectory(null, imp_corr); // title as filename
}
// -POSE-RT-COMPOSITE (DEBUG): hyperstack [t: transformed-real, virtual][z: scene] -
// the composite (TD-averaged, grid-transformed) scene actually correlated and the
// virtual-center render it correlates against (same for all scenes, repeated so the
// component slider blink-compares at any scene). Same z as -POSE-RT-HYPER/-CORR2D.
// By Claude on 07/04/2026, per Andrey's layout.
if ((img_scenes != null) && !img_scenes.isEmpty()) {
final ImageStack stack_img = new ImageStack(img_width, img_height);
for (int ns = 0; ns < img_scenes.size(); ns++) {
stack_img.addSlice("real:"+hyper_ts.get(ns), img_scenes.get(ns));
}
for (int ns = 0; ns < img_scenes.size(); ns++) {
stack_img.addSlice("virtual:"+hyper_ts.get(ns), ref_render);
}
final ImagePlus imp_img = new ImagePlus(center_CLT.getImageName()+"-POSE-RT-COMPOSITE", stack_img);
imp_img.setDimensions(1, img_scenes.size(), 2); // z=scenes, t=[real, virtual]
imp_img.setOpenAsHyperStack(true);
imp_img.getProcessor().resetMinAndMax();
center_CLT.saveImagePlusInModelDirectory(null, imp_img); // title as filename
}
// -POSE-RT-HYPER: z = scenes (top slider), t = components (bottom slider) -
// same layout as renderSceneSequence make_hyper (component is the outer slice order)
if (!hyper_scenes.isEmpty()) {
......
......@@ -26,6 +26,7 @@ public class CuasRtParameters {
public boolean pose_lean = false; // phase B measurement engine: TD-average the 16 sensors (CuasTD, CPU bridge) then ONE conj-multiply vs the virtual-center TD -> FZ-normalize -> PD -> argmax+eigen (getMaxXYCmEig) -> 3-angle LMA. All existing GPU kernels. v1: NO motion-blur compensation - compare vs the NOMB baseline. // By Claude on 07/05/2026
public boolean pose_full = false; // DEBUG: use ALL strength-selected tiles (~1074) - the -POSE-RT-TILE-CALIB calibration is neither read nor written (temporary bypass of the 150-tile filter for measurement debugging). // By Claude on 07/04/2026
public boolean pose_corr_save = false; // DEBUG: save the per-scene 2D correlations vs the virtual center in the pixel domain (-POSE-RT-CORR2D: z=scenes, tile grid of 16x16 cells, last LMA cycle) - lean engine only. // By Claude on 07/04/2026
public boolean pose_img_save = false; // DEBUG: save the composite scenes actually correlated - imclt render of the consolidated 16-sensor TD average at the converged pose (-POSE-RT-COMPOSITE: z=scenes; NaN outside task tiles) + the virtual-center reference render (-POSE-RT-CENTER-REF). Lean engine only. // By Claude on 07/04/2026
public double psf_radius = 1.0; // sensor PSF radius for LoG pre-filter
public double n_sigma = 4.0; // cutoff LoG kernel array, number of sigmas
public int pyramid = 7; // temporal pyramid levels
......@@ -103,6 +104,8 @@ public class CuasRtParameters {
"DEBUG: use all strength-selected tiles (~1074); the tile-selection calibration is neither read nor written.");
gd.addCheckbox ("Pose test save 2D correlations", this.pose_corr_save, // By Claude on 07/04/2026
"DEBUG: save per-scene pixel-domain 2D correlations vs the virtual center (-POSE-RT-CORR2D, z=scenes, last LMA cycle). Lean engine only.");
gd.addCheckbox ("Pose test save composite scenes", this.pose_img_save, // By Claude on 07/04/2026
"DEBUG: save the rendered composite (TD-averaged, grid-transformed) scenes correlated against the virtual center (-POSE-RT-COMPOSITE, z=scenes) + the center reference render (-POSE-RT-CENTER-REF). Lean engine only.");
gd.addMessage("=== LoG prefilter ===");
gd.addNumericField("Optical PSF radius", this.psf_radius, 6,8,"pix",
......@@ -236,6 +239,7 @@ public class CuasRtParameters {
this.pose_lean = gd.getNextBoolean(); // By Claude on 07/05/2026
this.pose_full = gd.getNextBoolean(); // By Claude on 07/04/2026
this.pose_corr_save = gd.getNextBoolean(); // By Claude on 07/04/2026
this.pose_img_save = gd.getNextBoolean(); // By Claude on 07/04/2026
this.psf_radius = gd.getNextNumber();
this.n_sigma = gd.getNextNumber();
......@@ -313,6 +317,7 @@ public class CuasRtParameters {
properties.setProperty(prefix+"pose_lean", this.pose_lean+""); // boolean // By Claude on 07/05/2026
properties.setProperty(prefix+"pose_full", this.pose_full+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_corr_save", this.pose_corr_save+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"pose_img_save", this.pose_img_save+""); // boolean // By Claude on 07/04/2026
properties.setProperty(prefix+"psf_radius", this.psf_radius+""); // double
properties.setProperty(prefix+"n_sigma", this.n_sigma+""); // double
......@@ -390,6 +395,7 @@ public class CuasRtParameters {
if (properties.getProperty(prefix+"pose_lean")!=null) this.pose_lean=Boolean.parseBoolean(properties.getProperty(prefix+"pose_lean")); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"pose_full")!=null) this.pose_full=Boolean.parseBoolean(properties.getProperty(prefix+"pose_full")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_corr_save")!=null) this.pose_corr_save=Boolean.parseBoolean(properties.getProperty(prefix+"pose_corr_save")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"pose_img_save")!=null) this.pose_img_save=Boolean.parseBoolean(properties.getProperty(prefix+"pose_img_save")); // By Claude on 07/04/2026
if (properties.getProperty(prefix+"psf_radius")!=null) this.psf_radius=Double.parseDouble(properties.getProperty(prefix+"psf_radius"));
if (properties.getProperty(prefix+"n_sigma")!=null) this.n_sigma=Double.parseDouble(properties.getProperty(prefix+"n_sigma"));
......@@ -470,6 +476,7 @@ public class CuasRtParameters {
cp.pose_lean = this.pose_lean;
cp.pose_full = this.pose_full; // By Claude on 07/04/2026
cp.pose_corr_save = this.pose_corr_save; // By Claude on 07/04/2026
cp.pose_img_save = this.pose_img_save; // By Claude on 07/04/2026
cp.psf_radius = this.psf_radius;
cp.n_sigma = this.n_sigma;
cp.pyramid = this.pyramid;
......
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