Commit 25c2bbf2 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Detect mines with morning/evenimg pair

parent 2ebcdb9c
Loading
Loading
Loading
Loading
+14 −8
Original line number Original line Diff line number Diff line
@@ -104,7 +104,7 @@ public class ComboMatch {
				"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_19_sep13_25-50-75-100m",
				"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_19_sep13_25-50-75-100m",
				"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_nov3_50-75",
				"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_nov3_50-75",
				"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_sep12-50m"};
				"/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_sep12-50m"};
		
		int default_list_choice = 0; // files_lists_paths.length-1;
//		String files_list_path =          "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_nov3_50-75.list";
//		String files_list_path =          "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_nov3_50-75.list";
//		String orthoMapsCollection_path = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_nov3_50-75.data";
//		String orthoMapsCollection_path = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_nov3_50-75.data";
//maps_nov3_50-75		
//maps_nov3_50-75		
@@ -148,10 +148,11 @@ public class ComboMatch {
		boolean use_saved_collection = true; // false;
		boolean use_saved_collection = true; // false;
		boolean save_collection = true;
		boolean save_collection = true;
		boolean process_correlation = true; // use false to save new version of data
		boolean process_correlation = true; // use false to save new version of data
		int num_tries_fit =           10;
		boolean update_match =        true; // use false to save new version of data
		boolean update_match =        true; // use false to save new version of data
		boolean render_match =        true;
		boolean render_match =        false; // true;


		boolean pattern_match =       false;
		boolean pattern_match =       true; // false;
		
		
		boolean bounds_to_indices =   true;
		boolean bounds_to_indices =   true;
		int     temp_mode =           1;
		int     temp_mode =           1;
@@ -166,10 +167,13 @@ public class ComboMatch {
		
		
		
		
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,900);
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,900);
		gd.addChoice      ("Files list/data path (w/o extension):", files_lists_paths, files_lists_paths[files_lists_paths.length-1]);
		gd.addChoice      ("Files list/data path (w/o extension):", files_lists_paths, files_lists_paths[default_list_choice]);
		gd.addCheckbox    ("Use saved maps collection", use_saved_collection, "If false - use files list.");
		gd.addCheckbox    ("Use saved maps collection", use_saved_collection, "If false - use files list.");
		gd.addCheckbox    ("Save maps collection", save_collection, "Save maps collection to be able to restore.");
		gd.addCheckbox    ("Save maps collection", save_collection, "Save maps collection to be able to restore.");
		gd.addCheckbox    ("Process correlations", process_correlation, "false to skip to just regenerate new save file.");
		gd.addCheckbox    ("Process correlations", process_correlation, "false to skip to just regenerate new save file.");
//		int num_tries_fit =           10;
		gd.addNumericField("Num tries fit",        num_tries_fit,  0,4,"", "Try matching images this number of times");

		gd.addCheckbox    ("Update match if calculated", update_match, "Will update correlation match for a pair if found.");
		gd.addCheckbox    ("Update match if calculated", update_match, "Will update correlation match for a pair if found.");
		gd.addCheckbox    ("Render match", render_match, "Render a pair of matched images.");
		gd.addCheckbox    ("Render match", render_match, "Render a pair of matched images.");
		
		
