Commit 134a5bdb authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: Fix synth bg_avg to do real pyramid-level decimation

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: 's avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
parent c899aa2b
...@@ -133,34 +133,37 @@ public class CuasDetectRT { ...@@ -133,34 +133,37 @@ public class CuasDetectRT {
System.out.println("Synthetic mixing: scale "+synth_scale+", real background added to "+ System.out.println("Synthetic mixing: scale "+synth_scale+", real background added to "+
n_added+" of "+time_stamps.length+" frames from "+real_paths[0]); n_added+" of "+time_stamps.length+" frames from "+real_paths[0]);
} else { // By Claude on 06/13/2026 } else { // By Claude on 06/13/2026
// Pyramid-level emulation: background for synthetic frame i = mean of // Pyramid-level emulation by DECIMATION: output frame i is the mean of
// bg_avg consecutive real frames [i*N .. i*N+N-1] (non-overlapping // bg_avg consecutive frames [i*N .. i*N+N-1] of BOTH the scaled synthetic
// groups - level log2(N) noise statistics), while targets keep their // target AND the real background (non-overlapping groups). This matches
// per-frame motion (same relative velocity as LEV0). Sequence truncates // level log2(N): the sequence is DECIMATED by N (fewer output frames), the
// to the number of complete groups. // moving target is motion-averaged like the real pyramid, and the noise
// statistics are those of an N-frame average. Timestamp = LAST real frame
// of each group (pyramid-level convention), so labels increment by N/fps.
Integer sl0 = real_idx.get(time_stamps[0]); Integer sl0 = real_idx.get(time_stamps[0]);
if (sl0 == null) sl0 = 1; // fall back to the start of the real stack if (sl0 == null) sl0 = 1; // fall back to the start of the real stack
int n_synth = time_stamps.length; // By Claude on 06/13/2026 int n_synth = time_stamps.length; // By Claude on 06/13/2026
int usable = Math.min(n_synth, (real_stack.getSize() - sl0 + 1) / bg_avg);
int npix_frame = width * height; int npix_frame = width * height;
double [] bg_sum = new double [npix_frame]; int real_groups = (real_stack.getSize() - sl0 + 1) / bg_avg;
for (int i = 0; i < usable; i++) { int num_out = Math.min(n_synth / bg_avg, real_groups); // complete groups only
java.util.Arrays.fill(bg_sum, 0.0); float [][] dec_pixels = new float [num_out][npix_frame];
String [] dec_ts = new String [num_out];
double [] acc = new double [npix_frame];
for (int i = 0; i < num_out; i++) {
java.util.Arrays.fill(acc, 0.0);
for (int n = 0; n < bg_avg; n++) { for (int n = 0; n < bg_avg; n++) {
float [] syn_pix = fpixels[i * bg_avg + n]; // already scaled by synth_scale
float [] real_pix = (float[]) real_stack.getPixels(sl0 + i * bg_avg + n); float [] real_pix = (float[]) real_stack.getPixels(sl0 + i * bg_avg + n);
for (int pix = 0; pix < npix_frame; pix++) bg_sum[pix] += real_pix[pix]; for (int pix = 0; pix < npix_frame; pix++) acc[pix] += syn_pix[pix] + real_pix[pix];
} }
for (int pix = 0; pix < npix_frame; pix++) { for (int pix = 0; pix < npix_frame; pix++) dec_pixels[i][pix] = (float) (acc[pix] / bg_avg);
fpixels[i][pix] += (float) (bg_sum[pix] / bg_avg); dec_ts[i] = real_stack.getSliceLabel(sl0 + i * bg_avg + bg_avg - 1);
}
}
if (usable < time_stamps.length) {
fpixels = java.util.Arrays.copyOf(fpixels, usable);
time_stamps = java.util.Arrays.copyOf(time_stamps, usable);
} }
System.out.println("Synthetic mixing: scale "+synth_scale+", background = mean of "+bg_avg+ fpixels = dec_pixels;
" consecutive real frames per synthetic frame (pyramid-level emulation), "+ time_stamps = dec_ts;
usable+" of "+n_synth+" synthetic frames usable"); System.out.println("Synthetic mixing: scale "+synth_scale+", pyramid-level emulation by decimation x"+bg_avg+
" (mean of "+bg_avg+" consecutive synth+real frames per output frame), "+
num_out+" output frames from "+n_synth+" synthetic / "+real_stack.getSize()+" real");
} }
} else { } else {
System.out.println("Synthetic mixing: real background requested but no \""+SUFFIX_FPIXELS_TIFF+"\" found - synthetic only"); System.out.println("Synthetic mixing: real background requested but no \""+SUFFIX_FPIXELS_TIFF+"\" found - synthetic only");
......
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