Commit 95386703 authored by Andrey Filippov's avatar Andrey Filippov

adjusting parameters, improved filtering, added error display by the

targets
parent 25577f58
......@@ -546,7 +546,7 @@ public class LensAdjustment {
double targetMicrons, // target lens center distance (away from "best focus"
double toleranceMicrons, // microns
double toleranceTilt, //
double toleranceThreshold, // When each error is under swcaled thereshold, reduce correxction step twice
double toleranceThreshold, // When each error is under swcaled threshold, reduce correxction step twice
double parallelAdjustThreshold, // adjust 3 motors parallel if focal distance error in the center exceeds this
double motorsSigma, // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma
double motorsSigma3, // all 3 motors together (focusing center)
......@@ -710,7 +710,7 @@ public class LensAdjustment {
this.targetMicrons=targetMicrons; // target lens center distance (away from "best focus"
this.toleranceMicrons=toleranceMicrons; // microns
this.toleranceTilt=toleranceTilt; //
this.toleranceThreshold=toleranceThreshold; // When each error is under swcaled thereshold, reduce correxction step twice
this.toleranceThreshold=toleranceThreshold; // When each error is under swcaled threshold, reduce correxction step twice
this.parallelAdjustThreshold=parallelAdjustThreshold; // adjust 3 motors parallel if focal distance error in the center exceeds this
this.motorsSigma=motorsSigma; // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma
this.motorsSigma3=motorsSigma3; // same when 3 motors move together
......@@ -873,7 +873,7 @@ public class LensAdjustment {
this.targetMicrons, // target lens center distance (away from "best focus"
this.toleranceMicrons, // microns
this.toleranceTilt, //
this.toleranceThreshold, // When each error is under swcaled thereshold, reduce correxction step twice
this.toleranceThreshold, // When each error is under swcaled threshold, reduce correxction step twice
this.parallelAdjustThreshold, // adjust 3 motors parallel if focal distance error in the center exceeds this
this.motorsSigma, // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma
......
......@@ -3512,7 +3512,7 @@ public class CLTParameters {
gd.addCheckbox ("Add port weights to RGBA stack (debug feature)", this.keep_weights);
gd.addCheckbox ("Replace port weights with per-channel MIDCT (16x16) - were relevant", this.replace_weights);
gd.addCheckbox ("Alpha channel: use center 8x8 (unchecked - treat same as RGB)", this.sharp_alpha);
gd.addNumericField("Alpha channel 0.0 thereshold (lower - transparent)", this.alpha0, 3);
gd.addNumericField("Alpha channel 0.0 threshold (lower - transparent)", this.alpha0, 3);
gd.addNumericField("Alpha channel 1.0 threshold (higher - opaque)", this.alpha1, 3);
gd.addCheckbox ("Generate shifted channel linear RGB stacks", this.gen_chn_stacks);
gd.addCheckbox ("Generate shifted channel color image stack", this.gen_chn_img);
......@@ -4130,11 +4130,11 @@ public class CLTParameters {
"Absolute inter-sensor difference to seed transparent texture.");
gd.addNumericField("Seed fat zero of combo variance", this.lre_seed_same_fz, 5,7,"", // 6.5; // 13; // seed_inter = 50.0;
"Add to the denominator (to combined variance) to divide inter-sensor variance.");
gd.addNumericField("Seed FOM thereshold", this.lre_seed_fom, 5,7,"", // 2.0; // 1.9; // 1.2;
gd.addNumericField("Seed FOM threshold", this.lre_seed_fom, 5,7,"", // 2.0; // 1.9; // 1.2;
"Seed threshold for var_inter/(var_same+var_same_fz) - definitely not a foreground.");
gd.addNumericField("Seed fat zero of inter-sensor variance",this.lre_trim_inter_fz, 5,7,"", //5.0; // 13.0;
"Add to the denominator (to inter-sensor variance) to divide combo variance.");
gd.addNumericField("Trim FOM thereshold", this.lre_trim_fom, 5,7,"", // 0.5; // 0.8; // 1.3; // 1.8; // 1.2; // 0.8; // 0.4; // 0.7;
gd.addNumericField("Trim FOM threshold", this.lre_trim_fom, 5,7,"", // 0.5; // 0.8; // 1.3; // 1.8; // 1.2; // 0.8; // 0.4; // 0.7;
"Trim threshold for var_same/(var_inter+var_inter_fz) - seems to be foreground.");
gd.addMessage("Reducing Trim FOM near high-contrast FG over sky by thresholding, bluring and dividing");
// Scale down FOM for pixels near high-variance VAR_SAME
......
......@@ -106,7 +106,8 @@ public class DoubleGaussianBlur {
return;
}
/* Blur an image in one direction (x or y) by a Gaussian.
/**
* Blur an image in one direction (x or y) by a Gaussian.
* @param ip The Image with the original data where also the result will be stored
* @param sigma Standard deviation of the Gaussian
* @param accuracy Accuracy of kernel, should not be > 0.02
......@@ -188,7 +189,8 @@ public class DoubleGaussianBlur {
}
return;
}
/* Create a 1-dimensional normalized Gaussian kernel with standard deviation sigma
/**
* Create a 1-dimensional normalized Gaussian kernel with standard deviation sigma
* and the running sum over the kernel
* Note: this is one side of the kernel only, not the full kernel as used by the
* Convolver class of ImageJ.
......@@ -252,14 +254,15 @@ public class DoubleGaussianBlur {
}
return kernel;
}
/* Scale a line (row or column of a FloatProcessor or part thereof)
/** Scale a line (row or column of a FloatProcessor or part thereof)
* down by a factor <code>reduceBy</code> and write the result into
* <code>cache</code>.
* Input line pixel # <code>unscaled0</code> will correspond to output
* line pixel # 0. <code>unscaled0</code> may be negative. Out-of-line
* pixels of the input are replaced by the edge pixels.
*/
void downscaleLine(double[] pixels, double[] cache, double[] kernel,
static void downscaleLine(double[] pixels, double[] cache, double[] kernel,
int reduceBy, int pixel0, int unscaled0, int length, int pointInc, int newLength) {
if (pixel0 > pixels.length) {
System.out.println("++++++ Error in DoubleGaussianBlur, pixel0="+pixel0+", pixels.length="+(pixels.length));
......@@ -280,7 +283,8 @@ public class DoubleGaussianBlur {
}
}
/* Create a kernel for downscaling. The kernel function preserves
/**
* Create a kernel for downscaling. The kernel function preserves
* norm and 1st moment (i.e., position) and has fixed 2nd moment,
* (in contrast to linear interpolation).
* In scaled space, the length of the kernel runs from -1.5 to +1.5,
......@@ -288,7 +292,7 @@ public class DoubleGaussianBlur {
* Array index corresponding to the kernel center is
* unitLength*3/2
*/
double[] makeDownscaleKernel (int unitLength) {
static double[] makeDownscaleKernel (int unitLength) {
int mid = unitLength*3/2;
double[] kernel = new double[3*unitLength];
for (int i=0; i<=unitLength/2; i++) {
......@@ -306,10 +310,11 @@ public class DoubleGaussianBlur {
return kernel;
}
/* Scale a line up by factor <code>reduceBy</code> and write as a row
/**
* Scale a line up by factor <code>reduceBy</code> and write as a row
* or column (or part thereof) to the pixels array of a FloatProcessor.
*/
void upscaleLine (double[] cache, double[] pixels, double[] kernel,
static void upscaleLine (double[] cache, double[] pixels, double[] kernel,
int reduceBy, int pixel0, int unscaled0, int writeFrom, int writeTo, int pointInc) {
int p = pixel0 + pointInc*writeFrom;
for (int xout = writeFrom; xout < writeTo; xout++, p+=pointInc) {
......@@ -322,7 +327,8 @@ public class DoubleGaussianBlur {
}
}
/* Create a kernel for upscaling. The kernel function is a convolution
/**
* Create a kernel for upscaling. The kernel function is a convolution
* of four unit squares, i.e., four uniform kernels with value +1
* from -0.5 to +0.5 (in downscaled coordinates). The second derivative
* of this kernel is smooth, the third is not. Its standard deviation
......@@ -330,7 +336,7 @@ public class DoubleGaussianBlur {
* The kernel runs from [-2 to +2[, corresponding to array index
* 0 ... 4*unitLength (whereby the last point is not in the array any more).
*/
double[] makeUpscaleKernel (int unitLength) {
static double[] makeUpscaleKernel (int unitLength) {
double[] kernel = new double[4*unitLength];
int mid = 2*unitLength;
kernel[0] = 0;
......@@ -349,7 +355,8 @@ public class DoubleGaussianBlur {
return kernel;
}
/* Convolve a line with a symmetric kernel and write to a separate array,
/**
* Convolve a line with a symmetric kernel and write to a separate array,
* possibly the pixels array of a FloatProcessor (as a row or column or part thereof)
*
* @param input Input array containing the line
......@@ -371,7 +378,7 @@ public class DoubleGaussianBlur {
* @param pointInc Increment of the pixels array index to the next point (for an ImageProcessor,
* it should be <code>1</code> for a row, <code>width</code> for a column)
*/
public void convolveLine(double[] input, double[] pixels, double[][] kernel, int readFrom,
public static void convolveLine(double[] input, double[] pixels, double[][] kernel, int readFrom,
int readTo, int writeFrom, int writeTo, int point0, int pointInc) {
int length = input.length;
double first = input[0]; //out-of-edge pixels are replaced by nearest edge pixels
......
......@@ -17,6 +17,7 @@ import java.net.URISyntaxException;
import java.net.URL;
import com.elphel.imagej.cameras.CLTParameters;
import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.gpu.GPUTileProcessor;
......@@ -33,6 +34,7 @@ import com.elphel.imagej.tileprocessor.TileNeibs;
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.plugin.filter.GaussianBlur;
import ij.process.ByteProcessor;
import ij.process.ColorProcessor;
import ij.process.FloatProcessor;
......@@ -54,7 +56,9 @@ public class CuasMotion {
final static public int TARGET_VX = 2;
final static public int TARGET_VY = 3;
final static public int TARGET_STRENGTH = 4;
final static public int TARGET_LENGTH = TARGET_STRENGTH+1;
final static public int TARGET_NTILE = 5;
final static public int TARGET_LENGTH = TARGET_NTILE+1;
public static String RESOURCE_GRAPICS_DIR ="graphics";
public static String ICON_TARGET_1X = "TDbox_dashed21x21_bold.png";
......@@ -317,7 +321,8 @@ public class CuasMotion {
double lma_maxr = clt_parameters.imp.cuas_lma_maxr; // = 5.0; // Maximal radius (>3.8)
double lma_mink = clt_parameters.imp.cuas_lma_mink; // = 0.0; // Minimal K (overshoot) <0.007
double lma_maxk = clt_parameters.imp.cuas_lma_maxk; // = 5.0; // Minimal K (overshoot) > 3.8
boolean remove_isolated= clt_parameters.imp.cuas_isolated; // false;
boolean remove_isolated= clt_parameters.imp.cuas_isolated; // true;
double max_mismatch = clt_parameters.imp.cuas_max_mismatch; // 2;
double mask_width = clt_parameters.imp.cuas_mask_width; // 9;
double mask_blur = clt_parameters.imp.cuas_mask_blur; // 3;
......@@ -413,7 +418,7 @@ public class CuasMotion {
"Finish fitting when the relative RMS improvement drops below this value.");
gd.addNumericField("LMA iterations", num_iter, 0,3,"",
"Maximal number of the LMA iterations.");
gd.addMessage("--- Moving target discrimination parameters theresholds ---");
gd.addMessage("--- Moving target discrimination parameters thresholds ---");
gd.addNumericField("Maximal RMS", lma_rms, 5,8,"",
"Maximal RMS for target that should match always, regardless of the amplitude.");
gd.addNumericField("Maximal sufficient RMS", lma_arms, 5,8,"",
......@@ -2092,6 +2097,66 @@ public class CuasMotion {
return frames_accum;
}
/**
* Calculate image x,y for each target half keyframe interval before the keyframe and half-interval after.
* It is used to filter out stray targets, these coordinates for the consecutive frames should be close:
* "after" for the earlier keyframe and "before" for the later one.
* @param vector_field [keyframe_number][tile][] first two elements - targets vX, vY in pixels per frame. Empty are nulls, same velocities for 5x5
* @param target_positions [keyframe_number][tile][] target positions of the targets relative to the tile center
* @param interseq_scale multiply velocity vector to get pixel offset in the middle between the two keyframes
* @param tilesX number of tiles in a row
* @param debugLevel debug level
* @return [keyframe_number][tile]{before=0, after=1}{px, py}
*/
public static double [][][][] getHalfBeforeAfterPixXY(
final double [][][] vector_field,
final double [][][] target_positions,
final double interseq_scale,
final int tilesX,
final int debugLevel) {
final int num_seq = vector_field.length;
final int num_tiles = vector_field[0].length;
final double [][][][] pix_xy = new double [num_seq][num_tiles][][]; // [][]{0-before,1 - after}{px, py}
final int tileSize = GPUTileProcessor.DTT_SIZE;
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
// for (int nseq = 0; nseq < vector_field.length; nseq++) {
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 [] vvector = vector_field[nSeq][ntile];
if (vvector != null) {
double [] target_pos = target_positions[nSeq][ntile];
if (target_pos != null) { // should be always
int tileX = ntile % tilesX;
int tileY = ntile / tilesX;
double xc = tileSize * tileX + tileSize/2;
double yc = tileSize * tileY + tileSize/2;
double xtk = xc + target_pos[CuasMotionLMA.RSLT_X];
double ytk = yc + target_pos[CuasMotionLMA.RSLT_Y];
double dx = vvector[INDX_VX] * interseq_scale;
double dy = vvector[INDX_VY] * interseq_scale;
double [][] baxy = new double [2][2];
//baxy[0][0]
baxy[0][0] = xtk - dx; // before, x
baxy[0][1] = ytk - dy; // before, y
baxy[1][0] = xtk + dx; // after, x
baxy[1][1] = ytk + dy; // after, y
pix_xy[nSeq][ntile] = baxy;
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return pix_xy;
}
/**
* Generate target images
* @param clt_parameters
......@@ -2131,7 +2196,7 @@ public class CuasMotion {
fpix_out[i]= background[i].clone();
}
final int tileSize = GPUTileProcessor.DTT_SIZE;
final int tileSize2 = 2 * tileSize;
// final int tileSize2 = 2 * tileSize;
final int half_step0 = -(frame_step+1)/2;
final int half_step1 = frame_step + half_step0;
final int num_scenes = background.length;
......@@ -2155,6 +2220,7 @@ public class CuasMotion {
target_list.add(ntile);
}
final int[] targets = target_list.stream().mapToInt(Integer::intValue).toArray();
for (int dscene = half_step0; dscene < half_step1; dscene ++) {
final int fdscene = dscene;
int nscene = frame_center + dscene;
......@@ -2190,6 +2256,7 @@ public class CuasMotion {
targets_data[nTarget][TARGET_VX] = vvector[INDX_VX];
targets_data[nTarget][TARGET_VY] = vvector[INDX_VY];
targets_data[nTarget][TARGET_STRENGTH] = target_pos[CuasMotionLMA.RSLT_A];
targets_data[nTarget][TARGET_NTILE] = ntile;
int pxl = (int) Math.round(targets_data[nTarget][TARGET_X]) - offs;
int pyt = (int) Math.round(targets_data[nTarget][TARGET_Y]) - offs;
for (int ym = 0; ym < isize; ym++) {
......@@ -2292,6 +2359,173 @@ public class CuasMotion {
return out_pix;
}
public static float [][] runningGaussian(
final float [][] fpixels,
final int ra_length,
final int width){
final int num_scenes = fpixels.length;
final int num_pixels = fpixels[0].length;
final int height = num_pixels/width;
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final double sigma = 0.5* ra_length;
final float [][] out_pix = new float [num_scenes][num_pixels];
/*
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int nSeq = ai.getAndIncrement(); nSeq < num_scenes; nSeq = ai.getAndIncrement()) {
Arrays.fill(out_pix[nSeq],Float.NaN);
}
}
};
}
ImageDtt.startAndJoin(threads);
ai.set(0);
*/
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
double [] temp_line = new double[width*num_scenes];
DoubleGaussianBlur gb = new DoubleGaussianBlur();
for (int nLine = ai.getAndIncrement(); nLine < height; nLine = ai.getAndIncrement()) {
for (int nseq = 0; nseq < num_scenes; nseq++) {
int src_index = nLine*width;
int dst_index = nseq*width;
for (int i = 0; i < width; i++) {
temp_line[dst_index++] = fpixels[nseq][src_index++];
}
}
gb.blur1Direction(
temp_line, // double [] pixels,
width, // int width,
num_scenes, // int height,
sigma, // double sigma,
0.001, // double accuracy,
false); // boolean xDirection vertical along time line
for (int nseq = 0; nseq < num_scenes; nseq++) {
int dst_index = nLine*width;
int src_index = nseq*width;
for (int i = 0; i < width; i++) {
out_pix[nseq][dst_index++] = (float)(temp_line[src_index++]);
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return out_pix;
}
public static float [][] runningGaussianNaN(
final float [][] fpixels,
final int ra_length,
final int width){
final int num_scenes = fpixels.length;
final int num_pixels = fpixels[0].length;
final int height = num_pixels/width;
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final double sigma = 0.5* ra_length;
final float [][] out_pix = new float [num_scenes][num_pixels];
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int nSeq = ai.getAndIncrement(); nSeq < num_scenes; nSeq = ai.getAndIncrement()) {
System.arraycopy(
fpixels[nSeq],
0,
out_pix[nSeq],
0,
num_pixels);
/*
for (int npix = 0; npix < num_pixels; npix++) {
out_pix[nSeq][npix] = fpixels[nSeq][npix];
}
*/
}
}
};
}
ImageDtt.startAndJoin(threads);
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
double [] temp_line = new double[width*num_scenes];
boolean [] has_nans = new boolean[width];
DoubleGaussianBlur gb = new DoubleGaussianBlur();
for (int nLine = ai.getAndIncrement(); nLine < height; nLine = ai.getAndIncrement()) {
Arrays.fill(has_nans, false);
boolean has_some_nans = false;
for (int nseq = 0; nseq < num_scenes; nseq++) {
int src_index = nLine*width;
int dst_index = nseq*width;
for (int x = 0; x < width; x++) {
double dpix = out_pix[nseq][src_index++];
temp_line[dst_index++] = dpix;
boolean nan = Double.isNaN(dpix);
has_nans[x] |= nan;
has_some_nans |= nan;
}
}
if (has_some_nans) {
for (int x = 0; x < width; x++) if (has_nans[x]){
// duplicate first/last, interpolate middle
if (Double.isNaN(temp_line[x])) {
int i;
for (i = 1; Double.isNaN(temp_line[i * width+x]) && (i < num_scenes); i++);
temp_line[x] = temp_line[i * width+x];
}
if (Double.isNaN(temp_line[(num_scenes-1)*width + x])) {
int i;
for (i = num_scenes-1; Double.isNaN(temp_line[i*width+x]) && (i >=0); i--);
temp_line[(num_scenes - 1) * width + x] = temp_line[i*width+x];
}
// interpolate remaining gaps
int i;
for (i=0; i < num_scenes; i++) {
if (Double.isNaN(temp_line[i * width + x])) {
int gap_start = i-1;
for (i = i+1; Double.isNaN(temp_line[i * width + x]); i++); // last is not NaN, set above
int gap_end = i;
double v0 = temp_line[gap_start * width + x];
double v1 = temp_line[gap_end * width + x];
for (int k = 1; k < (gap_end - gap_start); k++) {
temp_line[(gap_start + k) * width + x] = v0 + (v1-v0) * k;
}
}
}
}
}
gb.blur1Direction(
temp_line, // double [] pixels,
width, // int width,
num_scenes, // int height,
sigma, // double sigma,
0.001, // double accuracy,
false); // boolean xDirection vertical along time line
for (int nseq = 0; nseq < num_scenes; nseq++) {
int dst_index = nLine*width;
int src_index = nseq*width;
for (int i = 0; i < width; i++) {
out_pix[nseq][dst_index++] = (float)(temp_line[src_index++]);
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return out_pix;
}
/**
* Version of runningAverage) that tolerates NaN value. It modifies fpixels[][] replacing first/last scene values if they were NaNs
* @param fpixels
......@@ -2329,7 +2563,7 @@ public class CuasMotion {
Arrays.fill(line_ra, 0.0f);
Arrays.fill(line_ra_length, 0);
int pix0 = nLine* width;
// fix first and last pixels if they ar nulls;
// fix first and last pixels if they are nulls;
for (int x = 0; x < width; x++) {
if (Float.isNaN(fpixels[0][pix0+x])) {
int i;
......@@ -2546,6 +2780,7 @@ public class CuasMotion {
final int target_type, // = 0; // 0 - unknown, 1 - known, 2 - friend, 3 - foe
final float [][] fpixels,
final double [][][] targets60hz,
final double [][][] mismatch_ba,
final int frame0,
final int frame_step,
final int width_src,
......@@ -2578,11 +2813,6 @@ public class CuasMotion {
final String font_name = clt_parameters.imp.cuas_font_name;
final int font_size = clt_parameters.imp.cuas_font_size;
final int font_type = clt_parameters.imp.cuas_font_type;
final double ifov = clt_parameters.imp.cuas_ifov;
final int px0 = clt_parameters.imp.cuas_px0;
final int py0 = clt_parameters.imp.cuas_py0;
final double az0 = clt_parameters.imp.cuas_az0;
final double el0 = clt_parameters.imp.cuas_el0;
final int space_before_text = 2;
ColorProcessor diamond_cp = null;
......@@ -2769,6 +2999,13 @@ public class CuasMotion {
String txt = getTargetText(
clt_parameters, // CLTParameters clt_parameters,
targets[ntarget]); // double [] target);
int ntile = (int) targets[ntarget][TARGET_NTILE];
if ((mismatch_ba != null)) {
double [] mm = mismatch_ba[nSeq][ntile];
if (mm != null) {
txt += String.format("\nErr-%3.1f\nErr-%3.1f", mm[0],mm[1]);
}
}
ip.setColor(text_color);
ip.setFont(font_target);
if (target_text_transparent) {
......@@ -3049,6 +3286,7 @@ public class CuasMotion {
boolean intermed_low = clt_parameters.imp.cuas_intermed_low; //true;
boolean intermed_high = clt_parameters.imp.cuas_intermed_high; //true;
boolean intermed_giga = clt_parameters.imp.cuas_intermed_giga; //false;
boolean cuas_gaussian_ra = clt_parameters.imp.cuas_gaussian_ra; // use gaussian temporal Gaussian instead of running average
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];
......@@ -3065,7 +3303,7 @@ public class CuasMotion {
final int frame0 = start_frame + seq_length/2;
final int half_accum_range = corr_pairs/2;
int [] remain = new int [num_corr_samples];
boolean debug_tum= false;
boolean debug_tum= true; // false;
String model_prefix = parentCLT.getImageName()+getParametersSuffix(clt_parameters,null);
float [][] fpixels_tum = fpixels;
if (temporal_um > 0) {
......@@ -3082,16 +3320,24 @@ public class CuasMotion {
}
parentCLT.saveImagePlusInModelDirectory(imp_src); // ImagePlus imp)
}
float [][] fpixels_ra = runningAverage(
fpixels, // final float [][] fpixels,
temporal_um, // final int ra_length,
cuasMotion.gpu_max_width); // final int width);
float [][] fpixels_ra;
if (cuas_gaussian_ra) {
fpixels_ra= runningGaussian(
fpixels, // final float [][] fpixels,
temporal_um, // final int ra_length,
cuasMotion.gpu_max_width); // final int width);
} else {
fpixels_ra= runningAverage(
fpixels, // final float [][] fpixels,
temporal_um, // final int ra_length,
cuasMotion.gpu_max_width); // final int width);
}
if (intermed_high && debug_tum) {
ImagePlus imp_src_ra = ShowDoubleFloatArrays.makeArrays(
fpixels_ra, // float[][] pixels,
cuasMotion.gpu_max_width, // int width,
cuasMotion.gpu_max_height, // int height,
model_prefix+"-SOURCE-RA"+temporal_um, //String title,
model_prefix+(cuas_gaussian_ra?"-SOURCE-RG":"-SOURCE-RA")+temporal_um, //String title,
scene_titles); //String [] titles)
imp_src_ra.getProcessor().setMinAndMax(-input_range/2, input_range/2);
if (!batch_mode) {
......@@ -3118,16 +3364,23 @@ public class CuasMotion {
}
parentCLT.saveImagePlusInModelDirectory(imp_outliers); // ImagePlus imp)
}
fpixels_ra = runningAverageNaN(
fpixels_nan, // final float [][] fpixels,
temporal_um, // final int ra_length,
cuasMotion.gpu_max_width); // final int width);
if (cuas_gaussian_ra) {
fpixels_ra = runningGaussianNaN(
fpixels_nan, // final float [][] fpixels,
temporal_um, // final int ra_length,
cuasMotion.gpu_max_width); // final int width);
} else {
fpixels_ra = runningAverageNaN(
fpixels_nan, // final float [][] fpixels,
temporal_um, // final int ra_length,
cuasMotion.gpu_max_width); // final int width);
}
if (intermed_high && debug_tum) {
ImagePlus imp_src_ra = ShowDoubleFloatArrays.makeArrays(
fpixels_ra, // float[][] pixels,
cuasMotion.gpu_max_width, // int width,
cuasMotion.gpu_max_height, // int height,
model_prefix+"-SOURCE-RA-NOOUTLIERS"+temporal_um, //String title,
model_prefix+(cuas_gaussian_ra?"-SOURCE-RG":"-SOURCE-RA")+"-NOOUTLIERS"+temporal_um, //String title,
scene_titles); //String [] titles)
imp_src_ra.getProcessor().setMinAndMax(-input_range/2, input_range/2);
if (!batch_mode) {
......@@ -3158,16 +3411,23 @@ public class CuasMotion {
float [][] fpixels_ra = fpixels_tum; //fpixels;
if (precorr_ra > 1) {
fpixels_ra = runningAverage(
fpixels_tum, // fpixels, // final float [][] fpixels,
precorr_ra, // final int ra_length,
cuasMotion.gpu_max_width); // final int width)
if (cuas_gaussian_ra) {
fpixels_ra = runningGaussian(
fpixels_tum, // fpixels, // final float [][] fpixels,
precorr_ra, // final int ra_length,
cuasMotion.gpu_max_width); // final int width)
} else {
fpixels_ra = runningAverage(
fpixels_tum, // fpixels, // final float [][] fpixels,
precorr_ra, // final int ra_length,
cuasMotion.gpu_max_width); // final int width)
}
if (intermed_high) {
ImagePlus imp_ra = ShowDoubleFloatArrays.makeArrays(
fpixels_ra, // float[][] pixels,
cuasMotion.gpu_max_width, // int width,
cuasMotion.gpu_max_height, // int height,
model_prefix+"-SOURCE-RA", //String title,
model_prefix+(cuas_gaussian_ra?"-SOURCE-RG":"-SOURCE-RA"), //String title,
scene_titles); //String [] titles)
imp_ra.getProcessor().setMinAndMax(-input_range/2, input_range/2);
if (!batch_mode) {
......@@ -3634,6 +3894,9 @@ public class CuasMotion {
double lma_mink = clt_parameters.imp.cuas_lma_mink; // = 0.0; // Minimal K (overshoot) <0.007
double lma_maxk = clt_parameters.imp.cuas_lma_maxk; // = 5.0; // Minimal K (overshoot) > 3.8
boolean remove_isolated= clt_parameters.imp.cuas_isolated;
double max_mismatch = clt_parameters.imp.cuas_max_mismatch; // 2;
boolean ignore_mismatch= clt_parameters.imp.cuas_ignore_mismatch;
int target_type = clt_parameters.imp.cuas_target_type; //0; // 0 - unknown, 1 - known, 2 - friend, 3 - foe
double input_range = clt_parameters.imp.cuas_input_range; // 5;
boolean scale2x = clt_parameters.imp.cuas_scale2x; //true;
......@@ -3647,6 +3910,8 @@ public class CuasMotion {
boolean save_color = clt_parameters.imp.cuas_save_color; //true;
boolean save_video = clt_parameters.imp.cuas_save_video; //true;
boolean cuas_gaussian_ra = clt_parameters.imp.cuas_gaussian_ra; // use gaussian temporal Gaussian instead of running average
int start_frame = 0;
int seq_length = corr_offset + corr_pairs;
final int frame0 = start_frame + seq_length/2;
......@@ -3802,9 +4067,27 @@ public class CuasMotion {
parentCLT.saveImagePlusInModelDirectory(imp_filtered_combo); // ImagePlus imp)
}
double [][][] mismatch_ba = null;
if (remove_isolated) {
double interseq_scale = 0.5* corr_inc/corr_offset; // multiply target velocity to get offset in the middle between the key frames
double [][][][] ba_xy = getHalfBeforeAfterPixXY(
targets_vf_combo, // final double [][][] vector_field,
targets_lma_combo, // final double [][][] target_positions,
interseq_scale, // final double interseq_scale,
cuasMotion.tilesX, // final int tilesX,
debugLevel); // final int debugLevel)
boolean debug_mismatch = clt_parameters.imp.cuas_target_debug;
if (debug_mismatch) {
mismatch_ba = new double [targets_vf_combo.length][][];
}
targets_vf_combo = filterIsolatedTargets(
targets_vf_combo, // final double [][][] all_tiles,
ba_xy, // final double [][][][] ba_xy,
max_mismatch, // final double max_mismatch,
ignore_mismatch, // final boolean ignore_mismatch
mismatch_ba, // final double [][][] mismatch_ba,
remain, // final int [] remain,
cuasMotion.tilesX); // final int tilesX)
// synchronize targets_lma_combo with targets_vf_combo
......@@ -3889,11 +4172,21 @@ public class CuasMotion {
float [][] background = fpixels;
String ra_bg_suffix=(ra_background? "-RABG":"");
if (mismatch_ba != null) {
ra_bg_suffix += "-DBG";
}
if (ra_background) {
background = runningAverage(
fpixels, // final float [][] fpixels,
corr_pairs, // final int ra_length,
cuasMotion.gpu_max_width); // final int width)
if (cuas_gaussian_ra) {
background = runningGaussian(
fpixels, // final float [][] fpixels,
corr_pairs, // final int ra_length,
cuasMotion.gpu_max_width); // final int width)
} else {
background = runningAverage(
fpixels, // final float [][] fpixels,
corr_pairs, // final int ra_length,
cuasMotion.gpu_max_width); // final int width)
}
}
......@@ -3907,7 +4200,7 @@ public class CuasMotion {
targets_lma_combo, // final double [][][] target_positions,
background, // final float [][] background, // background image
frame0, // final int frame0,
corr_inc, // final int frame_step,
corr_inc, // final int frame_step,
velocity_scale, // final double velocity_scale, // 1.0/(disparity in frames)
targets60hz, // final double [][][] targets60hz,
batch_mode, // final boolean batch_mode,
......@@ -3933,6 +4226,7 @@ public class CuasMotion {
target_type, // final int target_type, // = 0; // 0 - unknown, 1 - known, 2 - friend, 3 - foe
replaced_targets, // final float [][] fpixels,
targets60hz, // final double [][][] targets60hz,
mismatch_ba, // final double [][][] mismatch_ba, if not null (in debug mode) print data in the image. this is [keyframes]
frame0, // final int frame0,
corr_inc, // final int frame_step,
cuasMotion.gpu_max_width, // final int width,
......@@ -3962,12 +4256,15 @@ public class CuasMotion {
public static double [][][] filterIsolatedTargets(
final double [][][] all_tiles,
final int [] remain,
final double [][][][] ba_xy,
final double max_mismatch, // if <=0, do not calculate mismatch_ba and filter
final boolean ignore_mismatch,
final double [][][] mismatch_ba, // if not null, will provide mismatches (before, after) and still keep them. Then output debug data in the final image with targets
final int [] remain,
final int tilesX) {
final int num_seq = all_tiles.length;
final int num_tiles = all_tiles[0].length;
final double [][][] filtered_tiles = 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++) {
......@@ -3975,6 +4272,9 @@ public class CuasMotion {
public void run() {
TileNeibs tn = new TileNeibs(tilesX, num_tiles/tilesX);
for (int nSeq = ai.getAndIncrement(); nSeq < num_seq; nSeq = ai.getAndIncrement()) {
if (mismatch_ba != null) {
mismatch_ba[nSeq] = new double [num_tiles][];
}
if (remain != null) {
remain[nSeq] = 0;
}
......@@ -3998,6 +4298,45 @@ public class CuasMotion {
has_neib = false;
}
if (has_neib) {
if (max_mismatch > 0) {
double [] mm = {Double.NaN, Double.NaN};
for (int dseq = -1; dseq <= 1; dseq+=2) {
double [] this_ba = ba_xy[nSeq][ntile][(dseq > 0) ? 1 : 0];
double [] other_ba = null;
int nSeq1 = nSeq+dseq;
if ((nSeq1 >= 0) && (nSeq1 < num_seq)) {
get_ba: {
if (ba_xy[nSeq1][ntile] != null) {
other_ba = ba_xy[nSeq1][ntile][(dseq > 0) ? 0 : 1];
break get_ba;
}
for (int dir = 0; dir < 8; dir++) {
int tile1 = tn.getNeibIndex(ntile, dir);
if ((tile1 >= 0) && (ba_xy[nSeq1][tile1] != null)) {
other_ba = ba_xy[nSeq1][tile1][(dseq > 0) ? 0 : 1];
break get_ba;
}
}
}
if (other_ba != null) {
double dx = this_ba[0] - other_ba[0];
double dy = this_ba[1] - other_ba[1];
mm[(dseq > 0) ? 1 : 0] = Math.sqrt(dx*dx + dy*dy);
}
}
}
if (mismatch_ba != null) {
mismatch_ba[nSeq][ntile] = mm;
}
if (!ignore_mismatch){
if (mm[0] > max_mismatch) {
continue; // for (int ntile = 0; ntile < num_tiles; ntile++) if (all_tiles[nSeq][ntile] != null) {
}
if (mm[1] > max_mismatch) {
continue; // for (int ntile = 0; ntile < num_tiles; ntile++) if (all_tiles[nSeq][ntile] != null) {
}
}
}
filtered_tiles[nSeq][ntile] = all_tiles[nSeq][ntile]; // clone()?
if (remain != null) {
remain[nSeq]++;
......
......@@ -707,6 +707,7 @@ min_str_neib_fpn 0.35
public boolean cuas_smooth = true; // used cosine window when averaging correlations
public int cuas_corr_pairs = 50; // number of correlation pairs to accumulate
public int cuas_corr_offset = 20; // offset between motion detection pairs
public boolean cuas_gaussian_ra = true; // use gaussian temporal Gaussian instead of running average
public int cuas_temporal_um = 100; // temporal "unsharp mask" - subtract running
public double cuas_tum_threshold = 5.0; // if >0, remove outliers frim the running average and recalculate RA
......@@ -754,6 +755,9 @@ min_str_neib_fpn 0.35
public double cuas_lma_maxk = 5.0; // Maximal K (overshoot) = 5.0 (>3.8)
public boolean cuas_isolated = true; // remove targets that do not have neighbors before/after
public double cuas_max_mismatch = 2.0; // maximal position error between consecutive scene sequences
public boolean cuas_ignore_mismatch = false; // calculate mismatch but do not remove
public double cuas_mask_width = 9;
......@@ -793,7 +797,7 @@ min_str_neib_fpn 0.35
public boolean cuas_debug = false; // save debug images (and show them if not in batch mode)
public boolean cuas_step_debug = false; // save debug images during per-step cuas recalculation (and show them if not in batch mode)
public boolean cuas_target_debug = false; // save debug images during per-step cuas recalculation (and show them if not in batch mode)
public boolean cuas_overwrite = false; // overwrite num_orient and num_accum
public int cuas_num_orient = 2; // initial value for num_orient
public int cuas_num_accum = 1; // initial value for num_accum
......@@ -2213,6 +2217,8 @@ min_str_neib_fpn 0.35
"The number of correlation pairs to accumulate.");
gd.addNumericField("Pairs offset", this.cuas_corr_offset, 0,3,"scenes",
"Offset between the correlation pairs");
gd.addCheckbox ("Gaussian instead of Running Average", this.cuas_gaussian_ra,
"Use gaussian temporal Gaussian instead of running average.");
gd.addNumericField("Temporal unsharp mask length", this.cuas_temporal_um, 0,3,"scenes",
"Subtract running average this long.");
gd.addNumericField("Temporal UM threshold", this.cuas_tum_threshold, 5,8,"",
......@@ -2284,7 +2290,7 @@ min_str_neib_fpn 0.35
"Finish fitting when the relative RMS improvement drops below this value.");
gd.addNumericField("LMA iterations", this.cuas_num_iter, 0,3,"",
"Maximal number of the LMA iterations.");
gd.addMessage("--- Moving target discrimination parameters theresholds ---");
gd.addMessage("--- Moving target discrimination parameters thresholds ---");
gd.addNumericField("Maximal RMS", this.cuas_lma_rms, 5,8,"",
"Maximal RMS for target that should match always, regardless of the amplitude.");
gd.addNumericField("Maximal sufficient RMS", this.cuas_lma_arms, 5,8,"",
......@@ -2302,7 +2308,10 @@ min_str_neib_fpn 0.35
gd.addCheckbox ("Remove single-frame targets", this.cuas_isolated,
"Remove targets that do not have neighbors before/afte.");
gd.addNumericField("Remove by mismatch", this.cuas_max_mismatch, 5,8,"pix",
"Maximal position error between consecutive scene sequences.");
gd.addCheckbox ("Ignore mismatch", this.cuas_ignore_mismatch,
"Calculate mismatch, but keep targets for debugging (see cuas_target_debug).");
gd.addMessage("=== Targets video generation (see also Vidoe/Stereo tab) ===");
......@@ -2375,6 +2384,8 @@ min_str_neib_fpn 0.35
"Save CUAS-related debug images and show them in non-batch mode.");
gd.addCheckbox ("Save/show debug images for each tuning step",this.cuas_step_debug,
"Save CUAS-related debug images during per-step cuas recalculation and show them in non-batch mode.");
gd.addCheckbox ("Add debug to the target text", this.cuas_target_debug,
"Add additional debug text to the .");
gd.addCheckbox ("Overwrite number of performed adjustments", this.cuas_overwrite,
"Debug feature: overwrite actual number of performed orientation and disparity refinements to re-run them.");
......@@ -3329,7 +3340,7 @@ min_str_neib_fpn 0.35
this.cuas_smooth = gd.getNextBoolean();
this.cuas_corr_pairs = (int) gd.getNextNumber();
this.cuas_corr_offset = (int) gd.getNextNumber();
this.cuas_gaussian_ra = gd.getNextBoolean();
this.cuas_temporal_um = (int) gd.getNextNumber();
this.cuas_tum_threshold = gd.getNextNumber();
......@@ -3373,6 +3384,8 @@ min_str_neib_fpn 0.35
this.cuas_lma_maxk = gd.getNextNumber();
this.cuas_isolated = gd.getNextBoolean();
this.cuas_max_mismatch= gd.getNextNumber();
this.cuas_ignore_mismatch = gd.getNextBoolean();
this.cuas_mask_width = gd.getNextNumber();
this.cuas_mask_blur = gd.getNextNumber();
......@@ -3413,8 +3426,9 @@ min_str_neib_fpn 0.35
this.cuas_el0 = gd.getNextNumber();
this.cuas_debug = gd.getNextBoolean();
this.cuas_target_debug = gd.getNextBoolean();
this.cuas_step_debug = gd.getNextBoolean();
this.cuas_overwrite = gd.getNextBoolean();
this.cuas_num_orient = (int) gd.getNextNumber();
this.cuas_num_accum = (int) gd.getNextNumber();
......@@ -4295,6 +4309,7 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"cuas_smooth", this.cuas_smooth+""); // boolean
properties.setProperty(prefix+"cuas_corr_pairs", this.cuas_corr_pairs+""); // int
properties.setProperty(prefix+"cuas_corr_offset", this.cuas_corr_offset+""); // int
properties.setProperty(prefix+"cuas_gaussian_ra", this.cuas_gaussian_ra+""); // boolean
properties.setProperty(prefix+"cuas_temporal_um", this.cuas_temporal_um+""); // int
properties.setProperty(prefix+"cuas_tum_threshold", this.cuas_tum_threshold+""); // double
......@@ -4337,7 +4352,9 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"cuas_lma_mink", this.cuas_lma_mink+""); // double
properties.setProperty(prefix+"cuas_lma_maxk", this.cuas_lma_maxk+""); // double
properties.setProperty(prefix+"cuas_isolated", this.cuas_isolated+""); // boolean
properties.setProperty(prefix+"cuas_isolated", this.cuas_isolated+""); // boolean
properties.setProperty(prefix+"cuas_max_mismatch", this.cuas_max_mismatch+""); // double
properties.setProperty(prefix+"cuas_ignore_mismatch", this.cuas_ignore_mismatch+"");// boolean
properties.setProperty(prefix+"cuas_mask_width", this.cuas_mask_width+""); // double
properties.setProperty(prefix+"cuas_mask_blur", this.cuas_mask_blur+""); // double
......@@ -4374,6 +4391,7 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"cuas_debug", this.cuas_debug+""); // boolean
properties.setProperty(prefix+"cuas_step_debug", this.cuas_step_debug+""); // boolean
properties.setProperty(prefix+"cuas_target_debug", this.cuas_target_debug+""); // boolean
properties.setProperty(prefix+"cuas_overwrite", this.cuas_overwrite+""); // boolean
properties.setProperty(prefix+"cuas_num_orient", this.cuas_num_orient+""); // int
......@@ -5227,6 +5245,7 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"cuas_smooth")!=null) this.cuas_smooth=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_smooth"));
if (properties.getProperty(prefix+"cuas_corr_pairs")!=null) this.cuas_corr_pairs=Integer.parseInt(properties.getProperty(prefix+"cuas_corr_pairs"));
if (properties.getProperty(prefix+"cuas_corr_offset")!=null) this.cuas_corr_offset=Integer.parseInt(properties.getProperty(prefix+"cuas_corr_offset"));
if (properties.getProperty(prefix+"cuas_gaussian_ra")!=null) this.cuas_gaussian_ra=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_gaussian_ra"));
if (properties.getProperty(prefix+"cuas_temporal_um")!=null) this.cuas_temporal_um=Integer.parseInt(properties.getProperty(prefix+"cuas_temporal_um"));
if (properties.getProperty(prefix+"cuas_tum_threshold")!=null) this.cuas_tum_threshold=Double.parseDouble(properties.getProperty(prefix+"cuas_tum_threshold"));
......@@ -5271,6 +5290,8 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"cuas_lma_maxk")!=null) this.cuas_lma_maxk=Double.parseDouble(properties.getProperty(prefix+"cuas_lma_maxk"));
if (properties.getProperty(prefix+"cuas_isolated")!=null) this.cuas_isolated=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_isolated"));
if (properties.getProperty(prefix+"cuas_max_mismatch")!=null) this.cuas_max_mismatch=Double.parseDouble(properties.getProperty(prefix+"cuas_max_mismatch"));
if (properties.getProperty(prefix+"cuas_ignore_mismatch")!=null) this.cuas_ignore_mismatch=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_ignore_mismatch"));
if (properties.getProperty(prefix+"cuas_mask_width")!=null) this.cuas_mask_width=Double.parseDouble(properties.getProperty(prefix+"cuas_mask_width"));
if (properties.getProperty(prefix+"cuas_mask_blur")!=null) this.cuas_mask_blur=Double.parseDouble(properties.getProperty(prefix+"cuas_mask_blur"));
......@@ -5307,7 +5328,8 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"cuas_debug")!=null) this.cuas_debug=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_debug"));
if (properties.getProperty(prefix+"cuas_step_debug")!=null) this.cuas_step_debug=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_step_debug"));
if (properties.getProperty(prefix+"cuas_target_debug")!=null) this.cuas_target_debug=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_target_debug"));
if (properties.getProperty(prefix+"cuas_overwrite")!=null) this.cuas_overwrite=Boolean.parseBoolean(properties.getProperty(prefix+"cuas_overwrite"));
if (properties.getProperty(prefix+"cuas_num_orient")!=null) this.cuas_num_orient=Integer.parseInt(properties.getProperty(prefix+"cuas_num_orient"));
if (properties.getProperty(prefix+"cuas_num_accum")!=null) this.cuas_num_accum=Integer.parseInt(properties.getProperty(prefix+"cuas_num_accum"));
......@@ -6162,6 +6184,7 @@ min_str_neib_fpn 0.35
imp.cuas_smooth = this.cuas_smooth;
imp.cuas_corr_pairs = this.cuas_corr_pairs;
imp.cuas_corr_offset = this.cuas_corr_offset;
imp.cuas_gaussian_ra = this.cuas_gaussian_ra;
imp.cuas_temporal_um = this.cuas_temporal_um;
imp.cuas_tum_threshold = this.cuas_tum_threshold;
......@@ -6203,6 +6226,8 @@ min_str_neib_fpn 0.35
imp.cuas_lma_maxk = this.cuas_lma_maxk;
imp.cuas_isolated = this.cuas_isolated;
imp.cuas_max_mismatch = this.cuas_max_mismatch;
imp.cuas_ignore_mismatch = this.cuas_ignore_mismatch;
imp.cuas_mask_width = this.cuas_mask_width;
imp.cuas_mask_blur = this.cuas_mask_blur;
......@@ -6237,6 +6262,7 @@ min_str_neib_fpn 0.35
imp.cuas_debug = this.cuas_debug;
imp.cuas_step_debug = this.cuas_step_debug;
imp.cuas_target_debug = this.cuas_target_debug;
imp.cuas_overwrite = this.cuas_overwrite;
imp.cuas_num_orient = this.cuas_num_orient;
......
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