Commit f97f3155 authored by Andrey Filippov's avatar Andrey Filippov

Implemented OrthoMapCollection class and possibility to save maps state

w/o images
parent 624f1144
...@@ -109,7 +109,7 @@ import com.elphel.imagej.ims.EventLogger; ...@@ -109,7 +109,7 @@ import com.elphel.imagej.ims.EventLogger;
import com.elphel.imagej.ims.Imx5; import com.elphel.imagej.ims.Imx5;
import com.elphel.imagej.jp4.JP46_Reader_camera; import com.elphel.imagej.jp4.JP46_Reader_camera;
import com.elphel.imagej.lwir.LwirReader; import com.elphel.imagej.lwir.LwirReader;
import com.elphel.imagej.orthomosaic.ComboMap; import com.elphel.imagej.orthomosaic.OrthoMap;
import com.elphel.imagej.orthomosaic.ComboMatch; import com.elphel.imagej.orthomosaic.ComboMatch;
import com.elphel.imagej.readers.ChangeImageResolution; import com.elphel.imagej.readers.ChangeImageResolution;
import com.elphel.imagej.readers.DumpImageMetadata; import com.elphel.imagej.readers.DumpImageMetadata;
...@@ -5732,7 +5732,7 @@ public class Eyesis_Correction implements PlugIn, ActionListener { ...@@ -5732,7 +5732,7 @@ public class Eyesis_Correction implements PlugIn, ActionListener {
IJ.showMessage("Error", "No images selected"); IJ.showMessage("Error", "No images selected");
return; return;
} }
ComboMap.testVideo(imp_sel); OrthoMap.testVideo(imp_sel);
} }
} }
......
...@@ -45,7 +45,8 @@ public class ComboMatch { ...@@ -45,7 +45,8 @@ public class ComboMatch {
GPU_TILE_PROCESSOR = gpu_tile_processor; GPU_TILE_PROCESSOR = gpu_tile_processor;
// find -L /media/elphel/SSD3-4GB/lwir16-proc/berdich3/linked/linked_1697875868-1697879449-b/ -type f -name "*-GCORR-GEO.tiff" | sort > GCORR-GEO.list // 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_berdich2.list"; String files_list_path = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/maps_03_short.list";
String orthoMapsCollection_path = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/ortho_maps_collection.data";
double [][][] image_enuatr = {{{0,0,0},{0,0,0}},{{0,0,0},{0,0,0}}}; 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_width= clt_parameters.imp.rln_gpu_width; // 3008;
...@@ -53,8 +54,13 @@ public class ComboMatch { ...@@ -53,8 +54,13 @@ public class ComboMatch {
int zoom_lev = -4; // 0; // +1 - zoom in twice, -1 - zoom out twice int zoom_lev = -4; // 0; // +1 - zoom in twice, -1 - zoom out twice
boolean use_alt = false; boolean use_alt = false;
boolean show_centers = true; boolean show_centers = true;
boolean use_saved_collection = false;
boolean save_collection = true;
GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,800); GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,800);
gd.addStringField ("Image list full path ", files_list_path, 180, "Image listfull path."); 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, "If false - use files list.");
// for (int n = 0; n < image_paths_pre.length; n++) { // 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"); // gd.addStringField ("Image path "+n, image_paths_pre[n], 180, "Image "+n+" full path w/o ext");
// } // }
...@@ -81,11 +87,11 @@ public class ComboMatch { ...@@ -81,11 +87,11 @@ public class ComboMatch {
gd.showDialog(); gd.showDialog();
if (gd.wasCanceled()) return false; if (gd.wasCanceled()) return false;
files_list_path = gd.getNextString(); files_list_path = gd.getNextString();
// for (int n = 0; n < image_paths_pre.length; n++) {
// image_paths_pre[n] = gd.getNextString(); orthoMapsCollection_path = gd.getNextString();
// } use_saved_collection = gd.getNextBoolean();
// image_paths_pre[0] = gd.getNextString(); save_collection = gd.getNextBoolean();
// image_paths_pre[1] = gd.getNextString();
for (int n = 0; n < image_enuatr.length; n++) { for (int n = 0; n < image_enuatr.length; n++) {
image_enuatr[n][0][0] = gd.getNextNumber(); image_enuatr[n][0][0] = gd.getNextNumber();
image_enuatr[n][0][1] = gd.getNextNumber(); image_enuatr[n][0][1] = gd.getNextNumber();
...@@ -98,58 +104,71 @@ public class ComboMatch { ...@@ -98,58 +104,71 @@ public class ComboMatch {
gpu_width = (int) gd.getNextNumber(); gpu_width = (int) gd.getNextNumber();
gpu_height = (int) gd.getNextNumber(); gpu_height = (int) gd.getNextNumber();
ComboMap.setGPUWidthHeight(gpu_width,gpu_height); OrthoMap.setGPUWidthHeight(gpu_width,gpu_height);
show_centers = gd.getNextBoolean(); show_centers = gd.getNextBoolean();
use_alt = gd.getNextBoolean(); use_alt = gd.getNextBoolean();
// ComboMap[] combo_maps = ComboMap.initializeComboMaps( OrthoMapsCollection maps_collection=null;
// full_paths); // String [] image_paths); if (use_saved_collection) {
ComboMap[] combo_maps = ComboMap.initializeComboMaps( try {
files_list_path); // String [] image_paths); maps_collection = OrthoMapsCollection.readOrthoMapsCollection (orthoMapsCollection_path);
String [] map_names = ComboMap.getNames(combo_maps); } catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
maps_collection = new OrthoMapsCollection(files_list_path); // should have ".list" extensiohn
}
String [] names = maps_collection.getNames();
// which pair to compare
int [] gpu_pair = {1,2};
String [] gpu_spair = {names[gpu_pair[0]],names[gpu_pair[1]]};
int [] origin = new int[2]; int [] origin = new int[2];
ImagePlus imp_img = ComboMap.renderMulti ( ImagePlus imp_img = maps_collection.renderMulti (
"multi_"+zoom_lev, // String title, "multi_"+zoom_lev, // String title,
false, // boolean use_alt, false, // boolean use_alt,
show_centers, // boolean show_centers, show_centers, // boolean show_centers,
combo_maps, // ComboMap [] maps,
zoom_lev, // int zoom_level, zoom_lev, // int zoom_level,
origin); // int [] origin){ origin); // int [] origin){
imp_img.show(); imp_img.show();
ImagePlus imp_alt = null; ImagePlus imp_alt = null;
if (use_alt) { if (use_alt) {
imp_alt =ComboMap.renderMulti ( imp_alt =maps_collection.renderMulti (
"multi_alt_"+zoom_lev, // String title, "multi_alt_"+zoom_lev, // String title,
true, // boolean use_alt, true, // boolean use_alt,
show_centers, // boolean show_centers, show_centers, // boolean show_centers,
combo_maps, // ComboMap [] maps,
zoom_lev, // int zoom_level, zoom_lev, // int zoom_level,
origin); // int [] origin){ origin); // int [] origin){
imp_alt.show(); imp_alt.show();
} }
// which pair to compare
int [] gpu_pair = {1,2};
float [][] gpu_pair_img = new float [2][]; float [][] gpu_pair_img = maps_collection.getPaddedPairGPU(
for (int n = 0; n < gpu_pair.length; n++) { gpu_spair, // String [] spair,
gpu_pair_img[n] = combo_maps[gpu_pair[n]].getPaddedGPU ( zoom_lev); // int zoom_lev);
zoom_lev, // int zoom_level,
gpu_width, // int gpu_width,
gpu_height); // int gpu_height)
}
ShowDoubleFloatArrays.showArrays( ShowDoubleFloatArrays.showArrays(
gpu_pair_img, gpu_pair_img,
gpu_width, gpu_width,
gpu_height, gpu_height,
true, true,
"gpu_pair-zoom"+zoom_lev+"-"+combo_maps[gpu_pair[0]].getName()+"-"+combo_maps[gpu_pair[1]].getName(), "gpu_pair-zoom"+zoom_lev+"-"+gpu_spair[0]+"-"+gpu_spair[1],
map_names); gpu_spair);
if (save_collection) {
try {
maps_collection.writeOrthoMapsCollection(orthoMapsCollection_path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (debugLevel <1000) { if (debugLevel <1000) {
return true; return true;
} }
/* */ /* */
OrthoMap [] ortho_maps = maps_collection.getMaps(); // just temporarily
int [] widths = new int[imp_src.length]; int [] widths = new int[imp_src.length];
int [] heights = new int[imp_src.length]; int [] heights = new int[imp_src.length];
for (int n = 0; n < imp_src.length; n++) { for (int n = 0; n < imp_src.length; n++) {
...@@ -178,8 +197,8 @@ public class ComboMatch { ...@@ -178,8 +197,8 @@ public class ComboMatch {
} }
/* */ /* */
if (show_centers) { if (show_centers) {
for (int n = 0; n < combo_maps.length; n++) { for (int n = 0; n < ortho_maps.length; n++) {
combo_maps[n].getOriginalImage(true); ortho_maps[n].getOriginalImage(true);
} }
} }
/* /*
...@@ -187,11 +206,12 @@ public class ComboMatch { ...@@ -187,11 +206,12 @@ public class ComboMatch {
imp_src[n].show(); imp_src[n].show();
} }
*/ */
if (combo_maps[0].orig_zoom_level != combo_maps[1].orig_zoom_level) {
if (ortho_maps[0].orig_zoom_level != ortho_maps[1].orig_zoom_level) {
System.out.println("openTestPairGps() does not yet handle different scales, aborting"); System.out.println("openTestPairGps() does not yet handle different scales, aborting");
return false; return false;
} }
double [] enu_diff = combo_maps[0].enuOffsetTo(combo_maps[0]); double [] enu_diff = ortho_maps[0].enuOffsetTo(ortho_maps[0]);
double pix_size1 = ElphelTiffReader.getPixelSize(imp_prop[0])[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 double [] pix_shift = {enu_diff[0]/pix_size1, -enu_diff[1]/pix_size1}; // E->X, N->-Y
......
...@@ -4,6 +4,9 @@ import java.awt.Color; ...@@ -4,6 +4,9 @@ import java.awt.Color;
import java.awt.Font; import java.awt.Font;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
...@@ -39,28 +42,73 @@ import ij.process.FloatProcessor; ...@@ -39,28 +42,73 @@ import ij.process.FloatProcessor;
import ij.process.ImageConverter; import ij.process.ImageConverter;
import ij.process.ImageProcessor; import ij.process.ImageProcessor;
public class ComboMap { public class OrthoMap implements Comparable <OrthoMap>, Serializable{
private static final long serialVersionUID = 1L;
public static boolean FIX_VERT_Y = false; // true; // temporarily fix vertical Y coordinate bug (use -GCORR in the filename?) public static boolean FIX_VERT_Y = false; // true; // temporarily fix vertical Y coordinate bug (use -GCORR in the filename?)
public static int gpu_width = 4096; public static int gpu_width = 4096;
public static int gpu_height = 4096; public static int gpu_height = 4096;
public static final String [] KEY_DIRS= {"rootDirectory", // from EyesisCorrectionParameters public static final String [] KEY_DIRS= {"rootDirectory", // from EyesisCorrectionParameters
"sourceDirectory","linkedModels","videoDirectory","x3dDirectory","resultsDirectory"}; "sourceDirectory","linkedModels","videoDirectory","x3dDirectory","resultsDirectory"};
public static final String ALT_SUFFIX = "-ALT"; public static final String ALT_SUFFIX = "-ALT";
public final String name; // timestamp // public transient final String name; // timestamp
public String path; // full path to the model directory (including /vXX?) // public transient final double ts;
public transient String name; // timestamp
public transient double ts;
public transient String path; // full path to the model directory (including /vXX?)
public double [] lla; // lat/long/alt public double [] lla; // lat/long/alt
public LocalDateTime dt; public LocalDateTime dt;
// affine convert (input) rectified coordinates (meters) relative to vert_meters to source image // affine convert (input) rectified coordinates (meters) relative to vert_meters to source image
// coordinates relative to vert_meters // coordinates relative to vert_meters
private double [][] affine = new double[][] {{1,0,0},{0,1,0}}; // relative to vert_meters[] public double [][] affine = new double[][] {{1,0,0},{0,1,0}}; // relative to vert_meters[]
public double orig_pix_meters; public double orig_pix_meters;
public double [] vert_meters; // offset of the image vertical in meters (scale-invariant) public double [] vert_meters; // offset of the image vertical in meters (scale-invariant)
public FloatImageData orig_image; public transient FloatImageData orig_image;
public FloatImageData alt_image; public transient FloatImageData alt_image;
public int orig_zoom_level; public int orig_zoom_level;
public boolean orig_zoom_valid; public boolean orig_zoom_valid;
public double need_extra_zoom; public double need_extra_zoom;
HashMap <Integer, FloatImageData> images; transient HashMap <Integer, FloatImageData> images;
HashMap <Double, PairwiseOrthoMatch> pairwise_matches;
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(path);
// lla is not transient
// dt is not transient
// affine is not transient
// orig_pix_meters is not transient
// vert_meters is not transient
// orig_image does not need to be saved
// alt_image does not need to be saved
// orig_zoom_level is not transient
// orig_zoom_valid is not transient
// need_extra_zoom is not transient
// images is not saved
// pairwise_matches is not transient
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
path = (String) ois.readObject();
name = getNameFromPath(path);
ts= Double.parseDouble(name.replace("_", "."));
// lla is not transient
// dt is not transient
// affine is not transient
// orig_pix_meters is not transient
// vert_meters is not transient
// orig_image was not saved
// alt_image was not saved
images = new HashMap <Integer, FloatImageData>(); // field images was not saved
// pairwise_matches is not transient
// pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>();
}
@Override
public int compareTo(OrthoMap otherPlayer) {
return Double.compare(ts, otherPlayer.ts);
}
public static void setGPUWidthHeight( public static void setGPUWidthHeight(
int width, int width,
...@@ -83,9 +131,10 @@ public class ComboMap { ...@@ -83,9 +131,10 @@ public class ComboMap {
return path.substring(p1+1, p2); return path.substring(p1+1, p2);
} }
public ComboMap (String path) { public OrthoMap (String path) {
this.path = path; this.path = path;
name = getNameFromPath(path); name = getNameFromPath(path);
ts= Double.parseDouble(name.replace("_", "."));
Properties imp_prop = null; Properties imp_prop = null;
try { try {
imp_prop = ElphelTiffReader.getTiffMeta(path); imp_prop = ElphelTiffReader.getTiffMeta(path);
...@@ -107,87 +156,13 @@ public class ComboMap { ...@@ -107,87 +156,13 @@ public class ComboMap {
orig_zoom_valid = FloatImageData.isZoomValid(orig_pix_meters); orig_zoom_valid = FloatImageData.isZoomValid(orig_pix_meters);
need_extra_zoom = FloatImageData.needZoomIn(orig_pix_meters); need_extra_zoom = FloatImageData.needZoomIn(orig_pix_meters);
images = new HashMap <Integer, FloatImageData>(); images = new HashMap <Integer, FloatImageData>();
pairwise_matches = new HashMap<Double, PairwiseOrthoMatch>();
} }
public LocalDateTime getLocalDateTime() { public LocalDateTime getLocalDateTime() {
return dt; return dt;
} }
public static ComboMap[] initializeComboMaps(
String [] image_paths) { // full paths, including ext
double [][] affine = {{1,0,0},{0,1,0}}; // maybe later calculate from mage_enuatr
ComboMap[] combo_maps = new ComboMap[image_paths.length];
for (int n = 0; n < combo_maps.length; n++) {
combo_maps[n] = new ComboMap(image_paths[n]);
combo_maps[n].setAffine(affine);
}
return combo_maps;
}
public static ComboMap[] initializeComboMaps(
String files_list) {
List<String> lines;
List<String> rel_files = new ArrayList<String>();
Path seq_path = Paths.get(files_list);
try {
lines = Files.readAllLines(seq_path, StandardCharsets.UTF_8);
// lines.stream().forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
return null;
}
Path base_path = seq_path.getParent();
HashMap<String,String> dir_map = new HashMap<String,String>();
for (String line:lines){
if (line.split("#").length > 0) {
String[] tokens = line.split("#")[0].trim().split("[\\s,;=]+");
if ((tokens.length > 2) && (tokens[0].toUpperCase().equals("SET"))) {
parse_set:
{
for (String dir_name:KEY_DIRS) if (dir_name.equals(tokens[1])) {
dir_map.put(dir_name,tokens[2]);
System.out.println("Parsed SET: "+tokens[1]+" in line: "+line);
break parse_set;
}
System.out.println("*********** Unknown SET: "+tokens[1]+" in line: "+line);
}
} else if ((tokens.length == 1) && (tokens[0].length() > 0)) {
rel_files.add(tokens[0]);
}
}
}
if (dir_map.containsKey("rootDirectory")) {
base_path=base_path.resolve(Paths.get(dir_map.get("rootDirectory")));
File base_dir = new File(base_path.toString());
// if (!base_dir.exists()) {
// base_dir.mkdirs();
// }
}
String sourceDirectory = base_path.toString();
// set sourceDirectory:
if (dir_map.containsKey("sourceDirectory")) {
sourceDirectory=(base_path.resolve(Paths.get(dir_map.get("sourceDirectory")))).toString();
}
Path source_path = Paths.get(sourceDirectory);
File source_dir = new File(source_path.toString());
String [] paths = new String[rel_files.size()];
for (int i = 0; i < paths.length; i++) {
paths[i] = (source_path.resolve(Paths.get(rel_files.get(i)))).toString();
}
return initializeComboMaps(paths);
}
public static String[] getNames(
ComboMap[] maps) {
String [] names = new String [maps.length];
for (int n = 0; n < maps.length; n++) {
names[n] = maps[n].getName();
}
return names;
}
public String getName() { public String getName() {
return name; return name;
...@@ -293,7 +268,7 @@ public class ComboMap { ...@@ -293,7 +268,7 @@ public class ComboMap {
return null; return null;
} }
public double [] enuOffsetTo(ComboMap other) { public double [] enuOffsetTo(OrthoMap other) {
return Imx5.enuFromLla(other.lla, lla); return Imx5.enuFromLla(other.lla, lla);
} }
...@@ -378,27 +353,6 @@ public class ComboMap { ...@@ -378,27 +353,6 @@ public class ComboMap {
return bounds_pix; return bounds_pix;
} }
/**
* Get rectified bounds of all provided combo images relative to the origin (vertical
* point) of the first one in meters
* @param maps array of combo images
* @return {{min_x,max_x},{min_y,max_y}} bounds that include all provided maps
* relative to the origin (vertical point) of the first image
*/
public static double [][] getBoundsMeters(ComboMap [] maps){ // maps[0] as a reference
double [][] bounds = maps[0].getBoundsMeters(true);
for (int nmap = 1; nmap < maps.length; nmap++) {
double [][] bounds_other = maps[nmap].getBoundsMeters(true);
double [] enuOffset = maps[0].enuOffsetTo(maps[nmap]);
double [] rd = {enuOffset[0], -enuOffset[1]}; // {right,down} of the image
for (int n = 0; n < bounds.length; n++) {
bounds[n][0] = Math.min(bounds[n][0],bounds_other[n][0]+ rd[n]);
bounds[n][1] = Math.max(bounds[n][1],bounds_other[n][1]+ rd[n]);
}
}
return bounds;
}
/** /**
* In preparation for the GPU correlation (zoomed out images of the fixed * In preparation for the GPU correlation (zoomed out images of the fixed
* size are calculated separately and have NaN for unused pixels. * size are calculated separately and have NaN for unused pixels.
...@@ -407,8 +361,8 @@ public class ComboMap { ...@@ -407,8 +361,8 @@ public class ComboMap {
* affine matrices for both images ([2][2][3]). * affine matrices for both images ([2][2][3]).
* The overlap area should fit into gpu_width, gpu_hight, the affine-generated * The overlap area should fit into gpu_width, gpu_hight, the affine-generated
* image coordinates will be limited during TpTask[][] generation * image coordinates will be limited during TpTask[][] generation
* @param ref_map ComboMap instance for the reference map * @param ref_map OrthoMap instance for the reference map
* @param var_map ComboMap instance for the variable map instance * @param var_map OrthoMap instance for the variable map instance
* @param zoom_lev zoom level (0 - 1 pix=1cm, 1 - 1 pix = 0.5cm, -1 - 1 pix = 2 cm. * @param zoom_lev zoom level (0 - 1 pix=1cm, 1 - 1 pix = 0.5cm, -1 - 1 pix = 2 cm.
* @param var_offset additional (to affine and lla, vert_meters) x,y offset of * @param var_offset additional (to affine and lla, vert_meters) x,y offset of
* the var_map (in output pixels). Used for spiral search for initial * the var_map (in output pixels). Used for spiral search for initial
...@@ -420,36 +374,14 @@ public class ComboMap { ...@@ -420,36 +374,14 @@ public class ComboMap {
* (is centered) to the reference image origin (vertical point) * (is centered) to the reference image origin (vertical point)
*/ */
public static int [][] getPairOvelapBoundsAffine( public static int [][] getPairOvelapBoundsAffine(
ComboMap ref_map, OrthoMap ref_map,
ComboMap var_map, OrthoMap var_map,
int zoom_lev, int zoom_lev,
int [] var_offset, int [] var_offset,
double [][][] gpu_affine){ double [][][] gpu_affine){
return null; return null;
} }
/**
* Get rectified bounds of all provided combo images relative to the origin (vertical
* point) of the first one in pixels at the provided zoom level. Center of the first
* image correspond to the {0,0} point from which the bounds are counted
* @param maps array of map instances
* @param zoom_level zoom level - 0 corresponds to 1pix=1cm scale, +1 - to 1pix = 0.5cm
* @return {{min_x,max_x},{min_y, max_y}} relative to the origin of the first image
*/
public static int [][] getBoundsPixels(
ComboMap [] maps,
int zoom_level){ // maps[0] as a reference
double [][] bounds_meters = getBoundsMeters(maps);
double pix_size = getPixelSizeMeters (zoom_level);
int [][] bounds_pix = new int[2][2];
for (int n = 0; n < bounds_pix.length; n++) {
bounds_pix[n][0] = (int) Math.floor(bounds_meters[n][0]/pix_size);
bounds_pix[n][1] = (int) Math.ceil (bounds_meters[n][1]/pix_size);
}
return bounds_pix;
}
/** /**
* Convert from the affine matrix that calculates image coordinates from the rectified one * Convert from the affine matrix that calculates image coordinates from the rectified one
* (relative to the origin point) to the matrix that provides rectified coordinates from the * (relative to the origin point) to the matrix that provides rectified coordinates from the
...@@ -550,14 +482,10 @@ public class ComboMap { ...@@ -550,14 +482,10 @@ public class ComboMap {
* Copy prepared scaled image to the top-left corner of the fixed-size * Copy prepared scaled image to the top-left corner of the fixed-size
* float[] array for the GPU input * float[] array for the GPU input
* @param zoom_level * @param zoom_level
* @param gpu_width
* @param gpu_height
* @return * @return
*/ */
public float [] getPaddedGPU ( public float [] getPaddedGPU (
int zoom_level, int zoom_level){
int gpu_width,
int gpu_height){
boolean got_image = downScaleForGPU (zoom_level); // will create if does not exist boolean got_image = downScaleForGPU (zoom_level); // will create if does not exist
if (!got_image) { if (!got_image) {
System.out.println("getPaddedGPU(): failed to prepare a scaled image"); System.out.println("getPaddedGPU(): failed to prepare a scaled image");
...@@ -593,179 +521,7 @@ public class ComboMap { ...@@ -593,179 +521,7 @@ public class ComboMap {
return padded_gpu; return padded_gpu;
} }
public static ImagePlus renderMulti (
String title,
boolean use_alt,
boolean show_centers,
ComboMap [] maps,
int zoom_level,
int [] origin){
int [] wh = new int[2];
double [][] centers = new double [maps.length][];
float [][] multi = renderMulti (
use_alt, // boolean use_alt,
maps, // ComboMap [] maps,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
String [] map_names = new String[maps.length];
for (int n = 0; n < maps.length; n++) {
map_names[n] = maps[n].getName()+"_"+maps[n].getLocalDateTime().toString().replace("T","_")+"_UTC";
}
ImageStack stack = ShowDoubleFloatArrays.makeStack(
multi,
wh[0],
wh[1],
map_names,
false);
ImagePlus imp = new ImagePlus(title, stack);
if (show_centers) {
PointRoi roi = new PointRoi();
for (int i = 0; i < centers.length; i++) {
roi.addPoint(centers[i][0],centers[i][1], i+1);
}
roi.setOptions("label");
imp.setRoi(roi);
}
return imp;
}
/**
* Rectify and render multiple images (as slices) matching vert_meters to
* their (vert_meters points) provided IMS coordinates
* @param show altitudes instead of thermal data
* @param maps array of the combo images
* @param zoom_level zoom level (0 - 1pix=1cm, 1 - 1pix=0.5cm, -1 - 1pix=2cm
* @param wh null or int [2], will return {width, height}
* @param origin - null or double [2], will return {x0, y0} in pixels
* @param centers - null or double[maps.length][] - will return image centers coordinates
* @return
*/
public static float [][] renderMulti (
boolean use_alt,
ComboMap [] maps,
int zoom_level,
int [] wh,
int [] origin, // maps[0] as a reference
double [][] centers){
int [][] bounds = getBoundsPixels( // should be for rectified, {-bounds[0][0], -bounds[0][1]} - exact center
maps,
zoom_level);
int width = bounds[0][1] - bounds[0][0]; // bounds[x][0] - negative
int height = bounds[1][1] - bounds[1][0];
if (wh != null) {
wh[0] = width;
wh[1] = height;
}
if (origin != null) {
origin[0] = -bounds[0][0];
origin[1] = -bounds[1][0];
}
final float [][] fpixels = new float [maps.length][width * height];
for (int nmap = 0; nmap< maps.length; nmap++) {
final int fnmap = nmap;
Arrays.fill(fpixels[nmap], Float.NaN);
final double scale = 1.0/getPixelSizeMeters(zoom_level);
final double src_scale = 1.0/getPixelSizeMeters(maps[nmap].orig_zoom_level); // pix per meter
// metric bounds of the rectified image relative to its origin
double [][] mbounds = maps[nmap].getBoundsMeters(true);
double [] enu_offset = maps[0].enuOffsetTo(maps[nmap]);
final double [] scaled_out_center = { // xy center to apply affine to
-bounds[0][0] + scale * enu_offset[0],
-bounds[1][0] - scale * enu_offset[1]};
if (centers != null) {
centers[nmap] = scaled_out_center;
}
final int [][] obounds = new int [2][2]; // output (rectified, combined) image bounds, relative to thje top-left
for (int n = 0; n< 2; n++) {
obounds[n][0] = (int) Math.floor(scaled_out_center[n] + scale*mbounds[n][0]);
obounds[n][1] = (int) Math.ceil (scaled_out_center[n] + scale*mbounds[n][1]);
}
// Output window size
final int ownd_width = obounds[0][1] - obounds[0][0];
final int ownd_height = obounds[1][1] - obounds[1][0];
final int ownd_len = ownd_width * ownd_height;
double [][] src_bounds=maps[nmap].getBoundsMeters (true);
final double [] src_center = {-src_bounds[0][0],-src_bounds[1][0]}; // x,y center offset in the source image
final double [][] affine = maps[nmap].affine;
final int src_width = use_alt? maps[nmap].getAltData().width: maps[nmap].getImageData().width;
final int src_height = use_alt? maps[nmap].getAltData().height : maps[nmap].getImageData().height;
final float [] src_img = use_alt? maps[nmap].getAltData().data : maps[nmap].getImageData().data;
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 nPix = ai.getAndIncrement(); nPix < ownd_len; nPix = ai.getAndIncrement()) {
int opX = nPix % ownd_width + obounds[0][0]; // absolute output pX, pY
int opY = nPix / ownd_width + obounds[1][0];
double dX = (opX - scaled_out_center[0]) /scale; // in original image scale
double dY = (opY - scaled_out_center[1]) /scale;
double [] xy_src = { // pixels of the source image
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 ((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]) };
double [] kxy = {xy_src[0]-ixy_src[0], xy_src[1]-ixy_src[1]};
int indx00 = ixy_src[0] + ixy_src[1] * src_width;
double d00 = src_img[indx00];
if (!Double.isNaN(d00)) {
double d01 = src_img[indx00 + 1];
double d10 = src_img[indx00 + src_width];
double d11 = src_img[indx00 + src_width + 1];
double d = d00*(1.0 - kxy[0])*(1.0 - kxy[1])+
d01* kxy[0] *(1.0 - kxy[1])+
d10*(1.0 - kxy[0])* kxy[1]+
d11* kxy[0] * kxy[1];
fpixels[fnmap][opX + opY*width] = (float) d;
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
}
return fpixels;
}
public static double [][] correlateComboPair(
CLTParameters clt_parameters,
ComboMap [] combo_maps,
int first_index,
int second_index,
int zoom_lev,
double [] offset_xy_second, // on top of affine and GPS
final int debugLevel){
int [] gpu_pair = {first_index,second_index};
double [][][] bounds_out = new double [2][][];
float [][] gpu_pair_img = new float [2][];
for (int n = 0; n < gpu_pair.length; n++) {
gpu_pair_img[n] = combo_maps[gpu_pair[n]].getPaddedGPU (
zoom_lev, // int zoom_level,
gpu_width, // int gpu_width,
gpu_height); // int gpu_height)
}
if (debugLevel > 1) {
String [] map_names = {combo_maps[gpu_pair[0]].getName(),combo_maps[gpu_pair[1]].getName()};
ShowDoubleFloatArrays.showArrays(
gpu_pair_img,
gpu_width,
gpu_height,
true,
"gpu_pair-zoom"+zoom_lev+"-"+combo_maps[gpu_pair[0]].getName()+"-"+combo_maps[gpu_pair[1]].getName(),
map_names);
}
return null;
}
public static void testVideo(ImagePlus imp) { public static void testVideo(ImagePlus imp) {
String path_prefix = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/videos/video_"; String path_prefix = "/media/elphel/SSD3-4GB/lwir16-proc/ortho_videos/videos/video_";
boolean keep_original = true; boolean keep_original = true;
......
package com.elphel.imagej.orthomosaic;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.elphel.imagej.cameras.CLTParameters;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.tileprocessor.ImageDtt;
import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.PointRoi;
public class OrthoMapsCollection implements Serializable{
private static final long serialVersionUID = 1L;
public static final String [] KEY_DIRS= {"rootDirectory", // from EyesisCorrectionParameters
"sourceDirectory","linkedModels","videoDirectory","x3dDirectory","resultsDirectory"};
OrthoMap [] ortho_maps;
transient HashMap<Double,Integer> map_index;
transient HashMap<String,Integer> map_index_string;
private void writeObject(ObjectOutputStream oos) throws IOException { // ?
oos.defaultWriteObject();
// oos.writeObject(path);
// ortho_maps is not transient
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
reindex(); // will recreate map_index, map_index_string
// lla is not transient
}
public OrthoMapsCollection(
String path) {
if (path.endsWith(".list")) {
String[] paths = getPathsFromSorceList(path);
double [][] affine = {{1,0,0},{0,1,0}}; // maybe later calculate from mage_enuatr
ortho_maps = new OrthoMap[paths.length];
for (int n = 0; n < ortho_maps.length; n++) {
ortho_maps[n] = new OrthoMap(paths[n]);
ortho_maps[n].setAffine(affine);
}
}
Arrays.sort(ortho_maps);
reindex();
}
public int reindex() {
map_index = new HashMap<Double,Integer>();
map_index_string = new HashMap<String,Integer>();
for (int i = 0; i < ortho_maps.length; i++) {
map_index.put(ortho_maps[i].ts, i);
map_index_string.put(ortho_maps[i].name,i);
}
return ortho_maps.length;
}
OrthoMap [] getMaps() {
return ortho_maps;
}
public String[] getNames() {
String [] names = new String [ortho_maps.length];
for (int n = 0; n < ortho_maps.length; n++) {
names[n] = ortho_maps[n].getName();
}
return names;
}
public static String[] getPathsFromSorceList(
String files_list) {
List<String> lines;
List<String> rel_files = new ArrayList<String>();
Path seq_path = Paths.get(files_list);
try {
lines = Files.readAllLines(seq_path, StandardCharsets.UTF_8);
// lines.stream().forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
return null;
}
Path base_path = seq_path.getParent();
HashMap<String,String> dir_map = new HashMap<String,String>();
for (String line:lines){
if (line.split("#").length > 0) {
String[] tokens = line.split("#")[0].trim().split("[\\s,;=]+");
if ((tokens.length > 2) && (tokens[0].toUpperCase().equals("SET"))) {
parse_set:
{
for (String dir_name:KEY_DIRS) if (dir_name.equals(tokens[1])) {
dir_map.put(dir_name,tokens[2]);
System.out.println("Parsed SET: "+tokens[1]+" in line: "+line);
break parse_set;
}
System.out.println("*********** Unknown SET: "+tokens[1]+" in line: "+line);
}
} else if ((tokens.length == 1) && (tokens[0].length() > 0)) {
rel_files.add(tokens[0]);
}
}
}
if (dir_map.containsKey("rootDirectory")) {
base_path=base_path.resolve(Paths.get(dir_map.get("rootDirectory")));
File base_dir = new File(base_path.toString());
}
String sourceDirectory = base_path.toString();
// set sourceDirectory:
if (dir_map.containsKey("sourceDirectory")) {
sourceDirectory=(base_path.resolve(Paths.get(dir_map.get("sourceDirectory")))).toString();
}
Path source_path = Paths.get(sourceDirectory);
// File source_dir = new File(source_path.toString());
String [] paths = new String[rel_files.size()];
for (int i = 0; i < paths.length; i++) {
paths[i] = (source_path.resolve(Paths.get(rel_files.get(i)))).toString();
}
return paths;
}
/**
* Get rectified bounds of all provided ortho images relative to the origin (vertical
* point) of the first one in pixels at the provided zoom level. Center of the first
* image correspond to the {0,0} point from which the bounds are counted
* @param zoom_level zoom level - 0 corresponds to 1pix=1cm scale, +1 - to 1pix = 0.5cm
* @return {{min_x,max_x},{min_y, max_y}} relative to the origin of the first image
*/
public int [][] getBoundsPixels(
int zoom_level){ // maps[0] as a reference
double [][] bounds_meters = getBoundsMeters();
double pix_size = OrthoMap.getPixelSizeMeters (zoom_level);
int [][] bounds_pix = new int[2][2];
for (int n = 0; n < bounds_pix.length; n++) {
bounds_pix[n][0] = (int) Math.floor(bounds_meters[n][0]/pix_size);
bounds_pix[n][1] = (int) Math.ceil (bounds_meters[n][1]/pix_size);
}
return bounds_pix;
}
/**
* Get rectified bounds of all provided ortho images relative to the origin (vertical
* point) of the first one in meters
* @return {{min_x,max_x},{min_y,max_y}} bounds that include all provided maps
* relative to the origin (vertical point) of the first image
*/
public double [][] getBoundsMeters(){ // maps[0] as a reference
double [][] bounds = ortho_maps[0].getBoundsMeters(true);
for (int nmap = 1; nmap < ortho_maps.length; nmap++) {
double [][] bounds_other = ortho_maps[nmap].getBoundsMeters(true);
double [] enuOffset = ortho_maps[0].enuOffsetTo(ortho_maps[nmap]);
double [] rd = {enuOffset[0], -enuOffset[1]}; // {right,down} of the image
for (int n = 0; n < bounds.length; n++) {
bounds[n][0] = Math.min(bounds[n][0],bounds_other[n][0]+ rd[n]);
bounds[n][1] = Math.max(bounds[n][1],bounds_other[n][1]+ rd[n]);
}
}
return bounds;
}
public ImagePlus renderMulti (
String title,
boolean use_alt,
boolean show_centers,
// OrthoMap [] maps,
int zoom_level,
int [] origin){
int [] wh = new int[2];
double [][] centers = new double [ortho_maps.length][];
float [][] multi = renderMulti (
use_alt, // boolean use_alt,
// maps, // OrthoMap [] maps,
zoom_level, // int zoom_level,
wh, // int [] wh,
origin, // int [] origin){ // maps[0] as a reference
centers); // double [][] centers)
String [] map_names = new String[ortho_maps.length];
for (int n = 0; n < ortho_maps.length; n++) {
map_names[n] = ortho_maps[n].getName()+"_"+ortho_maps[n].getLocalDateTime().toString().replace("T","_")+"_UTC";
}
ImageStack stack = ShowDoubleFloatArrays.makeStack(
multi,
wh[0],
wh[1],
map_names,
false);
ImagePlus imp = new ImagePlus(title, stack);
if (show_centers) {
PointRoi roi = new PointRoi();
for (int i = 0; i < centers.length; i++) {
roi.addPoint(centers[i][0],centers[i][1], i+1);
}
roi.setOptions("label");
imp.setRoi(roi);
}
return imp;
}
/**
* Rectify and render multiple images (as slices) matching vert_meters to
* their (vert_meters points) provided IMS coordinates
* @param show altitudes instead of thermal data
* @param maps array of the ortho images
* @param zoom_level zoom level (0 - 1pix=1cm, 1 - 1pix=0.5cm, -1 - 1pix=2cm
* @param wh null or int [2], will return {width, height}
* @param origin - null or double [2], will return {x0, y0} in pixels
* @param centers - null or double[maps.length][] - will return image centers coordinates
* @return
*/
public float [][] renderMulti (
boolean use_alt,
// OrthoMap [] maps,
int zoom_level,
int [] wh,
int [] origin, // maps[0] as a reference
double [][] centers){
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
int height = bounds[1][1] - bounds[1][0];
if (wh != null) {
wh[0] = width;
wh[1] = height;
}
if (origin != null) {
origin[0] = -bounds[0][0];
origin[1] = -bounds[1][0];
}
final float [][] fpixels = new float [ortho_maps.length][width * height];
for (int nmap = 0; nmap< ortho_maps.length; nmap++) {
final int fnmap = nmap;
Arrays.fill(fpixels[nmap], Float.NaN);
final double scale = 1.0/OrthoMap.getPixelSizeMeters(zoom_level);
final double src_scale = 1.0/OrthoMap.getPixelSizeMeters(ortho_maps[nmap].orig_zoom_level); // pix per meter
// metric bounds of the rectified image relative to its origin
double [][] mbounds = ortho_maps[nmap].getBoundsMeters(true);
double [] enu_offset = ortho_maps[0].enuOffsetTo(ortho_maps[nmap]);
final double [] scaled_out_center = { // xy center to apply affine to
-bounds[0][0] + scale * enu_offset[0],
-bounds[1][0] - scale * enu_offset[1]};
if (centers != null) {
centers[nmap] = scaled_out_center;
}
final int [][] obounds = new int [2][2]; // output (rectified, combined) image bounds, relative to thje top-left
for (int n = 0; n< 2; n++) {
obounds[n][0] = (int) Math.floor(scaled_out_center[n] + scale*mbounds[n][0]);
obounds[n][1] = (int) Math.ceil (scaled_out_center[n] + scale*mbounds[n][1]);
}
// Output window size
final int ownd_width = obounds[0][1] - obounds[0][0];
final int ownd_height = obounds[1][1] - obounds[1][0];
final int ownd_len = ownd_width * ownd_height;
double [][] src_bounds=ortho_maps[nmap].getBoundsMeters (true);
final double [] src_center = {-src_bounds[0][0],-src_bounds[1][0]}; // x,y center offset in the source image
final double [][] affine = ortho_maps[nmap].affine;
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;
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 nPix = ai.getAndIncrement(); nPix < ownd_len; nPix = ai.getAndIncrement()) {
int opX = nPix % ownd_width + obounds[0][0]; // absolute output pX, pY
int opY = nPix / ownd_width + obounds[1][0];
double dX = (opX - scaled_out_center[0]) /scale; // in original image scale
double dY = (opY - scaled_out_center[1]) /scale;
double [] xy_src = { // pixels of the source image
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 ((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]) };
double [] kxy = {xy_src[0]-ixy_src[0], xy_src[1]-ixy_src[1]};
int indx00 = ixy_src[0] + ixy_src[1] * src_width;
double d00 = src_img[indx00];
if (!Double.isNaN(d00)) {
double d01 = src_img[indx00 + 1];
double d10 = src_img[indx00 + src_width];
double d11 = src_img[indx00 + src_width + 1];
double d = d00*(1.0 - kxy[0])*(1.0 - kxy[1])+
d01* kxy[0] *(1.0 - kxy[1])+
d10*(1.0 - kxy[0])* kxy[1]+
d11* kxy[0] * kxy[1];
fpixels[fnmap][opX + opY*width] = (float) d;
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
}
return fpixels;
}
public float [][] getPaddedPairGPU(
String [] spair,
int zoom_lev){
int [] pair = new int [spair.length];
for (int i = 0; i < pair.length; i++) {
pair[i] = map_index_string.get(spair[i]);
}
return getPaddedPairGPU(
pair, // int [] pair,
zoom_lev); // int zoom_lev,
}
private float [][] getPaddedPairGPU(
int [] pair,
int zoom_lev){
float [][] gpu_pair_img = new float [2][];
for (int n = 0; n < pair.length; n++) {
gpu_pair_img[n] = ortho_maps[pair[n]].getPaddedGPU (
zoom_lev); // int zoom_level,
}
return gpu_pair_img;
}
public double [][] correlateOrthoPair(
CLTParameters clt_parameters,
String first_name,
String second_name,
int zoom_lev,
double [] offset_xy_second, // on top of affine and GPS
final int debugLevel){
int first_index = map_index_string.get(first_name);
int second_index = map_index_string.get(second_name);
return correlateOrthoPair(
clt_parameters, // CLTParameters clt_parameters,
first_index, // int first_index,
second_index, // int second_index,
zoom_lev, // int zoom_lev,
offset_xy_second, // double [] offset_xy_second, // on top of affine and GPS
debugLevel); // final int debugLevel)
}
private double [][] correlateOrthoPair(
CLTParameters clt_parameters,
int first_index,
int second_index,
int zoom_lev,
double [] offset_xy_second, // on top of affine and GPS
final int debugLevel){
int [] gpu_pair = {first_index,second_index};
double [][][] bounds_out = new double [2][][];
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,
}
if (debugLevel > 1) {
String [] map_names = {ortho_maps[gpu_pair[0]].getName(),ortho_maps[gpu_pair[1]].getName()};
ShowDoubleFloatArrays.showArrays(
gpu_pair_img,
OrthoMap.gpu_width,
OrthoMap.gpu_height,
true,
"gpu_pair-zoom"+zoom_lev+"-"+ortho_maps[gpu_pair[0]].getName()+"-"+ortho_maps[gpu_pair[1]].getName(),
map_names);
}
return null;
}
public static OrthoMapsCollection readOrthoMapsCollection (
String path) throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream(path);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
OrthoMapsCollection orthoMapsCollection = (OrthoMapsCollection) objectInputStream.readObject();
objectInputStream.close();
return orthoMapsCollection;
}
public void writeOrthoMapsCollection (String path) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(path);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(this);
objectOutputStream.flush();
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)
}
map_index_string
*/
}
package com.elphel.imagej.orthomosaic;
import java.io.IOException;
import java.io.ObjectInputStream;
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];
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
for (int i = 0; i < jtj.length; i++) {
for (int j = i; j < jtj[i].length; j++) {
oos.writeObject(jtj[i][j]);
}
}
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
for (int i = 0; i < jtj.length; i++) {
for (int j = i; j < jtj[i].length; j++) {
jtj[i][j] = (Double) ois.readObject();
if (j > i) {
jtj[j][i] = jtj[i][j];
}
}
}
}
//private void readObjectNoData() throws ObjectStreamException; // used to modify default values
}
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