Commit 7a793de1 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: promote CuasRtParameters to a CLTParameters peer (clt_parameters.curt)

Per Andrey: CuasRtParameters should be instantiated like the other parameter
classes at CLTParameters:1175..1185 (img_dtt/ofp/imp/ilp/...), not nested
inside IntersceneMatchParameters. Changes:
- CLTParameters: new peer field curt, set/getProperties wiring, own
  "CUAS RT" dialog tab right after imp's questions/answers (tab content
  unchanged; tab position moves from inside imp's tab row to after it).
- IntersceneMatchParameters: the six curt wiring sites removed (field,
  dialogQ/A, set/getProperties, clone).
- Access rename: clt_parameters.imp.curt.X -> clt_parameters.curt.X
  (105 sites: OpticalFlow, CuasDetectRT, CuasPoseRT).
- corr-xml keys change _imp_curt_* -> _curt_*. getProperties keeps a legacy
  fallback (reads _imp_curt_* first, _curt_* overrides), so old configs
  still load unmigrated.
- NEW scripts/migrate_curt_config.py: renames _imp_curt_* keys in existing
  corr-xml files (in-place with .bak, --dry-run, idempotent, drops duplicate
  legacy entries with a warning). Validated on a copy of
  LV396-v013-...-POSEJP4-ENMB.corr-xml: 87 keys renamed, byte-identical
  otherwise.

