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

Detect mines with morning/evenimg pair

parent 2ebcdb9c
...@@ -104,7 +104,7 @@ public class ComboMatch { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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(
......
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;
}
}
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;
}
}
...@@ -10,6 +10,8 @@ import com.elphel.imagej.common.ShowDoubleFloatArrays; ...@@ -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 { ...@@ -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,
......
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