Commit 2f0611e3 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: 3-A3 fix - pure border-ring interior gate (morphological shrink...

CLAUDE: 3-A3 fix - pure border-ring interior gate (morphological shrink annihilated the patchy selection)

First attempt (8fb0eea4) shrank the finite-calibration mask morphologically -
but the calibration is NaN wherever a tile was not STRENGTH-selected (whole sky
+ scattered terrain holes, ~21% finite density), so a 2-tile 8-dir shrink left
~2 tiles per scene: num=2 fits, dstored 6-10 px, LMA failures (07/13 run,
killed). Andrey's ruling: pure border ring - the OOB-missing band is
geometrically confined to the frame border (margin-dropped ring 1-2 tiles +
partial-OOB soft band 12 px = 1.5 tiles), so excluding tiles within
curt.pose_shrink (default now 4) tiles of the array border covers
hard+soft+slack with zero collateral on interior strength holes. No TileNeibs,
no morphology. Dialog label now "Pose tile selection border ring (tiles)";
key _curt_pose_shrink unchanged.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 8fb0eea4
......@@ -41,7 +41,6 @@ import com.elphel.imagej.tileprocessor.OpticalFlow;
import com.elphel.imagej.tileprocessor.QuadCLT;
import com.elphel.imagej.tileprocessor.QuadCLTCPU;
import com.elphel.imagej.tileprocessor.TDCorrTile;
import com.elphel.imagej.tileprocessor.TileNeibs; // By Claude on 07/13/2026
import com.elphel.imagej.tileprocessor.TwoQuadCLT;
import ij.ImagePlus;
......@@ -124,32 +123,27 @@ public class CuasPoseRT {
final int tilesX,
final double k_nmad, // <=0 - skip the gate
final int num_tiles, // <=0 - no cap
final int shrink_tiles,// interior gate: shrink the usable mask by this many tiles (8-dir), 0 - off // By Claude on 07/13/2026
final int border_tiles,// interior gate: exclude tiles within this many tiles of the array border, 0 - off // By Claude on 07/13/2026
final int debugLevel) {
final boolean [] sel = new boolean [fmax.length];
final int tilesY = fmax.length / tilesX;
// Interior gate (3-A3, Andrey's ruling 07/13/2026): usable = finite (measured in
// EVERY scene - NaN-in-any-scene tiles are already non-finite here) SHRUNK by
// shrink_tiles. Tiles adjacent to the missing/edge band may still carry partial
// 16-sensor OOB masks (consolidation soft margin 12 px = 1.5 tiles); excluding
// the band guarantees all-16-interior tiles at every scene pose, so the GPU pose
// chain can use a FIXED per-sequence tile list with the OOB pass bypassed.
// The array-border ring is cleared explicitly: TileNeibs shrink cannot reach in
// from outside the tile array (normally moot - margin-dropped edge tiles are NaN).
// Interior gate (3-A3, Andrey's ruling 07/13/2026, PURE BORDER RING - second
// ruling same day): exclude tiles within border_tiles of the tile-array border.
// The OOB-missing band is geometrically confined to the frame border (fitted
// poses move the grid sub-pixel-to-few-px; margin-dropped centers = 1-2 tile
// ring; partial 16-sensor OOB soft band 12 px = 1.5 tiles), so a ring of 4
// covers hard+soft+slack and guarantees all-16-interior tiles at every scene
// pose - the GPU pose chain can then use a FIXED per-sequence tile list with
// the consolidation OOB pass bypassed. NO morphological shrink of the finite
// mask: the calibration is NaN wherever a tile was not STRENGTH-selected (all
// of the sky + scattered terrain holes, ~21% finite density) - a blind 2-tile
// shrink annihilated the selection to ~2 tiles (07/13 run, killed).
final boolean [] usable = new boolean [fmax.length];
for (int i = 0; i < fmax.length; i++) {
usable[i] = !Float.isNaN(fmax[i]) && !Float.isInfinite(fmax[i]);
}
if (shrink_tiles > 0) {
for (int i = 0; i < fmax.length; i++) {
final int y = i / tilesX, x = i % tilesX;
if ((y < shrink_tiles) || (y >= tilesY - shrink_tiles) ||
(x < shrink_tiles) || (x >= tilesX - shrink_tiles)) usable[i] = false;
}
(new TileNeibs(tilesX, tilesY)).shrinkSelection(
2 * shrink_tiles, // TileNeibs convention: 2 = one tile in 8 directions
usable,
null); // no prohibit
final int y = i / tilesX, x = i % tilesX;
usable[i] = !Float.isNaN(fmax[i]) && !Float.isInfinite(fmax[i]) &&
(y >= border_tiles) && (y < tilesY - border_tiles) &&
(x >= border_tiles) && (x < tilesX - border_tiles);
}
float [] finite = new float [fmax.length];
int num_finite = 0;
......@@ -166,13 +160,13 @@ public class CuasPoseRT {
final boolean [] eligible = new boolean [fmax.length];
int num_gated = 0;
for (int i = 0; i < fmax.length; i++) {
eligible[i] = usable[i] && (fmax[i] <= gate); // usable folds in the interior shrink // By Claude on 07/13/2026
eligible[i] = usable[i] && (fmax[i] <= gate); // usable folds in the interior border ring // By Claude on 07/13/2026
if (eligible[i]) num_gated++;
}
if (debugLevel > -4) {
System.out.println(String.format(
"CuasPoseRT.deriveSelection(): usable=%d (interior shrink %d), median=%.3f, NMAD=%.3f, gate=%.3f (k=%.2f) -> %d gated tiles",
num_finite, shrink_tiles, median, nmad, gate, k_nmad, num_gated));
"CuasPoseRT.deriveSelection(): usable=%d (border ring %d), median=%.3f, NMAD=%.3f, gate=%.3f (k=%.2f) -> %d gated tiles",
num_finite, border_tiles, median, nmad, gate, k_nmad, num_gated));
}
if ((num_tiles <= 0) || (num_gated <= num_tiles)) {
System.arraycopy(eligible, 0, sel, 0, sel.length);
......
......@@ -22,7 +22,7 @@ public class CuasRtParameters {
public double pose_str = 1.0; // reliable-tile strength threshold over the combo-DSI strength for the pose test tile selection (1.0 ~ old getReliableTiles population). // By Claude on 07/03/2026
public double pose_dxy_k = 0.75; // tile-selection outlier gate: keep tiles with max-over-scenes residual <= median + k*NMAD of the finite per-tile maxes (scale-free - adapts to footage quality/sequence length; NaN-in-any-scene = +inf, always rejected). <=0 - skip the gate. // By Claude on 07/04/2026
public int pose_num_tiles = 150; // tile-selection compute budget: after the gate, keep this many BEST (smallest max-residual) tiles; threshold-free rank - always yields the best available population. <=0 - no cap. // By Claude on 07/04/2026
public int pose_shrink = 2; // tile-selection interior gate (3-A3, Andrey's ruling 07/13/2026): shrink the usable (finite-calibration = measured in EVERY scene) tile mask by this many tiles (8-direction) before selection. Tiles measured everywhere but adjacent to the missing/edge band may still carry PARTIAL 16-sensor OOB masks (soft margin 12 px = 1.5 tiles); shrinking excludes that band so every selected tile has all 16 sensors interior at every scene pose - the GPU pose chain can then bypass the consolidation OOB pass with a FIXED per-sequence tile list. 0 = no shrink (legacy selection). // By Claude on 07/13/2026
public int pose_shrink = 4; // tile-selection interior gate (3-A3, Andrey's rulings 07/13/2026): exclude tiles within this many tiles of the tile-array BORDER before selection (pure ring, NO morphological shrink - the calibration is NaN wherever a tile was not strength-selected, ~21% finite density, so a blind shrink annihilated the selection to ~2 tiles in the first attempt). The OOB-missing band is geometrically confined to the frame border (margin-dropped ring 1-2 tiles + partial 16-sensor OOB soft band 12 px = 1.5 tiles); ring 4 = hard+soft+slack, guaranteeing all-16-interior tiles at every scene pose - the GPU pose chain can then bypass the consolidation OOB pass with a FIXED per-sequence tile list. 0 = off (legacy selection). // By Claude on 07/13/2026
public boolean pose_raw = false; // phase A2 ingest: per scene read RAW /jp4/, condition with the current calibration (CuasConditioning: rowcol + photometric + FPN) and FORCE-upload straight to the GPU, bypassing the QuadCLT prepared image_data (which carries the old broken Photogrammetric Calibration). Judge by own dstored quality, not agreement with phase A. // By Claude on 07/05/2026
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
......@@ -126,8 +126,8 @@ public class CuasRtParameters {
"Keep tiles with max-over-scenes residual <= median + k*NMAD of finite per-tile maxes (scale-free; NaN in any scene always rejected). <=0 - skip the gate.");
gd.addNumericField("Pose test number of best tiles", this.pose_num_tiles, 0,7,"", // By Claude on 07/04/2026
"After the gate keep this many best (smallest max-residual) tiles - the RT compute budget. <=0 - no cap.");
gd.addNumericField("Pose tile selection shrink (tiles)", this.pose_shrink, 0,7,"", // By Claude on 07/13/2026
"Shrink the usable (measured-in-every-scene) tile mask by this many tiles (8-dir) before selection: excludes the partial-OOB edge band so every selected tile keeps all 16 sensors interior at every scene pose (enables the fixed GPU tile list + OOB-pass bypass). 0 = off (legacy).");
gd.addNumericField("Pose tile selection border ring (tiles)", this.pose_shrink, 0,7,"", // By Claude on 07/13/2026
"Exclude tiles within this many tiles of the tile-array border before selection: the OOB band is confined to the frame border, so the ring guarantees every selected tile keeps all 16 sensors interior at every scene pose (enables the fixed GPU tile list + OOB-pass bypass). 0 = off (legacy).");
gd.addCheckbox ("Pose test raw-jp4 ingest (A2)", this.pose_raw, // By Claude on 07/05/2026
"Per scene: read RAW /jp4/, condition with the CURRENT calibration (rowcol+photometric+FPN, CuasConditioning) and force-upload straight to the GPU, bypassing the prepared image_data (old broken Photogrammetric Calibration).");
gd.addCheckbox ("Pose test lean correlation (B)", this.pose_lean, // By Claude on 07/05/2026
......
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