- 16 Jun, 2026 2 commits
-
-
Andrey Filippov authored
inferROI's receptive-field patch was hardcoded P=24. Add CuasDnnInfer.setPatch and new param curt_dnn_patch (default 24) so a wider-attention model (patch 32) can be deployed: CuasDetectRT sets it on the inferer. The 32-patch model widens off-center suppression reach (off_max 9->13 px) and removes the trajectory-alias ghosts seen in the clean synthetic grid (field ~0.16 -> ~0.003). Must match the loaded model's training patch. Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
The DNN velocity grid (radius vel_radius) extends past the trained velocity disk, so untrained corner cells emit spurious sidelobes (ghosts) of non-trivial strength (s up to ~0.09) that would confuse the recurrent layer. New dnnGhostbust() zeros velocity cells with cell-radius > curt_dnn_vmax*vel_decimate, and if a pixel's peak lands in the untrained corner it discards the whole detection (field=0, s=0). Applied to the DNN field + offset before save and the recurrent feed. New param curt_dnn_vmax (px/frame, default 1.4 = PM models' training vmax_px; set to match the loaded model; <=0 disables). Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
- 15 Jun, 2026 4 commits
-
-
Andrey Filippov authored
curt_synth_bg was fully parsed/persisted in IntersceneMatchParameters but never read by the detector: the synthetic grid was always ADDED on top of the LoG-conditioned real pyramid, so "Synthetic over real background = false" had no effect (real background noise, and any NaN border pixels, always present). Now when curt_synth_bg=false the level is zeroed before the synthetic targets are injected -> truly clean, noise-free targets. Logs which path was taken. Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
Synthetic mode previously force-overrode the ROI with the full-grid SYNTH_ROI (320x320). showConvKernel5d expands each ROI pixel by (vout_dim+1)*sub_dim per axis, so 320x320 blows the heap. Now synthetic mode uses curt_save_select directly and falls back to SYNTH_ROI only when no ROI is set, so the user can shrink it to a slice of the grid. Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
CuasDnnInfer reads N (temporal frame count) from the model's input shape [B,N,H,W] and exposes getNFrames(); the constructor arg is now only a fallback hint. CuasDetectRT uses dnn.getNFrames() instead of the hardcoded 8, so an 8- vs 9-frame ONNX swaps purely by changing curt_dnn_model (N follows automatically). Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
- curt_subtract_avg (+ -SUBAVG filename tag): subtract the input per-pixel temporal mean before LoG. Removes the static treeline edge (and so its 8px tile-grid horizontal streak and the first-LReLU amplification of it); the moving target is not in the average, so it survives. Uses the whole sequence (not realtime; realtime would use a prior-run average). - DNN compute-window: the timing ROI (curt_time_from/to) now gates the DNN inference loop (only in-window scenes are inferred), not just the saved output - fast iteration on a target's few seconds. - DNN -> recurrent layer: feed the DNN field to runRecurrentLevel (per selected level, curt_recur_*). curt_dnn_recur_splat toggles feed-as-is vs bilinear splat of each pixel's velocity vector to its fractional (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin (-SPLAT mark). curt_dnn_recur_scale (default 10) lifts the [0,1] field (peaks ~0.1) to the recurrent's tuned rs_min~1.0 scale. splatField() helper added. Co-authored-by:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
- 14 Jun, 2026 5 commits
-
-
Andrey Filippov authored
CLAUDE: CUAS-RT overhaul - real-base synthetic-grid injection, level/time ROIs, 3d3 bypass, DNN offset/stride/window Reworks the synthetic B-measurement and detector flow on the real pyramid base: - Load: the real -CUAS-MERGED-CUAS stack is always the pyramid base (full-length levels); when curt_synth_src, the synthetic grid is loaded separately (scaled, NOT LoG'd) and injected TILED into each selected pyramid level AFTER the pure pyramid is built - same grid at every level, real noise averaged (sqrt(2)/level, printed). Both file picks use newestFile(). The old load-time mixing and the curt_synth_bg_avg (N=) decimation are retired. - Level selection unified on curt_c5_levels for ALL heavy paths (3d3/conv5d, C5P-direct, DNN); cheap temporalAverage pyramid still builds up to the max selected level. Pyramid-depth guard stops building when a level would have <1 frame (was NegativeArraySizeException on short sequences). - Timing ROI curt_time_from/to (timestamp seconds; last-4-of-seconds shortcut, rollover-aware, 3-decimal fixed display) clips saved RECT/HYPER/DNN/C5P stacks and gates the DNN inference (compute-window, not just save). - curt_3d3_en (default false) bypasses the 3d3 coarse-velocity path and its ~W*H*9 arrays. Full-velocities hyperstack render is guarded by a free-heap estimate (it is also an unfilled stub) and skipped if it would not fit. - DNN: curt_dnn_stride (1 testing / 4 production 50%-overlap), and -DNN-OFFSET visualization (dx, dy, s over the ROI) from the offset channels. Co-authored-by:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
CuasRTUtils.getNumVout()/getSubDim() expose the 5D render dimensions for the full-velocity-hyperstack memory estimate. CuasDnnInfer adds an inferROI(..., double[][] offOut) overload that also returns the two offset channels {dx, dy, s} per pixel (the DNN's per-pixel sub-pixel position estimate); the existing 6-arg call delegates with offOut=null, so the field output is unchanged. Both are prerequisites used by the CUAS-RT overhaul that follows. Co-authored-by:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
Prepend velocity index 0 = max over all velocities (per scene, per pixel) to showConvKernel5dHyperRect, and scale the display range to that slice instead of the fixed IMP_MINMAX, so the small (~0.1) maxima are visible on open. It is the first slice ImageJ shows - a quick map of non-empty pixels before scanning scenes (Z) and velocities (T). Applies to both -HYPER-RECT and -DNN-HYPER-RECT. Co-authored-by:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
The bg_avg>1 path kept all n_synth frames and only added an averaged background, so AVG4 and AVG8 produced the same frame count and 1/fps timestamps. Now output frame i is the mean of bg_avg consecutive frames of BOTH the scaled synthetic target AND the real background (non-overlapping groups): the sequence is decimated by N (n_synth/N frames), the moving target is motion-averaged like a real pyramid level, and each timestamp is the last real frame of its group (N/fps increments). Co-authored-by:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
When curt_dnn_model is set, run the ONNX DNN per-pixel inference over curt_save_select across all available scenes (not just the first few), saving -DNN-RECT / -DNN-HYPER-RECT. Slice labels carry timestamp + absolute frame index for matching to real targets. New curt_dnn_thresh (6 sites in IntersceneMatchParameters) zeroes the (Vx,Vy,s) field below confidence s - display/FP-suppression only. inferROI tiles the ROI batch (CHUNK) to bound ONNX Runtime activation memory. Co-authored-by:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
- 13 Jun, 2026 2 commits
-
-
Andrey Filippov authored
PyTorch-trained, ONNX-exported all-conv FCN (per-pixel Vx,Vy,s) run in Java via ONNX Runtime 1.20.0 (CPU EP). CuasDnnInfer loads the model with a location resolver (local path / scp user@host:path / http(s) -> ~/.cache/c5p_dnn/, fetching the model.onnx + external-data .data pair) and runs a float[N][H][W] patch to raw det/vel/off output. Verified bit-exact vs PyTorch (max abs diff 2.9e-6) via a fixed test vector. New config param curt_dnn_model (empty default) selects the model, mirroring the tile_processor_gpu kernel-source default/override scheme. CPU first (.224 has no cuDNN; 82k net is microseconds/patch); GPU (CUDA/TensorRT EP) and the CuasDetectRT integration are the next phase. Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-
Andrey Filippov authored
-
- 11 Jun, 2026 3 commits
-
-
Andrey Filippov authored
-
Andrey Filippov authored
-
Andrey Filippov authored
-
- 10 Jun, 2026 2 commits
-
-
Andrey Filippov authored
Per Andrey's continuity requirement: a sub-pixel target shift switching between 1 and 2 surviving cells must not change the total injected energy (filterConv5dROI does not conserve energy - it zeroes weaker components). condition() now labels 4D-connected survivor clusters (3^4-1 connectivity, BFS) and applies three regimes: 1. Single survivor: full 3x3x3x3 spread with fading peripherals (as before). 2. Compact cluster (2..curt_recur_max_clust near-equal survivors): spread limited along resolved dimensions; cluster total output = cluster max M, shared proportionally (survivor i contributes M*m_i/sum(m_j)) - exactly continuous across the 1<->2 survivor transition. 3. Cluster larger than curt_recur_max_clust (default 5): weak signal that passed the filter linearly - identity, no spreading/renormalization. New parameter curt_recur_max_clust plumbed through dialog/properties/copy; -RC<n> added to the -RECUR image titles. Co-Authored-By:Claude Fable 5 <noreply@anthropic.com>
-
Andrey Filippov authored
Implements the recurrent 4D (px, py, vx, vy) accumulation buffer per the 2026-06-09 design (cuas_rt_gpu-internal CONTINUE.md, Step 4): - Update rule: buf = leak*(1-w_eff)*shift(buf, v) + w_eff*conditioned(meas), applied every curt_recur_period (default 4) time units so the per-update pixel shift is integer-clean (1 px per minimum velocity step). - shift(): each 4D point moves by its own velocity; predictions leaving the ROI are dropped. - conditioned(): adaptive 4D spreading of filterConv5dROI survivors - dimensions spanned by adjacent survivors are "resolved" and not expanded; total spread weight per survivor is 1. - w_eff: fixed curt_recur_w, or per-pixel adaptive w*tanh(strength/wthresh) when curt_recur_wthresh > 0 (dark frames then decay by curt_recur_leak alone - blind prediction). - convolve3d() still runs at every time step with unchanged output files; the buffer consumes every curt_recur_period-th ROI output (level 0 only). - New params (curt_recur_en/period/w/leak/wthresh/spread) plumbed through IntersceneMatchParameters (dialog, get/set, properties, copy). - Buffer state snapshots saved as -RECUR-RECT and -RECUR-HYPER-RECT images. Single-threaded over the ROI for now; optimization deferred by design. Co-Authored-By:Claude Fable 5 <noreply@anthropic.com>
-
- 09 Jun, 2026 6 commits
-
-
Andrey Filippov authored
Replace fixed ±1 pixel/velocity loops and indx_center_3d3/indx_margins_3d3 with configurable vel_suppr_rad loops and indx_center_vsupp/indx_margins_vsupp. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
-
Andrey Filippov authored
Suppress a point only when both conditions hold simultaneously: thresh = Math.max(athresh, M * rthresh) (M - val) >= thresh → zero the point athresh enforces a minimum absolute gap; M*rthresh enforces a minimum relative gap. Math.max means BOTH must be satisfied (either alone is insufficient). Replaces the previous M>=athresh && val<rthresh*M logic. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
CuasRTUtils: new filterConv5dROI(data, roi, athresh, rthresh) For each (pixel, velocity) point, finds max M over the ±1 neighbourhood in both pixel space (3×3) and velocity space (3×3 in vx/vy). Zeroes the point if M >= athresh AND val < rthresh*M (sidelobe suppression). Passes through unchanged when M < athresh (weak-signal linear regime). Uses indx_center_3d3 / indx_margins_3d3 for bit-reversed multithreaded pixel iteration; returns a new filtered array. CuasDetectRT: apply filterConv5dROI() to dpixels_5d_roi_pyramid[level][n5d] after convolve3d(), controlled by curt_vel_thresh_en / curt_vel_athresh / curt_vel_rthresh, at level-0 and all pyramid levels. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
-
Andrey Filippov authored
CuasRTUtils: new showConvKernel5dHyperRect(data, roi, scene_titles, title) - ImageJ hyperstack [num_vout][num_scenes][roi_w*sub_dim × roi_h*sub_dim] - Bottom slider (T): 121 velocities labelled "+vy:+vx" - Second slider (Z): scenes - Sub-pixels spatially embedded (no NaN separator grid) CuasDetectRT: add HYPER-RECT save immediately after each RECT save block (level-0 and pyramid loop), suffix "-HYPER-RECT" / "-LEV{n}-HYPER-RECT" Co-authored-by:Claude <claude@elphel.com>
-
- 07 Jun, 2026 5 commits
-
-
Andrey Filippov authored
- CuasRTUtils: add convolve3d(data, Rectangle roi, result_in) that allocates only [roi.width*roi.height][nsub][nvel] instead of full [width*height][nsub][nvel], skips non-ROI pixels in center/margin loops, uses roi-relative indexing. Also fix showConvKernel5d(data, roi, ...) pixel_idx to use ROI-relative (py_roi*roi.width+px_roi) instead of full-image indexing. - CuasDetectRT: add dpixels_5d_roi_pyramid alongside dpixels_5d_pyramid. Level-0 and pyramid loop 5D blocks now call convolve3d(window, null) only when curt_save_c5full, and convolve3d(window, curt_save_select, null) only when curt_save_c5rect. RECT save blocks now read from dpixels_5d_roi_pyramid. Eliminates the OutOfMemoryError when curt_save_c5full=false. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
New CuasRTUtils.showConvKernel5d(data, roi, titles, title): renders the vout_dim×vout_dim velocity map for each ROI pixel as a tiled flat image, with a 1-px NaN separator grid between pixel blocks (visible in ImageJ). Sub-pixels (pixel_decimate>1) tile within each block. CuasDetectRT: add curt_save_c5rect save calls at level-0 and each pyramid level (title suffix "-RECT", "-LEVn-RECT"). curt_save_c5full path unchanged. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
-
Andrey Filippov authored
Add convolve3d() (kernel5d) at level-0 before the temporal pyramid loop and at each pyramid level nlev+1 inside the loop, mirroring the existing 3D3 coarse-velocity pattern. Output saved as CONV5D hyperstack when debugLevel > -4. Add getNumHist() getter to CuasRTUtils. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
distributing for the power of coarse velocities
-
- 05 Jun, 2026 1 commit
-
-
Andrey Filippov authored
-
- 03 Jun, 2026 1 commit
-
-
Andrey Filippov authored
-
- 31 May, 2026 1 commit
-
-
Andrey Filippov authored
-
- 30 May, 2026 2 commits
-
-
Andrey Filippov authored
getInterseqScale() was calling getCorrIncExact() which returns 0.5*corr_offset for half_step mode instead of the actual integer keyframe step getCorrInc() (= corr_offset/2 with integer division). For odd corr_offset (e.g. 5) with half_step=true these differ: getCorrIncExact()=2.5 vs getCorrInc()=2. This caused getHalfBeforeAfterPixXY() to compute: after - before = RSLT_VX * 0.5 (wrong; observed by user) instead of: after - before = RSLT_VX * corr_inc/corr_offset = RSLT_VX * 0.4 (correct) recalcOmegas() uses the same interseq_scale in the inverse direction, so it also reconstructed RSLT_VX/VY incorrectly from neighbouring keyframe positions. Fix: use getCorrInc() (integer) in getInterseqScale() so that BX/AX positions correspond to actual raw-frame midpoints and the velocity round-trip is exact. Also adds an unambiguous convention comment near RSLT_VX/RSLT_VY in CuasMotionLMA.java documenting all required scale conversions. The omega calculation (getFrameVelocityScale * ifov * fps_raw) is independent of corr_inc and was already correct. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
coordinates relation
-
- 27 May, 2026 6 commits
-
-
Andrey Filippov authored
- parse_images_txt: store full R_cw (world→camera rotation) per frame - new compute_orientation_data(): per-frame COLMAP and ERS orientation in Sim(3)-aligned GPS frame; delta-rotation angle (convention-independent); cumulative rotation integrated from frame 0 - new print_orientation_report(): per-frame RMSE + cumulative totals - ers_to_R(): guessed convention Rz(az)*Rx(tilt)*Ry(roll) — to be verified - CSV: adds colmap_yaw/pitch/roll, delta_colmap/ers/diff, cum_colmap/ers/diff Key finding for water-tower straight-flight (378 frames): COLMAP cumulative rotation = 120.81° (photogrammetric noise ~0.25°/frame) ERS cumulative rotation = 14.10° (physically correct: 1.9° heading + vibration) → COLMAP orientation is dominated by pose-estimation noise for pure-nadir SfM → orientation comparison meaningful only for LARGE angular changes (turning sequences) → position comparison (Sim(3) RMSE) remains the primary validation metric Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
Compares COLMAP camera centers (images.txt) with three imagej-elphel position columns (ERS x/y/z, IMS imsX/Y/Z, PIMU pimuX-C/Y-C/Z-C) using 7-DOF Sim(3) alignment (Umeyama 1991). Reports scale, rotation (Euler angles), per-frame residuals in both COLMAP units and physical meters, and saves a CSV. Key results for water-tower scene (1763233718_057205, rect/PINHOLE, 378 frames): Scale ~0.054 (1 COLMAP unit ≈ 18.5 m; flight spans 225 m → 12.2 COLMAP units) ERS RMSE=8.3 m, max=19.6 m at trajectory endpoints Worst frames are at both ends of the 378-frame sequence — consistent with the SfM nadir doming artifact (camera orientations rotate outward from center) Two near-zero crossings at frames ~74 and ~296 confirm dome vs straight-line fit Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
Generates a multi-slice float32 TIFF (NaN-padded, ImageJ-compatible): Slice 1: tile-processor disparity D scattered to nadir image pixels (from *-NADIR-DISPARITY-MAPS.tiff, averaged across all scenes) Slice 2: COLMAP sparse Z_cam projected to the same nadir pixel grid (optional --dense PLY for OpenMVS dense cloud) Slice 3: spatial superposition (tile-proc priority; COLMAP where missing; average at overlapping pixels) Slice 4: tile-processor scene-count per pixel (--counts flag) Uses the COLMAP reference-image pose (auto-detected as centroid of camera centres, or specified via --ref-image) to project 3D points. Handles OPENCV lens distortion model (--no-distortion to skip). Intended for evaluating depth-fusion approaches (tile processor + SIFT): python3 scripts/fopen_nadir_compare.py \ --disp <ts>-NADIR-DISPARITY-MAPS.tiff \ --colmap sparse/0_txt/ [--dense scene_dense.ply] \ --out nadir_compare.tif --counts Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
Update calling code in OpticalFlow.java to compute nadir_pXpYD once and render two passes when either nadir_gen or nadir_undistort is enabled: - nadir_gen=true → renderNadirSequence(..., false) → *-NADIR-MERGED - nadir_undistort=true → renderNadirSequence(..., true) → *-NADIR-MERGED-RECTILINEAR The nadir_pXpYD array is deep-copied per scene for the undistort pass so the original sensor-coordinate data is preserved for the non-undistorted pass. Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
Add nadir_undistort (boolean, default true) to IntersceneMatchParameters at all 6 required locations (field, dialog, read, save, load, clone). When enabled, renderNadirSequence() undistorts the pX,pY coordinates of each scene's nadir disparity map before calling renderGPUFromDSI(), so the rendered NADIR-MERGED TIFF images are rectilinear (pinhole projection) rather than retaining the sensor's native radial distortion. Analysis of the Boson 640 calibration (lwir16-06-72-00.calib-tiff) showed: - True distortion polynomial terms: < 1 px magnitude across the full image - The dominant issue was d = K0 = 1.00997 (a ~1% focal-length constant offset) which, when modeled as PINHOLE with the nominal focal length, curves the ground plane into the 'Little Prince planet' sphere effect seen in Blender - With nadir_undistort=true, COLMAP can use a pure PINHOLE model with the correct effective focal length (f * d = 1121.8 px instead of 1110.8 px) The undistortPxPy() helper mirrors getWorldCoordinates() in GeometryCorrection: rD_mm = ||(pX-cx, pY-cy)|| * pixelSize_mm factor = getRByRDist(rD_mm / distortionRadius) pX_rect = (pX - cx) * factor + cx Co-authored-by:Claude <claude@elphel.com>
-
Andrey Filippov authored
Add three dedicated unsharp-mask parameters to IntersceneMatchParameters: nadir_um_en (boolean, default false) - enable UM on nadir images nadir_um_sigma (double, default 2.0) - Gaussian sigma in pixels nadir_um_weight (double, default 1.0) - blend weight (1.0 = 100%) These are separate from the existing um_sigma/weight and terr_um_* / cuas_rng_um_* parameters so they can be independently tuned for SIFT feature extraction. LWIR nadir images with UM sigma=2 go from ~500 to ~5000 SIFT keypoints/frame. Updated all 6 required locations: field declarations, dialog, dialog-read, save, load, and clone. Applied the filter in renderNadirSequence() using the existing applyUM() helper, matching the renderSceneSequence() pattern. Co-authored-by:Claude <claude@elphel.com>
-