Commit 9a4d969e authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Profiling and convenience features

parent 5961834e
Loading
Loading
Loading
Loading
+149 −98
Original line number Diff line number Diff line
@@ -1762,104 +1762,6 @@ public class CuasMotion {
	}
	

	
	// By Claude on 05/07/2026: pre-populate target_sequence_multi with FAIL_PENDING sentinels from motion_sequence.
	// Each sentinel is a clone of the motion entry with RSLT_FAIL=FAIL_PENDING, RSLT_CENTERED=CENTERED_NO,
	// RSLT_QSCORE initialized from RSLT_MSCORE. Preserves VX/VY/X/Y and all other motion fields.
	@Deprecated
	public static void initFromMotionSequence(
			final double [][][]   motion_sequence,
			final double [][][][] target_sequence_multi) {
		final int num_seq   = motion_sequence.length;
		final int num_tiles = motion_sequence[0].length;
		for (int nSeq = 0; nSeq < num_seq; nSeq++) {
			for (int ntile = 0; ntile < num_tiles; ntile++) {
				if (motion_sequence[nSeq][ntile] != null && target_sequence_multi[nSeq][ntile] == null) {
					double [] sentinel = motion_sequence[nSeq][ntile].clone();
					sentinel[CuasMotionLMA.RSLT_FAIL]     = CuasMotionLMA.FAIL_PENDING;
					sentinel[CuasMotionLMA.RSLT_CENTERED] = CuasMotionLMA.CENTERED_NO;
					sentinel[CuasMotionLMA.RSLT_QSCORE]   = motion_sequence[nSeq][ntile][CuasMotionLMA.RSLT_MSCORE];
					target_sequence_multi[nSeq][ntile] = new double [][] {sentinel};
				}
			}
		}
	}

	// By Claude on 05/07/2026: after each getEffectiveStrengthMV call, keep RSLT_QSCORE in FAIL_PENDING sentinels
	// current with the freshly computed RSLT_MSCORE so filter5 ranks by up-to-date motion confidence.
	@Deprecated
	public static void syncMotionScoreToSentinels(
			final double [][][]   motion_sequence,
			final double [][][][] target_sequence_multi) {
		final int num_seq   = motion_sequence.length;
		final int num_tiles = motion_sequence[0].length;
		for (int nSeq = 0; nSeq < num_seq; nSeq++) {
			for (int ntile = 0; ntile < num_tiles; ntile++) {
				double [] mv = motion_sequence[nSeq][ntile];
				if (mv != null && target_sequence_multi[nSeq][ntile] != null) {
					for (double [] entry : target_sequence_multi[nSeq][ntile]) {
						if ((entry != null) &&
								((entry[CuasMotionLMA.RSLT_FAIL]     == CuasMotionLMA.FAIL_PENDING) &&
								( entry[CuasMotionLMA.RSLT_CENTERED] == CuasMotionLMA.CENTERED_NO))) {
							// copy all other
///							entry[CuasMotionLMA.RSLT_QSCORE] = mv[CuasMotionLMA.RSLT_MSCORE]; Why was that needed?
// Make a mrthod to copy all motion-related parameters							
							entry[CuasMotionLMA.RSLT_VX] =     mv[CuasMotionLMA.RSLT_VX];
							entry[CuasMotionLMA.RSLT_VY] =     mv[CuasMotionLMA.RSLT_VY];
							entry[CuasMotionLMA.RSLT_VSTR] =   mv[CuasMotionLMA.RSLT_VSTR];
							entry[CuasMotionLMA.RSLT_VFRAC] =  mv[CuasMotionLMA.RSLT_VFRAC];
							entry[CuasMotionLMA.RSLT_VBOOST] = mv[CuasMotionLMA.RSLT_VBOOST];
							entry[CuasMotionLMA.RSLT_VCORR] =  mv[CuasMotionLMA.RSLT_VCORR];
						}
					}
				}
			}
		}
	}

	// fills out additional fields in target_coords
	@Deprecated
	public static double [][] getEffectiveStrengthMV( // calculate tiles effective strength by the motion vectors. Combine with the target LMA?
			final double [][][] targets_sequence,
			int                 niter, // save iteration number on failure if >=
			final int           tilesX,
			final double        min_score_mv,
			double              speed_min,		
			double              speed_pref,		
			double              speed_boost	){
		final int num_seq = targets_sequence.length;
		final int num_tiles = targets_sequence[0].length;
		final double [][] effective_strength = new double [num_seq][num_tiles];
		final Thread[] threads = ImageDtt.newThreadArray();
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int nSeq = ai.getAndIncrement(); nSeq < num_seq; nSeq = ai.getAndIncrement()) {
						double [][] targets = targets_sequence[nSeq];
						for (int ntile = 0; ntile < num_tiles; ntile++) {
							if (targets[ntile] != null) {
								double es =	getEffectiveStrengthMV(
										targets[ntile],  // double [] target,
										speed_min,  // double speed_min,		
										speed_pref, // double speed_pref,		
										speed_boost); //double speed_boost)
								targets[ntile][CuasMotionLMA.RSLT_MSCORE] = es;
								effective_strength[nSeq][ntile] = es;
								if ((niter >= 0) && !(es >= min_score_mv)) {
									targets[ntile][CuasMotionLMA.RSLT_FAIL] = CuasMotionLMA.FAIL_MOTION;
									targets[ntile][CuasMotionLMA.RSLT_WHEN] = niter;
								}
							}
						}
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		return effective_strength;
	}

	/**
	 * When used, each tile has a single target
	 * @param targets_sequence_multi
@@ -2366,6 +2268,11 @@ public class CuasMotion {
		final Thread[] threads = ImageDtt.newThreadArray();
		final AtomicInteger ai = new AtomicInteger(0);
		final boolean show_dbg = (dbg_nseq >= 0 || dbg_tile >= 0) && debugLevel >= 0;
		// By Claude on 05/24/2026: profiling accumulators
		long t_clear = 0, t_mask = 0, t_corr = 0, t_pd = 0;
		int prof_nseq = 0, prof_targets = 0;
		long t_corr_sparse = 0, t_corr_dense = 0; // sparse: <10 targets, dense: >=10
		int prof_nseq_sparse = 0, prof_nseq_dense = 0;
		// Collect per-nseq correlation for end-of-method CORR2D stack
		final double[][][] corr2d_ref = show_dbg ? new double[targets_nonoverlap.length][][] : null;
		final String[] scene_titles_all = cuasMotion.getSceneTitles();
@@ -2394,7 +2301,9 @@ public class CuasMotion {
			if (fmin_alloc > fmax_alloc) continue;  // no valid pairs in range

			// Clear staging frames for this scan position
			long t0 = System.nanoTime(); // By Claude on 05/24/2026
			for (int f = fmin_alloc; f <= fmax_alloc; f++) Arrays.fill(fpixels_masked[f], 0.0f);
			long t1 = System.nanoTime(); // By Claude on 05/24/2026

			// Pre-extract tile center/velocity for thread-safe parallel access
			final int ntiles = targets_nonoverlap[nseq].length;
@@ -2413,6 +2322,9 @@ public class CuasMotion {
				tvy[ntile]  = target[CuasMotionLMA.RSLT_VY];
			}

			// By Claude on 05/24/2026: count valid targets for profiling
			int nseq_targets = 0;
			for (int ntile = 0; ntile < ntiles; ntile++) if (tile_valid[ntile]) nseq_targets++;
			// Parallel over frames: each thread applies all tile masks to one frame
			final int fmin_f  = fmin_alloc;
			final int frange  = fmax_alloc - fmin_f + 1;
@@ -2449,6 +2361,7 @@ public class CuasMotion {
				};
			}
			ImageDtt.startAndJoin(threads);
			long t2 = System.nanoTime(); // By Claude on 05/24/2026

			// Debug: show full fmin..fmax masked frame stack for dbg_nseq
			if ((nseq == dbg_nseq) && (debugLevel >= 0)) { //  && (dbg_iter_index<= max_index_dbg)) {
@@ -2478,6 +2391,7 @@ public class CuasMotion {
						"refineMotionVectors-boost"+recalc_mv_boost+"-nseq" + nseq+"-niter"+dbg_iter_index+dbg_suffix, stack_titles);
			}

			long t3 = System.nanoTime(); // By Claude on 05/24/2026
			TDCorrTile[] tdCorrTiles = cuasMotion.correlatePairs( // By Claude on 05/06/2026
					clt_parameters,                   // CLTParameters clt_parameters
					fpixels_masked,                   // float [][]    fpixels
@@ -2493,6 +2407,7 @@ public class CuasMotion {
					null,                             // String        dbg_suffix
					debugLevel);

			long t4 = System.nanoTime(); // By Claude on 05/24/2026
			double scale_fat_zero = 1.0 / recalc_mv_boost;
			double[][] corr_tiles_pd = cuasMotion.convertTDtoPD(
					tdCorrTiles,
@@ -2513,6 +2428,7 @@ public class CuasMotion {
					true);


			long t5 = System.nanoTime(); // By Claude on 05/24/2026
			// Add differential MV to targets_nonoverlap in-place
			for (int ntile = 0; ntile < targets_nonoverlap[nseq].length; ntile++) {
				double[] target = targets_nonoverlap[nseq][ntile];
@@ -2539,6 +2455,30 @@ public class CuasMotion {
					// set RSLT_WHEN - will be set in public static int addNewResults()
				}
			}
			// By Claude on 05/24/2026: accumulate profiling times
			t_clear += t1 - t0;
			t_mask  += t2 - t1;
			t_corr  += t4 - t3;
			t_pd    += t5 - t4;
			prof_nseq++;
			prof_targets += nseq_targets;
			if (nseq_targets < 10) { t_corr_sparse += t4 - t3; prof_nseq_sparse++; }
			else                   { t_corr_dense  += t4 - t3; prof_nseq_dense++;  }
		}
		// By Claude on 05/24/2026: profiling summary
		if (prof_nseq > 0) {
			double ms = 1e-6;
			System.out.printf("refineMotionVectors() profiling (%d nseq, %d total targets, avg %.1f/iter, boost=%.1f):%n",
					prof_nseq, prof_targets, (double)prof_targets/prof_nseq, recalc_mv_boost);
			System.out.printf("  clear (Arrays.fill)           : %8.1f ms total, %6.3f ms/iter%n", t_clear*ms, t_clear*ms/prof_nseq);
			System.out.printf("  mask  (startAndJoin)          : %8.1f ms total, %6.3f ms/iter%n", t_mask *ms, t_mask *ms/prof_nseq);
			System.out.printf("  corr  (correlatePairs) total  : %8.1f ms total, %6.3f ms/iter%n", t_corr *ms, t_corr *ms/prof_nseq);
			if (prof_nseq_sparse > 0) System.out.printf("    corr sparse (<10 targ, %3d iters): %8.1f ms, %6.3f ms/iter%n",
					prof_nseq_sparse, t_corr_sparse*ms, t_corr_sparse*ms/prof_nseq_sparse);
			if (prof_nseq_dense  > 0) System.out.printf("    corr dense  (>=10 targ, %3d iters): %8.1f ms, %6.3f ms/iter%n",
					prof_nseq_dense,  t_corr_dense *ms, t_corr_dense *ms/prof_nseq_dense);
			System.out.printf("  pd    (convertTD+getMismatch) : %8.1f ms total, %6.3f ms/iter%n", t_pd*ms, t_pd*ms/prof_nseq);
			System.out.printf("  total accounted               : %8.1f ms%n", (t_clear+t_mask+t_corr+t_pd)*ms);
		}
		// Debug: CORR2D overview — one slice per keyframe, same layout as *CORR2D.tiff
		if (show_dbg && (corr2d_ref != null)) { // && (dbg_iter_index<= max_index_dbg)) {
@@ -6761,6 +6701,85 @@ public class CuasMotion {
		return;
	}
	
	/**
	 * Fail early after phase 1 to increase performance
	 * Use the following procedure to select values:
	 * 1) Relax them and run the program
	 * 2) Analyze RSLT_PHASE1_* parameters of the survived targets at the last stage (currently, *-CENT.tiff)
	 * 3) Set the threshold values somewhat lower.
	 * Each threshold below, if set  
	 * @param target_multi target data to be modified [nseq][ntile][ntarget][nparam] 
	 * @param niter        current iteration number, will be applied to [RSLT_WHEN]
	 * @param min_mscore   minimal value for [RSLT_MSCORE]
	 * @param min_vstr     minimal value for [RSLT_VSTR]
	 * @param min_score    minimal value for [RSLT_QSCORE]
	 * @param min_amp      minimal value for [RSLT_A]
	 * @return             int [] : total number of failures and for each of the 4 input parameters (same target may fail by several parameters 
	 */
	public static int [] earlyFail( // Fail after Phase 1
			final double [][][][] target_multi,
			final int             niter,
			final double          min_mscore,
			final double          min_vstr,			
			final double          min_score,
			final double          min_amp) {
		final int num_seq =           target_multi.length;
		final int num_tiles =         target_multi[0].length;
		final Thread[] threads =      ImageDtt.newThreadArray();
		final AtomicInteger ai =      new AtomicInteger(0);
		final AtomicInteger afail =    new AtomicInteger(0);
		final AtomicInteger amscore = new AtomicInteger(0);
		final AtomicInteger avstr =   new AtomicInteger(0);
		final AtomicInteger ascore =  new AtomicInteger(0);
		final AtomicInteger aamp =    new AtomicInteger(0);
		
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int nSeq = ai.getAndIncrement(); nSeq < num_seq; nSeq = ai.getAndIncrement()) {
						for (int ntile = 0; ntile < num_tiles; ntile++) {
							double [][] targets = target_multi[nSeq][ntile];
							if (targets != null){
								for (int ntarg = 0; ntarg <targets.length; ntarg++) if (targets[ntarg] != null){
									if (Double.isNaN(targets[ntarg][CuasMotionLMA.RSLT_FAIL]) || (targets[ntarg][CuasMotionLMA.RSLT_FAIL]==CuasMotionLMA.FAIL_NONE)) {
										int fail_type = 0;
										if (!Double.isNaN(min_mscore) && !(targets[ntarg][CuasMotionLMA.RSLT_MSCORE] >= min_mscore)) {
											if (fail_type == 0) fail_type = CuasMotionLMA.FAIL_MOTION;
											amscore.getAndIncrement();
										}
										if (!Double.isNaN(min_vstr) && !(targets[ntarg][CuasMotionLMA.RSLT_VSTR] >= min_vstr)) {
											if (fail_type == 0) fail_type = CuasMotionLMA.FAIL_MOTION;
											avstr.getAndIncrement();
										}
										if (!Double.isNaN(min_score) && !(targets[ntarg][CuasMotionLMA.RSLT_QSCORE] >= min_score)) {
											if (fail_type == 0) fail_type = CuasMotionLMA.FAIL_Q_LOW;
											ascore.getAndIncrement();
										}
										if (!Double.isNaN(min_amp) && !(targets[ntarg][CuasMotionLMA.RSLT_A] >= min_amp)) {
											if (fail_type == 0) fail_type = CuasMotionLMA.FAIL_A_LOW;
											aamp.getAndIncrement();
										}
										if (fail_type != 0) {
											targets[ntarg][CuasMotionLMA.RSLT_FAIL] = fail_type;
											targets[ntarg][CuasMotionLMA.RSLT_WHEN] = niter;
											afail.getAndIncrement();
										}
									}
								}
							}
						}
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		return new int [] {
				afail.get(),
				amscore.get(),
				avstr.get(),
				ascore.get(),
				aamp.get()};
	}
	
	
	
