Commit 2a60dccc authored by Andrey Filippov's avatar Andrey Filippov

Next snapshot,

parent 360eb591
......@@ -484,7 +484,7 @@ public class CLTParameters {
// sfm-related parameters
public boolean gsmth_sfm_gnd = true; // use smooth ground for SfM DSI
public boolean gsmth_sfm_deviate = true; // enable SfM deviations from the plain
public double gsmth_sfm_gain = 10.0; // minimal SfM gain to enable deviations from the smooth level
public double gsmth_sfm_gain = 8; // 10.0; // minimal SfM gain to enable deviations from the smooth level
public int gsmth_sfm_rad = 3; // minimal radius (+/-, in tiles) to have sufficient SfM gain (skip margins)
public int gsmth_sfm_lev = 2; // start this radius level smaller if SfM is available (2 - hstep=1, ...)
public double gsmth_str_bump = 0.55; // enable bumps above level stronger than this
......
package com.elphel.imagej.orthomosaic;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Properties;
import java.util.Random;
......@@ -19,12 +21,14 @@ import com.elphel.imagej.gpu.TpTask;
import com.elphel.imagej.ims.Imx5;
import com.elphel.imagej.readers.ElphelTiffReader;
import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.OpticalFlow;
import com.elphel.imagej.tileprocessor.QuadCLT;
import com.elphel.imagej.tileprocessor.TDCorrTile;
import Jama.Matrix;
import ij.ImagePlus;
import ij.ImageStack;
import ij.WindowManager;
import ij.gui.PointRoi;
import ij.process.FloatPolygon;
......@@ -44,6 +48,25 @@ public class ComboMatch {
GPUTileProcessor gpu_tile_processor, // initialized by the caller
int debugLevel) {
GPU_TILE_PROCESSOR = gpu_tile_processor;
PairwiseOrthoMatch pairwiseOrthoMatch = null;
String [] pair_names = new String[2];
ImagePlus imp_sel = WindowManager.getCurrentImage();
String [] gpu_spair = null;
boolean use_marked_image = false; // will be set if found
String [] all_scenes = null;
if (imp_sel != null) {
pair_names = new String[2];
String [][] all_scenes1=new String[1][];
pairwiseOrthoMatch = getPairFromSelectedImage(
imp_sel, // ImagePlus imp,
pair_names, // String [] names)
all_scenes1); // String [][] all_scenes
if (pairwiseOrthoMatch != null) {
gpu_spair = pair_names;
use_marked_image = true;
all_scenes = all_scenes1[0];
}
}
// find -L /media/elphel/SSD3-4GB/lwir16-proc/berdich3/linked/linked_1697875868-1697879449-b/ -type f -name "*-GCORR-GEO.tiff" | sort > GCORR-GEO.list
// String files_list_path = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_03_short.list";
......@@ -67,6 +90,8 @@ public class ComboMatch {
// int [] gpu_ipair = {1,2};
// int [] gpu_ipair = {4,9}; //-> {4,24}
// int [] gpu_ipair = {4,18};
/*
if (gpu_spair == null) {
// String [] gpu_spair = {"1697877420_556997", "1697877527_942766"}; // 1697877564_888405"}; //58, 220
// String [] gpu_spair = {"1697877419_940125", "1697877527_942766"}; // 1697877564_888405"}; //58, 220
// String [] gpu_spair = {"1697877412_004148", "1697877522_274211"}; // 1697877564_888405"}; //58, 220
......@@ -85,8 +110,10 @@ public class ComboMatch {
// String [] gpu_spair = {"1694564270_086631", "1694564822_637346"}; // Morning Sep, 13 50m, 75m
// String [] gpu_spair = {"1694564272_770858", "1694564778_589341"}; // Morning Sep, 13 50m, 75m #13-#63
// String [] gpu_spair = {"1694564275_538447", "1694564744_411290"}; // Morning Sep, 13 50m, 75m #14-#58
String [] gpu_spair = {"1694564270_086631", "1694563011_045597"}; // Morning Sep, 13 50m, 25m #88-#68
//
// gpu_spair = new String[]{"1694564270_086631", "1694563011_045597"}; // Morning Sep, 13 50m, 25m #88-#68
gpu_spair = new String[]{"1694564291_293695","1694564778_589341"}; // Morning Sep, 13 50m, 75m #97, #139
}
*/
double [][][] image_enuatr = {{{0,0,0},{0,0,0}},{{0,0,0},{0,0,0}}};
int gpu_width= clt_parameters.imp.rln_gpu_width; // 3008;
int gpu_height= clt_parameters.imp.rln_gpu_height; // 3008;
......@@ -97,14 +124,25 @@ public class ComboMatch {
boolean use_saved_collection = true; // false;
boolean save_collection = true;
boolean process_correlation = 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 restore_temp = true;
double frac_remove = 0.25;
double frac_remove = 0.15;
double metric_error = 0.05; // 0.02;// 2 cm
if (!use_marked_image) {
process_correlation=false; // use already adjusted by defualt
}
GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,900);
gd.addStringField ("Image list full path", files_list_path, 180, "Image list full path.");
gd.addStringField ("Maps collection save path", orthoMapsCollection_path, 180, "Save path for serialized map collection data.");
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 ("Process correlations", process_correlation, "false to skip to just regenerate new save file.");
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.");
//
// for (int n = 0; n < image_paths_pre.length; n++) {
// gd.addStringField ("Image path "+n, image_paths_pre[n], 180, "Image "+n+" full path w/o ext");
......@@ -129,10 +167,13 @@ public class ComboMatch {
gd.addCheckbox ("Show transformation centers", show_centers, "Mark verticals from the UAS on the ground.");
gd.addCheckbox ("Show combo image map", show_combo_map, "Load and process altitude maps.");
gd.addCheckbox ("Show altitude combo image", use_alt, "Load and process altitude maps.");
gd.addStringField ("First matching timestamp", gpu_spair[0], 20, "First GPU-matching timestamp with '_' for decimal point.");
gd.addStringField ("Second matching timestamp", gpu_spair[1], 20, "First GPU-matching timestamp with '_' for decimal point.");
// gd.addStringField ("First matching timestamp", gpu_spair[0], 20, "First GPU-matching timestamp with '_' for decimal point.");
// gd.addStringField ("Second matching timestamp", gpu_spair[1], 20, "First GPU-matching timestamp with '_' for decimal point.");
gd.addNumericField("Remove fraction of worst matches", frac_remove, 3,7,"", "When fitting scenes remove this fraction of worst match.");
gd.addNumericField("Maximal metric error", metric_error, 3,7,"m", "Maximal tolerable fitting error caused by elevation variations.");
if (use_marked_image ) {
gd.addCheckbox ("Use marked image data", true, "Use markes from the selected image");
}
gd.showDialog();
if (gd.wasCanceled()) return false;
files_list_path = gd.getNextString();
......@@ -141,7 +182,8 @@ public class ComboMatch {
use_saved_collection = gd.getNextBoolean();
save_collection = gd.getNextBoolean();
process_correlation= gd.getNextBoolean();
update_match= gd.getNextBoolean();
render_match= gd.getNextBoolean();
for (int n = 0; n < image_enuatr.length; n++) {
image_enuatr[n][0][0] = gd.getNextNumber();
image_enuatr[n][0][1] = gd.getNextNumber();
......@@ -160,10 +202,13 @@ public class ComboMatch {
show_combo_map = gd.getNextBoolean();
use_alt = gd.getNextBoolean();
gpu_spair[0] = gd.getNextString();
gpu_spair[1] = gd.getNextString();
// gpu_spair[0] = gd.getNextString();
// gpu_spair[1] = gd.getNextString();
frac_remove = gd.getNextNumber();
metric_error= gd.getNextNumber();
if (use_marked_image ) { // will only be used if found and asked
use_marked_image= gd.getNextBoolean();
}
OrthoMapsCollection maps_collection=null;
if (use_saved_collection) {
try {
......@@ -176,6 +221,27 @@ public class ComboMatch {
maps_collection = new OrthoMapsCollection(files_list_path); // should have ".list" extension
}
String [] names = maps_collection.getNames();
if (use_marked_image) {
// verify matching names
//all_scenes
boolean image_ok = false;
wrong_image:{
if (names.length != all_scenes.length) {
break wrong_image;
}
for (int i = 0; i < names.length; i++) {
if (!names[i].equals(all_scenes[i])) {
break wrong_image;
}
}
image_ok = true;
}
if (!image_ok) {
System.out.println("Using wrong image - scenes names do not match!");
return false;
}
maps_collection.ortho_maps[maps_collection.getIndex(gpu_spair[0])].setMatch(gpu_spair[1],pairwiseOrthoMatch);
}
//getTemperature()
// get all temperatures
......@@ -188,7 +254,7 @@ public class ComboMatch {
ImagePlus imp_img = null;
if (show_combo_map) {
imp_img = maps_collection.renderMulti (
"multi_"+zoom_lev, // String title,
"multi_zoom"+zoom_lev, // String title,
false, // boolean use_alt,
show_centers, // boolean show_centers,
zoom_lev, // int zoom_level,
......@@ -198,14 +264,55 @@ public class ComboMatch {
ImagePlus imp_alt = null;
if (use_alt) {
imp_alt =maps_collection.renderMulti (
"multi_alt_"+zoom_lev, // String title,
"multi_alt_zoom"+zoom_lev, // String title,
true, // boolean use_alt,
show_centers, // boolean show_centers,
zoom_lev, // int zoom_level,
origin); // int [] origin){
imp_alt.show();
}
if (process_correlation) {
if (process_correlation || render_match ) {
// int [] gpu_pair;
if (gpu_spair == null) {
ArrayList<Point> pairs_list = new ArrayList<Point>();
for (OrthoMap map : maps_collection.ortho_maps) {
for (String other_name: map.pairwise_matches.keySet()) {
pairs_list.add(new Point(
maps_collection.getIndex(map.getName()),
maps_collection.getIndex(other_name)));
}
}
int [][] available_pairs = new int [pairs_list.size()][2];
for (int i = 0; i < available_pairs.length; i++) {
available_pairs[i][0] = pairs_list.get(i).x;
available_pairs[i][1] = pairs_list.get(i).y;
}
String [] choices = getPairChoices(
available_pairs, // int [][] pairs,
names); // String [] names)
GenericJTabbedDialog gdc = new GenericJTabbedDialog("Select image pair",1200,400);
gdc.addChoice("Operation:", choices, choices[choices.length-1]);
gdc.showDialog();
if (gdc.wasCanceled()) return false;
int pair= gdc.getNextChoiceIndex();
gpu_spair = new String[] {
maps_collection.ortho_maps[available_pairs[pair][0]].getName(),
maps_collection.ortho_maps[available_pairs[pair][1]].getName()};
}
int [] gpu_pair = new int[gpu_spair.length];
for (int i = 0; i < gpu_pair.length; i++) {
gpu_pair[i] = maps_collection.getIndex(gpu_spair[i]);
}
int min_zoom_lev = Math.min(
maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel(),
maps_collection.ortho_maps[gpu_pair[1]].getOriginalZoomLevel());
int max_zoom_lev = Math.max(
maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel(),
maps_collection.ortho_maps[gpu_pair[1]].getOriginalZoomLevel());
int initial_zoom = max_zoom_lev - 3; // another algorithm?
System.out.println("Setting up GPU");
if (GPU_QUAD_AFFINE == null) {
try {
......@@ -222,92 +329,115 @@ public class ComboMatch {
return false;
} // final int debugLevel);
}
double [][] affine0 = {{1,0,0},{0,1,0}}; // will always stay the same
// double [][] affine1 = {
// {1,0,-1.47336},
// {0,1,-3.46664}}; // will be variable // here in meters, relative to vertical point
//1697877414_404948 - 4 (0)
//1697879062_336162 - 9 (1)
// double [][] affine1 = {
// {1.0002226408872814, -0.007965644488589378, -1.512310157498787},
// {0.006494702666097521, 1.0002691922354188, -3.4553628872407023}};
// double [][] affine1 = {{1,0,0},{0,1,0}}; // will always stay the same
// [[1.0001698416441531, 0.0035703780078751575, 1.3965061354976767],
// [0.005158652079706154, 1.0014361052510927, 1.204551528740014]]]
// double [][] affine1 = {{1,0,1.33},
// {0,1,1.227}};
double [][] affine1 = {
{1,0,0},
{0,1,0}};
// affine1[0][2] = 0.64; affine1[1][2] = 1.253; // {"1697877412_004148", "1697877522_274211"}; //
// (346.250-348.000)/12.5,(277.000-269.250)/12.5 = (-0.14, 0.62)
// affine1[0][2] =-0.14; affine1[1][2] = 0.62; // {"1697877409_353265", "1697877518_773045"}; //
// affine1[0][2] =-1.44; affine1[1][2] = 1.653; //"1697877465_672024", "1697877563_587972"
// affine1[0][2] =-0.25; affine1[1][2] = -1.627; //{"1697877465_672024", "1697878995_797332"};
// affine1[0][2] =-1.08; affine1[1][2] = 3.267; //{"1697877465_672024", "1697877528_776377"};
// affine1[0][2] =-1.2; affine1[1][2] = -0.9066; //{"1694564245_111645", "1694564701_230240"};
// affine1[0][2] = 0.933; affine1[1][2] = -2.2667; //{"1694564245_111645", "1694564822_637346"};
// affine1[0][2] = 2.08; affine1[1][2] = -0.093; //{"1694564248_145989", "1694564819_336247"};
// affine1[0][2] =-1.88; affine1[1][2] = -2.71; //{"1694564269_536448", "1694564822_637346"};
// affine1[0][2] =-2.7; affine1[1][2] = -0.59; //{"1694564269_536448", "1694565541_040640"}; 50m-100m
// affine1[0][2] =-0.78; affine1[1][2] = 2.1; //{"1694564822_637346", "1694565541_040640"}; 75m-100m #75-#95
// affine1[0][2] =-0.92; affine1[1][2] = 2.28; //{"1694564263_701171", "1694564816_468625"}; 50m-75m
// affine1[0][2] =-5.37; affine1[1][2] = -1.53; //{"1694564266_568793", "1694564819_336247"}; 50m-75m
// affine1[0][2] = 1.92; affine1[1][2] = -1.89; //{"1694564270_086631", "1694564822_637346"}; 50m-75m
// affine1[0][2] = 0.52; affine1[1][2] = -2.387; //{"1694564272_770858", "1694564778_589341"}; 50m-75m #13-#63
// affine1[0][2] =-4.75; affine1[1][2] = 0.44; //{"1694564275_538447", "1694564744_411290"}; 50m-75m #14-#58
affine1[0][2] = 2.59; affine1[1][2] = 0.133; //{"1694564270_086631", "1694563011_045597"}; 50m, 25m #88-#68
// String [] gpu_spair = {"1694564270_086631", "1694563011_045597"}; // Morning Sep, 13 50m, 25m #88-#68
// "1694564275_538447","1694564744_411290"
double [][][] affines = {affine0,affine1};
int [] gpu_pair = new int[gpu_spair.length];
for (int i = 0; i < gpu_pair.length; i++) {
gpu_pair[i] = maps_collection.getIndex(gpu_spair[i]);
}
int [] zooms = {-2,0,1000,1000};
debugLevel = 0;
boolean batch_mode = false; // true;
boolean ignore_prev_rms = true;
for (int zi = 0; zi < zooms.length; zi++) {
zoom_lev = zooms[zi];
if (zoom_lev >=1000) {
break;
}
// will modify affines[1], later add jtj, weight, smth. else?
double [][] corr_pair_rslt = maps_collection.correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
frac_remove, // double frac_remove, // = 0.25
ignore_prev_rms, // boolean ignore_prev_rms,
batch_mode, // boolean batch_mode,
gpu_pair, // String [] gpu_spair,
affines, // double [][][] affines, // on top of GPS offsets
zoom_lev, // int zoom_lev,
debugLevel); // final int debugLevel)
int render_zoom_lev = Math.min(
maps_collection.ortho_maps[gpu_pair[0]].getOriginalZoomLevel(),
maps_collection.ortho_maps[gpu_pair[1]].getOriginalZoomLevel());
ImagePlus imp_img_pair = maps_collection.renderMulti (
"multi_"+gpu_spair[0]+"-"+gpu_spair[1]+"-zoom_"+render_zoom_lev+"_"+zoom_lev, // String title,
false, // boolean use_alt,
gpu_pair, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
affines, // double [][][] affines, // null or [indices.length][2][3]
show_centers, // boolean show_centers,
render_zoom_lev, // int zoom_level,
origin); // int [] origin){
imp_img_pair.show();
System.out.println("Done");
if (debugLevel>-4) {
System.out.println("adjusted affines[1] for a pair: "+gpu_spair[0]+"/"+gpu_spair[1]);
System.out.println("[["+affines[1][0][0]+","+affines[1][0][1]+","+affines[1][0][2]+"],");
System.out.println(" ["+affines[1][1][0]+","+affines[1][1][1]+","+affines[1][1][2]+"]]");
System.out.println();
}
}
double [][] affine0 = {{1,0,0},{0,1,0}}; // will always stay the same
pairwiseOrthoMatch = maps_collection.ortho_maps[gpu_pair[0]].getMatch(
maps_collection.ortho_maps[gpu_pair[1]].getName());
double [][] affine1 = null;
if (pairwiseOrthoMatch == null) {
System.out.println("No correlation data is available for pairs "+gpu_spair[0]+
" - "+gpu_spair[1]+" need to implement/search reverse, a spiral search or restart command");
System.out.println("after loading a corresponding full map image and marking same feature on");
System.out.println("each of the two selected slices, reference one first");
} else {
affine1 = pairwiseOrthoMatch.getAffine();
double [][][] affines = {affine0,affine1};
int [] zooms = {initial_zoom, min_zoom_lev, 1000,1000}; // make automatic
double scale = 2.0; // scale vectors when warping;
int num_tries = 5;
if (!process_correlation) {
zooms = new int[] {min_zoom_lev, 1000};
num_tries = 0;
update_match = false;
}
debugLevel = 0;
boolean batch_mode = true; // false; // true;
boolean ignore_prev_rms = true;
Rectangle woi = new Rectangle(); // used to return actual woi from correlateOrthoPair()
for (int zi = 0; zi < zooms.length; zi++) {
zoom_lev = zooms[zi];
if (zoom_lev >=1000) {
break;
}
// will modify affines[1], later add jtj, weight, smth. else?
FineXYCorr warp = maps_collection.correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
(process_correlation? pairwiseOrthoMatch: null), //PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
frac_remove, // double frac_remove, // = 0.25
metric_error, // double metric_error,
ignore_prev_rms, // boolean ignore_prev_rms,
num_tries, // = 5int num_tries, // = 5
true, // boolean calc_warp,
batch_mode, // boolean batch_mode,
gpu_pair, // String [] gpu_spair,
affines, // double [][][] affines, // on top of GPS offsets
woi, // Rectangle woi,
zoom_lev, // int zoom_lev,
debugLevel); // final int debugLevel)
//maps_collection.ortho_maps[gpu_pair[1]]
if (process_correlation) {
if (update_match) {
pairwiseOrthoMatch.zoom_lev = zoom_lev;
pairwiseOrthoMatch.affine = affines[1];
maps_collection.ortho_maps[gpu_pair[0]].setMatch(
maps_collection.ortho_maps[gpu_pair[1]].getName(),
pairwiseOrthoMatch);
if (debugLevel > -4) {
System.out.println("Updated correleation data in the database");
}
} else {
if (debugLevel > -4) {
System.out.println("Updating correlation data is DISABLED");
}
}
System.out.println("Done");
if (debugLevel>-4) {
System.out.println("adjusted affines[1] for a pair: "+gpu_spair[0]+"/"+gpu_spair[1]);
System.out.println("[["+affines[1][0][0]+","+affines[1][0][1]+","+affines[1][0][2]+"],");
System.out.println(" ["+affines[1][1][0]+","+affines[1][1][1]+","+affines[1][1][2]+"]]");
System.out.println();
}
}
if (render_match) {
ImagePlus imp_img_pair = maps_collection.renderMulti (
"multi_"+gpu_spair[0]+"-"+gpu_spair[1]+"-zoom_"+min_zoom_lev+"_"+zoom_lev, // String title,
false, // boolean use_alt,
gpu_pair, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
affines, // double [][][] affines, // null or [indices.length][2][3]
warp, // FineXYCorr warp,
show_centers, // boolean show_centers,
min_zoom_lev, // int zoom_level,
origin); // int [] origin){
imp_img_pair.show();
/*
int gpu_tilesX = gpu_width/GPUTileProcessor.DTT_SIZE;
Rectangle tile_woi = OrthoMapsCollection.scaleRectangle (woi, GPUTileProcessor.DTT_SIZE);
double [][] vector_field_interpolated = interpolateVectorField(
vector_field, // final double [][] vector_field, // sparse {vx,vy,strength}
gpu_tilesX, // final int gpu_tilesX, // 512
tile_woi, // final Rectangle tile_woi, // only width, height are used top-left corners are the same
scale, // final double scale,
1); // final int debugLevel);
ImagePlus imp_img_pair = maps_collection.renderMulti (
"multi_"+gpu_spair[0]+"-"+gpu_spair[1]+"-zoom_"+min_zoom_lev+"_"+zoom_lev, // String title,
false, // boolean use_alt,
gpu_pair, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
affines, // double [][][] affines, // null or [indices.length][2][3]
show_centers, // boolean show_centers,
min_zoom_lev, // int zoom_level,
origin); // int [] origin){
imp_img_pair.show();
*/
}
}
}
}
if (save_collection) {
try {
......@@ -317,11 +447,37 @@ public class ComboMatch {
e.printStackTrace();
}
}
if (debugLevel <1000) {
return true;
}
return true;
}
/*
double [][] affine1 = {
{1,0,0},
{0,1,0}};
// affine1[0][2] = 0.64; affine1[1][2] = 1.253; // {"1697877412_004148", "1697877522_274211"}; //
// (346.250-348.000)/12.5,(277.000-269.250)/12.5 = (-0.14, 0.62)
// affine1[0][2] =-0.14; affine1[1][2] = 0.62; // {"1697877409_353265", "1697877518_773045"}; //
// affine1[0][2] =-1.44; affine1[1][2] = 1.653; //"1697877465_672024", "1697877563_587972"
// affine1[0][2] =-0.25; affine1[1][2] = -1.627; //{"1697877465_672024", "1697878995_797332"};
// affine1[0][2] =-1.08; affine1[1][2] = 3.267; //{"1697877465_672024", "1697877528_776377"};
// affine1[0][2] =-1.2; affine1[1][2] = -0.9066; //{"1694564245_111645", "1694564701_230240"};
// affine1[0][2] = 0.933; affine1[1][2] = -2.2667; //{"1694564245_111645", "1694564822_637346"};
// affine1[0][2] = 2.08; affine1[1][2] = -0.093; //{"1694564248_145989", "1694564819_336247"};
// affine1[0][2] =-1.88; affine1[1][2] = -2.71; //{"1694564269_536448", "1694564822_637346"};
// affine1[0][2] =-2.7; affine1[1][2] = -0.59; //{"1694564269_536448", "1694565541_040640"}; 50m-100m
// affine1[0][2] =-0.78; affine1[1][2] = 2.1; //{"1694564822_637346", "1694565541_040640"}; 75m-100m #75-#95
// affine1[0][2] =-0.92; affine1[1][2] = 2.28; //{"1694564263_701171", "1694564816_468625"}; 50m-75m
// affine1[0][2] =-5.37; affine1[1][2] = -1.53; //{"1694564266_568793", "1694564819_336247"}; 50m-75m
// affine1[0][2] = 1.92; affine1[1][2] = -1.89; //{"1694564270_086631", "1694564822_637346"}; 50m-75m
// affine1[0][2] = 0.52; affine1[1][2] = -2.387; //{"1694564272_770858", "1694564778_589341"}; 50m-75m #13-#63
// affine1[0][2] =-4.75; affine1[1][2] = 0.44; //{"1694564275_538447", "1694564744_411290"}; 50m-75m #14-#58
affine1[0][2] = 2.59; affine1[1][2] = 0.133; //{"1694564270_086631", "1694563011_045597"}; 50m, 25m #88-#68
// String [] gpu_spair = {"1694564270_086631", "1694563011_045597"}; // Morning Sep, 13 50m, 25m #88-#68
//"1694564275_538447","1694564744_411290"
*/
/*
adjusted affines[1] for a pair: 1697877465_672024/1697877563_587972 RMS= 0.14511264718699468 (0.14577676900752629)
[[1.0065661054211072,0.009234141675959222,-1.4706666954418992],
......@@ -366,204 +522,163 @@ adjusted affines[1] for a pair: 1694564275_538447/1694564744_411290
[[1.016644878296508,0.004929435606711805,-4.693221236458512],
[-0.0049692732545438024,1.0068633692157516,0.3968458715663825]]
*
*
double [] offset_xy_second = {0,0};
double [][] corr_pair_rslt = maps_collection. correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
gpu_spair[0], // String first_name,
gpu_spair[1], // String second_name,
zoom_lev, // int zoom_lev,
offset_xy_second, //double [] offset_xy_second, // on top of affine and GPS
debugLevel); // final int debugLevel)
float [][] gpu_pair_img = maps_collection.getPaddedPairGPU(
gpu_spair, // String [] spair,
zoom_lev); // int zoom_lev);
ShowDoubleFloatArrays.showArrays(
gpu_pair_img,
gpu_width,
gpu_height,
true,
"gpu_pair-zoom"+zoom_lev+"-"+gpu_spair[0]+"-"+gpu_spair[1],
gpu_spair);
*/
/* */
OrthoMap [] ortho_maps = maps_collection.getMaps(); // just temporarily
adjusted affines[1] for a pair: 1694564291_293695/1694564778_589341
[[1.0192476964620238,0.028926271825940476,4.945477523680564],
[-0.03767671444357569,1.0214533434667925,-1.4730239331163375]]
int [] widths = new int[imp_src.length];
int [] heights = new int[imp_src.length];
for (int n = 0; n < imp_src.length; n++) {
// imp_src[n] = new ImagePlus(image_paths_pre[n]+".tiff"); // may use +"-ALT.tiff"
widths[n] = imp_src[n].getWidth();
heights[n] = imp_src[n].getHeight();
}
//imp_prop
double [][] llas = new double [imp_src.length][];
LocalDateTime [] dts = new LocalDateTime[2];
double [][] xy_pix_centers = new double [2][];
double [] pix_sizes = new double[2]; // ElphelTiffReader.getPixelSize(imp_prop[0])[0];
for (int n = 0; n < imp_src.length; n++) {
/*
try {
// imp_prop[n] = ElphelTiffReader.getTiffMeta(image_paths_pre[n]+".tiff");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
llas[n] = ElphelTiffReader.getLLA(imp_prop[n]);
dts[n] = ElphelTiffReader.getLocalDateTime(imp_prop[n]);
xy_pix_centers[n] = ElphelTiffReader.getXYOffsetPixels(imp_prop[n]);
pix_sizes[n] = ElphelTiffReader.getPixelSize(imp_prop[n])[0];
}
/* */
if (show_centers) {
for (int n = 0; n < ortho_maps.length; n++) {
ortho_maps[n].getOriginalImage(true);
}
*/
public static double [][] interpolateVectorField(
final double [][] vector_field, // sparse {vx,vy,strength}
final int gpu_tilesX, // 512
final Rectangle tile_woi, // only width, height are used top-left corners are the same
final double scale,
final int debugLevel) {
// final Rectangle tile_woi = OrthoMapsCollection.scaleRectangle (woi, GPUTileProcessor.DTT_SIZE);
final int tiles = tile_woi.width*tile_woi.height;
final double [][] vf = new double[2][tile_woi.width*tile_woi.height];
for (int i = 0; i < vf.length; i++) {
Arrays.fill(vf[i], Double.NaN);
}
/*
for (int n = 0; n < imp_src.length; n++) {
imp_src[n].show();
final Thread[] threads = ImageDtt.newThreadArray();
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 < tiles; ipix = ai.getAndIncrement()) {
int y = ipix / tile_woi.width;
int x = ipix % tile_woi.width;
double [] v = vector_field[y*gpu_tilesX+x];
if (v != null) {
for (int i = 0; i < vf.length; i++) {
vf[i][ipix] = scale*v[i];
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
// now fill NaNs in each of vf[0], vf[1]
double [][] vf_filled = new double[vf.length][];
int num_passes = 100;
double max_diff = 1E-4;
for (int i = 0; i < vf.length; i++) {
vf_filled[i] = OpticalFlow.fillGapsDouble(
vf[i], // double [] data,
null, // boolean [] mask_in, // do not process if false (may be null)
tile_woi.width, // int width,
0, // int max_grow,
num_passes, // int num_passes,
max_diff, // double max_diff,
ImageDtt.THREADS_MAX, // int threadsMax,
debugLevel); // int debug_level)
}
if (debugLevel > 0) {
String [] dbg_titles = {"x-raw","x_filled","y-raw","y_filled"};
double [][] dbg_img = {vf[0], vf_filled[0],vf[1], vf_filled[1]};
ShowDoubleFloatArrays.showArrays(
dbg_img,
tile_woi.width,
dbg_img[0].length / tile_woi.width,
true,
"vector_field_filled",
dbg_titles);
}
*/
if (ortho_maps[0].orig_zoom_level != ortho_maps[1].orig_zoom_level) {
System.out.println("openTestPairGps() does not yet handle different scales, aborting");
return false;
}
double [] enu_diff = ortho_maps[0].enuOffsetTo(ortho_maps[0]);
double pix_size1 = ElphelTiffReader.getPixelSize(imp_prop[0])[0];
double [] pix_shift = {enu_diff[0]/pix_size1, -enu_diff[1]/pix_size1}; // E->X, N->-Y
int [] ipix_shift=new int[2];
for (int n = 0; n < 2; n++) {
ipix_shift[n] = (int) Math.round(pix_shift[n]);
}
System.out.println(String.format("Interscene pixel shift = [%9.3f, %9.3f]",pix_shift[0],pix_shift[1]));
int xmin=Math.min(0, ipix_shift[0]);
int xmax=Math.max(widths[0], widths[1]+ipix_shift[0]);
int ymin=Math.min(0, ipix_shift[1]);
int ymax=Math.max(heights[0], heights[1]+ipix_shift[1]);
int width = xmax-xmin;
int height = ymax-ymin;
int [] x0 = new int [2];
int [] y0 = new int [2];
if (ipix_shift[0] > 0) x0[1] = ipix_shift[0];
else x0[0] = -ipix_shift[0];
if (ipix_shift[1] > 0) y0[1] = ipix_shift[1];
else y0[0] = -ipix_shift[1];
float [][] spix = new float[2][];
for (int n = 0; n < 2; n++) {
spix[n] = (float []) imp_src[n].getProcessor().getPixels();
}
if (zoom_lev < 0) {
}
float [][] opix = new float[2][width*height];
for (int n = 0; n < 2; n++) {
Arrays.fill(opix[n], Float.NaN);
for (int line = 0; line < heights[n]; line++) {
System.arraycopy(
spix[n],
line * widths[n],
opix[n],
(line + y0[n])*width+ x0[n],
widths[n]);
}
}
ShowDoubleFloatArrays.showArrays(
opix,
width,
height,
true,
"overlap_pair");
float [][] gpu_pix = new float[2][];
double zoom_scale = 1.0;
boolean fill_with_rand=false;
double rnd_scale = 50;
return vf_filled;
}
public static PairwiseOrthoMatch getPairFromSelectedImage(
ImagePlus imp,
String [] names,
String [][] all_scenes) { // to verify the same scenes as expected
// get zoom from the name and list of the slice names prefixes (before second "_"
String title = imp.getTitle();
String[] tokens = title.replace(".","_").split("_");
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].startsWith("zoom")) {
int zoom_level = Integer.parseInt(tokens[i].substring(4));
System.out.println("zoom level = "+zoom_level);
double pix_size = OrthoMap.getPixelSizeMeters (zoom_level); // meters
ImageStack stack_scenes = imp.getStack();
int nSlices = stack_scenes.getSize();
String [] scene_names = new String [nSlices];
for (int n = 0; n < scene_names.length; n++) {
scene_names[n] = stack_scenes.getSliceLabel(n+1).substring(0,17);
}
if (all_scenes != null) {
all_scenes[0] = scene_names;
}
PointRoi pRoi = (PointRoi) imp.getRoi();
FloatPolygon fp = pRoi.getContainedFloatPoints();
// Use only 2 last markers
if (fp == null) {
System.out.println("getPairFromSelectedImage(): no markers found");
return null;
}
if (fp.npoints < 2) {
System.out.println("getPairFromSelectedImage(): need at least2 markers");
return null;
}
int pair = 0;
if (fp.npoints > 2) { // select pair
int [][] pairs = new int [fp.npoints/2][2];
for (int j = 0; j < pairs.length; j++) {
for (int k = 0; k < 2; k++) {
pairs[j][k] = pRoi.getPointPosition(2*j+k);
}
}
String [] choices = getPairChoices(
pairs, // int [][] pairs,
scene_names); // String [] names)
if (zoom_lev <= 0) {
zoom_scale /= (1 << -zoom_lev);
if ((gpu_width <= 0) || (gpu_height <= 0)) {
gpu_width = Math.max(widths[0], widths[1]);
gpu_height = Math.max(heights[0], heights[1]);
gpu_width >>= -zoom_lev;
gpu_height >>= -zoom_lev;
gpu_width = 16*((gpu_width + 15)/16);
gpu_height = 16*((gpu_height + 15)/16);
GenericJTabbedDialog gds = new GenericJTabbedDialog("Select image pair",1200,400);
gds.addChoice("Operation:", choices, choices[choices.length-1]);
gds.showDialog();
if (gds.wasCanceled()) return null;
pair= gds.getNextChoiceIndex();
}
double [][] points_xy= new double [2][2];
int [] pair_slices = new int[2];
for (int n = 0; n < points_xy.length; n++) {
int p = 2 * pair + n; // fp.npoints-2+n;
points_xy[n][0] = fp.xpoints[p];
points_xy[n][1] = fp.ypoints[p];
pair_slices[n] = pRoi.getPointPosition(p); // works
}
PairwiseOrthoMatch match= new PairwiseOrthoMatch();
match.affine = new double[][] {
{1,0,(points_xy[1][0]-points_xy[0][0])*pix_size},
{0,1,(points_xy[1][1]-points_xy[0][1])*pix_size}};
for (int n = 0; n < points_xy.length; n++) {
names[n] = stack_scenes.getSliceLabel(pair_slices[n]).substring(0,17);
}
System.out.println("names = [\""+names[0]+"\", \""+names[1]+"\"]");
System.out.println("match.affine = [["+match.affine[0][0]+", "+match.affine[0][1]+", "+match.affine[0][2]+"],");
System.out.println(" ["+match.affine[1][0]+", "+match.affine[1][1]+", "+match.affine[1][2]+"]]");
return match;
}
for (int n = 0; n < 2; n++) {
gpu_pix[n] = padScaleImage(
spix[n],
widths[n],
-zoom_lev, // int zoomout,
gpu_width, // int width,
gpu_height); // int height)
}
if (fill_with_rand && (rnd_scale > 0)) {
fillRandomFloatNans(
gpu_pix, // float [][] pixels,
rnd_scale); // double scale)
}
ShowDoubleFloatArrays.showArrays(
gpu_pix,
gpu_width,
gpu_height,
true,
"gpu_pair");
}
System.out.println("Setting up GPU");
if (GPU_QUAD_AFFINE == null) {
try {
GPU_QUAD_AFFINE = new GpuQuad(//
GPU_TILE_PROCESSOR, // GPUTileProcessor gpuTileProcessor,
// null, // QUAD_CLT_AUX,
gpu_max_width, // final int max_width,
gpu_max_height, // final int max_height,
1, // final int num_colors, // normally 1?
clt_parameters.gpu_debug_level);
} catch (Exception e) {
System.out.println("Failed to initialize GpuQuad class");
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} // final int debugLevel);
return null;
}
public static String [] getPairChoices(
int [][] pairs,
String [] names) {
String [] choices = new String[pairs.length];
for (int i =0; i < choices.length; i++) {
choices[i] = String.format("%3d -> %3d (%s -> %s)", pairs[i][0],pairs[i][1],names[pairs[i][0]], names[pairs[i][1]]);
}
//add offsets
final double [][][] affine = {{{1,0,0},{0,1,0}},{{1,0,0},{0,1,0}}};
affine[0][0][2] = 0.5*pix_shift[0]*zoom_scale;
affine[0][1][2] = 0.5*pix_shift[1]*zoom_scale;
affine[1][0][2] = -0.5*pix_shift[0]*zoom_scale;
affine[1][1][2] = -0.5*pix_shift[1]*zoom_scale;
// TDCorrTile [] td_corr_tiles =
rectilinearVectorField( // rectilinearCorrelate_TD( // scene0/scene1
clt_parameters, // final CLTParameters clt_parameters,
gpu_pix, // final float [][] fpixels, // to check for empty
gpu_width, // final int img_width,
null, // Rectangle woi, // if null, use full GPU window
affine, // final double [][][] affine, // [2][2][3] affine coefficients to translate common to 2 images
null, // TpTask [][] tp_tasks_o,
false, // final boolean batch_mode,
debugLevel); // final int debugLevel);
// renderFromTD (
// true, // boolean use_reference,
// "aaa"); //String suffix
return true;
return choices;
}
/*
public static TDCorrTile [] rectilinearCorrelate_TD( // scene0/scene1
final CLTParameters clt_parameters,
......@@ -584,6 +699,7 @@ adjusted affines[1] for a pair: 1694564275_538447/1694564744_411290
final double [][][] affine, // [2][2][3] affine coefficients to translate common to 2 images
TpTask [][] tp_tasks_o,
final boolean batch_mode,
final String dbg_suffix, // for image_names
final int debugLevel) {
int [] wh = {img_width, fpixels[0].length/img_width};
TpTask [][] tp_tasks = GpuQuad.setRectilinearInterTasks(
......@@ -622,10 +738,10 @@ adjusted affines[1] for a pair: 1694564275_538447/1694564744_411290
batch_mode? -3: debugLevel); // final int globalDebugLevel)
int tilesX = img_width/GPUTileProcessor.DTT_SIZE;
int tilesY = wh[1]/GPUTileProcessor.DTT_SIZE;
if (!batch_mode && (debugLevel > 1)) {
if (!batch_mode && (dbg_suffix != null)) {
renderFromTD (
true, // boolean use_reference,
"ref"); //String suffix
"ref"+dbg_suffix); //String suffix
}
float [][][][] fcorr_td = new float [tilesY][tilesX][][];
//null; // no accumulation, use data in GPU
......@@ -651,6 +767,11 @@ adjusted affines[1] for a pair: 1694564275_538447/1694564744_411290
clt_parameters.corr_blue, // final double corr_blue,// +used
-1, // final int sensor_mask_inter, // The bitmask - which sensors to correlate, -1 - all.
debugLevel); // final int globalDebugLevel)
if (!batch_mode && (dbg_suffix != null)) {
ComboMatch.renderFromTD (
false, // boolean use_reference,
"img"+dbg_suffix); //String suffix
}
//~ coord_motion = image_dtt.clt_process_tl_interscene( // convert to pixel domain and process correlations already prepared in fcorr_td and/or fcorr_combo_td
// simplified version?
// get TD interscene correlation of 2 scenes, use only combo (all channels) data
......
package com.elphel.imagej.orthomosaic;
import java.awt.Rectangle;
import com.elphel.imagej.gpu.GPUTileProcessor;
public class FineXYCorr {
public double [] top_left_metric; // relative to the reference image vertical point, normally negative
public int width_tiles;
public int height_tiles;
public double warp_pix_size;
public double warp_tile_size;
public double render_div_tile;
public double pix_div_render;
public double [] render_origin = new double[2]; // vertical point of the first image in render pixels
public double [][] warp_xy; // [width_tiles*height_tiles][2], values in pixel shift, data on tiles grid
public Rectangle render_woi;
public double render_pix_size; // in meters
public double [] render_tl; // top left corner in render pixels for the top-left corner of the warp array
public FineXYCorr (
int zoom_lev,
int width,
double [] tl_metric,// relative to the reference image vertical point, normally negative
double [][] vf) { // [tiles][2], may have nulls
warp_pix_size = OrthoMap.getPixelSizeMeters (zoom_lev); // meters
warp_tile_size = warp_pix_size * GPUTileProcessor.DTT_SIZE;
width_tiles = width;
height_tiles = vf.length/width_tiles;
top_left_metric = tl_metric;
warp_xy = vf;
}
public void setRender(int zoom_lev,
double px0, // in render pixels
double py0) {
render_pix_size = OrthoMap.getPixelSizeMeters (zoom_lev); // meters
render_origin = new double [] {px0,py0};
render_tl = new double[]{
render_origin[0] + top_left_metric[0] / render_pix_size,
render_origin[1] + top_left_metric[1] / render_pix_size};
render_div_tile = render_pix_size/warp_tile_size;
pix_div_render = warp_pix_size/render_pix_size;
}
/**
* Return rectangular area where this instance's warp changes
* rendering of the (second image). Use to optimize accesses to getCorrectedXY
* @return Rectangle that contains all the render pixels that may be warped
*/
public Rectangle getRenderWOI (){
int x0 = (int) Math.floor(render_tl[0]);
int y0 = (int) Math.floor(render_tl[1]);
int x1 = (int) Math.ceil(render_tl[0] + warp_tile_size*(width_tiles-1)/render_pix_size);
int y1 = (int) Math.ceil(render_tl[1] + warp_tile_size*((warp_xy.length/width_tiles)-1)/render_pix_size);
return new Rectangle(x0,y0,x1-x0+1, y1-y0+1);
}
/**
* Apply warping to the x,y pair
* @param xy {X,Y} before and after warping
*/
public void warpXY(// in render pixels
double [] xy) { // no interpolation - using nearest
int ix = (int) Math.round((xy[0] - render_tl[0]) * render_div_tile);
int iy = (int) Math.round((xy[1] - render_tl[1]) * render_div_tile);
if ((ix >= 0) && (ix < width_tiles) && (iy >= 0) && (iy < height_tiles)){
double [] dxdy = warp_xy[ix + width_tiles * iy];
if (dxdy != null) {
xy[0] -= dxdy[0]*pix_div_render;
xy[1] -= dxdy[1]*pix_div_render;
}
}
}
public double [] getWarp(
double x,
double y) {
int ix = (int) Math.round((x - render_tl[0]) * render_div_tile);
int iy = (int) Math.round((y- render_tl[1]) * render_div_tile);
if ((ix >= 0) && (ix < width_tiles) && (iy >= 0) && (iy < height_tiles)){
double [] dxdy = warp_xy[ix + width_tiles * iy];
if (dxdy != null) {
return new double [] {
dxdy[0]*pix_div_render,
dxdy[1]*pix_div_render};
}
}
return new double [2];
}
}
......@@ -32,6 +32,7 @@ import com.elphel.imagej.readers.ImagejJp4Tiff;
import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.IntersceneMatchParameters;
import com.elphel.imagej.tileprocessor.QuadCLT;
import com.elphel.imagej.tileprocessor.TileNeibs;
import Jama.Matrix;
import ij.ImagePlus;
......@@ -40,6 +41,7 @@ import ij.Prefs;
import ij.gui.PointRoi;
import ij.plugin.filter.AVI_Writer;
import ij.plugin.filter.GaussianBlur;
import ij.process.ColorProcessor;
import ij.process.FloatProcessor;
import ij.process.ImageConverter;
import ij.process.ImageProcessor;
......@@ -76,8 +78,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
public double averageRawPixel = Double.NaN; // measure of scene temperature
public transient double averageImagePixel = Double.NaN; // average image pixel value (to combine with raw)
transient HashMap <Integer, FloatImageData> images;
HashMap <Double, PairwiseOrthoMatch> pairwise_matches;
HashMap <String, PairwiseOrthoMatch> pairwise_matches;
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
......@@ -140,6 +141,15 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
return orig_height;
}
public void setMatch(
String name,
PairwiseOrthoMatch match) {
pairwise_matches.put(name, match);
}
public PairwiseOrthoMatch getMatch(String name) {
return pairwise_matches.get(name);
}
public int getOriginalZoomLevel() {
return orig_zoom_level;
}
......@@ -240,7 +250,7 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
orig_zoom_valid = FloatImageData.isZoomValid(orig_pix_meters);
need_extra_zoom = FloatImageData.needZoomIn(orig_pix_meters);
images = new HashMap <Integer, FloatImageData>();
pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>();
pairwise_matches = new HashMap<String, PairwiseOrthoMatch>();
averageRawPixel = Double.NaN; // measure of scene temperature
averageImagePixel = Double.NaN; // average image pixel value (to combine with raw)
}
......@@ -420,9 +430,12 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
* @return double [4][2] array [corner number]{x,y}
*/
public double [][] get4SourceCornersMeters(){
FloatImageData orig_image = getImageData();
double width_meters = getWidth() * orig_pix_meters;
double height_meters = getHeight() * orig_pix_meters;
// FloatImageData orig_image = getImageData();
if ((orig_width <=0) || (orig_height <=0)) {
getImageData();
}
double width_meters = orig_width * orig_pix_meters;
double height_meters = orig_height * orig_pix_meters;
return new double[][] { // CW from TL
{ - vert_meters[0], - vert_meters[1]},
{width_meters - vert_meters[0], - vert_meters[1]},
......@@ -673,13 +686,13 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
int ipy = (int) Math.floor(py);
double fpx = px -ipx;
double fpy = py -ipy;
if ((ipx >= 0) && (ipy >= 0) && (ipx < src_width) && (ipy < src_height)) {
if ((ipx >= 0) && (ipy >= 0) && (ipx < (src_width-1)) && (ipy < (src_height-1))) {
int indx00 = ipy*src_width+ipx;
int indx = task.getTileY()*tilesX + task.getTileX();
elev[indx] =
(1.0-fpx)*(1.0-fpy)*felev[indx00] +
( fpx)*(1.0-fpy)*felev[indx00 + 1] +
(1.0-fpx)*( fpy)*felev[indx00 + src_width] +
(1.0-fpx)*( fpy)*felev[indx00 + src_width] + // throwing
( fpx)*( fpy)*felev[indx00 + src_width + 1];
}
}
......@@ -770,6 +783,11 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
int video_crf = 10; // lower - better, larger file size
boolean remove_avi = true;
int debugLevel = 0;
int num_slices = imp.getImageStack().getSize();
int first_slice = 1;
int last_slice = num_slices;
boolean create_image = false; // instead of video
int border_width = 3;
GenericJTabbedDialog gd = new GenericJTabbedDialog("Parameters for video from orthographic imges",1200,800);
gd.addStringField ("Output video path prefix", path_prefix, 180,
"Absolute path prefix for the video (image title will be added).");
......@@ -797,6 +815,12 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
gd.addNumericField("WEBM CRF", video_crf, 0, 4, "", "WEBM compression quality (lower - better, 10 - good).");
gd.addCheckbox ("Remove AVI", remove_avi, "Remove AVI (large file) after WEBM generation.");
gd.addNumericField("Debug level", debugLevel, 0, 4, "", "Debug level (not yet used).");
gd.addMessage("--- parameters for single image generation ---");
gd.addCheckbox ("Create image instead of video", create_image, "Create image instead of video.");
gd.addNumericField("First slice", first_slice, 0, 4, "", "First slice number (starts with 1)");
gd.addNumericField("Last slice", last_slice, 0, 4, "", "Last slice to combine.");
gd.addNumericField("Border width", border_width, 0, 4, "pix", "Uses \"Annotation color\".");
gd.showDialog();
if (gd.wasCanceled()) return;
path_prefix = gd.getNextString();
......@@ -829,7 +853,14 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
video_crf = (int) gd.getNextNumber();
remove_avi = gd.getNextBoolean();
debugLevel = (int) gd.getNextNumber();
create_image=gd.getNextBoolean();
first_slice = (int) gd.getNextNumber();
last_slice = (int) gd.getNextNumber();
border_width = (int) gd.getNextNumber();
if (create_image) {
keep_original = false; // not used
}
ImagePlus imp_um;
if (um_apply) {
imp_um = applyUnsharpMask(
......@@ -841,6 +872,20 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
imp_um = keep_original? imp.duplicate():imp;
}
System.out.println("applyUnsharpMask() DONE!");
if (create_image) {
ImagePlus imp_rgb_single = convertToColorAndCombine(
imp_um, // ImagePlus imp_src,
first_slice, // int first_slice,
last_slice, // int last_slice,
border_width, // int border_width,
mono_range, // double mono_range, // >0 - apply
annotate_color, // Color border_color,
debugLevel); // int debugLevel);
imp_rgb_single.show();
System.out.println("convertToColorAndCombine() DONE!");
return;
}
ImagePlus imp_rgb = convertToColorAnnotate(
imp_um, // ImagePlus imp_src,
false, // boolean keep_original,
......@@ -967,6 +1012,56 @@ public class OrthoMap implements Comparable <OrthoMap>, Serializable{
return imp;
}
public static ImagePlus convertToColorAndCombine(
ImagePlus imp_src,
int first_slice,
int last_slice,
int border_width,
double mono_range, // >0 - apply
Color border_color,
int debugLevel) {
int width = imp_src.getWidth();
int height = imp_src.getHeight();
int [] pixels = new int [width* height];
ImageStack stack = imp_src.getStack();
boolean [] mask = new boolean[pixels.length];
final TileNeibs tnSurface = new TileNeibs(width, height);
for (int nslice = first_slice; nslice <= last_slice; nslice++) {
float [] fpixels = (float[]) stack.getPixels(nslice);
Arrays.fill(mask, false);
for (int i = 0; i <fpixels.length; i++) if (!Float.isNaN(fpixels[i])) {
mask[i]= true;
int v255 = (int) Math.round(255*(fpixels[i] + mono_range/2)/mono_range);
if (v255 < 0) v255= 0;
else if (v255 > 255) {
v255 = 255;
}
pixels[i] = v255 * 0x10101;
}
if (border_width > 0) {
tnSurface.growSelection(
border_width, // grow,
mask, // tiles,
null); // prohibit);
int border_RGB = border_color.getRGB();
for (int i = 0; i <fpixels.length; i++) if (Float.isNaN(fpixels[i]) && mask[i]) {
pixels[i]=border_RGB;
}
}
if (debugLevel >=0) {
System.out.println("Slice "+nslice+" is done. Last is "+last_slice);
}
}
ColorProcessor cp=new ColorProcessor(width,height);
cp.setPixels(pixels);
ImagePlus imp_combo=new ImagePlus(
removeKnownExtension(imp_src.getTitle())+"-collage_"+first_slice+"-"+last_slice,cp);
return imp_combo;
}
public static String removeKnownExtension(String path) {
String [] remove_ext = {".tiff", ".tif", ".avi"};
for (String ext:remove_ext) {
......
......@@ -23,6 +23,7 @@ import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.gpu.GPUTileProcessor;
import com.elphel.imagej.gpu.TpTask;
import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.OpticalFlow;
import com.elphel.imagej.tileprocessor.TDCorrTile;
import ij.ImagePlus;
......@@ -53,7 +54,7 @@ public class OrthoMapsCollection implements Serializable{
String path) {
if (path.endsWith(".list")) {
String[] scenes0 = new String[1];
String[] paths = getPathsAndScenesFromSorceList(path, scenes0);
String[] paths = getPathsAndScenesFromSourceList(path, scenes0);
String scenes_path = scenes0[0];
double [][] affine = {{1,0,0},{0,1,0}}; // maybe later calculate from mage_enuatr
ortho_maps = new OrthoMap[paths.length];
......@@ -122,10 +123,10 @@ public class OrthoMapsCollection implements Serializable{
public static String[] getPathsFromSorceList(
String files_list) {
return getPathsAndScenesFromSorceList(files_list, null);
return getPathsAndScenesFromSourceList(files_list, null);
}
public static String[] getPathsAndScenesFromSorceList(
public static String[] getPathsAndScenesFromSourceList(
String files_list,
String[] scenes0) {
List<String> lines;
......@@ -263,7 +264,8 @@ public class OrthoMapsCollection implements Serializable{
title, // String title,
use_alt, //boolean use_alt,
null, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
null, // double [][][] affines, // null or [indices.length][2][3]
null, // double [][][] affines, // null or [indices.length][2][3]
null, // FineXYCorr warp,
show_centers, // boolean show_centers,
zoom_level, // int zoom_level,
origin); // int [] origin)
......@@ -274,6 +276,7 @@ public class OrthoMapsCollection implements Serializable{
boolean use_alt,
int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
double [][][] affines, // null or [indices.length][2][3]
FineXYCorr warp, // use for a single pair only
boolean show_centers,
int zoom_level,
int [] origin){
......@@ -282,11 +285,12 @@ public class OrthoMapsCollection implements Serializable{
float [][] multi = renderMulti (
use_alt, // boolean use_alt,
indices, // int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
affines, // double [][][] affines, // null or [indices.length][2][3]
affines, // double [][][] affines, // null or [indices.length][2][3]
warp, // FineXYCorr warp,,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
int num_images = (indices != null)? indices.length : ortho_maps.length;
// String [] map_names = new String[(indices != null) ? indices.length : ortho_maps.length];
String [] map_names = new String[num_images + ((num_images==2)? 1 : 0)];
......@@ -355,22 +359,25 @@ public class OrthoMapsCollection implements Serializable{
int [] origin, // maps[0] as a reference
double [][] centers){
return renderMulti (
use_alt, // boolean use_alt,
null, // int [] indices,
use_alt, // boolean use_alt,
null, // int [] indices,
null, // double [][][] affines,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin, // maps[0] as a reference
centers); // double [][] centers)
null, // FineXYCorr warp,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin, // maps[0] as a reference
centers); // double [][] centers)
}
public float [][] renderMulti (
boolean use_alt,
int [] indices, // null or which indices to use (normally just 2 for pairwise comparison)
double [][][] affines, // null or [indices.length][2][3]
FineXYCorr warp,
int zoom_level,
int [] wh,
int [] origin, // maps[0] as a reference
double [][] centers){
final int dbg_x=2783, dbg_y=-5228;
int [][] bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
zoom_level);
int width = bounds[0][1] - bounds[0][0]; // bounds[x][0] - negative
......@@ -428,6 +435,13 @@ public class OrthoMapsCollection implements Serializable{
final int src_width = use_alt? ortho_maps[nmap].getAltData().width: ortho_maps[nmap].getImageData().width;
final int src_height = use_alt? ortho_maps[nmap].getAltData().height : ortho_maps[nmap].getImageData().height;
final float [] src_img = use_alt? ortho_maps[nmap].getAltData().data : ortho_maps[nmap].getImageData().data;
if ((indx==0) && (warp != null)) { // set center from the first image
warp.setRender(
zoom_level, // int zoom_lev,
scaled_out_center[0], // double px0, // in render pixels
scaled_out_center[1]); // // double py0);
}
final Rectangle warp_woi =((indx==1) && (warp != null))? warp.getRenderWOI():null;
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
......@@ -442,6 +456,14 @@ public class OrthoMapsCollection implements Serializable{
src_scale * (affine[0][0]*dX + affine[0][1]*dY + affine[0][2] + src_center[0]),
src_scale * (affine[1][0]*dX + affine[1][1]*dY + affine[1][2] + src_center[1])};
// limit to the source image
if ((warp_woi != null) && (warp_woi.contains(opX,opY))) {
if ((opX==dbg_x) && (opY==dbg_y)) {
System.out.println("opX="+opX+", opy="+opY);
}
double [] dxy = warp.getWarp(opX,opY);
xy_src[0] += dxy[0];
xy_src[1] += dxy[1];
}
if ((xy_src[0] >= 0) && (xy_src[0] < (src_width-1)) &&
(xy_src[1] >= 0) && (xy_src[1] < (src_height-1))) {
int [] ixy_src = {(int) Math.floor(xy_src[0]), (int)Math.floor(xy_src[1]) };
......@@ -543,13 +565,18 @@ public class OrthoMapsCollection implements Serializable{
} */
public double [][] correlateOrthoPair(
public FineXYCorr correlateOrthoPair(
CLTParameters clt_parameters,
PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
double frac_remove, // = 0.25
double metric_error,
boolean ignore_prev_rms,
int num_tries, // = 5
boolean calc_warp,
boolean batch_mode,
String [] gpu_spair,
double [][][] affines, // here in meters, relative to vertical points
Rectangle woi,
int zoom_lev,
final int debugLevel){
int [] gpu_pair = new int[gpu_spair.length];
......@@ -558,33 +585,46 @@ public class OrthoMapsCollection implements Serializable{
}
return correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
pairwiseOrthoMatch, //PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics
frac_remove, // double frac_remove, // = 0.25
metric_error, // double metric_error,
ignore_prev_rms, // boolean ignore_prev_rms,
num_tries, // = 5int num_tries, // = 5
calc_warp, // boolean calc_warp,
batch_mode, // boolean batch_mode,
gpu_pair, // int [] gpu_pair,
affines, // double [][][] affines, // here in meters, relative to vertical points
woi, // Rectangle woi,
zoom_lev, // int zoom_lev,
debugLevel); // final int debugLevel)
}
double [][] correlateOrthoPair(
public FineXYCorr correlateOrthoPair(
CLTParameters clt_parameters,
PairwiseOrthoMatch pairwiseOrthoMatch, // will return statistics, may be null if not needed
double frac_remove, // = 0.25
double metric_error,
boolean ignore_prev_rms,
int num_tries, // = 5
boolean calc_warp,
boolean batch_mode,
int [] gpu_pair,
double [][][] affines, // here in meters, relative to vertical points
Rectangle woi,
int zoom_lev,
int debugLevel){
if (woi == null) {
woi = new Rectangle();
}
boolean show_gpu_img = true; // (debugLevel > 1);
boolean show_tile_centers = false; // true; // (debugLevel > 1);
if (!batch_mode) {
debugLevel = 3;
debugLevel = 0;
} else {
show_gpu_img = false; // (debugLevel > 1);
show_tile_centers = false; // true; // (debugLevel > 1);
}
boolean show_vector_field = !batch_mode && (debugLevel>0); // true;
boolean show_vector_field = !batch_mode && (debugLevel>-1); // true;
double [][] bounds_overlap_meters = getOverlapMeters(
gpu_pair[0], // int ref_index,
gpu_pair[1], // int other_index)
......@@ -654,7 +694,8 @@ public class OrthoMapsCollection implements Serializable{
dbg_titles);
}
Rectangle woi = new Rectangle(0, 0, overlap_wh_pixel[0], overlap_wh_pixel[1]);
woi.width = overlap_wh_pixel[0];
woi.height = overlap_wh_pixel[1]; // = new Rectangle(0, 0, overlap_wh_pixel[0], overlap_wh_pixel[1]);
if (woi.width > OrthoMap.gpu_width) {
if (debugLevel > -3) {
System.out.println("correlateOrthoPair() correlation woi.width="+woi.width+" > gpu_width="+OrthoMap.gpu_width+". Truncating.");
......@@ -671,11 +712,11 @@ public class OrthoMapsCollection implements Serializable{
final int gpu_height = OrthoMap.gpu_height; // static
int tilesX = gpu_width/GPUTileProcessor.DTT_SIZE;
int tilesY = gpu_height/GPUTileProcessor.DTT_SIZE;
Rectangle tile_woi = scaleRectangle (woi, GPUTileProcessor.DTT_SIZE);
// uses fixed_size gpu image size
TpTask [][] tp_tasks = new TpTask [2][];
int num_tries = 5;
// int num_tries = 5;
double prev_rms = Double.NaN;
double rel_improve = 1E-3;
double [][] elevations = new double [tp_tasks.length][];
......@@ -686,13 +727,15 @@ public class OrthoMapsCollection implements Serializable{
int num_refine = 3;
double frac_above = 0.3;
double frac_below = 0.1;
double metric_error = 0.01;// 1 cm
double [][] jtj = null;
double rms = Double.NaN;
for (int ntry = 0; ntry < num_tries; ntry++) {
if (!batch_mode) {
if (debugLevel>-3) {
System.out.println("correlateOrthoPair(): ntry="+ntry);
}
}
String dbg_suffix = batch_mode? null: String.format("_%02d", ntry);
double [][][] vector_field =
ComboMatch.rectilinearVectorField(//rectilinearCorrelate_TD( // scene0/scene1
clt_parameters, // final CLTParameters clt_parameters,
......@@ -702,6 +745,7 @@ public class OrthoMapsCollection implements Serializable{
affines_gpu, // final double [][][] affine, // [2][2][3] affine coefficients to translate common to 2 images
tp_tasks, // TpTask [][] tp_tasks_o,
batch_mode, // final boolean batch_mode,
dbg_suffix,// final String dbg_suffix, // for image_names
debugLevel); // final int debugLevel);
// get elevations
int zoom_lev_tiles = zoom_lev-3;
......@@ -714,7 +758,7 @@ public class OrthoMapsCollection implements Serializable{
tilesX, // final int tilesX,
tilesY, // final int tilesY,
debugLevel); // final int debugLevel)
String debug_title = show_vector_field? (ortho_maps[gpu_pair[n]].getName()+"_plane"):null;
String debug_title = (show_vector_field && (ntry==0))? (ortho_maps[gpu_pair[n]].getName()+"_plane"+dbg_suffix):null;
ground_planes_metric[n] = ortho_maps[gpu_pair[n]].getPlaneMeters (
zoom_lev_tiles, // int zoom_lev, // of the data (3 levels down for tiles)
elevations[n], // double [] elev,
......@@ -740,13 +784,17 @@ public class OrthoMapsCollection implements Serializable{
ground_planes_weight[i] = 1.0;
}
}
System.out.println("correlateOrthoPair(): left "+num_left+" tiles (was "+tp_tasks[0].length+" before filtering)");
System.out.println("correlateOrthoPair(): left "+num_left+" tiles (was "+tp_tasks[0].length+" before filtering). metric_error="+metric_error);
System.out.println();
if (num_left < tp_tasks[0].length/4) {
num_elevations--;
System.out.println("too few tiles remain, try again. metric_error="+metric_error);
}
}
Rectangle tile_woi = scaleRectangle (woi, GPUTileProcessor.DTT_SIZE);
double max_err= 5.0;
// Rectangle tile_woi = scaleRectangle (woi, GPUTileProcessor.DTT_SIZE);
double max_err= 7.0;
int num_bins = 1000;
boolean ignore_strength = false;
//double frac_remove = 0.15;
......@@ -827,7 +875,7 @@ public class OrthoMapsCollection implements Serializable{
dbg_width,
dbg_height,
true,
"vector_field",
"vector_field"+dbg_suffix,
dbg_titles);
}
......@@ -860,7 +908,7 @@ public class OrthoMapsCollection implements Serializable{
tilesX,
tile_centers.length/tilesX,
true,
"tile_centers",
"tile_centers"+dbg_suffix,
dbg_titles);
}
if (!batch_mode) {
......@@ -903,7 +951,7 @@ public class OrthoMapsCollection implements Serializable{
System.out.println("LMA failed, result="+lma_rslt);
return null;
}
double rms = orthoPairLMA.getRms();
rms = orthoPairLMA.getRms();
if (debugLevel > -3) {
System.out.println("RMS= "+rms+" ("+orthoPairLMA.getInitialRms()+")");
}
......@@ -924,7 +972,7 @@ public class OrthoMapsCollection implements Serializable{
}
}
affines_gpu[1]=OrthoMap.combineAffine(affines_gpu[1], orthoPairLMA.getAffine());
double [][] jtj = orthoPairLMA.getLastJtJ();
jtj = orthoPairLMA.getLastJtJ();
if ((prev_rms - rms)/prev_rms < rel_improve) {
if (debugLevel > -2) {
System.out.println("LMA relative RMSE improvement = "+((prev_rms - rms)/prev_rms)+" < "+rel_improve+", exiting.");
......@@ -939,10 +987,13 @@ public class OrthoMapsCollection implements Serializable{
}
prev_rms=rms;
} // for (int ntry = 0; ntry < num_tries; ntry++) {
// unrapping backwards, for "other" map only, reference is not modified.
if (pairwiseOrthoMatch != null) {
pairwiseOrthoMatch.jtj = jtj;
pairwiseOrthoMatch.rms= rms;
}
double [] tlo_src_metric_other = new double[2]; // check affines[][][] here -
for (int i = 0; i < 2; i++) {
// tlo_source_pixel[n][i] = (tlo_src_metric[n][i] + ortho_maps[gpu_pair[n]].vert_meters[i])/pix_size;
tlo_src_metric_other[i] = affines_gpu[1][i][2] * pix_size - ortho_maps[gpu_pair[1]].vert_meters[i];
for (int j = 0; j < 2; j++) {
affines[1][i][j] = affines_gpu[1][i][j];
......@@ -959,45 +1010,9 @@ public class OrthoMapsCollection implements Serializable{
System.out.println(" ["+affines[1][1][0]+","+affines[1][1][1]+","+affines[1][1][2]+"]]");
}
// analyze result, re-run correlation
/*
if (show_vector_field) {
double [][] dbg_vf = new double [3 * vector_field.length][tilesX * tilesY];
String [] dbg_titles = new String[dbg_vf.length];
String [] prefix= {"single","neibs"};
for (int n = 0; n < vector_field.length; n++) {
dbg_titles [3*n+0] = prefix[n]+"-vx";
dbg_titles [3*n+1] = prefix[n]+"-vy";
dbg_titles [3*n+2] = prefix[n]+"-str";
}
for (int i = 0; i < dbg_vf.length; i++) {
Arrays.fill(dbg_vf[i], Double.NaN);
}
for (int t=0; t<dbg_vf[0].length; t++) {
for (int n = 0; n < vector_field.length; n++) {
if (vector_field[n][t] != null) {
for (int k = 0; k < 3; k++) {
dbg_vf[n*3 + k][t] = vector_field[n][t][k];
}
}
}
}
ShowDoubleFloatArrays.showArrays(
dbg_vf,
tilesX,
tilesY,
true,
"vector_field",
dbg_titles);
}
*/
// modify affines[1]
if (debugLevel > 1) {// show result here
if ((debugLevel > 1) && (num_tries>0)) {// show result here
String [] map_names = {ortho_maps[gpu_pair[0]].getName(),ortho_maps[gpu_pair[1]].getName()};
ShowDoubleFloatArrays.showArrays(
gpu_pair_img,
......@@ -1007,6 +1022,37 @@ public class OrthoMapsCollection implements Serializable{
"gpu_pair-zoom"+zoom_lev+"-"+ortho_maps[gpu_pair[0]].getName()+"-"+ortho_maps[gpu_pair[1]].getName(),
map_names);
}
if (calc_warp) {
double scale = 2.0;
String dbg_suffix = batch_mode? null: "_warp";
// return only neighbors vector field
double [][] vf = ComboMatch.rectilinearVectorField(//rectilinearCorrelate_TD( // scene0/scene1
clt_parameters, // final CLTParameters clt_parameters,
gpu_pair_img, // final float [][] fpixels, // to check for empty
gpu_width, // final int img_width,
woi, // Rectangle woi, // if null, use full GPU window
affines_gpu, // final double [][][] affine, // [2][2][3] affine coefficients to translate common to 2 images
tp_tasks, // TpTask [][] tp_tasks_o,
batch_mode, // final boolean batch_mode,
dbg_suffix, // final String dbg_suffix,
debugLevel)[1]; // final int debugLevel);
double [][] vf_interpolated = interpolateVectorField(
vf, // final double [][] vector_field, // sparse {vx,vy,strength}
tp_tasks[1], // final TpTask [] tp_tasks, // to remove no-overlap tiles
tilesX, // final int gpu_tilesX, // 512
tile_woi, // final Rectangle tile_woi, // only width, height are used top-left corners are the same
scale, // final double scale,
1); // final int debugLevel);
double [] tl_metric = {bounds_overlap_meters[0][0],bounds_overlap_meters[1][0]};
FineXYCorr warp = new FineXYCorr(
zoom_lev, // int zoom_lev,
tile_woi.width, // int width,
tl_metric, // double [] tl_metric,// relative to the reference image vertical point, normally negative
vf_interpolated); // double [][] vf);
return warp;
}
return null;
}
......@@ -1161,17 +1207,99 @@ public class OrthoMapsCollection implements Serializable{
objectOutputStream.close();
}
/*
float [][] gpu_pair_img = new float [2][];
for (int n = 0; n < gpu_pair.length; n++) {
gpu_pair_img[n] = ortho_maps[gpu_pair[n]].getPaddedGPU (
zoom_lev, // int zoom_level,
gpu_width, // int gpu_width,
gpu_height); // int gpu_height)
public static double [][] interpolateVectorField(
final double [][] vector_field, // sparse {vx,vy,strength}
final TpTask [] tp_tasks, // to remove no-overlap tiles
final int gpu_tilesX, // 512
final Rectangle tile_woi, // only width, height are used top-left corners are the same
final double scale,
final int debugLevel) {
final int tiles = tile_woi.width*tile_woi.height;
final double [][] vf = new double[2][tile_woi.width*tile_woi.height];
for (int i = 0; i < vf.length; i++) {
Arrays.fill(vf[i], Double.NaN);
}
map_index_string
*/
final boolean [] mask = (tp_tasks==null)? null: new boolean [tiles];
final Thread[] threads = ImageDtt.newThreadArray();
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 < tiles; ipix = ai.getAndIncrement()) {
int y = ipix / tile_woi.width;
int x = ipix % tile_woi.width;
double [] v = vector_field[y*gpu_tilesX+x];
if (v != null) {
for (int i = 0; i < vf.length; i++) {
vf[i][ipix] = scale*v[i];
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
if (mask != null) {
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int iTile = ai.getAndIncrement(); iTile < tp_tasks.length; iTile = ai.getAndIncrement()) {
TpTask task = tp_tasks[iTile];
int[] txy = task.getTileXY();
if ((txy[0] < tile_woi.width) && (txy[1] < tile_woi.height)) {
mask[txy[0] + txy[1] * tile_woi.width] = true;
}
}
}
};
}
ImageDtt.startAndJoin(threads);
}
// now fill NaNs in each of vf[0], vf[1]
double [][] vf_filled = new double[vf.length][];
int num_passes = 100;
double max_diff = 1E-4;
for (int i = 0; i < vf.length; i++) {
vf_filled[i] = OpticalFlow.fillGapsDouble(
vf[i], // double [] data,
mask, // boolean [] mask_in, // do not process if false (may be null)
tile_woi.width, // int width,
0, // int max_grow,
num_passes, // int num_passes,
max_diff, // double max_diff,
ImageDtt.THREADS_MAX, // int threadsMax,
debugLevel); // int debug_level)
}
if (debugLevel > 0) {
String [] dbg_titles = {"x-raw","x_filled","y-raw","y_filled"};
double [][] dbg_img = {vf[0], vf_filled[0],vf[1], vf_filled[1]};
ShowDoubleFloatArrays.showArrays(
dbg_img,
tile_woi.width,
dbg_img[0].length / tile_woi.width,
true,
"vector_field_filled",
dbg_titles);
}
double [][] vf_out = new double [tiles][];
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int ipix = ai.getAndIncrement(); ipix < tiles; ipix = ai.getAndIncrement()) {
if (!Double.isNaN(vf_filled[0][ipix]) && !Double.isNaN(vf_filled[1][ipix])) {
vf_out[ipix] = new double[] {vf_filled[0][ipix],vf_filled[1][ipix]};
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return vf_out;
}
}
......@@ -6,13 +6,22 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
public class PairwiseOrthoMatch implements Serializable {
public PairwiseOrthoMatch(double [][] affine, double [][] jtj) {
this.affine = affine;
this.jtj = jtj;
}
private static final long serialVersionUID = 1L;
public double [][] affine = new double[2][3];
public transient double [][] jtj = new double [6][6];
public int zoom_lev;
public double rms = Double.NaN;
public PairwiseOrthoMatch() {
}
public PairwiseOrthoMatch(double [][] affine, double [][] jtj, double rms, int zoom_lev) {
this.affine = affine;
this.jtj = jtj;
}
public double [][] getAffine(){
return affine;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
for (int i = 0; i < jtj.length; i++) {
......@@ -23,6 +32,7 @@ public class PairwiseOrthoMatch implements Serializable {
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
jtj = new double [6][6]; // readObject does not use constructor!
for (int i = 0; i < jtj.length; i++) {
for (int j = i; j < jtj[i].length; j++) {
jtj[i][j] = (Double) ois.readObject();
......
......@@ -1177,7 +1177,7 @@ public class ImageDtt extends ImageDttCPU {
use_reference_buffer,
wh,
erase_clt); // put results into a "reference" buffer
if (!batch_mode && (globalDebugLevel > 2)) {
if (!batch_mode && (globalDebugLevel > 2000)) {
ComboMatch.renderFromTD (
false, // boolean use_reference,
"img"); //String suffix
......@@ -1406,7 +1406,7 @@ public class ImageDtt extends ImageDttCPU {
};
gpuQuad.setLpfRbg( // constants memory - same for all cameras
lpf_rgb,
globalDebugLevel > -2);
globalDebugLevel > 2);
// gpuQuad.printConstMem("lpf_data", true);
gpuQuad.setTasks( // copy tp_tasks to the GPU memory
......
......@@ -8646,7 +8646,7 @@ ImageDtt.startAndJoin(threads);
* @return scaled down data[]. Each item (tile) is average of the corresponding data[] pixels
* or NaN if it has no non-NaN pixels in a tile.
*/
public static double [] fillNaNsScaleDown(
public static double [] fillNaNsScaleDown( // extendBlueSky
final double [] data,
final boolean [] prohibit,
final int tile_size,
......@@ -8704,7 +8704,7 @@ ImageDtt.startAndJoin(threads);
* @param width input data[] width in pixels (height = data.length/width)
* @param threadsMax maximal number of threads to use
*/
public static void fillNaNsScaleUp(
public static void fillNaNsScaleUp( // extendBlueSky
final double [] data, // will be replaced
final double [] data_scaled,
final boolean [] prohibit,
......@@ -8734,7 +8734,7 @@ ImageDtt.startAndJoin(threads);
}
public static boolean [] fillNaNsGetFixed(
public static boolean [] fillNaNsGetFixed( // never used
final double [] data,
final boolean [] prohibit,
final int threadsMax) { // maximal number of threads to launch
......
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