Commit 1671728b authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Equalizing intensities

parent c4df622d
Loading
Loading
Loading
Loading
+513 −353
Original line number Diff line number Diff line
package com.elphel.imagej.common;
import java.util.concurrent.atomic.AtomicInteger;

import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.QuadCLT;

import Jama.LUDecomposition;
import Jama.Matrix;

@@ -601,6 +606,161 @@ public class PolynomialApproximation {
		return norm;
	}

	public static double [] getYXRegression(
			final double []  data_x,
			final double []  data_y,
			final boolean [] mask) {
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
		final AtomicInteger ai = new AtomicInteger(0);
		final double [] as0 =  new double[threads.length];
		final double [] asx =  new double[threads.length];
		final double [] asx2 = new double[threads.length];
		final double [] asy =  new double[threads.length];
		final double [] asxy=  new double[threads.length];
		final AtomicInteger ati = new AtomicInteger(0);
		ai.set(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					int thread_num = ati.getAndIncrement();
					for (int ipix = ai.getAndIncrement(); ipix < data_x.length; ipix = ai.getAndIncrement()) if ((mask == null) || mask[ipix]){
						double x = data_x[ipix];
						double y = data_y[ipix];
						if (!Double.isNaN(x) && !Double.isNaN(y)) {
							as0 [thread_num] += 1;
							asx [thread_num] += x;
							asx2[thread_num] += x * x;
							asy [thread_num] += y;
							asxy[thread_num] += x * y;
						}
					} // for (int ipix
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		double s0 = 0.0;
		double sx = 0.0;
		double sx2 = 0.0;
		double sy = 0.0;
		double sxy= 0.0;
		for (int i = 0; i < threads.length; i++) {
			s0+=  as0[i];
			sx+=  asx[i];
			sx2+= asx2[i];
			sy+=  asy[i];
			sxy+= asxy[i];
		}
		double dnm = s0 * sx2 - sx*sx;
		double a = (sxy * s0 - sy * sx) / dnm;
		double b = (sy * sx2 - sxy * sx) / dnm;
		return new double[] {a,b};
	}
	
	/**
	 * Get best fit ax+b symmetrical for X and Y, same weights
	 * https://en.wikipedia.org/wiki/Deming_regression#Orthogonal_regression
	 * @param data_x
	 * @param data_y
	 * @param mask
	 * @return
	 */
	
//RuntimeException
	public static double [] getOrthoRegression( // symmetrical for X and Y, same eror weights
			final double []  data_x,
			final double []  data_y,
			final boolean [] mask_in) {
		final boolean [] mask = new boolean [data_x.length];
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
		final AtomicInteger ai = new AtomicInteger(0);
		final double [] as0 =  new double[threads.length];
		final double [] asx =  new double[threads.length];
		final double [] asy =  new double[threads.length];
		final AtomicInteger ati = new AtomicInteger(0);
		ai.set(0);
		// Find centroid first
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					int thread_num = ati.getAndIncrement();
					for (int ipix = ai.getAndIncrement(); ipix < data_x.length; ipix = ai.getAndIncrement()) if ((mask_in == null) || mask_in[ipix]){
						
						double x = data_x[ipix];
						double y = data_y[ipix];
						if (!Double.isNaN(x) && !Double.isNaN(y)) {
							as0 [thread_num] += 1;
							asx [thread_num] += x;
							asy [thread_num] += y;
							mask[ipix] = true;
						}
					} // for (int ipix
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		double s0 = 0.0;
		double sx = 0.0;
		double sy = 0.0;
		for (int i = 0; i < threads.length; i++) {
			s0+=  as0[i];
			sx+=  asx[i];
			sy+=  asy[i];
		}
		double [] z_mean = {sx/s0, sy/s0}; // complex
		final double [] as_re =  new double[threads.length];
		final double [] as_im =  new double[threads.length];
		ai.set(0);
		ati.set(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					int thread_num = ati.getAndIncrement();
					for (int ipix = ai.getAndIncrement(); ipix < data_x.length; ipix = ai.getAndIncrement()) if ((mask == null) || mask[ipix]){
						double x = data_x[ipix]-z_mean[0];
						double y = data_y[ipix]-z_mean[1];
						as_re[thread_num] += x*x - y*y;
						as_im[thread_num] += 2*x*y;
					} // for (int ipix
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		double s_re = 0.0;
		double s_im = 0.0;
		for (int i = 0; i < threads.length; i++) {
			s_re+=  as_re[i];
			s_im+=  as_im[i];
		}
		// https://en.wikipedia.org/wiki/Square_root#Algebraic_formula
		// sqrt (s_re+i*s_im)
		double sqrt_re = Math.sqrt(0.5 * (Math.sqrt(s_re*s_re + s_im*s_im) +s_re));
		double sqrt_im = ((s_im > 0)? 1 : -1) *  Math.sqrt(0.5 * (Math.sqrt(s_re*s_re + s_im*s_im) - s_re));
		double a = sqrt_im/sqrt_re;
		double b = z_mean[1]-  a * z_mean[0];
		return new double[] {a,b};
	}
	
	
	
	
	
	
	public static void applyRegression(
			final double [] data, // clone by caller
			final double [] regression) {
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
		final AtomicInteger ai = new AtomicInteger(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					for (int ipix = ai.getAndIncrement(); ipix < data.length; ipix = ai.getAndIncrement()){
						data[ipix] = regression[0] * data[ipix] + regression[1];
					}
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
	}
	public static double [] invertRegression(double [] regression) {
		return new double [] {1.0/regression[0], -regression[1]/regression[0]};
	}
}
+6 −3
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ public class ComboMatch {
		boolean pattern_match =       true; // false;
		
		boolean bounds_to_indices =   true;
		int     temp_mode =           1;
		int     temp_mode =           0;
		boolean restore_temp =        true;
		double  frac_remove  =        clt_parameters.imp.pmtch_frac_remove; //   0.15;
		double  metric_error =        clt_parameters.imp.pmtch_metric_err; // 0.05; // 0.02;//  2 cm
@@ -1030,10 +1030,13 @@ public class ComboMatch {
        				}
        				if (render_match) {
        					String title=String.format("multi_%03d-%03d_%s-%s_zoom%d_%d",gpu_pair[0],gpu_pair[1],gpu_spair[0],gpu_spair[1],min_zoom_lev,zoom_lev);
        					// Avoid renderMulti() - it duplicates code renderMultiDouble()
        					int eq_mode = 2; // calculate
        					ImagePlus imp_img_pair = 	maps_collection.renderMulti (
        							//_zoom<integer> is needed for opening with "Extract Objects" command
        							title,             // String      title,
        							OrthoMapsCollection.MODE_IMAGE,  // int           mode,    // 0 - regular image, 1 - altitudes, 2 - black/white mask       // boolean     use_alt,
//        							OrthoMapsCollection.MODE_IMAGE,  // int           mode,    // 0 - regular image, 1 - altitudes, 2 - black/white mask       // boolean     use_alt,
        							eq_mode,           //int           eq_mode, // 0 - ignore equalization, 1 - use stored equalization, 2 - calculate equalization 
        							gpu_pair,          // int []        indices, // null or which indices to use (normally just 2 for pairwise comparison)
        							bounds_to_indices, // boolean       bounds_to_indices,
        							temp_mode,         // int           temp_mode, // 0 - do nothing, 1 - equalize average,2 - try to correct
+20 −54
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
	public transient double                     agl = Double.NaN;
	public transient int                        num_scenes = -1;;   // number of scenes that made up this image
	public transient double                     sfm_gain = Double.NaN;     // maximal SfM gain of this map
	public transient double []                  equalize = {1,0}; // rectified value = equalize[0]*source_value+equalize[1]
	private void writeObject(ObjectOutputStream oos) throws IOException {
		oos.defaultWriteObject();
		oos.writeObject(path);
@@ -137,6 +138,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
		oos.writeObject(agl);
		oos.writeObject(num_scenes);
		oos.writeObject(sfm_gain);
		oos.writeObject(equalize);
	}
	
	private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
@@ -160,6 +162,8 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
		agl = (double)  ois.readObject();
		num_scenes = (int) ois.readObject();
		sfm_gain = (double) ois.readObject();
//		equalize = new double[] {1,0};
		equalize = (double []) ois.readObject();
		images = new HashMap <Integer, FloatImageData>(); // field images was not saved
		averageImagePixel = Double.NaN; // average image pixel value (to combine with raw)
		
@@ -167,6 +171,18 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
//		pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>();
	}

	double getEqualized(double d) {
		return d * equalize[0] + equalize[1];
	}
	
	double [] getEqualize() {
		return equalize;
	}
	
	void setEqualize(double [] equalize) {
		this.equalize = equalize;
	}
	
    @Override
    public int compareTo(OrthoMap otherPlayer) {
        return Double.compare(ts, otherPlayer.ts);
@@ -1717,9 +1733,9 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
			};
		}		      
		ImageDtt.startAndJoin(threads);
		double [] ab = getDatiRegression(
				temp, // final double []  temp,
				dati, // final double []  dati,
		double [] ab = PolynomialApproximation.getYXRegression(
				temp, // final double []  data_x,
				dati, // final double []  data_y,
				flat); // final boolean [] mask);
		double a = ab[0];
		double b = ab[1];
@@ -1774,56 +1790,6 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
		return flat;
	}
	
	private static double [] getDatiRegression(
			final double []  temp,
			final double []  dati,
			final boolean [] mask) {
		final Thread[] threads = ImageDtt.newThreadArray(QuadCLT.THREADS_MAX);
		final AtomicInteger ai = new AtomicInteger(0);
		final double [] as0 =  new double[threads.length];
		final double [] asx =  new double[threads.length];
		final double [] asx2 = new double[threads.length];
		final double [] asy =  new double[threads.length];
		final double [] asxy=  new double[threads.length];
		final AtomicInteger ati = new AtomicInteger(0);
		ai.set(0);
		for (int ithread = 0; ithread < threads.length; ithread++) {
			threads[ithread] = new Thread() {
				public void run() {
					int thread_num = ati.getAndIncrement();
					for (int ipix = ai.getAndIncrement(); ipix < temp.length; ipix = ai.getAndIncrement()) if (mask[ipix]){
						double x = temp[ipix];
						double y = dati[ipix];
						if (!Double.isNaN(x+y)) {
							as0 [thread_num] += 1;
							asx [thread_num] += x;
							asx2[thread_num] += x * x;
							asy [thread_num] += y;
							asxy[thread_num] += x * y;
						}
					} // for (int ipix
				}
			};
		}		      
		ImageDtt.startAndJoin(threads);
		double s0 = 0.0;
		double sx = 0.0;
		double sx2 = 0.0;
		double sy = 0.0;
		double sxy= 0.0;
		for (int i = 0; i < threads.length; i++) {
			s0+=  as0[i];
			sx+=  asx[i];
			sx2+= asx2[i];
			sy+=  asy[i];
			sxy+= asxy[i];
		}
		double dnm = s0 * sx2 - sx*sx;
		double a = (sxy * s0 - sy * sx) / dnm;
		double b = (sy * sx2 - sxy * sx) / dnm;
		return new double[] {a,b};
	}
	
	
	private static int [][] getCirclePoints(
			double radius) {
Loading