@@ -8020,6 +8039,13 @@ public class CuasMotion {
		boolean accum_boosted =        clt_parameters.imp.cuas_accum_boosted;// By AF on 05/12/2026
		// at least one of accum_boosted, accum_base should be used, normally both
		boolean accum_base =           clt_parameters.imp.cuas_accum_base || !accum_boosted;   // By AF on 05/12/2026
		
		boolean early_en =        clt_parameters.imp.cuas_early_en;     // Apply early fail filter after phase 1
		double  early_mscore =    clt_parameters.imp.cuas_early_mscore; // Minimal motion score  (RSLT_MSCORE)
		double  early_vstr =      clt_parameters.imp.cuas_early_vstr;   // Minimal MV confidence (RSLT_VSTR)
		double  early_score =     clt_parameters.imp.cuas_early_score;  // Minimal score         (RSLT_QSCORE)
		double  early_amp =       clt_parameters.imp.cuas_early_amp;    // Minimal amplitude     (RSLT_A)
		
		for (int i = 0; i < target_frac.length; i++) {
			if (clt_parameters.imp.cuas_target_frac[i].length >= 2) {
				target_frac[i][0] = clt_parameters.imp.cuas_target_frac[i][0];
@@ -8531,6 +8557,28 @@ public class CuasMotion {
					score_coeff,       // final double []     importance, // for now (each - squared?): [0] - Amplitude (A/A0), 1 - RMS (RMS0/RMS), 2 - RRMS((RMS/A0) / (RMS/A)
					slow_score,        // final double          slow_score,           // multiply total score for targets detected in slow target mode
					cuasMotion.tilesX);            // final int         tilesX,
			if (early_en) {
				int [] early_fail =  earlyFail( // Fail after Phase 1
						target_sequence_multi,  // final double [][][][] target_multi,
						niter,                  // final int             niter,
						early_mscore,           // final double          min_mscore,
						early_vstr,             // final double          min_vstr,			
						early_score,            // final double          min_score,
						early_amp);             // final double          min_amp);
				if (debugLevel > -4) {
					System.out.println("Early failed:");
					System.out.println(String.format("     total: %5d", early_fail[0]));
					System.out.println(String.format("    mscore: %5d (<%f)", early_fail[1],early_mscore));
					System.out.println(String.format("      vstr: %5d (<%f)", early_fail[2],early_vstr));
					System.out.println(String.format("     score: %5d (<%f)", early_fail[3],early_score));
					System.out.println(String.format(" amplitude: %5d (<%f)", early_fail[4],early_amp));
				}
			} else {
				if (debugLevel > -4) {
					System.out.println("Early fail DISABLED.");
				}
			}
			
			sortMultiTargets(
					target_sequence_multi, // final double [][][][] target_multi,
					true);                 // final boolean         trim_nulls) { // trim null targets
@@ -10624,6 +10672,9 @@ public class CuasMotion {
					false,                // boolean               slow_mode,
					debugLevel);          // final int             debugLevel)

			
			
			
			double [][][][] targets_good_multi = targets_fast;
			/*
			 * Before running with slow_en== true, verify temporal (scene) offset between slow and fast mode.
+17 −16
Original line number Diff line number Diff line
@@ -160,28 +160,29 @@ public class CuasMotionLMA {
	public static final String EXTRA_SLICE_DISCARD_ON_LOAD = "Targets"; 
	public static final int FAIL_PENDING =  -1; // By Claude on 05/07/2026: motion sentinel — tile tracked but not yet processed by LMA
	public static final int FAIL_NONE =      0;
	public static final int FAIL_MOTION =    1;  // motion strength/fraction too low
	public static final int FAIL_MOTION =    1;  // motion strength/fraction too low, also - motion score too low
	public static final int FAIL_NO_MAX =    2;  // no suitable local maximum 
	public static final int FAIL_CENT_STR =  3;  // centroid amplitude is too low
	public static final int FAIL_CENT_FRAC = 4;  // centroid fraction (energy in the peak fraction of all) is too low
	public static final int FAIL_LMA =       5;  // LMA fail to converge
	public static final int FAIL_A_PRE =     6;  // amplitude is too low at preliminary filter (just after LMA)
	public static final int FAIL_A_LOW =     7;  // amplitude is too low
	public static final int FAIL_ACENT =     8;  // ratio of maximal pixel to amplitude is too low
	public static final int FAIL_RMSE =      9;  // RMSE is too high
	public static final int FAIL_RMSE_R =   10;  // BOTH RMSE is not sufficient and RMSE/A is too high
	public static final int FAIL_R0_HIGH =  11;  // Full radius (including negative overshoot) is too high
	public static final int FAIL_R1_LOW =   12;  // Inner (positive) peak radius is too low
	public static final int FAIL_K_LOW =    13;  // Overshoot is too low (not used, it can be down to 0)
	public static final int FAIL_K_HIGH =   14;  // Overshoot is too high
	public static final int FAIL_FAR =      15;  // Peak is too far from the center
	public static final int FAIL_VCORR =    16;  // MV refinement (fine pass) resulted in a too high correction (not yet checked)
	public static final int FAIL_HORIZON =  17;  // Peak is below horizon 
	public static final int FAIL_MISMATCH = 18;  // Mismatch on both ends is too high 
	public static final int FAIL_NEIGHBOR = 19;  // failed because some neighbor is stronger   
	public static final int FAIL_DUPLICATE= 20;  // coordinate are (almost) the same as those of a stronger tile   
	public static final int FAIL_USED=      21;  // non-centered used to generate centered, remove this   
	public static final int FAIL_FL_ONLY=   22;  // Flight log data only, no target detected here   
	public static final int FAIL_Q_LOW =     8;  // score too low
	public static final int FAIL_ACENT =     9;  // ratio of maximal pixel to amplitude is too low
	public static final int FAIL_RMSE =     10;  // RMSE is too high
	public static final int FAIL_RMSE_R =   11;  // BOTH RMSE is not sufficient and RMSE/A is too high
	public static final int FAIL_R0_HIGH =  12;  // Full radius (including negative overshoot) is too high
	public static final int FAIL_R1_LOW =   13;  // Inner (positive) peak radius is too low
	public static final int FAIL_K_LOW =    14;  // Overshoot is too low (not used, it can be down to 0)
	public static final int FAIL_K_HIGH =   15;  // Overshoot is too high
	public static final int FAIL_FAR =      16;  // Peak is too far from the center
	public static final int FAIL_VCORR =    17;  // MV refinement (fine pass) resulted in a too high correction (not yet checked)
	public static final int FAIL_HORIZON =  18;  // Peak is below horizon 
	public static final int FAIL_MISMATCH = 19;  // Mismatch on both ends is too high 
	public static final int FAIL_NEIGHBOR = 20;  // failed because some neighbor is stronger   
	public static final int FAIL_DUPLICATE= 21;  // coordinate are (almost) the same as those of a stronger tile   
	public static final int FAIL_USED=      22;  // non-centered used to generate centered, remove this   
	public static final int FAIL_FL_ONLY=   23;  // Flight log data only, no target detected here   
	
	public static final int CENTERED_NO =    0; 
	public static final int CENTERED_YES =   1; 
+49 −6

File changed.

Preview size limit exceeded, changes collapsed.