Commit f97f3155 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Implemented OrthoMapCollection class and possibility to save maps state

w/o images
parent 624f1144
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ import com.elphel.imagej.ims.EventLogger;
import com.elphel.imagej.ims.Imx5;
import com.elphel.imagej.jp4.JP46_Reader_camera;
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.readers.ChangeImageResolution;
import com.elphel.imagej.readers.DumpImageMetadata;
@@ -5732,7 +5732,7 @@ public class Eyesis_Correction implements PlugIn, ActionListener {
				IJ.showMessage("Error", "No images selected");
				return;
			}
			ComboMap.testVideo(imp_sel);
			OrthoMap.testVideo(imp_sel);
		}
		
	}
+53 −33
Original line number Diff line number Diff line
@@ -45,7 +45,8 @@ public class ComboMatch {
		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

		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}}};
		int gpu_width=  clt_parameters.imp.rln_gpu_width; // 3008;
@@ -53,8 +54,13 @@ public class ComboMatch {
		int zoom_lev = -4; // 0; // +1 - zoom in twice, -1 - zoom out twice
		boolean use_alt = false;
		boolean show_centers = true;
		boolean use_saved_collection = false;
		boolean save_collection = true;
		GenericJTabbedDialog gd = new GenericJTabbedDialog("Set image pair",1200,800);
		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++) {
//			gd.addStringField ("Image path "+n,  image_paths_pre[n], 180, "Image "+n+" full path w/o ext");		
//		}
@@ -81,11 +87,11 @@ public class ComboMatch {
		gd.showDialog();
		if (gd.wasCanceled()) return false;
		files_list_path = gd.getNextString();
//		for (int n = 0; n < image_paths_pre.length; n++) {
//			image_paths_pre[n] = gd.getNextString();
//		}		
//		image_paths_pre[0] = gd.getNextString();
//		image_paths_pre[1] = gd.getNextString();
		
		orthoMapsCollection_path = gd.getNextString();
		use_saved_collection =     gd.getNextBoolean();
		save_collection =          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();
@@ -98,58 +104,71 @@ public class ComboMatch {
		gpu_width =           (int) gd.getNextNumber();
		gpu_height =          (int) gd.getNextNumber();

		ComboMap.setGPUWidthHeight(gpu_width,gpu_height);
		OrthoMap.setGPUWidthHeight(gpu_width,gpu_height);
		
		show_centers =              gd.getNextBoolean();
		use_alt =                   gd.getNextBoolean();
//		ComboMap[] combo_maps = ComboMap.initializeComboMaps(
//				full_paths); // String [] image_paths);
		ComboMap[] combo_maps = ComboMap.initializeComboMaps(
				files_list_path); // String [] image_paths);
		String [] map_names = ComboMap.getNames(combo_maps);
		
		OrthoMapsCollection maps_collection=null;
		if (use_saved_collection) {
			try {
				maps_collection = OrthoMapsCollection.readOrthoMapsCollection (orthoMapsCollection_path);
			} 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];
		ImagePlus imp_img = 	ComboMap.renderMulti (
		ImagePlus imp_img = 	maps_collection.renderMulti (
				"multi_"+zoom_lev, // String      title,
				false,             // boolean     use_alt,
				show_centers,      // boolean     show_centers,
				combo_maps,        // ComboMap [] maps,
				zoom_lev,          // int         zoom_level,
				origin);           // int []      origin){
		imp_img.show();
		ImagePlus imp_alt = null;
        if (use_alt) {
        	imp_alt =ComboMap.renderMulti (
        	imp_alt =maps_collection.renderMulti (
    				"multi_alt_"+zoom_lev, // String      title,
    				true,             // boolean     use_alt,
    				show_centers,      // boolean     show_centers,
    				combo_maps,        // ComboMap [] maps,
    				zoom_lev,          // int         zoom_level,
    				origin);           // int []      origin){
    		imp_alt.show();
        }
        // which pair to compare
		int [] gpu_pair = {1,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)
		}
		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+"-"+combo_maps[gpu_pair[0]].getName()+"-"+combo_maps[gpu_pair[1]].getName(),
        		map_names);
        		"gpu_pair-zoom"+zoom_lev+"-"+gpu_spair[0]+"-"+gpu_spair[1],
        		gpu_spair);
        if (save_collection) {
        	try {
				maps_collection.writeOrthoMapsCollection(orthoMapsCollection_path);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
        
        
		if (debugLevel <1000) {
			return true;
		}
		/* */
		OrthoMap [] ortho_maps = maps_collection.getMaps(); // just temporarily

		int [] widths = new int[imp_src.length];
		int [] heights = new int[imp_src.length];
		for (int n = 0; n < imp_src.length; n++) { 
@@ -178,8 +197,8 @@ public class ComboMatch {
		}
		/* */
		if (show_centers) {
			for (int n = 0; n < combo_maps.length; n++) {
				combo_maps[n].getOriginalImage(true);
			for (int n = 0; n < ortho_maps.length; n++) {
				ortho_maps[n].getOriginalImage(true);
			}
		}
		/*
@@ -187,11 +206,12 @@ public class ComboMatch {
			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");
			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_shift = {enu_diff[0]/pix_size1, -enu_diff[1]/pix_size1}; // E->X, N->-Y
+414 −0
Original line number Diff line number Diff line
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
	 */
	
	
}
+36 −0
Original line number Diff line number Diff line
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
}