Verified: mvn -DskipTests clean package OK; no imp.curt references remain.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 45f1f35b
#!/usr/bin/env python3
# By Claude on 07/04/2026
"""Migrate corr-xml configuration files to the current curt_* key format.
CuasRtParameters history:
pre-07/2026 keys CLT_PARAMETERS._imp_curt_<name> (curt_* fields inside IntersceneMatchParameters,
then the extracted class still saved under imp with the same keys)
07/2026 - keys CLT_PARAMETERS._curt_<name> (CuasRtParameters is a CLTParameters peer,
like imp/ofp/ilp)
The Java reader keeps a legacy fallback (it reads _imp_curt_* when present, then
_curt_* overrides), so unmigrated files still load. This script rewrites the keys
so files are in the current format and future removal of the fallback is safe.
Usage:
migrate_curt_config.py FILE [FILE ...] # in-place, keeps FILE.bak
migrate_curt_config.py --dry-run FILE ... # report only, no changes
migrate_curt_config.py --no-backup FILE ... # in-place without .bak
Only the literal substring '_imp_curt_' inside key="..." attributes is renamed to
'_curt_'; everything else (values, formatting, comments) is byte-preserved. If a
file already contains a _curt_ key that a rename would duplicate, the old key is
dropped (the new one wins) and a warning is printed.
"""
import argparse
import re
import shutil
import sys
KEY_RE = re.compile(r'(<entry key=")([^"]*)_imp_curt_([^"]*)(")')
def migrate_text(text):
"""Return (new_text, n_renamed, dropped_keys)."""
existing_new = set(re.findall(r'<entry key="([^"]*_curt_[^"]*)"', text))
existing_new = {k for k in existing_new if '_imp_curt_' not in k}
renamed = [0]
dropped = []
out_lines = []
for line in text.splitlines(keepends=True):
m = KEY_RE.search(line)
if m:
new_key = m.group(2) + '_curt_' + m.group(3)
if new_key in existing_new:
dropped.append(m.group(2) + '_imp_curt_' + m.group(3))
continue # drop the whole legacy entry line - the new key already exists
line = KEY_RE.sub(r'\g<1>\g<2>_curt_\g<3>\g<4>', line)
renamed[0] += 1
out_lines.append(line)
return ''.join(out_lines), renamed[0], dropped
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument('files', nargs='+', help='corr-xml files to migrate')
ap.add_argument('--dry-run', action='store_true', help='report only, do not modify')
ap.add_argument('--no-backup', action='store_true', help='do not keep a .bak copy')
args = ap.parse_args()
status = 0
for path in args.files:
try:
with open(path, encoding='utf-8') as f:
text = f.read()
except OSError as e:
print(f"{path}: ERROR - {e}", file=sys.stderr)
status = 1
continue
new_text, n, dropped = migrate_text(text)
for k in dropped:
print(f"{path}: WARNING - dropped legacy entry '{k}' (current-format key already present)")
if n == 0 and not dropped:
print(f"{path}: already current (no _imp_curt_ keys)")
continue
if args.dry_run:
print(f"{path}: would rename {n} key(s)" +
(f", drop {len(dropped)} duplicate legacy entrie(s)" if dropped else ""))
continue
if not args.no_backup:
shutil.copy2(path, path + '.bak')
with open(path, 'w', encoding='utf-8') as f:
f.write(new_text)
print(f"{path}: renamed {n} key(s)" +
(f", dropped {len(dropped)} duplicate legacy entrie(s)" if dropped else "") +
("" if args.no_backup else f" (backup: {path}.bak)"))
return status
if __name__ == '__main__':
sys.exit(main())
......@@ -40,6 +40,7 @@ import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.correction.CorrectionColorProc;
import com.elphel.imagej.lwir.LwirReaderParameters;
import com.elphel.imagej.tileprocessor.BiQuadParameters;
import com.elphel.imagej.tileprocessor.CuasRtParameters; // By Claude on 07/04/2026
import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.ImageDttParameters;
import com.elphel.imagej.tileprocessor.IntersceneGlobalLmaParameters;
......@@ -1183,6 +1184,7 @@ public class CLTParameters {
public IntersceneGlobalLmaParameters iglp = new IntersceneGlobalLmaParameters();
public InterNoiseParameters inp = new InterNoiseParameters();
public LWIRWorldParameters lwp = new LWIRWorldParameters();
public CuasRtParameters curt = new CuasRtParameters(); // CUAS real-time (was imp.curt) // By Claude on 07/04/2026
public HashMap<String,Double> z_corr_map = new HashMap<String,Double>(); //old one
public HashMap<String,Double> infinity_distace_map = new HashMap<String,Double>(); //new one
......@@ -2338,6 +2340,7 @@ public class CLTParameters {
iglp.setProperties (prefix+"_iglp_", properties);
inp.setProperties (prefix+"_inp_", properties);
lwp.setProperties (prefix+"_lwp_", properties);
curt.setProperties (prefix+"_curt_", properties); // By Claude on 07/04/2026
}
......@@ -3408,6 +3411,8 @@ public class CLTParameters {
iglp.getProperties (prefix+"_iglp_", properties);
inp.getProperties (prefix+"_inp_", properties);
lwp.getProperties (prefix+"_lwp_", properties);
curt.getProperties (prefix+"_imp_curt_", properties); // legacy keys (curt was inside imp until 07/2026) // By Claude on 07/04/2026
curt.getProperties (prefix+"_curt_", properties); // current keys override legacy if both present // By Claude on 07/04/2026
}
public boolean showJDialog() {
......@@ -4898,6 +4903,9 @@ public class CLTParameters {
this.imp.dialogQuestions(gd);
gd.addTab ("CUAS RT", "CUAS Real Time");
this.curt.dialogQuestions(gd); // By Claude on 07/04/2026
this.lwp.dialogQuestions(gd);
gd.addTab ("Inter-LMA", "parameters for the interscene LMA fitting");
......@@ -5965,6 +5973,7 @@ public class CLTParameters {
this.lwir.dialogAnswers(gd);
this.ofp.dialogAnswers(gd);
this.imp.dialogAnswers(gd);
this.curt.dialogAnswers(gd); // By Claude on 07/04/2026
this.lwp.dialogAnswers(gd);
this.ilp.dialogAnswers(gd);
this.iglp.dialogAnswers(gd);
......
......@@ -466,7 +466,7 @@ public class CuasPoseRT {
/**
* Re-generate per-scene poses against the virtual-center reference, RT-style.
*
* @param clt_parameters processing parameters (uses imp.curt.pose_str threshold,
* @param clt_parameters processing parameters (uses curt.pose_str threshold,
* imp.lma_use_R, LMA/offset limits as the offline flow)
* @param center_CLT virtual-center reference: must have CenterClt (fclt) and
* the final combo DSI restored
......@@ -480,7 +480,7 @@ public class CuasPoseRT {
final QuadCLT center_CLT,
final QuadCLT [] quadCLTs,
final int debugLevel) {
final double min_str = clt_parameters.imp.curt.pose_str; // e.g. 1.0
final double min_str = clt_parameters.curt.pose_str; // e.g. 1.0
final boolean use_lma_dsi = clt_parameters.imp.use_lma_dsi;
final int margin = clt_parameters.imp.margin;
final double mb_tau = clt_parameters.imp.mb_tau;
......@@ -530,9 +530,9 @@ public class CuasPoseRT {
// rank-N budget) and AND with the strength mask - a filtered run. Otherwise run FULL
// (all strength-selected tiles) and generate the calibration at the end.
boolean full_selection = true; // the tile calibration is (re)saved only from a full-selection run
ImagePlus imp_max = clt_parameters.imp.curt.pose_recalc ? null :
ImagePlus imp_max = clt_parameters.curt.pose_recalc ? null :
center_CLT.readImagePlusFromModelDirectory(TILE_CALIB_SUFFIX);
if ((imp_max == null) && !clt_parameters.imp.curt.pose_recalc) { // legacy name fallback
if ((imp_max == null) && !clt_parameters.curt.pose_recalc) { // legacy name fallback
imp_max = center_CLT.readImagePlusFromModelDirectory(TILE_CALIB_SUFFIX_OLD);
}
if (imp_max != null) {
......@@ -540,8 +540,8 @@ public class CuasPoseRT {
final boolean [] filt = deriveSelection(
fmax,
center_CLT.getTilesX(),
clt_parameters.imp.curt.pose_dxy_k,
clt_parameters.imp.curt.pose_num_tiles,
clt_parameters.curt.pose_dxy_k,
clt_parameters.curt.pose_num_tiles,
debugLevel);
int num_filt = 0;
for (int i = 0; i < reliable_ref.length; i++) {
......@@ -553,7 +553,7 @@ public class CuasPoseRT {
num_filt+" tiles (of "+num_reliable+" by strength)");
} else {
System.out.println("CuasPoseRT.testPoseSequence(): "+
(clt_parameters.imp.curt.pose_recalc ? "curt_pose_recalc ON" : TILE_CALIB_SUFFIX+" not found")+
(clt_parameters.curt.pose_recalc ? "curt_pose_recalc ON" : TILE_CALIB_SUFFIX+" not found")+
" - FULL run, will generate the calibration");
}
final double [][] pXpYD_center = OpticalFlow.transformToScenePxPyD(
......@@ -620,7 +620,7 @@ public class CuasPoseRT {
}
// Phase B lean engine (curt_pose_lean): ImageDtt instance for the convert stage,
// created once (mirrors interCorrPair's construction)
final ImageDtt image_dtt_lean = clt_parameters.imp.curt.pose_lean ? new ImageDtt(
final ImageDtt image_dtt_lean = clt_parameters.curt.pose_lean ? new ImageDtt(
center_CLT.getNumSensors(),
clt_parameters.transform_size,
clt_parameters.img_dtt,
......@@ -629,7 +629,7 @@ public class CuasPoseRT {
center_CLT.isLwir(),
clt_parameters.getScaleStrength(center_CLT.isAux()),
center_CLT.getGPU()) : null;
if (clt_parameters.imp.curt.pose_lean) {
if (clt_parameters.curt.pose_lean) {
System.out.println("CuasPoseRT.testPoseSequence(): LEAN measurement engine (phase B): "+
"TD-average(16) x virtual-center single conj-multiply. NOTE: no MB compensation "+
"in lean v1 - compare against the NOMB baseline");
......@@ -666,7 +666,7 @@ public class CuasPoseRT {
// the upload alive through interCorrPair's own setBayerImages(false).
// A2 results legitimately diverge from phase A (cleaner input) - judge by own
// dstored quality. By Claude on 07/05/2026, from Andrey's design.
if (clt_parameters.imp.curt.pose_raw) {
if (clt_parameters.curt.pose_raw) {
final boolean raw_ok = CuasConditioning.conditionSceneToGpu(
quadCLTs[nscene], // QuadCLT scene (jp4 + calibration + FPN)
null, // Config (defaults: rowcol + photometric + FPN)
......@@ -711,7 +711,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
double [][] pose;
if (clt_parameters.imp.curt.pose_lean) {
if (clt_parameters.curt.pose_lean) {
pose = leanFitScene(
clt_parameters, // CLTParameters clt_parameters,
image_dtt_lean, // ImageDtt image_dtt,
......@@ -882,8 +882,8 @@ public class CuasPoseRT {
final boolean [] keep = deriveSelection(
fmax,
tilesX,
clt_parameters.imp.curt.pose_dxy_k,
clt_parameters.imp.curt.pose_num_tiles,
clt_parameters.curt.pose_dxy_k,
clt_parameters.curt.pose_num_tiles,
debugLevel);
final float [] fkeep = new float [num_pix];
for (int i = 0; i < num_pix; i++) fkeep[i] = keep[i] ? 1.0f : 0.0f;
......
......@@ -1123,8 +1123,6 @@ min_str_neib_fpn 0.35
public double cuas_min_disp_str = 0.4; // Minimal disparity strength to consider disparity valid
public double cuas_rng_limit = 5000; // maximal displayed distance to target
// CUAS Realtime
public CuasRtParameters curt = new CuasRtParameters(); // all curt_* extracted here // By Claude on 07/05/2026
//=== LoG prefilter ===
// rleak0 removed 2026-06-20: LReLU conditioning is now LINEAR (alpha=1.0); predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
//=== Temporal binary pyramid ===
......@@ -3356,9 +3354,6 @@ min_str_neib_fpn 0.35
gd.addNumericField("Maximal displayed distance", this.cuas_rng_limit, 6,8,"m",
"Maximal displayed distance to target.");
gd.addTab("CUAS RT", "CUAS Real Time");
curt.dialogQuestions(gd); // By Claude on 07/05/2026
gd.addTab("Airplane","Airplane mode (fast forward movement, low vertical speed");
gd.addCheckbox ("Enable airplane mode", this.air_mode_en,
"Apply algorithms specific to the airplane mode.");
......@@ -4829,8 +4824,6 @@ min_str_neib_fpn 0.35
this.cuas_min_disp_str = gd.getNextNumber();
this.cuas_rng_limit = gd.getNextNumber();
curt.dialogAnswers(gd); // By Claude on 07/05/2026
this.air_mode_en = gd.getNextBoolean();
this.air_sync_ims = gd.getNextBoolean();
this.air_disp_corr = gd.getNextBoolean();
......@@ -6131,8 +6124,6 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"cuas_min_disp_str", this.cuas_min_disp_str+""); // double
properties.setProperty(prefix+"cuas_rng_limit", this.cuas_rng_limit+""); // double
curt.setProperties(prefix+"curt_", properties); // By Claude on 07/05/2026
properties.setProperty(prefix+"air_mode_en", this.air_mode_en+""); // boolean
properties.setProperty(prefix+"air_sync_ims", this.air_sync_ims+""); // boolean
properties.setProperty(prefix+"air_disp_corr", this.air_disp_corr+""); // boolean
......@@ -7421,8 +7412,6 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"cuas_min_disp_str")!=null) this.cuas_min_disp_str=Double.parseDouble(properties.getProperty(prefix+"cuas_min_disp_str"));
if (properties.getProperty(prefix+"cuas_rng_limit")!=null) this.cuas_rng_limit=Double.parseDouble(properties.getProperty(prefix+"cuas_rng_limit"));
curt.getProperties(prefix+"curt_", properties); // By Claude on 07/05/2026
if (properties.getProperty(prefix+"air_mode_en")!=null) this.air_mode_en=Boolean.parseBoolean(properties.getProperty(prefix+"air_mode_en"));
if (properties.getProperty(prefix+"air_sync_ims")!=null) this.air_sync_ims=Boolean.parseBoolean(properties.getProperty(prefix+"air_sync_ims"));
if (properties.getProperty(prefix+"air_disp_corr")!=null) this.air_disp_corr=Boolean.parseBoolean(properties.getProperty(prefix+"air_disp_corr"));
......@@ -8687,8 +8676,6 @@ min_str_neib_fpn 0.35
imp.cuas_min_disp_str = this.cuas_min_disp_str;
imp.cuas_rng_limit = this.cuas_rng_limit;
try { imp.curt = this.curt.clone(); } catch (CloneNotSupportedException e) {} // By Claude on 07/05/2026
imp.air_mode_en = this.air_mode_en;
imp.air_sync_ims = this.air_sync_ims;
imp.air_disp_corr = this.air_disp_corr;
......
......@@ -7239,7 +7239,7 @@ java.lang.NullPointerException
// Moved to the very end, after 3D
// boolean test_vegetation = true;
if (master_CLT.hasCenterClt() && clt_parameters.imp.cuas_targets_en && !clt_parameters.imp.curt.en) { // cuas mode
if (master_CLT.hasCenterClt() && clt_parameters.imp.cuas_targets_en && !clt_parameters.curt.en) { // cuas mode
if (debugLevel >-3) {
System.out.println("===== Running CUAS ranging in Oracle mode. =====");
}
......@@ -7264,7 +7264,7 @@ java.lang.NullPointerException
// Generate the merged-CUAS stack on the GPU EXPLICITLY here (CuasRanging.prepareFpixels() uses the CUDA
// tile-processor kernels - may be incompatible with a future CUDA), then hand the plain ImagePlus to the
// CUDA-free CuasDetectRT. By Claude on 06/24/2026
if (clt_parameters.imp.curt.en && master_CLT.hasCenterClt()) {
if (clt_parameters.curt.en && master_CLT.hasCenterClt()) {
System.out.println("===== Running CUAS RT detection (curt_en). =====");
CuasRanging cuasRangingRT = new CuasRanging(
clt_parameters, // CLTParameters clt_parameters,
......@@ -7274,7 +7274,7 @@ java.lang.NullPointerException
ImagePlus imp_targets = cuasRangingRT.prepareFpixels(); // GPU generator (explicit, CUDA-sensitive); also builds the QuadCLT instances = borrowed-calibration source
if (clt_parameters.imp.curt.calib) {
if (clt_parameters.curt.calib) {
// By Claude on 07/03/2026: first step of the CUAS RT processing flow - per-sensor photometric
// (re)calibration: fit a+b*x over safe (weak/far) tiles, fold into the 16+16 lwir offsets/scales,
// apply in memory (master_CLT + reference scene + quadCLT_main -> top-menu config, template for
......@@ -7285,11 +7285,11 @@ java.lang.NullPointerException
master_CLT, // QuadCLT master_CLT (combo DSI source, in-memory apply)
quadCLTs[ref_index], // QuadCLT ref_scene (photometric owner, INTERFRAME corr-xml)
quadCLT_main, // QuadCLT quadCLT_main (main config + new-instance template)
clt_parameters.imp.curt.cond_test, // boolean save_stacks
clt_parameters.curt.cond_test, // boolean save_stacks
ImageDtt.THREADS_MAX, // int threadsMax,
debugLevel); // int debugLevel
}
if (clt_parameters.imp.curt.pose_test) {
if (clt_parameters.curt.pose_test) {
// RT pose-adjustment prototype phase A (curt_pose_test), runs INSTEAD of RT detection:
// re-generate per-scene 3-angle poses against the virtual-center reference, ascending,
// prediction-seeded, single pass on the final combo DSI. Output: -POSE-RT-TEST.csv +
......@@ -7301,14 +7301,14 @@ java.lang.NullPointerException
master_CLT, // QuadCLT center_CLT,
quadCLTs, // QuadCLT [] quadCLTs,
debugLevel); // int debugLevel
} else if (clt_parameters.imp.curt.cond_test) {
} else if (clt_parameters.curt.cond_test) {
// Conditioning/calibration diagnostic (curt_cond_test), runs INSTEAD of RT detection:
// raw /jp4/ baseline (no photometric/FPN/conditioning), saved as -CUAS-PERSENSOR-RAW for
// side-by-side compare with the conditioned -CUAS-PERSENSOR (saved by the calibration step when
// curt_calib is on, or rendered here otherwise). Both stacks use the same uniform sensor-domain
// task grid - never leftover GPU task state. By Claude on 07/01/2026, restructured 07/03/2026.
System.out.println("===== CUAS RT conditioning test (curt_cond_test): per-sensor average spread =====");
if (!clt_parameters.imp.curt.calib) { // conditioned baseline not yet rendered by the calibration step
if (!clt_parameters.curt.calib) { // conditioned baseline not yet rendered by the calibration step
QuadCLT cond_phys = master_CLT.getGPUQuad().getQuadCLT(); // physical scene bound to the GPU
if (cond_phys != null) { // the actual image_data (bypass image_data_alt), same grid as raw
CuasMotion.perSensorFromData(clt_parameters, master_CLT, cond_phys.getOrigImageData(),
......
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