@@ -215,6 +219,7 @@ public class ComboMatch {
		use_saved_collection =     gd.getNextBoolean();
		use_saved_collection =     gd.getNextBoolean();
		save_collection =          gd.getNextBoolean();
		save_collection =          gd.getNextBoolean();
		process_correlation=       gd.getNextBoolean();
		process_correlation=       gd.getNextBoolean();
		num_tries_fit =      (int) gd.getNextNumber();
		update_match=              gd.getNextBoolean();
		update_match=              gd.getNextBoolean();
		render_match=              gd.getNextBoolean();
		render_match=              gd.getNextBoolean();
		
		
@@ -728,10 +733,10 @@ public class ComboMatch {
				double [][][] affines = {affine0,affine1};
				double [][][] affines = {affine0,affine1};
				int [] zooms = {initial_zoom, min_zoom_lev, 1000,1000}; // make automatic
				int [] zooms = {initial_zoom, min_zoom_lev, 1000,1000}; // make automatic
				double scale = 2.0; // scale vectors when warping;
				double scale = 2.0; // scale vectors when warping;
				int num_tries  = 5;
//				int num_tries  = 5; // make configurable
				if (!process_correlation) {
				if (!process_correlation) {
					zooms = new int[] {min_zoom_lev, 1000};
					zooms = new int[] {min_zoom_lev, 1000};
					num_tries = 0;
					num_tries_fit = 0;
					update_match = false;
					update_match = false;
				}
				}
				debugLevel = 0;
				debugLevel = 0;
@@ -750,7 +755,7 @@ public class ComboMatch {
							frac_remove,    // double           frac_remove, //  =        0.25
							frac_remove,    // double           frac_remove, //  =        0.25
							metric_error, // 			double           metric_error,
							metric_error, // 			double           metric_error,
							ignore_prev_rms, // boolean ignore_prev_rms,
							ignore_prev_rms, // boolean ignore_prev_rms,
							num_tries,      //  = 5int              num_tries, //  = 5
							num_tries_fit,      //  = 5int              num_tries, //  = 5
							true, // boolean          calc_warp,
							true, // boolean          calc_warp,
							batch_mode,     // boolean          batch_mode,
							batch_mode,     // boolean          batch_mode,
							gpu_pair,      // String []        gpu_spair,
							gpu_pair,      // String []        gpu_spair,
@@ -814,6 +819,7 @@ public class ComboMatch {
        		// TODO Auto-generated catch block
        		// TODO Auto-generated catch block
        		e.printStackTrace();
        		e.printStackTrace();
        	}
        	}
        	System.out.println("Saved data to "+ orthoMapsCollection_path);
        }
        }
        return true;
        return true;
	}
	}
