Commit 4b7711ef authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Claude: Fix correlatePairs to use per-tile motion-tracking TpTask centers



Add targets_mv / frame_center_mv / corr_offset_mv overloads to
correlatePairs() and correlatePair().  When targets_mv is non-null,
GpuQuad.setRectilinearMovingTasks() generates per-tile TpTask centers
that follow the target at each frame (cx0 + vx*offset_scale), so the
GPU correlates tiles centered on the moving object and the result is the
residual velocity rather than the full VX displacement.

Callers that don't need this pass through the old uniform-grid overload
unchanged.  Also reverts the wrong "fixed-destination / shifted-read"
masking edit from the previous session; the masking was already correct
(mask tracks the target per frame) before that edit.

Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent a57f2dfc
Loading
Loading
Loading
Loading
+147 −81
Original line number Diff line number Diff line
@@ -2211,8 +2211,8 @@ public class CuasMotion {
		final int corr_pairs_ref = (int) Math.round(2 * half_accum_range * recalc_mv_boost);

		// Hard-coded debug selectors: set >= 0 to enable per-scan/per-tile visualisation
		final int dbg_nseq = 20; // -1;
		final int dbg_tile = 50+38*80; // -1;
		final int dbg_nseq = 116; // 57; // 20; // -1;
		final int dbg_tile = 17 + 33*80; // 48+32*80; // 50+38*80; // -1;

		// Pre-compute integer-pixel raised-cosine mask kernel once (shared across all nseq)
		final int r1i = (int) Math.ceil(recalc_mv_r1);
@@ -2299,7 +2299,7 @@ public class CuasMotion {
							float[] dst = fpixels_masked[f];
							double offset_scale = (double)(f - fcenter) / corr_offset;
							for (int ntile = 0; ntile < ntiles; ntile++) {
								if (!tile_valid[ntile]) continue;
								if (!tile_valid[ntile]) continue; // By Claude on 05/06/2026
								double cx = tcx0[ntile] + tvx[ntile] * offset_scale;
								double cy = tcy0[ntile] + tvy[ntile] * offset_scale;
								int icx = (int) Math.round(cx);
@@ -2336,14 +2336,30 @@ public class CuasMotion {
				ShowDoubleFloatArrays.showArrays(stack_slices, width, height, true,
						"refineMotionVectors-masked-nseq" + nseq, stack_titles);
			}
			if (nseq == dbg_nseq && debugLevel >= 0) {
				int fcount = fmax_alloc - fmin_alloc + 1;
				float[][] stack_slices = new float[fcount][];
				String[] stack_titles = new String[fcount];
				for (int fi = 0; fi < fcount; fi++) {
					stack_slices[fi] = fpixels[fmin_alloc + fi].clone();
					int f = fmin_alloc + fi;
					stack_titles[fi] = (scene_titles_all != null && f < scene_titles_all.length)
							? scene_titles_all[f] : "f" + f;
				}
				ShowDoubleFloatArrays.showArrays(stack_slices, width, height, true,
						"refineMotionVectors-nseq" + nseq, stack_titles);
			}

			TDCorrTile[] tdCorrTiles = cuasMotion.correlatePairs(
			TDCorrTile[] tdCorrTiles = cuasMotion.correlatePairs( // By Claude on 05/06/2026
					clt_parameters,                   // CLTParameters clt_parameters
					fpixels_masked,                   // float [][]    fpixels
					frame0_ref,                       // int           frame0
					frame1_ref,                       // int           frame1
					corr_pairs_ref,                   // int           frame_len
					1,                                // int           corr_ra_step (direct accumulation, no rolling avg)
					targets_nonoverlap[nseq],         // double [][]   targets_mv (per-tile motion centers)
					frame_center,                     // int           frame_center_mv
					corr_offset,                      // int           corr_offset_mv
					smooth,                           // boolean       smooth
					batch_mode,                       // boolean       batch_mode
					null,                             // String        dbg_suffix
@@ -2444,18 +2460,44 @@ public class CuasMotion {
			final boolean batch_mode,
			final String  dbg_suffix, // for image_names
			int           debugLevel) {
		return correlatePairs(clt_parameters, fpixels, frame0, frame1, frame_len, corr_ra_step,
				null, 0, 1, smooth, batch_mode, dbg_suffix, debugLevel);
	}

	// By Claude on 05/06/2026
	public TDCorrTile [] correlatePairs(
			CLTParameters clt_parameters,
			float [][]    fpixels,
			int           frame0, // OK if <0
			int           frame1, // OK if >= fpixels.length
			int           frame_len,
			int           corr_ra_step,
			double [][]   targets_mv,       // null: uniform grid; non-null: per-tile motion-tracking centers
			int           frame_center_mv,  // only used when targets_mv != null
			int           corr_offset_mv,   // only used when targets_mv != null
			boolean       smooth, // use cosine mask
			final boolean batch_mode,
			final String  dbg_suffix, // for image_names
			int           debugLevel) {
		TDCorrTile [] tdCorrTiles = new TDCorrTile[tilesX * tilesY];
		double sw = 0;
		for (int dframe = corr_ra_step/2; dframe < frame_len; dframe += corr_ra_step) {
			double weight = smooth ? Math.sin((dframe+0.5)/frame_len*Math.PI) : 1.0;
			if (((frame0+dframe) >= 0) && ((frame1+dframe) < fpixels.length)) {
				String dbg_n_suffix = (dbg_suffix != null) ? (dbg_suffix+"-"+dframe) : null;
				double offset_scale_ref = (targets_mv != null) ?
						(double)(frame0 + dframe - frame_center_mv) / corr_offset_mv : 0.0;
				double offset_scale_img = (targets_mv != null) ?
						(double)(frame1 + dframe - frame_center_mv) / corr_offset_mv : 0.0;
				TDCorrTile [] pairTiles = correlatePair(
						clt_parameters,          // CLTParameters clt_parameters,
						fpixels[frame0+dframe],  // float []      fpixels_ref,
						fpixels[frame1+dframe],  // float []      fpixels_img,
						targets_mv,              // double [][]   targets_mv,
						offset_scale_ref,        // double        offset_scale_ref,
						offset_scale_img,        // double        offset_scale_img,
						batch_mode,              // final boolean batch_mode,
						dbg_n_suffix,           // final String  dbg_suffix, // for image_names
						dbg_n_suffix,            // final String  dbg_suffix,
						debugLevel);             // int           debugLevel)
				TDCorrTile.accumulate(
						tdCorrTiles,             // final TDCorrTile [] dst,
@@ -2693,64 +2735,88 @@ public class CuasMotion {
			final boolean batch_mode,
			final String  dbg_suffix, // for image_names
			int           debugLevel) {
		return correlatePair(clt_parameters, fpixels_ref, fpixels_img,
				null, 0.0, 0.0, batch_mode, dbg_suffix, debugLevel);
	}

	// By Claude on 05/06/2026
	public TDCorrTile [] correlatePair(
			CLTParameters  clt_parameters,
			float []       fpixels_ref,
			float []       fpixels_img,
			double [][]    targets_mv,      // null: uniform grid; non-null: per-tile motion-tracking centers
			double         offset_scale_ref,// (frame_ref - frame_center) / corr_offset; only used when targets_mv != null
			double         offset_scale_img,// (frame_img - frame_center) / corr_offset; only used when targets_mv != null
			final boolean  batch_mode,
			final String   dbg_suffix, // for image_names
			int            debugLevel) {
		int [] wh = {gpu_max_width, gpu_max_height};
		TpTask [] tp_ref, tp_img;
		if (targets_mv != null) {
			tp_ref = GpuQuad.setRectilinearMovingTasks(
					targets_mv,             // final double [][] targets_array,
					offset_scale_ref,       // final double      offset_scale,
					0.0,                    // final double      magnitude_scale,
					CuasMotionLMA.RSLT_VX,  // final int         index_vx,
					CuasMotionLMA.RSLT_X,   // final int         index_xc,
					tilesX);                // final int         tilesX
			tp_img = GpuQuad.setRectilinearMovingTasks(
					targets_mv,
					offset_scale_img,
					0.0,
					CuasMotionLMA.RSLT_VX,
					CuasMotionLMA.RSLT_X,
					tilesX);
		} else {
			Rectangle woi = new Rectangle(0, 0, wh[0], wh[1]);
			float [][] fpixels = {fpixels_ref, fpixels_img};
			TpTask [][] tp_tasks = GpuQuad.setRectilinearInterTasks(
				fpixels, // final float  [][]   fpixels, // to check for empty (no processing where it images have NaN
				wh[0],   // final int           img_width,
				woi,     // Rectangle           woi,
				null);   // final double [][][] affine  // [2][2][3] affine coefficients to translate common to 2 images
//		if (tp_tasks_o != null) {
//			for (int i = 0; i < tp_tasks_o.length; i++) tp_tasks_o[i] = tp_tasks[i];
//		}
					fpixels, wh[0], woi, null);
			tp_ref = tp_tasks[0];
			tp_img = tp_tasks[1];
		}
		int erase_cltr = -1;
		int erase_clt  = -1;
		image_dtt.setRectilinearReferenceTD(
				erase_cltr,                  // final int                 erase_clt,
				fpixels_ref,                 // final float []            fpixels_ref,
				wh,                         // final int []              wh,               // null (use sensor dimensions) or pair {width, height} in pixels
				clt_parameters.img_dtt,     // final ImageDttParameters  imgdtt_params,    // Now just extra correlation parameters, later will include, most others
				wh,                          // final int []              wh,
				clt_parameters.img_dtt,      // final ImageDttParameters  imgdtt_params,
				true,                        // final boolean             use_reference_buffer,
				tp_tasks[0],                // final TpTask[]            tp_tasks,
				clt_parameters.gpu_sigma_r, // final double              gpu_sigma_r,     // 0.9, 1.1
				clt_parameters.gpu_sigma_b, // final double              gpu_sigma_b,     // 0.9, 1.1
				clt_parameters.gpu_sigma_g, // final double              gpu_sigma_g,     // 0.6, 0.7
				clt_parameters.gpu_sigma_m, // final double              gpu_sigma_m,     //  =       0.4; // 0.7;
				batch_mode? -3: debugLevel);                // final int                 globalDebugLevel)
				tp_ref,                      // final TpTask[]            tp_tasks,
				clt_parameters.gpu_sigma_r,  // final double              gpu_sigma_r,
				clt_parameters.gpu_sigma_b,  // final double              gpu_sigma_b,
				clt_parameters.gpu_sigma_g,  // final double              gpu_sigma_g,
				clt_parameters.gpu_sigma_m,  // final double              gpu_sigma_m,
				batch_mode ? -3 : debugLevel);
		if (!batch_mode && (dbg_suffix != null)) {
    		renderFromTD (
    				true, // boolean             use_reference,
    				"ref"+dbg_suffix); //String              suffix
			renderFromTD(true, "ref"+dbg_suffix);
		}
		float [][][][] fcorr_td = new float [tilesY][tilesX][][];
    	//null; // no accumulation, use data in GPU
		final double gpu_sigma_corr =     clt_parameters.getGpuCorrSigma(image_dtt.isMonochrome());
		final double gpu_sigma_rb_corr =  image_dtt.isMonochrome() ? 1.0 : clt_parameters.gpu_sigma_rb_corr;
		final double gpu_sigma_log_corr = clt_parameters.getGpuCorrLoGSigma(image_dtt.isMonochrome());
		image_dtt.interRectilinearCorrTD(
				clt_parameters.img_dtt,     //final ImageDttParameters  imgdtt_params,    // Now just extra correlation parameters, later will include, most others
				clt_parameters.img_dtt,      // final ImageDttParameters  imgdtt_params,
				batch_mode,                  // final boolean batch_mode,
				erase_clt,                   // final int                 erase_clt,
				fpixels_img,                 // final float []            fpixels,
				wh,                         // final int []              wh,               // null (use sensor dimensions) or pair {width, height} in pixels
				tp_tasks[1],                // final TpTask[]            tp_tasks,
				fcorr_td,                   // final float  [][][][]     fcorr_td,        // [tilesY][tilesX][pair][4*64] transform domain representation of 6 corr pairs
				clt_parameters.gpu_sigma_r, // final double              gpu_sigma_r,     // 0.9, 1.1
				clt_parameters.gpu_sigma_b, // final double              gpu_sigma_b,     // 0.9, 1.1
				clt_parameters.gpu_sigma_g, // final double              gpu_sigma_g,     // 0.6, 0.7
				clt_parameters.gpu_sigma_m, // final double              gpu_sigma_m,     //  =       0.4; // 0.7;
				gpu_sigma_rb_corr,          // final double              gpu_sigma_rb_corr,    //  = 0.5; // apply LPF after accumulating R and B correlation before G, monochrome ? 1.0 :
				gpu_sigma_corr,             // final double              gpu_sigma_corr,       //  =    0.9;gpu_sigma_corr_m
				gpu_sigma_log_corr,         // final double              gpu_sigma_log_corr,   // hpf to reduce dynamic range for correlations
				clt_parameters.corr_red,    // final double              corr_red, // +used
				clt_parameters.corr_blue,   // final double              corr_blue,// +used
				-1,                         // final int                 sensor_mask_inter, // The bitmask - which sensors to correlate, -1 - all.
				debugLevel);                // final int                 globalDebugLevel)
				wh,                          // final int []              wh,
				tp_img,                      // final TpTask[]            tp_tasks,
				fcorr_td,                    // final float  [][][][]     fcorr_td,
				clt_parameters.gpu_sigma_r,  // final double              gpu_sigma_r,
				clt_parameters.gpu_sigma_b,  // final double              gpu_sigma_b,
				clt_parameters.gpu_sigma_g,  // final double              gpu_sigma_g,
				clt_parameters.gpu_sigma_m,  // final double              gpu_sigma_m,
				gpu_sigma_rb_corr,           // final double              gpu_sigma_rb_corr,
				gpu_sigma_corr,              // final double              gpu_sigma_corr,
				gpu_sigma_log_corr,          // final double              gpu_sigma_log_corr,
				clt_parameters.corr_red,     // final double              corr_red,
				clt_parameters.corr_blue,    // final double              corr_blue,
				-1,                          // final int                 sensor_mask_inter,
				debugLevel);
		if (!batch_mode && (dbg_suffix != null)) {
			renderFromTD (
					false, // boolean             use_reference,
					"img"+dbg_suffix); //String              suffix
			renderFromTD(false, "img"+dbg_suffix);
		}
		TDCorrTile [] tdCorrTiles = TDCorrTile.getFromGpu(gpuQuad);
		return tdCorrTiles;