Commit 08bccd0d authored by Andrey Filippov's avatar Andrey Filippov
Browse files

implementing moving objects masking for ERS fitting, this is debug

version for GPU geometry correction
parent fabadb74
Loading
Loading
Loading
Loading
+377 −330
Original line number Diff line number Diff line
@@ -42,10 +42,57 @@ public class DoubleGaussianBlur {

	/* Default constructor */
	public DoubleGaussianBlur() {
		
	}

	public double [] blurWithNaN(
			double[] pixels,
			double [] in_weight, // or null
			int width,
			int height,
			double sigmaX,
			double sigmaY,
			double accuracy
			) {
		double [] weight;
		double [] blured = new double[pixels.length];
		if (in_weight == null) {
			weight = new double [pixels.length];
			for (int i = 0; i < weight.length; i++) {
				weight[i] = 1.0;
			}
		} else {
			weight = in_weight.clone();
		}
		for (int i = 0; i < pixels.length; i++) {
			if (Double.isNaN(pixels[i])) {
				weight[i] = 0.0;
			} else {
				blured[i] = pixels[i] * weight[i];
			}
		}
		blurDouble(
				blured,
				width,
				height,
				sigmaX,
				sigmaY,
				accuracy);
		blurDouble(
				weight,
				width,
				height,
				sigmaX,
				sigmaY,
				accuracy);
		for (int i = 0; i < pixels.length; i++) {
			blured[i] /= weight[i];
		}
		return blured;
	}

	  public void blurDouble(double[] pixels,
	public void blurDouble(
			double[] pixels,
			int width,
			int height,
			double sigmaX,
+48 −6
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ public class GPUTileProcessor {
	static String GPU_RBGA_NAME =                  "generate_RBGA";       // name in C code
	static String GPU_ROT_DERIV =                  "calc_rot_deriv";      // calculate rotation matrices and derivatives
	static String GPU_SET_TILES_OFFSETS =          "get_tiles_offsets";   // calculate pixel offsets and disparity distortions
	static String GPU_CALCULATE_TILES_OFFSETS =    "calculate_tiles_offsets";   // calculate pixel offsets and disparity distortions
	static String GPU_CALC_REVERSE_DISTORTION =    "calcReverseDistortionTable"; // calculate reverse radial distortion table from gpu_geometry_correction

//  pass some defines to gpu source code with #ifdef JCUDA
@@ -168,7 +169,8 @@ public class GPUTileProcessor {
    private CUfunction GPU_TEXTURES_kernel =                null;
    private CUfunction GPU_RBGA_kernel =                    null;
    private CUfunction GPU_ROT_DERIV_kernel =               null;
    private CUfunction GPU_SET_TILES_OFFSETS_kernel =       null;
//    private CUfunction GPU_SET_TILES_OFFSETS_kernel =       null;
    private CUfunction GPU_CALCULATE_TILES_OFFSETS_kernel = null;
    private CUfunction GPU_CALC_REVERSE_DISTORTION_kernel = null;

    CUmodule    module; // to access constants memory
@@ -393,7 +395,8 @@ public class GPUTileProcessor {
        		GPU_TEXTURES_NAME,
        		GPU_RBGA_NAME,
        		GPU_ROT_DERIV,
        		GPU_SET_TILES_OFFSETS,
//        		GPU_SET_TILES_OFFSETS,
        		GPU_CALCULATE_TILES_OFFSETS,
        		GPU_CALC_REVERSE_DISTORTION
        };
        CUfunction[] functions = createFunctions(kernelSources,
@@ -408,7 +411,8 @@ public class GPUTileProcessor {
        GPU_TEXTURES_kernel=                 functions[5];
        GPU_RBGA_kernel=                     functions[6];
        GPU_ROT_DERIV_kernel =               functions[7];
        GPU_SET_TILES_OFFSETS_kernel =       functions[8];
//        GPU_SET_TILES_OFFSETS_kernel =       functions[8];
        GPU_CALCULATE_TILES_OFFSETS_kernel = functions[8];
        GPU_CALC_REVERSE_DISTORTION_kernel = functions[9];

        System.out.println("GPU kernel functions initialized");
@@ -420,7 +424,8 @@ public class GPUTileProcessor {
        System.out.println(GPU_TEXTURES_kernel.toString());
        System.out.println(GPU_RBGA_kernel.toString());
        System.out.println(GPU_ROT_DERIV_kernel.toString());
        System.out.println(GPU_SET_TILES_OFFSETS_kernel.toString());
//        System.out.println(GPU_SET_TILES_OFFSETS_kernel.toString());
        System.out.println(GPU_CALCULATE_TILES_OFFSETS_kernel.toString());
        System.out.println(GPU_CALC_REVERSE_DISTORTION_kernel.toString());
        
        // GPU data structures are now initialized through GpuQuad instances
@@ -1603,7 +1608,8 @@ public class GPUTileProcessor {
/**
 * Calculate tiles offsets (before each direct conversion run)
 */
        public void execSetTilesOffsets() {
        /*
        public void execSetTilesOffsetsOld() {
        	execCalcReverseDistortions(); // will check if it is needed first
        	execRotDerivs();              // will check if it is needed first
            if (GPU_SET_TILES_OFFSETS_kernel == null)
@@ -1612,7 +1618,7 @@ public class GPUTileProcessor {
                return;
            }
            // kernel parameters: pointer to pointers
            int [] GridFullWarps =    {(num_task_tiles + TILES_PER_BLOCK_GEOM - 1)/TILES_PER_BLOCK_GEOM, 1, 1}; // round up
            int [] GridFullWarps =    {(num_task_tiles + 2 * TILES_PER_BLOCK_GEOM - 1)/TILES_PER_BLOCK_GEOM, 1, 1}; // round up
            int [] ThreadsFullWarps = {num_cams, TILES_PER_BLOCK_GEOM, 1}; // 4,8,1
            Pointer kernelParameters = Pointer.to(
            		Pointer.to(gpu_tasks),                   // struct tp_task     * gpu_tasks,
@@ -1632,6 +1638,42 @@ public class GPUTileProcessor {
    			System.out.println("======execSetTilesOffsets()");
    		}
        }
*/        
        public void execSetTilesOffsets() {
        	execCalcReverseDistortions(); // will check if it is needed first
        	execRotDerivs();              // will check if it is needed first
            if (GPU_CALCULATE_TILES_OFFSETS_kernel == null)
            {
                IJ.showMessage("Error", "No GPU kernel: GPU_CALCULATE_TILES_OFFSETS_kernel");
                return;
            }
    		if (gpu_debug_level > -1) {
    			System.out.println("num_task_tiles="+num_task_tiles);
    		}

            // kernel parameters: pointer to pointers
//            int [] GridFullWarps =    {(num_task_tiles + 2 * TILES_PER_BLOCK_GEOM - 1)/TILES_PER_BLOCK_GEOM, 1, 1}; // round up
//            int [] ThreadsFullWarps = {num_cams, TILES_PER_BLOCK_GEOM, 1}; // 4,8,1
            int [] GridFullWarps =    {1, 1, 1}; // round up
            int [] ThreadsFullWarps = {1, 1, 1}; // 4,8,1
            Pointer kernelParameters = Pointer.to(
            		Pointer.to(gpu_tasks),                   // struct tp_task     * gpu_tasks,
            		Pointer.to(new int[] { num_task_tiles }),// int                  num_tiles,          // number of tiles in task list
            		Pointer.to(gpu_geometry_correction),     //	struct gc          * gpu_geometry_correction,
            		Pointer.to(gpu_correction_vector),       //	struct corr_vector * gpu_correction_vector,
            		Pointer.to(gpu_rByRDist),                //	float *              gpu_rByRDist)      // length should match RBYRDIST_LEN
            		Pointer.to(gpu_rot_deriv));              // trot_deriv         * gpu_rot_deriv);
            cuCtxSynchronize();
        	cuLaunchKernel(GPU_CALCULATE_TILES_OFFSETS_kernel,
        			GridFullWarps[0],    GridFullWarps[1],   GridFullWarps[2],   // Grid dimension
        			ThreadsFullWarps[0], ThreadsFullWarps[1],ThreadsFullWarps[2],// Block dimension
        			0, null,                 // Shared memory size and stream (shared - only dynamic, static is in code)
        			kernelParameters, null);   // Kernel- and extra parameters
        	cuCtxSynchronize(); // remove later
    		if (gpu_debug_level > -1) {
    			System.out.println("======execSetTilesOffsets()");
    		}
        }

/**
 * Direct CLT conversion and aberration correction 
+375 −38
Original line number Diff line number Diff line
package com.elphel.imagej.tileprocessor;

import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.ShowDoubleFloatArrays;

import Jama.Matrix;
@@ -81,7 +82,7 @@ public class ExtrinsicAdjustment {
	public int clustersX;
	public int clustersY;
	
	public double dbg_delta = 1.0E-5; // if not null - use delta instead of the derivatives in getJacobianTransposed
	public double dbg_delta = 0; // 1.0E-5; // if not 0 - use delta instead of the derivatives in getJacobianTransposed

	public double [] getOldNewRMS() {
		double [] on_rms = new double[2];
@@ -272,7 +273,7 @@ public class ExtrinsicAdjustment {
		 double min_fg_disp = 0.0; //  25.0; // minimal disparity to boost foreground objects
		 double min_rel_over = 0.25; // minimal relative disparity over average for a row to boost foreground objects
		 int min_num_fg =      min_num_forced;
		 double fb_boost_fraction = 0.5; 
		 double fg_boost_fraction = 0.5; 
		 if (min_fg_disp > 0.0) {
			 boolean [] select_ers = selectERS(
					 measured_dsxy, // double  [][] measured_dsxy,
@@ -283,10 +284,62 @@ public class ExtrinsicAdjustment {
					 this.weights, // double []    weights, // will be updated
					 select_ers, // boolean []   fg,
					 min_num_fg, // int          min_num_fg,
					 fb_boost_fraction); // double       fg_boost_fraction)
					 fg_boost_fraction); // double       fg_boost_fraction)
		 }
		 double max_ers_disparity = 175.0;
		 limitDisparity(
				 measured_dsxy, // double  [][] measured_dsxy,
				 this.weights, // double []    weights, // will be updated 
				 max_ers_disparity); // double max_disparity
		 // remove moving objects here		 
		 if (debugLevel > -10) { // temporary
			 dbgYminusFxWeight(
					 this.last_ymfx,
					 this.weights, // will use current weights
					 "Initial y-fX");
			 double [][] ers_tilt_az = getMovingObjects(
					 corr_vector, // GeometryCorrection.CorrVector corr_vector,
					 null ); // double [] fx
			 showMovingObjects(
					 "Moving_objects", // String      title,
					 ers_tilt_az);
			 double moving_sigma = 1.0;

			 double [] ers_blured = showMovingObjects(
					 "Moving_objects_sigma"+moving_sigma, // String      title,
					 ers_tilt_az,
					 moving_sigma, // double sigmaX,
					 0.01); // double accuracy
			 System.out.println("Moving objects");

			 double mov_avg = 0.0;
			 int clusters = clustersX * clustersY;
			 for (int cluster = 0; cluster < clusters; cluster++) {
				 if (!Double.isNaN(ers_blured[cluster])) mov_avg += ers_blured[cluster];
			 }
			 mov_avg /= clusters;
			 System.out.println("Average moving object detection value = "+mov_avg+
					 " (use to abandon detection if too high?");
//			 double min_l2 = 1.0 * mov_avg; 
			 double min_l2 = 1.0 * mov_avg; 
			 boolean [] moving_maybe =  extractMovingObjects(
					 "Moving_objects_filtering", //  String    title,
					 ers_blured, //double [] ers_blured, // has NaNs
					 min_l2, // double min_l2); // minimal value (can use average or fraction of it?
					 4, // int       shrink, // prevents growing outer border (==4)
					 2); // int       grow) { // located moving areas

			 int num_moving = 0;
			 for (int cluster = 0; cluster < clusters; cluster++) {
				 if (moving_maybe[cluster]) num_moving++;
			 }
			 System.out.println("Number of clusters to remove from LMA fitting = "+num_moving);
			 System.out.println();
			 blockSelectedClusters(
					 measured_dsxy, // double  [][] measured_dsxy,
					 this.weights, // double []    weights, // will be updated
					 moving_maybe); // 	boolean []   prohibit
		 }
		 
		 

		 double lambda = 0.1;
		 double lambda_scale_good = 0.5;
@@ -606,6 +659,78 @@ public class ExtrinsicAdjustment {
		return;
	}
	
	private void limitDisparity(
			double  [][] measured_dsxy,
			double []    weights,
			double max_disparity
			) {
		double sw =  0.0;
		double sw_near = 0.0;
		int clusters = clustersX * clustersY;
		for (int cluster = 0; cluster < clusters; cluster++) if (measured_dsxy[cluster] != null){
			double disparity = measured_dsxy[cluster][ExtrinsicAdjustment.INDX_DISP];
			if (disparity <= max_disparity) {
				for (int i = 0; i < POINTS_SAMPLE; i++) {
					sw_near += weights[cluster * POINTS_SAMPLE + i];
				}
			}
			for (int i = 0; i < POINTS_SAMPLE; i++) {
				sw += weights[cluster * POINTS_SAMPLE + i];
			}
		}
		
		if (sw_near > 0.0) {
			double wboost = sw/sw_near;
			for (int cluster = 0; cluster < clusters; cluster++) if (measured_dsxy[cluster] != null){
				double disparity = measured_dsxy[cluster][ExtrinsicAdjustment.INDX_DISP];
				if (disparity <= max_disparity) {
					for (int i = 0; i < POINTS_SAMPLE; i++) {
						weights[cluster * POINTS_SAMPLE + i] *= wboost;
					}
				} else {
					for (int i = 0; i < POINTS_SAMPLE; i++) {
						weights[cluster * POINTS_SAMPLE + i] = 0;
					}
				}
			}
		}
	}
	
	private void blockSelectedClusters(
			double  [][] measured_dsxy,
			double  []   weights,
			boolean []   prohibit
			) {
		double sw =  0.0;
		double sw_en = 0.0;
		int clusters = clustersX * clustersY;
		for (int cluster = 0; cluster < clusters; cluster++) if (measured_dsxy[cluster] != null){
			if (!prohibit[cluster]) {
				for (int i = 0; i < POINTS_SAMPLE; i++) {
					sw_en += weights[cluster * POINTS_SAMPLE + i];
				}
			}
			for (int i = 0; i < POINTS_SAMPLE; i++) {
				sw += weights[cluster * POINTS_SAMPLE + i];
			}
		}
		
		if (sw_en > 0.0) {
			double wboost = sw/sw_en;
			for (int cluster = 0; cluster < clusters; cluster++) if (measured_dsxy[cluster] != null){
				if (!prohibit[cluster]) {
					for (int i = 0; i < POINTS_SAMPLE; i++) {
						weights[cluster * POINTS_SAMPLE + i] *= wboost;
					}
				} else {
					for (int i = 0; i < POINTS_SAMPLE; i++) {
						weights[cluster * POINTS_SAMPLE + i] = 0;
					}
				}
			}
		}

	}
	
	
	private double [] getWeights(
@@ -683,10 +808,14 @@ public class ExtrinsicAdjustment {
		Matrix [][] deriv_rots = corr_vector.getRotDeriveMatrices();
		double [] imu = corr_vector.getIMU(); // i)
		double [] y_minus_fx = new double  [clusters * POINTS_SAMPLE];
		for (int cluster = 0; cluster < clusters;  cluster++) if (measured_dsxy[cluster] != null){
			if ((cluster == 1735 ) || (cluster==1736)){
				System.out.print("");
			}
		for (int cluster = 0; cluster < clusters;  cluster++) {
//			if ((cluster == 1892) || (cluster == 1894) ||(cluster == 3205)) {
//				System.out.println("getFx() cluster="+cluster);
//			}
			if (measured_dsxy[cluster] != null){
//				if ((cluster == 1735 ) || (cluster==1736)){
//					System.out.print("");
//				}
				double [] ddnd = geometryCorrection.getPortsDDNDAndDerivativesNew( // USED in lwir
						geometryCorrection,     // GeometryCorrection gc_main,
						use_rig_offsets,        // boolean     use_rig_offsets,
@@ -709,6 +838,7 @@ public class ExtrinsicAdjustment {
				}
				System.arraycopy(ddnd, 0, y_minus_fx, cluster*POINTS_SAMPLE, POINTS_SAMPLE);
			}
		}
		return y_minus_fx;
	}

@@ -751,7 +881,7 @@ public class ExtrinsicAdjustment {
			double delta,
			boolean graphic) {
//		delta *= 0.1;
		int gap = 10; //pix
		int gap = 10+0; //pix
		int clusters = clustersX * clustersY;
		int num_pars = getNumPars();
		String [] titles = getSymNames();
@@ -902,10 +1032,168 @@ public class ExtrinsicAdjustment {
				titles);
	}

	private double [][] getMovingObjects(
			GeometryCorrection.CorrVector corr_vector,
			double [] fx // or null;
			) {
		int ers_tilt_index =    GeometryCorrection.CorrVector.IMU_INDEX;
		int ers_azimuth_index = GeometryCorrection.CorrVector.IMU_INDEX + 1;
		int clusters = clustersX * clustersY;
		double [][] ers_tilt_az = new double [clusters][];
		double [][] jt = getJacobianTransposed(corr_vector);
		for (int cluster = 0; cluster < clusters; cluster++) if ( measured_dsxy[cluster] != null) {
			ers_tilt_az[cluster] = new double [2];
			for (int i = 0; i < (POINTS_SAMPLE-1); i++) {
				int indx = cluster * POINTS_SAMPLE + i + 1; // skipping disparity
				double d = measured_dsxy[cluster][ExtrinsicAdjustment.INDX_DD0 + i];
				if (fx != null) {
					d += fx[indx];
				}
				ers_tilt_az[cluster][0] += d * jt[ers_tilt_index][indx];
				ers_tilt_az[cluster][1] += d * jt[ers_azimuth_index][indx];
			}
		}
		return ers_tilt_az;
	}

	private void showMovingObjects(
			String      title,
			double [][] ers_tilt_az) {
		showMovingObjects(
				title,
				ers_tilt_az,
				0, // double sigma,
				0);
	}

	private double [] showMovingObjects(
			String      title,
			double [][] ers_tilt_az,
			double sigma,
			double accuracy
			)
	{
		int clusters = clustersX * clustersY;
		
		String [] titles = {"vert", "hor", "amplitude"};
		double [][] dbg_img = new double [titles.length][clusters];
		double max_reasonable = 100.0;
		for (int cluster = 0; cluster < clusters; cluster++) {
			if (ers_tilt_az[cluster] != null) {
				dbg_img[0][cluster] = ers_tilt_az[cluster][0];
				dbg_img[1][cluster] = ers_tilt_az[cluster][1];
				dbg_img[2][cluster] = Math.sqrt(0.5*(ers_tilt_az[cluster][0]*ers_tilt_az[cluster][0] + ers_tilt_az[cluster][1]*ers_tilt_az[cluster][1]));
				if (dbg_img[2][cluster] > max_reasonable) {
					dbg_img[0][cluster] = Double.NaN;
					dbg_img[1][cluster] = Double.NaN;
					dbg_img[2][cluster] = Double.NaN;
				}
			} else {
				dbg_img[0][cluster] = Double.NaN;
				dbg_img[1][cluster] = Double.NaN;
				dbg_img[2][cluster] = Double.NaN;
			}
		}
		
		if (sigma > 0.0){
			double [] cluster_weights = new double [clusters];
			for (int cluster = 0; cluster < clusters; cluster++) {
				for (int i = 0; i < POINTS_SAMPLE; i++) {
					cluster_weights[cluster] += this.weights[cluster * POINTS_SAMPLE + i];
				}
			}
			for (int i = 0; i < dbg_img.length; i++) {
				dbg_img[i] = (new DoubleGaussianBlur()).blurWithNaN(
						dbg_img[i], // double[] pixels,
						cluster_weights, // null, // double [] in_weight, // or null
						clustersX,// int width,
						clustersY,// int height,
						sigma, // double sigmaX,
						sigma, // double sigmaY,
						0.01); // double accuracy
			}
		}
		
		(new ShowDoubleFloatArrays()).showArrays(
				dbg_img,
				clustersX,
				clustersY,
				true,
				title,
				titles);
		return dbg_img[2]; 

	}
	
	public boolean [] extractMovingObjects(
			String    title,
			double [] ers_blured, // has NaNs
			double    min_l2, // minimal value (can use average or fraction of it?
			int       shrink, // prevents growing outer border (==4)
			int       grow) { // located moving areas
		int clusters = clustersX * clustersY;
		TileNeibs tn = new TileNeibs(clustersX, clustersY);
		boolean [] terrain = new boolean[clusters];
		for (int i = 0; i < clusters; i++) {
			terrain[i] = ers_blured[i] <= min_l2; // NaNs not included
		}
		// find largest terrain area
		int [] iterrains = tn. enumerateClusters(
				terrain, // boolean [] tiles,
				true); //boolean ordered)
		boolean [] terrain_main = new boolean[clusters];
		for (int i = 0; i < clusters; i++) {
			terrain_main[i] = (iterrains[i] == 1); // largest cluster
		}
		
		boolean [] filled = tn.fillConcave(terrain_main);
		
		tn.shrinkSelection(
				 shrink, // int        shrink,
					filled, // boolean [] tiles,
					null); // boolean [] prohibit)
		boolean [] moving = filled.clone();
		for (int i = 0; i < clusters; i++) {
			moving[i] &= !terrain_main[i]; 
		}
		boolean [] grown = moving.clone();
		tn.growSelection(
				grow, // int        grow,           // grow tile selection by 1 over non-background tiles 1: 4 directions, 2 - 8 directions, 3 - 8 by 1, 4 by 1 more
				grown, // boolean [] tiles,
				null); // boolean [] prohibit)
		if (title != null) {
			String [] titles = {"terrain","clusters","main_terrain","filled","moving","grown"};
			double [][] dbg_img = new double [titles.length][clusters];
			for (int cluster = 0; cluster < clusters; cluster++) {
				dbg_img[0][cluster] = terrain[cluster]? 1.0 : 0.0;
				dbg_img[1][cluster] = iterrains[cluster];
				dbg_img[2][cluster] = terrain_main[cluster]? 1.0 : 0.0;
				dbg_img[3][cluster] = filled[cluster]? 1.0 : 0.0;
				dbg_img[4][cluster] = moving[cluster]? 1.0 : 0.0;
				dbg_img[5][cluster] = grown[cluster]? 1.0 : 0.0;
			}
			(new ShowDoubleFloatArrays()).showArrays(
					dbg_img,
					clustersX,
					clustersY,
					true,
					title,
					titles);
		}
		return grown;
	}
	
	
	
	
	
	private void dbgYminusFxWeight(
			double []   fx,
			double []   weights,
			String title) {
		if (fx == null) {
			fx = new double [weights.length];
		}
		int gap = 10; //pix
		int clusters = clustersX * clustersY;
		String [] titles = {"Y", "-fX", "Y+fx", "Weight", "W*(Y+fx)", "Masked Y+fx"};
@@ -979,23 +1267,33 @@ public class ExtrinsicAdjustment {
		double [][] xy = getXYNondistorted(corr_vector, false);

		double [][] dbg_img = new double [3][width*height];
		for (int mode = 0; mode < 2 * NUM_SENSORS; mode++) {
		double [][] moving_objects = new double [3][clusters];
		for (int mode = 0; mode < 2 * NUM_SENSORS + 1; mode++) {
			int x0 = (mode % 3) * (clustersX + gap);
			int y0 = (mode / 3) * (clustersY + gap);
			for (int cluster = 0; cluster < clusters;  cluster++) {
				int x = x0 + (cluster % clustersX);
				int y = y0 + (cluster / clustersX);
				int pix = x + y * width;
//				int indx = cluster * POINTS_SAMPLE + mode;
				if (measured_dsxy[cluster] != null){
					if (mode < (2 * NUM_SENSORS)) {
						dbg_img[0][pix] =  measured_dsxy[cluster][ExtrinsicAdjustment.INDX_X0+mode];
						dbg_img[1][pix] =  xy[cluster][mode] - x0y0[cluster][mode];
						dbg_img[2][pix] =  xy[cluster][mode] - x0y0[cluster][mode] - measured_dsxy[cluster][ExtrinsicAdjustment.INDX_X0+mode];
						dbg_img[2][pix] =  measured_dsxy[cluster][ExtrinsicAdjustment.INDX_X0+mode] - (xy[cluster][mode] - x0y0[cluster][mode]);
						moving_objects[0][cluster] += dbg_img[0][pix]*dbg_img[0][pix];
						moving_objects[1][cluster] += dbg_img[1][pix]*dbg_img[0][pix];
						moving_objects[2][cluster] += dbg_img[2][pix]*dbg_img[0][pix];
					} else {
						dbg_img[0][pix] = Math.sqrt(moving_objects[0][cluster]/(2 * NUM_SENSORS));
						dbg_img[1][pix] = Math.sqrt(moving_objects[0][cluster]/(2 * NUM_SENSORS));
						dbg_img[2][pix] = Math.sqrt(moving_objects[0][cluster]/(2 * NUM_SENSORS));
					}
				} else {
					dbg_img[ 0][pix] =  Double.NaN;
					dbg_img[ 1][pix] =  Double.NaN;
					dbg_img[ 2][pix] =  Double.NaN;
				}

			}
		}
		(new ShowDoubleFloatArrays()).showArrays(
@@ -1005,6 +1303,7 @@ public class ExtrinsicAdjustment {
				true,
				title,
				titles);
		System.out.println("dbgXY() DONE");
	}


@@ -1176,15 +1475,53 @@ public class ExtrinsicAdjustment {
//					this.last_jt); // double [][] jt) { // should be either [vector.length][samples.size()] or null - then only fx is calculated
			this.last_jt =  getJacobianTransposed(corr_vector); // new double [num_pars][num_points];
			this.last_ymfx = getFx(corr_vector);

			if (debug_level > 2) {
			if (debug_level > -10) { // temporary
				dbgYminusFxWeight(
						this.last_ymfx,
						this.weights,
						"Initial y-fX");
//				dbgYminusFx(this.last_ymfx, "Initial y-fX");
						"Initial_y-fX_after_moving_objects");
				
				/*
				double [][] ers_tilt_az = getMovingObjects(
						corr_vector, // GeometryCorrection.CorrVector corr_vector,
						null ); // double [] fx
				showMovingObjects(
						"Moving_objects", // String      title,
						ers_tilt_az);
				double moving_sigma = 1.0;
				
				double [] ers_blured = showMovingObjects(
						"Moving_objects_sigma"+moving_sigma, // String      title,
						ers_tilt_az,
						moving_sigma, // double sigmaX,
						0.01); // double accuracy
				System.out.println("Moving objects");
				
				double mov_avg = 0.0;
				int clusters = clustersX * clustersY;
				for (int cluster = 0; cluster < clusters; cluster++) {
					if (!Double.isNaN(ers_blured[cluster])) mov_avg += ers_blured[cluster];
				}
				mov_avg /= clusters;
				System.out.println("Average moving object detection value = "+mov_avg+
						" (use to abandon detection if too high?");
				double min_l2 = 1.0 * mov_avg; 
				boolean [] moving_maybe =  extractMovingObjects(
						"Moving_objects_filtering", //  String    title,
						ers_blured, //double [] ers_blured, // has NaNs
						min_l2, // double min_l2); // minimal value (can use average or fraction of it?
						4, // int       shrink, // prevents growing outer border (==4)
						2); // int       grow) { // located moving areas

				int num_moving = 0;
				for (int cluster = 0; cluster < clusters; cluster++) {
					if (moving_maybe[cluster]) num_moving++;
				}
				System.out.println("Number of clusters to remove from LMA fitting = "+num_moving);
				System.out.println();
				*/
				
			}

			if (last_ymfx == null) {
				return null; // need to re-init/restart LMA
Loading