@@ -942,7 +948,7 @@ adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
    				ImageDtt.THREADS_MAX, // int       threadsMax,
    				ImageDtt.THREADS_MAX, // int       threadsMax,
    				debugLevel);          // int       debug_level)
    				debugLevel);          // int       debug_level)
    	}		
    	}		
		if (debugLevel > 0) {
		if (debugLevel > 1) {
			String [] dbg_titles = {"x-raw","x_filled","y-raw","y_filled"};
			String [] dbg_titles = {"x-raw","x_filled","y-raw","y_filled"};
			double [][] dbg_img = {vf[0], vf_filled[0],vf[1], vf_filled[1]};
			double [][] dbg_img = {vf[0], vf_filled[0],vf[1], vf_filled[1]};
    		ShowDoubleFloatArrays.showArrays(
    		ShowDoubleFloatArrays.showArrays(
+97 −0
Original line number Original line Diff line number Diff line
package com.elphel.imagej.orthomosaic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

public class ItemMatch {
	public double [] combo_pxy; // combo image {pixel_x, pixel_y}
	public double [] lla; // add later
	public HashMap<String, ItemPatternMatch> pattern_matches = new HashMap<String, ItemPatternMatch>();
	
	public ItemMatch (double [] combo_pxy) {
		this.combo_pxy = combo_pxy;
	}
	
	public double [] getXY() {
		return combo_pxy;
	}
	public int [] getIntXY() {
		return new int [] {(int) Math.round(combo_pxy[0]), (int) Math.round(combo_pxy[1])};
	}
	
	public void addPatternMatches(
			GroundObjectPattern groundObjectPattern,
			double [] matches,
			int      best_sub) {
		String pattern_path = groundObjectPattern.getPatternPath();
		ItemPatternMatch match = pattern_matches.get(pattern_path);
		if (match == null) {
			match = new ItemPatternMatch(groundObjectPattern);
			pattern_matches.put(pattern_path, match);
		}
		match.setMatches(matches);
		match.setBestSub(best_sub);
	}
	
	public ItemPatternMatch getPatternMatch(GroundObjectPattern groundObjectPattern) {
		return getPatternMatch(groundObjectPattern.getPatternPath());
	}
	
	public ItemPatternMatch getPatternMatch(String pattern_path) {
		return pattern_matches.get(pattern_path);
	}
	
	public double [] getMatchValues(String pattern_path) {
		ItemPatternMatch match = pattern_matches.get(pattern_path);
		if (match == null) {
			System.out.println("No matches found for pattern "+pattern_path);
			return null;
		}
		return match.getMatches();
	}
	public double [] getMatchValues(GroundObjectPattern groundObjectPattern) {
		return getMatchValues(groundObjectPattern.getPatternPath());
	}
	
	public double getMatchValue(String pattern_path, int indx) {
		ItemPatternMatch match = pattern_matches.get(pattern_path);
		if (match == null) {
			System.out.println("No matches found for pattern "+pattern_path);
			return Double.NaN;
		}
		return match.getMatch(indx);
	}
	
	public double getMatchValue(GroundObjectPattern groundObjectPattern, int indx) {
		return getMatchValue(groundObjectPattern.getPatternPath(), indx);
	}
	
	public static ArrayList<Integer> sortByMatch(
			ArrayList<ItemMatch> match_list,
			GroundObjectPattern groundObjectPattern,
			int indx){
		String pattern_path = groundObjectPattern.getPatternPath();
		return sortByMatch(match_list, pattern_path, indx);
	}
	
	public static ArrayList<Integer> sortByMatch(
			ArrayList<ItemMatch> match_list,
			String pattern_path,
			int indx){
		ArrayList<Integer> result_list= new ArrayList<Integer>(match_list.size());
		for (int i = 0; i < match_list.size(); i++) {
			result_list.add(i);
		}
		Collections.sort(result_list, new Comparator<Integer>() {
			@Override
			public int compare(Integer lhs, Integer rhs) {
				double rhsd = match_list.get(rhs).getMatchValue(pattern_path, indx);
				double lhsd = match_list.get(lhs).getMatchValue(pattern_path, indx);
				return (rhsd > lhsd) ? 1 : (rhsd < lhsd) ? -1 : 0; // recreasing
			}
		});
		return result_list;
	}
	
}
+52 −0
Original line number Original line Diff line number Diff line
package com.elphel.imagej.orthomosaic;

import java.util.Arrays;

public class ItemPatternMatch {
//	public String pattern_path;
	public double [] sub_matches; // array of sub-pattern match qualities. [0] - is usually combo, [1] - full pattern, [2+] - obscured
	public int       best_sub = -1; // best subpattern
	public GroundObjectPattern groundObjectPattern;
	public ItemPatternMatch(GroundObjectPattern groundObjectPattern) {
		this.groundObjectPattern = groundObjectPattern;
	}
	public void setMatches(double [] matches) {
		sub_matches = matches;
	}
	public void setMatch(int indx, double match_value) {
		if (sub_matches == null) {
			sub_matches = new double [indx+1];
			Arrays.fill(sub_matches, Double.NaN);
		} else if (sub_matches.length <= indx) {
			double [] old_matches = sub_matches;
			sub_matches = new double [indx+1];
			Arrays.fill(sub_matches, Double.NaN);
			System.arraycopy(old_matches, 0, sub_matches, 0, old_matches.length);
		}
		sub_matches[indx] = match_value;
	}

	public void setBestSub(int sub) {
		best_sub = sub;
	}
	
	public int getBestSub() {
		return best_sub;
	}
	
	public double getMatch(int indx) {
		if ((sub_matches == null) || (sub_matches.length <= indx)) {
			return Double.NaN;	
		}
		return sub_matches[indx];
	}
	
	public double [] getMatches() {
		return sub_matches;
	}
	public GroundObjectPattern getGroundObjectPattern() {
		return groundObjectPattern;
	}
}

+236 −0
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@ import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.tileprocessor.Correlation2d;
import com.elphel.imagej.tileprocessor.Correlation2d;
import com.elphel.imagej.tileprocessor.TileNeibs;
import com.elphel.imagej.tileprocessor.TileNeibs;


import Jama.EigenvalueDecomposition;
import Jama.Matrix;
import ij.ImagePlus;
import ij.ImagePlus;
import ij.gui.PointRoi;
import ij.gui.PointRoi;


@@ -80,6 +82,240 @@ public class ObjectLocation {
		return dcrop;
		return dcrop;
	}
	}


	public static double [] extractObjectImage(
			double [] center_xy,
			int       size,
			double [] src_img,
			int width) {
		int height =   src_img.length / width;
		double [] dcrop = new double [size*size];
		Arrays.fill(dcrop, Double.NaN);
		int hsize = size/2;
		int [] xy = {(int) Math.round(center_xy[0]), (int) Math.round(center_xy[1])};
		boolean has_NaN=false;		
		for (int y = 0; y < size; y++) {
			int src_y = y - hsize + xy[1];
			if ((src_y >= 0) && (y < height)) {
				for (int x = 0; x < size; x++) {
					int src_x = x - hsize + xy[0];
					if ((src_x >= 0) && (x < width)) {
						double d = src_img[src_x + src_y * width];
						dcrop[x + size * y] = d;
						has_NaN |= Double.isNaN(d);
					} else {
						has_NaN=true;
					}
				}
			} else {
				has_NaN=true;
			}
		}
		if (has_NaN) {
			TileNeibs tn =  new TileNeibs(size,size);
			OrthoMap.fillNaNs(
					dcrop, // double [] data,
					tn, // TileNeibs tn,
					3); // int min_neibs)
		}
		return dcrop;
	}
	/**
	 * Search for maximum within specified radius from the center or specified offset from the center
	 * @param data square data
	 * @param cent_xy offset from the square center to search
	 * @param radius search for maximum within this radius
	 * @param frac_max fraction of maximum to measure area
	 * @return {maximum, area, dist, x, y}. No interpolation yet, each returned value is integer. 
	 * Returns null if no local maximum within area. x,y are offsets from the (provided) center 
	 */
	public static double [] getMaxLocAreaNaN(
			double [] data, // square data
			double [] cent_xy, // if null, use center of the square
			double    radius, // search for maximum within this radius
			double    frac_max,
			int       debugLevel) {
		double [] rslt = getMaxLocArea(
				data, // square data
				cent_xy, // if null, use center of the square
				radius, // search for maximum within this radius
				frac_max,
				debugLevel);
		if (rslt != null) {
			return rslt;
		} else {
			return new double[] {Double.NaN,Double.NaN,Double.NaN,Double.NaN,Double.NaN,Double.NaN};
		}
	}

	public static double [] getMaxLocArea(
			double [] data, // square data
			double [] cent_xy, // if null, use center of the square
			double    radius, // search for maximum within this radius
			double    frac_max,
			int       debugLevel) {
		boolean   debug = debugLevel > 1;
		int size = (int) Math.sqrt(data.length);
		if (cent_xy == null) {
			cent_xy = new double [] {size/2, size/2};
		}
		double maxr2 = radius * radius;
		double best_d = 0;
		int best_indx = -1;
		int min_x = Math.max(1, (int) Math.floor(cent_xy[0]-radius));
		int min_y = Math.max(1, (int) Math.floor(cent_xy[1]-radius));
		int max_x = Math.min(size-2, (int) Math.ceil(cent_xy[0]+radius));
		int max_y = Math.min(size-2, (int) Math.ceil(cent_xy[1]+radius));
		for (int y = min_y; y <= max_y; y++) { // do not search on very edges
			double dy = (y-cent_xy[1]);
			double y2 = dy*dy;
			if (y2 < maxr2) {
				for (int x = min_x; x <= max_x; x++) {
					double dx = x - cent_xy[0];
					double r2 = y2 + dx*dx;
					if (r2 < maxr2) {
						int indx = y * size + x;
						double d = data[indx];
						if (d > best_d) {
							best_indx = indx;
							best_d = d;
						}
					}
				}
			}
		}
		// is it local max?
		if     ((data[best_indx - 1] >    best_d) || (data[best_indx + 1] >    best_d) ||
				(data[best_indx - size] > best_d) || (data[best_indx + size] > best_d)) {
			return null; // on the edge, not a local max
		}
		
		boolean [] above_thresh = new boolean [data.length];
		double thresh = best_d * frac_max;
		for (int i = 0; i < data.length; i++) {
			above_thresh[i] = data[i] > thresh;
		}
		
		int [] clusters = (new TileNeibs(size,size)).enumerateClusters(
				above_thresh, // boolean [] tiles,
				null,   // int []     num_clusters,
				false); // boolean ordered)
		int center_cluster = clusters[best_indx];

		double xc = best_indx % size - cent_xy[0];
		double yc = best_indx / size - cent_xy[1];

		double s0=0, sx=0, sy=0, sx2 = 0, sy2=0, sxy = 0;
		for (int i = 0; i < clusters.length; i++) {
			if (clusters[i] == center_cluster) {
				double y = i / size - (yc + cent_xy[1]); //(yc + cent_xy[1]) - absolute, from (0,0)
				double x = i % size - (xc + cent_xy[0]);
				double w = data[i]-thresh;
				s0 += w;
				sx += w * x;
				sy += w * y;
				sx2 += w * x * x;
				sy2 += w * y * y;
				sxy += w * x * y;
			}
		}
		double cxx = sx2 - sx * sx / s0, cyy= sy2 - sy * sy / s0, cxy = sxy - sx * sy / s0; 
		/*
		 * sum(Mi*(Xi-avg(X))^2) =          SX2 - SX^2/S0		
		 * sum(Mi*(Yi-avg(Y))^2) =          SY2 - SY^2/S0
		 * sum(Mi*(Xi-avg(X)*(Yi-avg(Y))) =	SXY - SX*SY / S0	
		 */
		Matrix covar = new Matrix(new double[][] {{cxx, cxy},{cxy,cyy}});
		double [] cent_offs = {sx/s0 + xc,sy/s0 + yc};
		EigenvalueDecomposition eig = covar.eig(); 
		
		double [] eigval = {eig.getD().get(0, 0),eig.getD().get(1, 1)};
		Arrays.sort(eigval); // ascending
		double elong = Math.sqrt(eigval[1]/eigval[0]);
		double eff_rad = Math.sqrt(Math.sqrt(eigval[1]*eigval[0]));
		double dist = Math.sqrt(cent_offs[0]*cent_offs[0] + cent_offs[1]*cent_offs[1]);
		if (debug) {
			System.out.println("\ncenter offset ["+(sx/s0)+","+(sy/s0)+"] , from center: ["+cent_offs[0]+","+cent_offs[1]+"]");
			System.out.println("Covariance matrix:");
			covar.print(8, 6);
			System.out.println("eig.getV()");
			eig.getV().print(8, 6);
			System.out.println("eig.getD()");
			eig.getD().print(8, 6);
			System.out.println(String.format("best_d=%7.5f, rad=%6.3f, elong=%6.3f, dist=%6.3f, dx=%6.3f, dy=%6.3f",
					best_d, eff_rad, elong, dist, cent_offs[0], cent_offs[1]));
		}
		
		return new double [] {best_d, eff_rad, elong, dist, cent_offs[0], cent_offs[1]} ;
	}

	
	public static double [] getMaxLocAreaInt(
			double [] data, // square data
			double [] cent_xy, // if null, use center of the square
			double    radius, // search for maximum within this radius
			double    frac_max) {
		int size = (int) Math.sqrt(data.length);
		if (cent_xy == null) {
			cent_xy = new double [] {size/2, size/2};
		}
		double maxr2 = radius * radius;
		double best_d = 0;
		int best_indx = -1;
		int min_x = Math.max(1, (int) Math.floor(cent_xy[0]-radius));
		int min_y = Math.max(1, (int) Math.floor(cent_xy[1]-radius));
		int max_x = Math.min(size-2, (int) Math.ceil(cent_xy[0]+radius));
		int max_y = Math.min(size-2, (int) Math.ceil(cent_xy[1]+radius));
		for (int y = min_y; y <= max_y; y++) { // do not search on very edges
			double dy = (y-cent_xy[1]);
			double y2 = dy*dy;
			if (y2 < maxr2) {
				for (int x = min_x; x <= max_x; x++) {
					double dx = x - cent_xy[0];
					double r2 = y2 + dx*dx;
					if (r2 < maxr2) {
						int indx = y * size + x;
						double d = data[indx];
						if (d > best_d) {
							best_indx = indx;
							best_d = d;
						}
					}
				}
			}
		}
		// is it local max?
		if     ((data[best_indx - 1] >    best_d) || (data[best_indx + 1] >    best_d) ||
				(data[best_indx - size] > best_d) || (data[best_indx + size] > best_d)) {
			return null; // on the edge, not a local max
		}
		
		boolean [] above_thresh = new boolean [data.length];
		double thresh = best_d * frac_max;
		for (int i = 0; i < data.length; i++) {
			above_thresh[i] = data[i] > thresh;
		}
		
		int [] clusters = (new TileNeibs(size,size)).enumerateClusters(
				above_thresh, // boolean [] tiles,
				null,   // int []     num_clusters,
				false); // boolean ordered)
		int center_cluster = clusters[best_indx];
		double area_max = 0.0;
		for (int i = 0; i < clusters.length; i++) {
			if (clusters[i] == center_cluster) {
				area_max += 1;
			}
		}
		double x_max = best_indx % size - cent_xy[0];
		double y_max = best_indx / size - cent_xy[1];
		double dist = Math.sqrt(y_max * y_max + x_max * x_max);
		return new double [] {best_d, area_max, dist, x_max, y_max} ;
		
		
	}
	
	
	
	
	
	public static double [] getPatternCenter(
	public static double [] getPatternCenter(
			double [] data_in,
			double [] data_in,