Commit 571ef32e authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: -OFFSET in px (s-first, full-frame meta, s-gated NaN); curt_dnn_thresh...

CLAUDE: -OFFSET in px (s-first, full-frame meta, s-gated NaN); curt_dnn_thresh viz-only (recurrent gets full field)

-OFFSET (remote) reordered to {s,Vx,Vy,dx,dy} (s first -> ImageJ auto-ranges on it); Vx,Vy converted cells->px/level-frame (/vel_decimate); full-frame ROI written to the file metadata (self-describes its extent); Vx,Vy,dx,dy NaN'd where s<curt_dnn_thresh (s kept). curt_dnn_thresh is now VISUALIZATION-ONLY: the local inferROI feeds Layer 2 the FULL field (sThresh=0) so the recurrent gets the weak sub-threshold signal it integrates (no premature threshold = the LReLU lesson); dialog label/tooltip/decl updated to say viz-only, do-not-use-for-computation.
Co-Authored-By: 's avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 3c144146
......@@ -759,11 +759,28 @@ public class CuasDetectRT {
if (save_rect) QuadCLTCPU.saveImagePlusInDirectory(tagCuasImp(cuasRTUtils.showConvKernel5d( dnn_w, roi, ts_w, title+"-RECT"), clt_parameters.imp), getModelDirectory());
if (save_hyper) QuadCLTCPU.saveImagePlusInDirectory(tagCuasImp(cuasRTUtils.showConvKernel5dHyperRect(dnn_w, roi, ts_w, title+"-HYPER-RECT"), clt_parameters.imp), getModelDirectory());
int nsc = win_dnn[1]-win_dnn[0];
// -OFFSET reordered to {s,Vx,Vy,dx,dy}: s first so ImageJ auto-ranges on it (s shows the targets best). off5 is [dx,dy,s,Vx,Vy]. By Claude on 06/20/2026
final int [] ord = {2, 3, 4, 0, 1}; // [dx,dy,s,Vx,Vy] -> [s,Vx,Vy,dx,dy]
// NaN Vx,Vy,dx,dy where s < curt_dnn_thresh so velocity shows only at detections (ImageJ ignores NaN); keep s full. By Claude on 06/20/2026
final double off_thr = clt_parameters.imp.curt_dnn_thresh;
final double velScale = 1.0 / Math.max(1, clt_parameters.imp.curt_vel_decimate); // Vx,Vy: cells -> px/level-frame (1/vel_decimate) // By Claude on 06/20/2026
double [][][] off5_w = new double [5][nsc][]; // window the full-frame offset for -OFFSET
for (int c = 0; c < 5; c++) for (int k = 0; k < nsc; k++) off5_w[c][k] = off5[c][win_dnn[0]+k];
QuadCLTCPU.saveImagePlusInDirectory(tagCuasImp(ShowDoubleFloatArrays.showArraysHyperstack(
off5_w, W, title+"-OFFSET", ts_w, new String[]{"dx","dy","s","Vx","Vy"}, false), clt_parameters.imp), getModelDirectory());
System.out.println(now()+" runDnnRemote(): LEV"+nlev+" saved -RECT/-HYPER-RECT (ROI) + -OFFSET (full "+W+"x"+H+", {dx,dy,s,Vx,Vy})");
for (int k = 0; k < nsc; k++) {
double [] sCh = off5[2][win_dnn[0]+k]; // s channel (off5 index 2)
for (int c = 0; c < 5; c++) {
double [] src = off5[ord[c]][win_dnn[0]+k]; double [] dst = new double [src.length];
double scl = ((c == 1) || (c == 2)) ? velScale : 1.0; // c1=Vx, c2=Vy cells->px; s/dx/dy unscaled
if (c == 0) System.arraycopy(src, 0, dst, 0, src.length); // c0 = s: keep all, no scale/NaN
else for (int p = 0; p < src.length; p++) dst[p] = (sCh[p] >= off_thr) ? src[p] * scl : Double.NaN;
off5_w[c][k] = dst;
}
}
ImagePlus impOff = ShowDoubleFloatArrays.showArraysHyperstack(off5_w, W, title+"-OFFSET", ts_w, new String[]{"s","Vx","Vy","dx","dy"}, false);
tagCuasImp(impOff, clt_parameters.imp);
impOff.setProperty("curt_save_select", new Rectangle(0,0,W,H).toString()); // -OFFSET is full-frame: record its real extent, not the 70x20 ROI // By Claude on 06/20/2026
com.elphel.imagej.readers.EyesisTiff.encodeProperiesToInfo(impOff); // re-encode Info with the override
QuadCLTCPU.saveImagePlusInDirectory(impOff, getModelDirectory());
System.out.println(now()+" runDnnRemote(): LEV"+nlev+" saved -RECT/-HYPER-RECT (ROI) + -OFFSET (full "+W+"x"+H+", {s,Vx,Vy,dx,dy})");
}
} catch (Exception e) {
System.out.println("runDnnRemote() failed: "+e); e.printStackTrace();
......@@ -1137,7 +1154,7 @@ public class CuasDetectRT {
window[h] = fw; // By Claude on 06/13/2026
} // By Claude on 06/13/2026
double [][] off = new double [curt_save_select.width * curt_save_select.height][]; // {dx,dy,s} per ROI pixel // By Claude on 06/14/2026
dnn_roi[j] = dnn.inferROI(window, width, height, curt_save_select, vr_dnn, dnn_thresh, off); // By Claude on 06/14/2026
dnn_roi[j] = dnn.inferROI(window, width, height, curt_save_select, vr_dnn, 0.0, off); // full field, NO s-threshold: Layer 2 (recurrent) needs the weak sub-threshold signal to integrate; curt_dnn_thresh is viz-only. By Claude on 06/20/2026
dnn_off[j] = off; // By Claude on 06/14/2026
ts_dnn[j] = ts_pyramid[nlev][newest] + " f"+newest; // timestamp + abs frame index for matching // By Claude on 06/14/2026
System.out.println(now()+" DNN scene "+(j+1)+"/"+num+" (frame "+newest+", "+ts_pyramid[nlev][newest]+") done"); // By Claude on 06/14/2026
......
......@@ -1159,7 +1159,7 @@ min_str_neib_fpn 0.35
public String curt_dnn_model = ""; // C5P DNN front-end model (ONNX): empty = disabled; local path, scp user@host:path, or http(s) URL fetched to cache; overrides bundled resource (mirrors tile_processor_gpu) // By Claude on 06/13/2026
// DEPRECATED 2026-06-20 — may be revisited for Layer 2 // By Claude
public String curt_stage2_model = ""; // C5P DNN v2 Stage-2 (learned Hough-vote refine) ONNX: empty = Stage-1 reg field only; when set + a reg Stage-1 model, the reg branch votes (tail T=P-V*(N-1), s^2-weighted) + refines -> saves -VOTE heatmap + -REFINED detection views. By Claude on 06/18/2026
public double curt_dnn_thresh = 0.0; // DNN display threshold: zero the (Vx,Vy,s) field where detection s < this (0 - show all); cosmetic FP-suppression - real-clutter FPs need a retrain with real-bg negatives, not a threshold // By Claude on 06/13/2026
public double curt_dnn_thresh = 0.0; // VISUALIZATION-ONLY s-threshold: NaN's the -OFFSET Vx,Vy,dx,dy where s < this (0 = show all) so velocity shows only at detections. Does NOT gate Layer 2 / the recurrent (always full field) nor the -RECT/-HYPER-RECT data - do NOT use for critical computation. // By Claude on 06/13/2026, viz-only 06/20/2026
public int curt_dnn_stride = 1; // DNN temporal output stride (per pyramid-level slice): 1 = every step (testing, watch each temporal unit); 4 = production (50% overlap, matches the convolver's integer-pixel-shift cadence = curt_recur_period) // By Claude on 06/14/2026
public double curt_dnn_vmax = 1.4; // "ghostbuster": trained DNN velocity limit (px/frame); zero velocity-grid cells beyond this radius (cell-R > vmax*vel_decimate) and discard pixels whose peak lands there (s=0) - the untrained corner cells emit spurious sidelobes that would confuse the recurrent. Set to match the loaded model's training vmax_px (PM models=1.4, base=1.0); <=0 disables // By Claude on 06/15/2026
// dnn_t8frac (T-8 ghost filter) removed 2026-06-20; predecessor code at git tag cuas-layer1. // By Claude on 06/20/2026
......@@ -3478,8 +3478,8 @@ min_str_neib_fpn 0.35
"DGX-side run directory (containing model.pt) the auto-launched server loads, e.g. runs/weighted9_pm_s.");
gd.addStringField ("DNN remote server src (empty=bundled)", this.curt_dnn_remote_srcdir, 40, // By Claude on 06/20/2026
"Override dir for the DGX server scripts (infer_server.py / run_infer_server.sh): empty = bundled jar resource (cuas_dnn/); set = local dir. Same default-vs-override (bundled resource vs local repo) scheme as the GPU kernels - bundled is the working version, refresh it after server-script dev.");
gd.addNumericField("DNN confidence threshold", this.curt_dnn_thresh, 6,8,"", // By Claude on 06/13/2026
"Zero the DNN (Vx,Vy,s) field where detection confidence s < this (0 = show all). Display/FP-suppression only - real-clutter false positives need a retrain with real-background negatives, not a threshold."); // By Claude on 06/13/2026
gd.addNumericField("DNN s-threshold (VIZ ONLY)", this.curt_dnn_thresh, 6,8,"", // By Claude on 06/13/2026, viz-only 06/20/2026
"VISUALIZATION ONLY - NaN's the -OFFSET Vx,Vy,dx,dy where s < this (0 = show all) so velocity shows only at detections. Does NOT gate Layer 2 (the recurrent always sees the full field) nor the -RECT/-HYPER-RECT data. Do NOT use for critical computation - it is a display mask.");
gd.addCheckbox ("DNN recurrent feed: offset-splat", this.curt_dnn_recur_splat, // By Claude on 06/14/2026
"Feeding the DNN field to the recurrent layer: unchecked = feed per-pixel field as-is; checked = splat each pixel to its fractional (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin. Output gets a -SPLAT mark."); // By Claude on 06/14/2026
gd.addNumericField("DNN recurrent feed scale", this.curt_dnn_recur_scale, 4,8,"", // By Claude on 06/14/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