Commit 590d3aba authored by Andrey Filippov's avatar Andrey Filippov

More untested mapping code, bug fix in variable DSI average disparity

parent 98e487e9
......@@ -509,6 +509,8 @@ public class CLTParameters {
public int gmap_crop_extra = 20;
public int [] gmap_tex_pals = {0,1,2};
public boolean gmap_gnss_vert = true; // reference ll to the point below (false - top left corner)
// use Tiff XPosition, YPosition to specify offset to the vertical in the image
public boolean gmap_save_alt = true; // save height map (meters ASL)
public boolean gmap_save_tiff32 = true; // save float TIFF (NaN for transparency) with geo metadata (top left corner)
public boolean gmap_save_tiff = true; // save transparent TIFF with geo metadata (top left corner)
......@@ -1687,6 +1689,7 @@ public class CLTParameters {
properties.setProperty(prefix+"gmap_crop_extra", this.gmap_crop_extra+""); // int
properties.setProperty(prefix+"gmap_tex_pals", CLTParameters.arr_to_str(this.gmap_tex_pals)); // int[]
properties.setProperty(prefix+"gmap_gnss_vert", this.gmap_gnss_vert+""); // boolean
properties.setProperty(prefix+"gmap_save_alt", this.gmap_save_alt+""); // boolean
properties.setProperty(prefix+"gmap_save_tiff32", this.gmap_save_tiff32+""); // boolean
properties.setProperty(prefix+"gmap_save_tiff", this.gmap_save_tiff+""); // boolean
......@@ -2737,6 +2740,7 @@ public class CLTParameters {
if (properties.getProperty(prefix+"gmap_crop_extra")!=null) this.gmap_crop_extra=Integer.parseInt(properties.getProperty(prefix+ "gmap_crop_extra"));// int
if (properties.getProperty(prefix+"gmap_tex_pals")!=null) this.gmap_tex_pals=CLTParameters.str_to_iarr(properties.getProperty(prefix+"gmap_tex_pals"));
if (properties.getProperty(prefix+"gmap_gnss_vert")!=null) this.gmap_gnss_vert=Boolean.parseBoolean(properties.getProperty(prefix+ "gmap_gnss_vert"));
if (properties.getProperty(prefix+"gmap_save_alt")!=null) this.gmap_save_alt=Boolean.parseBoolean(properties.getProperty(prefix+ "gmap_save_alt"));
if (properties.getProperty(prefix+"gmap_save_tiff32")!=null) this.gmap_save_tiff32=Boolean.parseBoolean(properties.getProperty(prefix+ "gmap_save_tiff32"));
if (properties.getProperty(prefix+"gmap_save_tiff")!=null) this.gmap_save_tiff=Boolean.parseBoolean(properties.getProperty(prefix+ "gmap_save_tiff"));
......@@ -4055,6 +4059,8 @@ public class CLTParameters {
gd.addStringField ("LWIR palettes to render the maps", CLTParameters.arr_to_str(this.gmap_tex_pals), 40,
"Enter space-separated list of the palette numbers, such as, such as '0 1 2'");
gd.addCheckbox ("Reference GNSS LLA to below the camera", this.gmap_gnss_vert, // true; // enable change FG pixel to opaque from transparent
"If false - to the top left image corner(NW). Use Tiff XPosition, YPosition for the offset to the vertical.");
gd.addCheckbox ("Save height map (meters ASL)", this.gmap_save_alt, // true; // enable change FG pixel to opaque from transparent
"Save height map (meters Above Seal Level) as a floating-point single-slice TIFF (NAN for transparency).");
gd.addCheckbox ("Save float Tiff with transparency and Geo",this.gmap_save_tiff32, // true; // enable change FG pixel to opaque from transparent
......@@ -5315,6 +5321,7 @@ public class CLTParameters {
this.gmap_crop_extra= (int) gd.getNextNumber();
this.gmap_tex_pals = CLTParameters.str_to_iarr(gd.getNextString());
this.gmap_gnss_vert= gd.getNextBoolean();
this.gmap_save_alt= gd.getNextBoolean();
this.gmap_save_tiff32= gd.getNextBoolean();
this.gmap_save_tiff= gd.getNextBoolean();
......
......@@ -112,6 +112,7 @@ import com.elphel.imagej.lwir.LwirReader;
import com.elphel.imagej.orthomosaic.ComboMatch;
import com.elphel.imagej.readers.ChangeImageResolution;
import com.elphel.imagej.readers.DumpImageMetadata;
import com.elphel.imagej.readers.ElphelTiffReader;
import com.elphel.imagej.readers.EyesisTiff;
import com.elphel.imagej.tensorflow.TensorflowInferModel;
import com.elphel.imagej.tileprocessor.Clt1d;
......@@ -844,6 +845,8 @@ public class Eyesis_Correction implements PlugIn, ActionListener {
addButton("Show mice", panelLWIRWorld, color_process);
addButton("Set pair", panelLWIRWorld, color_process);
addButton("Warp pair", panelLWIRWorld, color_process);
addButton("Read Tiff", panelLWIRWorld, color_process);
addButton("Set pair GPS", panelLWIRWorld, color_process);
plugInFrame.add(panelLWIRWorld);
}
......@@ -5683,8 +5686,165 @@ public class Eyesis_Correction implements PlugIn, ActionListener {
DEBUG_LEVEL = MASTER_DEBUG_LEVEL;
EYESIS_CORRECTIONS.setDebug(DEBUG_LEVEL);
ComboMatch.testPair();
} else if (label.equals("Read Tiff")) {
DEBUG_LEVEL = MASTER_DEBUG_LEVEL;
EYESIS_CORRECTIONS.setDebug(DEBUG_LEVEL);
ImagePlus imp_sel = WindowManager.getCurrentImage();
if (imp_sel == null) {
IJ.showMessage("Error", "No images selected");
return;
}
String orig_path = imp_sel.getOriginalFileInfo().getFilePath();
try {
ElphelTiffReader.getTiffMeta(orig_path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// ComboMatch.testReadTiff();
} else if (label.equals("Set pair GPS")) {
DEBUG_LEVEL = MASTER_DEBUG_LEVEL;
EYESIS_CORRECTIONS.setDebug(DEBUG_LEVEL);
/*
boolean run_pre = true; // false;
if (run_pre) {
String path = loadProperties(null, CORRECTION_PARAMETERS.resultsDirectory, true, PROPERTIES);
if (path != null) {
getAllProperties(PROPERTIES);
if (DEBUG_LEVEL > -3)
System.out.println("Configuration parameters are restored from " + path);
} else {
if (DEBUG_LEVEL > -10)
System.out.println("Failed to restore configuration parameters");
return;
}
}
*/
if (GPU_TILE_PROCESSOR == null) {
try {
GPU_TILE_PROCESSOR = new GPUTileProcessor(CORRECTION_PARAMETERS.tile_processor_gpu);
} catch (Exception e) {
System.out.println("Failed to initialize GPU class");
// TODO Auto-generated catch block
e.printStackTrace();
return;
} // final int debugLevel);
}
/*
if (!run_pre) {
String path = loadProperties(null, CORRECTION_PARAMETERS.resultsDirectory, true, PROPERTIES);
if (path != null) {
getAllProperties(PROPERTIES);
if (DEBUG_LEVEL > -3)
System.out.println("Configuration parameters are restored from " + path);
} else {
if (DEBUG_LEVEL > -10)
System.out.println("Failed to restore configuration parameters");
return;
}
}
*/
//////////////////////
// Temporarily initialize on scene GPU
boolean init_scene = false; // true;
if (init_scene) {
debugInitOneScene();
}
ComboMatch.openTestPairGps(
CLT_PARAMETERS, // CLTParameters clt_parameters,
GPU_TILE_PROCESSOR,
DEBUG_LEVEL);
}
}
public boolean debugInitOneScene() {
DEBUG_LEVEL = MASTER_DEBUG_LEVEL;
if (EYESIS_CORRECTIONS_AUX == null) {
EYESIS_CORRECTIONS_AUX = new EyesisCorrections(SYNC_COMMAND.stopRequested,
CORRECTION_PARAMETERS.getAux());
}
EYESIS_CORRECTIONS_AUX.setDebug(DEBUG_LEVEL);
if (QUAD_CLT_AUX == null) {
QUAD_CLT_AUX = new QuadCLT(QuadCLT.PREFIX_AUX, PROPERTIES, EYESIS_CORRECTIONS_AUX,
CORRECTION_PARAMETERS.getAux());
if (DEBUG_LEVEL > 0) {
System.out.println("Created new QuadCLT AUX instance, will need to read CLT kernels");
}
}
String configPath = getSaveCongigPath();
if (configPath.equals("ABORT"))
return false;
EYESIS_CORRECTIONS_AUX.initSensorFiles(DEBUG_LEVEL, false, // boolean missing_ok,
true, // boolean all_sensors, Otherwise - Eyesis
COLOR_PROC_PARAMETERS_AUX.correct_vignetting); // boolean correct_vignetting
int numChannels = EYESIS_CORRECTIONS_AUX.getNumChannels();
// NONLIN_PARAMETERS.modifyNumChannels(numChannels);
CHANNEL_GAINS_PARAMETERS_AUX.modifyNumChannels(numChannels);
if (!QUAD_CLT_AUX.CLTKernelsAvailable()) {
if (DEBUG_LEVEL > 0) {
System.out.println("Reading AUX CLT kernels");
}
QUAD_CLT_AUX.readCLTKernels(CLT_PARAMETERS, THREADS_MAX, UPDATE_STATUS, // update status info
DEBUG_LEVEL);
if (DEBUG_LEVEL > 1) {
QUAD_CLT_AUX.showCLTKernels(THREADS_MAX, UPDATE_STATUS, // update status info
DEBUG_LEVEL);
}
}
if (!QUAD_CLT_AUX.geometryCorrectionAvailable()) {
if (DEBUG_LEVEL > 0) {
System.out.println("Calculating geometryCorrection");
}
if (!QUAD_CLT_AUX.initGeometryCorrection(DEBUG_LEVEL + 2)) {
return false;
}
}
// After kernels and GeometryCorrection
if (CLT_PARAMETERS.useGPU()) { // only init GPU instances if it is used
if (GPU_TILE_PROCESSOR == null) {
try {
GPU_TILE_PROCESSOR = new GPUTileProcessor(CORRECTION_PARAMETERS.tile_processor_gpu);
} catch (Exception e) {
System.out.println("Failed to initialize GPU class");
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} // final int debugLevel);
}
/*
* if (CLT_PARAMETERS.useGPU(false) && (QUAD_CLT != null) && (GPU_QUAD == null))
* { // if GPU main is needed try { GPU_QUAD = new GpuQuad( GPU_TILE_PROCESSOR,
* QUAD_CLT); } catch (Exception e) {
* System.out.println("Failed to initialize GpuQuad class"); // TODO
* Auto-generated catch block e.printStackTrace(); return; // false; } //final
* int debugLevel); QUAD_CLT.setGPU(GPU_QUAD); }
*/
if (CLT_PARAMETERS.useGPU(true) && (QUAD_CLT_AUX != null) && (GPU_QUAD_AUX == null)) { // if GPU AUX is
try {
GPU_QUAD_AUX = new GpuQuad(//
GPU_TILE_PROCESSOR, QUAD_CLT_AUX, 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; // false;
} // final int debugLevel);
QUAD_CLT_AUX.setGPU(GPU_QUAD_AUX);
}
}
return true;
}
/* ======================================================================== */
public boolean editIMU(boolean aux) {
......
This diff is collapsed.
package com.elphel.imagej.orthomosaic;
public class FloatImageData {
public int width;
public int height;
public int zoom_lev;
public double [] vert = new double[2]; // x,y offset (in meters) of the point under the camera
public float[] data;
public FloatImageData (
int width,
int height,
int zoom_lev,
double [] vert, // x,y pixel offset of the point under the camera
float[] data) {
this.width = width;
this.height = height;
this.zoom_lev = zoom_lev;
this.vert = vert.clone();
this.data = data;
}
public static int getZoomLevel(
double pix_in_meters) {
return getZoomLevel (pix_in_meters, null, null);
}
public static boolean isZoomValid(double pix_in_meters) {
boolean [] is_zoom_valid = new boolean[1];
getZoomLevel(pix_in_meters,is_zoom_valid, null);
return is_zoom_valid[0];
}
public static double needZoomIn(double pix_in_meters) {
double [] extra_zoom = new double[1];
getZoomLevel(pix_in_meters,null, extra_zoom);
return extra_zoom[0];
}
/**
* Find scale level (0: 1pix/cm, 1 - 2pix/cm, -1 - 0.5 pix/cm) from pixel size in meters
* If scale does not match, provide false in optional valid_zoom[0]
* zoom_in_extra
* @param pix_size_in_meters pixel size in meters (e.g. 0.02 means 2cm/pix)
* @param valid_zoom if provided boolean[1] will return true for valid scale
* @param zoom_in_extra enlarge (1.0x..2.0x) (reduce pixel size) to get to the standard scale
* @return zoom level (the higher - the more detailed) 0: - 1cm/pix,-1: 2cm/pix, 1: 0.5 cm/pix
*/
public static int getZoomLevel(
double pix_size_in_meters, // pixel size in meters
boolean [] valid_zoom,
double [] zoom_in_extra) {
int zl = 0;
double e = 1E-6;
double pix_size_in_cm = 100 * pix_size_in_meters; // pixel size in cm
boolean vz = true;
double ze = 1.0;
if (pix_size_in_cm > (1.0-e)) { // low resolution, pixel size > 1cm
zl++;
while (pix_size_in_cm > (1.0-e)) {
zl--;
pix_size_in_cm /= 2;
} // exits with (1-e) >= pix_in_cm > 0.5 - e/2
vz = pix_size_in_cm < (0.5+e);
if (!vz) {
ze = 2.0 * pix_size_in_cm;
}
} else { // high resolution, pixel size < 1
zl--;
while (pix_size_in_cm <= (1.0-e)) {
zl++;
pix_size_in_cm *= 2;
}// exits with (2-2*e) >= pix_in_cm > (1-e)
vz = pix_size_in_cm > (2.0 - e);
if (!vz) {
ze = pix_size_in_cm;
}
}
if (valid_zoom != null) {
valid_zoom[0] = vz;
}
if (zoom_in_extra != null) {
zoom_in_extra[0] = ze;
}
return zl;
}
}
......@@ -28,7 +28,8 @@ import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.plugins.tiff.TIFFDirectory;
import javax.imageio.plugins.tiff.TIFFField;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
......@@ -136,6 +137,9 @@ public class DumpImageMetadata
IIOMetadata metadata = reader.getImageMetadata(0);
indent(1);
System.out.println("Image metadata");
TIFFDirectory ifd = TIFFDirectory.createFromMetadata(metadata);
TIFFField [] tf = ifd.getTIFFFields();
// TIFFField f1 = ifd.get​TIFFField(286);
dumpMetadata(metadata);
IIOMetadata smetadata = reader.getStreamMetadata();
if (smetadata != null)
......
......@@ -32,9 +32,22 @@ import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.tiff.TIFFDirectory;
import javax.imageio.plugins.tiff.TIFFField;
import javax.imageio.plugins.tiff.TIFFTag;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.plugins.tiff.ExifGPSTagSet;
import org.apache.commons.compress.utils.IOUtils;
import org.joda.time.DateTime;
......@@ -588,4 +601,170 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
return comment != null && comment.startsWith("ImageJ=");
}
private static String getFileExtension(File file)
{
String fileName = file.getName();
int lastDot = fileName.lastIndexOf('.');
return fileName.substring(lastDot + 1);
}
public static Properties getTiffMeta(String path) throws IOException {
Properties properties = new Properties();
File file = new File(path);
String extension = getFileExtension(file);
// System.out.println("\nProcessing " + file.getName() + ":\n");
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(extension);
ImageInputStream stream = null;
while (readers.hasNext())
{
ImageReader reader = readers.next();
stream = ImageIO.createImageInputStream(file);
reader.setInput(stream, true);
IIOMetadata metadata = reader.getImageMetadata(0);
TIFFDirectory ifd = TIFFDirectory.createFromMetadata(metadata);
TIFFField [] tfs = ifd.getTIFFFields();
for (TIFFField tf: tfs) {
parseField(tf, properties);
}
stream.close();
}
// Set<String> pnames = properties.stringPropertyNames();
// for (String pn:pnames) {
// System.out.println(pn+": "+properties.getProperty(pn));
// }
return properties;
}
private static void parseField(TIFFField tf, Properties properties) {
if (tf.hasDirectory()) {
TIFFField [] stfs = tf.getDirectory().getTIFFFields();
if ("GPSInfoIFDPointer".equals(tf.getTag().getName())) {
TIFFDirectory gifd = tf.getDirectory();
long [][] lat = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_LATITUDE).getAsRationals();
double dlat = 1.0*lat[0][0]/lat[0][1]+1.0/60*lat[1][0]/lat[1][1]+1.0/3600*lat[2][0]/lat[2][1];
String lat_ref = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_LATITUDE_REF).getValueAsString(0);
if (!lat_ref.equals("N")) {
dlat =- dlat;
}
long [][] lon = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_LONGITUDE).getAsRationals();
double dlon = 1.0*lon[0][0]/lon[0][1]+1.0/60*lon[1][0]/lon[1][1]+1.0/3600*lon[2][0]/lon[2][1];
String lon_ref = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_LONGITUDE_REF).getValueAsString(0);
if (!lon_ref.equals("E")) {
dlon =- dlon;
}
long [] alt = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_ALTITUDE).getAsRational(0);
double dalt = 1.0 *alt[0]/alt[1];
String alt_ref = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_ALTITUDE_REF).getValueAsString(0);
if (!alt_ref.equals("0")) {
dalt =- dalt;
}
String [] date_stamp = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_DATE_STAMP).getValueAsString(0).split(":");
long [][] gts = gifd.getTIFFField(ExifGPSTagSet.TAG_GPS_TIME_STAMP).getAsRationals();
double secs = 3600.0*gts[0][0]/gts[0][1]+60.0*gts[1][0]/gts[1][1]+1.0*gts[2][0]/gts[2][1];
int isecs = (int) Math.floor(secs);
int nanos = (int) Math.round((secs - isecs)*1E9);
LocalDateTime dt = LocalDateTime.of(
Integer.parseInt(date_stamp[0]), // year
Integer.parseInt(date_stamp[1]), // month
Integer.parseInt(date_stamp[2]), // day
0,0,0);
dt = dt.plusSeconds(isecs);
dt = dt.plusNanos(nanos);
properties.setProperty ("GPSLatitude", ""+dlat);
properties.setProperty ("GPSLongitude", ""+dlon);
properties.setProperty ("GPSAltitude", ""+dalt);
properties.setProperty ("GPSDateTime", ""+dt.toString());
} else {
for (TIFFField stf: stfs) {
parseField(stf, properties);
}
}
} else { // will not parse long tags (>3)
if (tf.getCount() == 1) {
switch (tf.getType()) {
case TIFFTag.TIFF_RATIONAL:
{
long [] ndn = tf.getAsRational(0);
double v = 1.0*ndn[0]/ndn[1];
properties.setProperty(tf.getTag().getName(), ""+v);
}
break;
case TIFFTag.TIFF_SRATIONAL:
{
int [] ndn = tf.getAsSRational(0);
double v = 1.0*ndn[0]/ndn[1];
properties.setProperty(tf.getTag().getName(), ""+v);
}
break;
case TIFFTag.TIFF_ASCII:
case TIFFTag.TIFF_BYTE:
case TIFFTag.TIFF_DOUBLE:
case TIFFTag.TIFF_FLOAT:
case TIFFTag.TIFF_LONG:
case TIFFTag.TIFF_SHORT:
case TIFFTag.TIFF_SBYTE:
case TIFFTag.TIFF_SLONG:
case TIFFTag.TIFF_SSHORT:
properties.setProperty(tf.getTag().getName(), tf.getValueAsString(0));
break;
default:
System.out.println("not processed: "+tf.getTag().getName());
}
}
}
}
public static double [] getLLA(Properties properties) {
double [] lla = new double [3];
lla[0] = Double.parseDouble(properties.getProperty("GPSLatitude"));
lla[1] = Double.parseDouble(properties.getProperty("GPSLongitude"));
lla[2] = Double.parseDouble(properties.getProperty("GPSAltitude"));
return lla;
}
public static LocalDateTime getLocalDateTime(Properties properties) {
LocalDateTime dt = LocalDateTime.parse(properties.getProperty("GPSDateTime"));
return dt;
}
public static double [] getPixelSize(Properties properties) {
int res_unit = Integer.parseInt(properties.getProperty("ResolutionUnit"));
double unit_size = 0;
switch(res_unit) {
case 2: unit_size = 0.0254; break;
case 3: unit_size = 0.01; break;
default:
System.out.println("Wrong ResolutionUnit="+res_unit);
return null;
}
double [] xy_pixel_in_meters = new double[2];
xy_pixel_in_meters[0] = unit_size/Double.parseDouble(properties.getProperty("XResolution"));
xy_pixel_in_meters[1] = unit_size/Double.parseDouble(properties.getProperty("YResolution"));
return xy_pixel_in_meters;
}
public static double [] getXYOffsetMeters(Properties properties) {
int res_unit = Integer.parseInt(properties.getProperty("ResolutionUnit"));
double unit_size = 0;
switch(res_unit) {
case 2: unit_size = 0.0254; break;
case 3: unit_size = 0.01; break;
default:
System.out.println("Wrong ResolutionUnit="+res_unit);
return null;
}
double [] xy_offset_meters = new double[2];
xy_offset_meters[0] = unit_size * Double.parseDouble(properties.getProperty("XPosition"));
xy_offset_meters[1] = unit_size * Double.parseDouble(properties.getProperty("YPosition"));
return xy_offset_meters;
}
public static double [] getXYOffsetPixels(Properties properties) {
double [] xy_offset_pixels = new double[2];
xy_offset_pixels[0] = Double.parseDouble(properties.getProperty("XPosition")) * Double.parseDouble(properties.getProperty("XResolution"));
xy_offset_pixels[1] = Double.parseDouble(properties.getProperty("YPosition")) * Double.parseDouble(properties.getProperty("YResolution"));
return xy_offset_pixels;
}
}
......@@ -79,6 +79,7 @@ public class ElphelTiffWriter {
ImagePlus imp,
String path, // full path to save image
double [] lla, // latitude, longitude, altitude (or null)
double [] xy_center, // X,Y of top left to vertical (negative meters)
LocalDateTime dt, // local date/time or null
double pix_in_meters, // resolution or Double.NaN
boolean imageJTags, // later will use it to encode from properties
......@@ -149,7 +150,7 @@ public class ElphelTiffWriter {
ifd.appendChild(gpsRootNode);
}
addResolutionMetadata(ifd,pix_in_meters,cm_dig_after); // NOP if pix_in_meters is NaN
addXYPositionMetadata(ifd,xy_center,3);
if (debugLevel > 0) {
System.out.println("\n=== ifd ===:");DumpImageMetadata.displayMetadataNode(ifd, 1);
System.out.println("\n=== root_new ===:"); DumpImageMetadata.displayMetadataNode(root_new, 1);
......@@ -447,6 +448,42 @@ public class ElphelTiffWriter {
ifd.appendChild(node_y_resolution);
}
private static void addXYPositionMetadata(
IIOMetadataNode ifd,
double [] xy_position, // both should be negative
int digits_after) {
if (xy_position == null) {
return;
}
double xpos = Math.max(-xy_position[0] * 100, 0); // cm, prevent negative rationals, use 0 if negative
double ypos = Math.max(-xy_position[1] * 100, 0); // cm, prevent negative rationals, use 0 if negative
int denom = 1;
for (int i = 0; i < digits_after; i++) denom *= 10;
int ixpos = (int) Math.round(denom * xpos); // XPosition numerator
int iypos = (int) Math.round(denom * ypos); // YPosition numerator
IIOMetadataNode node_x_position = new IIOMetadataNode(TIFF_FIELD_TAG);
node_x_position.setAttribute("number", "286");
node_x_position.setAttribute("name", "XPosition");
IIOMetadataNode node_x_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG);
IIOMetadataNode node_x_rational = new IIOMetadataNode(TIFF_RATIONAL_TAG);
node_x_rational.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, ixpos+"/"+denom);
node_x_rationals.appendChild(node_x_rational);
node_x_position.appendChild(node_x_rationals);
ifd.appendChild(node_x_position);
IIOMetadataNode node_y_position = new IIOMetadataNode(TIFF_FIELD_TAG);
node_y_position.setAttribute("number", "287");
node_y_position.setAttribute("name", "YPosition");
IIOMetadataNode node_y_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG);
IIOMetadataNode node_y_rational = new IIOMetadataNode(TIFF_RATIONAL_TAG);
node_y_rational.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, iypos+"/"+denom);
node_y_rationals.appendChild(node_y_rational);
node_y_position.appendChild(node_y_rationals);
ifd.appendChild(node_y_position);
}
/*
*
FileImageOutputStream outputStream = new FileImageOutputStream(outputFile);
......
......@@ -318,6 +318,7 @@ the type of pixel data in this file getPixelType()
imp,
path,
lla, // double [] lla, // latitude, longitude, altitude (or null)
null, //double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
pix_in_meters, //double pix_in_meters, // resolution or Double.NaN
imageJTags,
......@@ -337,6 +338,7 @@ the type of pixel data in this file getPixelType()
imp,
path,
lla, // double [] lla, // latitude, longitude, altitude (or null)
null, //double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
pix_in_meters, //double pix_in_meters, // resolution or Double.NaN
imageJTags,
......@@ -371,6 +373,7 @@ the type of pixel data in this file getPixelType()
imp_rgb,
path,
lla, // double [] lla, // latitude, longitude, altitude (or null)
null, //double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
pix_in_meters, //double pix_in_meters, // resolution or Double.NaN
imageJTags,
......
......@@ -353,7 +353,7 @@ public class Interscene {
}
invertInitialOrientation(
int n_unresolved = invertInitialOrientation(
clt_parameters, // final CLTParameters clt_parameters,
batch_mode, // final boolean batch_mode,
readjust, // final boolean readjust,
......@@ -381,6 +381,12 @@ public class Interscene {
System.out.println("Egomotion table saved to "+ego_path);
}
}
if (n_unresolved != 0) {
earliest_scene2 = -1;
System.out.println("invertInitialOrientation(). Consider more graceful bail out.");
start_ref_pointers[0] = start_ref_pointers1[0];
return earliest_scene2; // cent_index;
}
String cent_ts = quadCLTs[cent_index].getImageName();
......@@ -442,7 +448,8 @@ public class Interscene {
final int earliest_index, // only used with readjust
final int debugLevel
) {
//Readjust may be needed similar to compensateDSI() - top DSI was calculated for wider scene
// range and be offset from the single-scene DSI
if (debugLevel > -3) {
System.out.println("\ninvertInitialOrientation(): earliest_index "+earliest_index+", ref_index="+
ref_index+", last_index="+last_index+". readjust="+readjust+"\n");
......@@ -700,6 +707,12 @@ public class Interscene {
avg_z, // double avg_z,
last_index, // ref_index, // int ref_index, // >= earliest_scene
earliest_index); // int earliest_scene)
if (getFPNUnResolved(fpn_pairs) > 0) {
System.out.println("Unresolved FPN pairs:"+getFPNUnResolved(fpn_pairs));
return getFPNUnResolved(fpn_pairs);
}
// mitigating problem, that in the process of adjusting offset can fall below
// the minimum and coordinates will be NaN:
/*
......@@ -788,10 +801,6 @@ public class Interscene {
sb.append("Maximal RMSE= "+maximal_series_rms+"\n");
sb.append("------------------------\n\n");
quadCLTs[ref_index].saveStringInModelDirectory(sb.toString(), QuadCLT.ORIENTATION_LOGS_SUFFIX); // String suffix)
}
return 0;
}
......@@ -1408,7 +1417,13 @@ public class Interscene {
return fpn_pairs;
}
public static int getFPNUnResolved(int [][] pairs) {
int n = 0;
for (int [] pair:pairs) {
if (pair[1] < 0) n++;
}
return n;
}
public static int setInitialOrientations(
final CLTParameters clt_parameters,
......@@ -2170,77 +2185,6 @@ public class Interscene {
scenes_xyzatr_pull[nscene][0], // double [] new_xyz,
avg_z); // double avg_z
}
/*
double [][][] pimu_xyzatr = QuadCLT.integratePIMU(
clt_parameters, // final CLTParameters clt_parameters,
quadCLTs, // final QuadCLT[] quadCLTs,
ref_index, // final int ref_index,
null, // double [][][] dxyzatr,
earliest_scene, // final int early_index,
last_scene //(quadCLTs.length -1) // int last_index,
);
double [] rms = new double[5];
double [] quat = new double[4];
// int quat_lma_mode = QuaternionLma.MODE_COMBO_LOCAL; // 2; // 1; // 2;
int quat_lma_mode = QuaternionLma.MODE_XYZQ; // MODE_XYZ4Q3; // MODE_XYZQ; // MODE_XYZQ_LOCAL; // 4; // 3; // 2; // 1;
int debug_lev = debugLevel; // 3;
// double avg_z = quadCLTs[ref_index].getAverageZ(true); // in meters
double translation_weight = 1.0 / (avg_z + 1.0);
//scenes_xyzatr
double [][][] rotated_xyzatr = QuadCLT.rotateImsToCameraXYZ(
clt_parameters, // CLTParameters clt_parameters,
quat_lma_mode, // int quat_lma_mode,
avg_z, // double avg_height,
translation_weight, // double translation_weight,
quadCLTs, // QuadCLT[] quadCLTs,
scenes_xyzatr, // double [][][] xyzatr,
pimu_xyzatr, // double [][][] ims_xyzatr,
ref_index, // int ref_index,
earliest_scene, // int early_index,
last_scene, // int last_index,
rms, // double [] rms, // null or double[5];
quat, // double [] quaternion, // null or double[4]
debug_lev); // int debugLevel
if (rotated_xyzatr == null) {
System.out.println("reAdjustPairsLMAInterscene(): QuadCLT.rotateImsToCameraXYZ() failed");
} else {
System.out.println("reAdjustPairsLMAInterscene(): QuadCLT.rotateImsToCameraXYZ() finished in "+((int) rms[4])+ "iterations.");
System.out.println("rms="+rms[0]+" ("+rms[2]+"), pure rms="+rms[1]+" ("+rms[3]+")");
if (debug_lev > -3) {
Rotation rot = new Rotation(quat[0],quat[1],quat[2],quat[3], false); // no normalization - see if can be scaled
double [] angles = rot.getAngles(RotationOrder.YXZ, ErsCorrection.ROT_CONV);
double [] degrees = new double[3];
for (int i = 0; i < 3; i++) degrees[i]=angles[i]*180/Math.PI;
System.out.println("quat=["+quat[0]+", "+quat[1]+", "+quat[2]+", "+quat[3]+"]");
System.out.println("ATR(rad)=["+angles[0]+", "+angles[1]+", "+angles[2]+"]");
System.out.println("ATR(deg)=["+degrees[0]+", "+degrees[1]+", "+degrees[2]+"]");
}
// TODO: Use quat[] to update corrections of the IMU relative to the camera?
for (int nscene = earliest_scene; nscene <= last_scene; nscene++) if (scenes_xyzatr[nscene] != null) {
scenes_xyzatr_pull[nscene] = modifyATRtoXYZ(
scenes_xyzatr[nscene], // double [][] cur_xyzatr, // careful with Z - using the new one
rotated_xyzatr[nscene][0], // double [] new_xyz,
avg_z); // double avg_z
}
}
*/
// old version
/*
scenes_xyzatr_pull = QuadCLT.refineFromImsVelocities(
clt_parameters, // CLTParameters clt_parameters,
quadCLTs, // QuadCLT[] quadCLTs,
scenes_xyzatr, // double [][][] xyzatr,
dxyzatr_dt, // double [][][] dxyzatr,
ref_index, // int ref_index,
earliest_scene, // int early_index,
last_scene); // int last_index)
*/
}
if (copy_pull_current) { // freeze_xy_pull) {
System.out.println("reAdjustPairsLMAInterscene(): freezing X,Y to X,Y pull values");
......
......@@ -93,6 +93,19 @@ public class IntersceneMatchParameters {
public boolean sfm_show_corr_ind = false; // Show SfM for each pairs group, each refinement run
public boolean sfm_show_corr = false; // Show combined SfM for each refinement run
// rectilinear matching parameters
public int rln_gpu_width = 4096; // horizontal GPU image size (applied during init)
public int rln_gpu_height = 4096; // vertical GPU image size (applied during init)
public double rln_fat_zero = 10000.0; // phase correlation fat zero
public boolean rln_use_neibs = true; // calculate TD neighbors in phase correlation
public boolean rln_neibs_fill = false; // fill empty neighbors centers
public double rln_neib_radius = 2.9; // neighbors radius (tiles)
public double rln_cent_radius = 4.0; // centroids center radius
public int rln_n_recenter = 2; // when cosine window, re-center window these many times
public double rln_sngl_rstr = 0.3; // minimal single-tile phase correlation maximums relative to max str
public double rln_neib_rstr = 0.5; // minimal neighbors phase correlation maximums relative to max str
public double [] getImsMountATR() {
return new double [] {
ims_mount_atr[0] * Math.PI/180,
......@@ -655,6 +668,30 @@ public class IntersceneMatchParameters {
gd.addCheckbox ("Show SfM combo per run", this.sfm_show_corr,
"Show combined SfM for each refinement run.");
gd.addTab ("Mosaic", "Combining scene series into a composite map map");
gd.addNumericField("GPU window width", this.rln_gpu_width, 0,5,"pix",
"Horizontal GPU image size (applied during init.)");
gd.addNumericField("GPU window height", this.rln_gpu_height, 0,5,"pix",
"Vertical GPU image size (applied during init).");
gd.addMessage ("Rectilinear image matching");
gd.addNumericField("Phase correlation fat zero", this.rln_fat_zero, 5,8,"",
"Phase correlation fat zero - was set to 10000.");
gd.addCheckbox ("Calculate neighbors", this.rln_use_neibs,
"Calculate TD neighbors in phase correlation .");
gd.addCheckbox ("Fill empty neighbors centers", this.rln_neibs_fill,
"Fill empty neighbors centers (false - only non-empty).");
gd.addNumericField("Neighbors radius", this.rln_neib_radius, 5,8,"tiles",
"Use these tiles around the center one.");
gd.addNumericField("Centroids radius", this.rln_cent_radius, 5,8,"",
"Centroids radius for maximums isolation.");
gd.addNumericField("Recenter centroid", this.rln_n_recenter, 0,3,"",
"when cosine window, re-center window these many times");
gd.addNumericField("Minimal relative strength (single tiles)",this.rln_sngl_rstr, 5,8,"",
"Minimal single-tile phase correlation maximums relative to maximal strength.");
gd.addNumericField("Minimal relative strength (neighbors)", this.rln_neib_rstr, 5,8,"",
"Minimal neighbors phase correlation maximums relative to maximal strength.");
gd.addTab ("Scene Series", "Processing series of scenes and multi-series sets");
gd.addMessage ("Build series options");
......@@ -1483,6 +1520,17 @@ public class IntersceneMatchParameters {
this.sfm_show_corr_ind = gd.getNextBoolean();
this.sfm_show_corr = gd.getNextBoolean();
this.rln_gpu_width = (int) gd.getNextNumber();
this.rln_gpu_height = (int) gd.getNextNumber();
this.rln_fat_zero = gd.getNextNumber();
this.rln_use_neibs = gd.getNextBoolean();
this.rln_neibs_fill = gd.getNextBoolean();
this.rln_neib_radius = gd.getNextNumber();
this.rln_cent_radius = gd.getNextNumber();
this.rln_n_recenter = (int) gd.getNextNumber();
this.rln_sngl_rstr = gd.getNextNumber();
this.rln_neib_rstr = gd.getNextNumber();
this.center_reference = gd.getNextBoolean();
this.overlap_sequences = gd.getNextBoolean();
this.reset_photometric = gd.getNextBoolean();
......@@ -1932,6 +1980,17 @@ public class IntersceneMatchParameters {
properties.setProperty(prefix+"sfm_show_corr_ind", this.sfm_show_corr_ind + ""); // boolean
properties.setProperty(prefix+"sfm_show_corr", this.sfm_show_corr + ""); // boolean
properties.setProperty(prefix+"rln_gpu_width", this.rln_gpu_width+""); // int
properties.setProperty(prefix+"rln_gpu_height", this.rln_gpu_height+""); // int
properties.setProperty(prefix+"rln_fat_zero", this.rln_fat_zero +""); // double
properties.setProperty(prefix+"rln_use_neibs", this.rln_use_neibs + ""); // boolean
properties.setProperty(prefix+"rln_neibs_fill", this.rln_neibs_fill + ""); // boolean
properties.setProperty(prefix+"rln_neib_radius", this.rln_neib_radius +""); // double
properties.setProperty(prefix+"rln_cent_radius", this.rln_cent_radius +""); // double
properties.setProperty(prefix+"rln_n_recenter", this.rln_n_recenter+""); // int
properties.setProperty(prefix+"rln_sngl_rstr", this.rln_sngl_rstr +""); // double
properties.setProperty(prefix+"rln_neib_rstr", this.rln_neib_rstr +""); // double
properties.setProperty(prefix+"center_reference", this.center_reference + ""); // boolean
properties.setProperty(prefix+"overlap_sequences", this.overlap_sequences + ""); // boolean
properties.setProperty(prefix+"reset_photometric", this.reset_photometric + ""); // boolean
......@@ -2344,6 +2403,17 @@ public class IntersceneMatchParameters {
if (properties.getProperty(prefix+"sfm_show_corr_ind")!=null) this.sfm_show_corr_ind=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_show_corr_ind"));
if (properties.getProperty(prefix+"sfm_show_corr")!=null) this.sfm_show_corr=Boolean.parseBoolean(properties.getProperty(prefix+"sfm_show_corr"));
if (properties.getProperty(prefix+"rln_gpu_width")!=null) this.rln_gpu_width=Integer.parseInt(properties.getProperty(prefix+"rln_gpu_width"));
if (properties.getProperty(prefix+"rln_gpu_height")!=null) this.rln_gpu_height=Integer.parseInt(properties.getProperty(prefix+"rln_gpu_height"));
if (properties.getProperty(prefix+"rln_fat_zero")!=null) this.rln_fat_zero=Double.parseDouble(properties.getProperty(prefix+"rln_fat_zero"));
if (properties.getProperty(prefix+"rln_use_neibs")!=null) this.rln_use_neibs=Boolean.parseBoolean(properties.getProperty(prefix+"rln_use_neibs"));
if (properties.getProperty(prefix+"rln_neibs_fill")!=null) this.rln_neibs_fill=Boolean.parseBoolean(properties.getProperty(prefix+"rln_neibs_fill"));
if (properties.getProperty(prefix+"rln_neib_radius")!=null) this.rln_neib_radius=Double.parseDouble(properties.getProperty(prefix+"rln_neib_radius"));
if (properties.getProperty(prefix+"rln_cent_radius")!=null) this.rln_cent_radius=Double.parseDouble(properties.getProperty(prefix+"rln_cent_radius"));
if (properties.getProperty(prefix+"rln_n_recenter")!=null) this.rln_n_recenter=Integer.parseInt(properties.getProperty(prefix+"rln_n_recenter"));
if (properties.getProperty(prefix+"rln_sngl_rstr")!=null) this.rln_sngl_rstr=Double.parseDouble(properties.getProperty(prefix+"rln_sngl_rstr"));
if (properties.getProperty(prefix+"rln_neib_rstr")!=null) this.rln_neib_rstr=Double.parseDouble(properties.getProperty(prefix+"rln_neib_rstr"));
if (properties.getProperty(prefix+"center_reference")!=null) this.center_reference=Boolean.parseBoolean(properties.getProperty(prefix+"center_reference"));
if (properties.getProperty(prefix+"overlap_sequences")!=null) this.overlap_sequences=Boolean.parseBoolean(properties.getProperty(prefix+"overlap_sequences"));
if (properties.getProperty(prefix+"reset_photometric")!=null) this.reset_photometric=Boolean.parseBoolean(properties.getProperty(prefix+"reset_photometric"));
......@@ -2783,6 +2853,18 @@ public class IntersceneMatchParameters {
imp.sfm_show_corr_ind = this.sfm_show_corr_ind;
imp.sfm_show_corr = this.sfm_show_corr;
imp.rln_gpu_width = this.rln_gpu_width;
imp.rln_gpu_height = this.rln_gpu_height;
imp.rln_fat_zero = this.rln_fat_zero;
imp.rln_use_neibs = this.rln_use_neibs;
imp.rln_neibs_fill = this.rln_neibs_fill;
imp.rln_neib_radius = this.rln_neib_radius;
imp.rln_cent_radius = this.rln_cent_radius;
imp.rln_n_recenter = this.rln_n_recenter;
imp.rln_sngl_rstr = this.rln_sngl_rstr;
imp.rln_neib_rstr = this.rln_neib_rstr;
imp.center_reference = this.center_reference;
imp.overlap_sequences = this.overlap_sequences;
imp.reset_photometric = this.reset_photometric;
......
......@@ -5241,9 +5241,11 @@ public class OpticalFlow {
}
}
if (!done_sfm) { // first pass or sfm failed
boolean compensate_dsi = true;
// should skip scenes w/o orientation 06/29/2022
combo_dsn_final = intersceneExport( // result indexed by COMBO_DSN_TITLES, COMBO_DSN_INDX_***
clt_parameters, // CLTParameters clt_parameters,
compensate_dsi, // boolean compensate_dsi,
ref_index, // int ref_index,
quadCLTs, // QuadCLT [] scenes,
colorProcParameters, // ColorProcParameters colorProcParameters,
......@@ -5259,6 +5261,9 @@ public class OpticalFlow {
updateStatus, // final boolean updateStatus,
debugLevel); // int debugLevel)
}
}
quadCLTs[ref_index].inc_accum();
// save with updated num_accum
......@@ -8733,8 +8738,51 @@ public class OpticalFlow {
return imp_stack;
}
public static double compensateDSI(
CLTParameters clt_parameters,
boolean compensate_dsi, // false - do not apply, just calculate
QuadCLT ref_scene,
double [] disparity, // new disparity
int debug_level
) {
double [] disparity_dsi = ref_scene.getDLS()[1]; // null
double [] strength = ref_scene.getDLS()[2];
double sw=0,swd=0, swdi=0; // old, new-old
for (int i = 0; i < disparity.length; i++) {
if (!Double.isNaN(disparity[i]) && !Double.isNaN(disparity_dsi[i])) {
sw += strength[i];
swd += strength[i]*disparity_dsi[i];
swdi += strength[i]*disparity[i];
}
}
double avg_zold = ref_scene.getGeometryCorrection().getZFromDisparity(swd/sw);
double avg_znew = ref_scene.getGeometryCorrection().getZFromDisparity(swdi/sw);
double zdiff = avg_znew- avg_zold; // negative in the case
double scale =avg_znew/avg_zold;
System.out.println("Scale = "+scale);
if (compensate_dsi) {
ErsCorrection ers_reference = ref_scene.getErsCorrection();
String [] timestamps = ers_reference.getScenes();
for (String ts:timestamps) {
double [][] xyzatr = ers_reference.getSceneXYZATR(ts);
for (int i = 0; i < xyzatr[0].length; i++) {
xyzatr[0][i] *= scale;
}
// xyzatr[0][2] -= zdiff;
ers_reference.addScene(ts,xyzatr);
}
ref_scene.saveInterProperties( // save properties for interscene processing (extrinsics, ers, ...)
null, // String path, // full name with extension or w/o path to use x3d directory
debug_level+1);
}
return zdiff;
}
public static double [][] intersceneExport(
CLTParameters clt_parameters,
boolean compensate_dsi,
// ErsCorrection ers_reference,
int ref_index,
QuadCLT [] scenes_in,
......@@ -9506,7 +9554,19 @@ public class OpticalFlow {
//noise_sigma_level
String rslt_suffix = "-INTER-INTRA-HISTORIC";
rslt_suffix += (clt_parameters.correlate_lma?"-LMA":"-NOLMA");
// ref_index from the center is moved to the very end (indx_ref)
if (compensate_dsi && !scenes[ref_index].interDsiExists()) {
System.out.println("Will compensate pose Z as average disparity may change");
double z_corr = compensateDSI(
clt_parameters, // CLTParameters clt_parameters,
compensate_dsi, // boolean compensate_dsi, // false - do not apply, just calculate
scenes[indx_ref], // ref_index], // QuadCLT ref_scene,
combo_dsn_final[COMBO_DSN_INDX_LMA], // double [] disparity, // new disparity
debug_level); // int debug_level
System.out.println("Z correction = "+z_corr);
}
ref_scene.saveDoubleArrayInModelDirectory(
rslt_suffix, // String suffix,
refine_titles, // null, // String [] labels, // or null
......
......@@ -774,7 +774,6 @@ public class QuadCLT extends QuadCLTCPU {
"****************************************\n");
clt_parameters.z_correction = 0.0;
}
this.startTime=System.nanoTime();
String [] sourceFiles=correctionsParameters.getSourcePaths();
SetChannels [] set_channels=setChannels(debugLevel);
......@@ -2281,6 +2280,10 @@ public class QuadCLT extends QuadCLTCPU {
final int threadsMax, // maximal number of threads to launch
final boolean updateStatus,
final int debugLevel){
if (debugLevel >= 100) {
return null;
}
if (gpuQuad == null) {
System.out.println("GPU instance is not initialized, using CPU mode");
processCLTQuadCorrCPU(
......@@ -2392,6 +2395,9 @@ public class QuadCLT extends QuadCLTCPU {
clt_parameters.img_dtt.gpu_verify); // boolean verify
gpuQuad.execSetTilesOffsets(true); // prepare tiles offsets in GPU memory // calculate tile centers
gpuQuad.updateTasks( // just for testing, not needed
tp_tasks,
false); // boolean use_aux // while is it in class member? - just to be able to free
if (showCoord) {
double max_r_by_rdist_err = gpuQuad.maxRbyRDistErr();
......@@ -2403,6 +2409,24 @@ public class QuadCLT extends QuadCLTCPU {
gpuQuad.execConvertDirect(-1); // boolean erase_clt
float [][] fclt = gpuQuad.getCltData(
false);// boolean use_ref);
System.out.println("Got CLT ["+fclt.length+"]["+fclt[0].length+"]");
ShowDoubleFloatArrays.showArrays(
fclt,
gpuQuad.img_width*2,
gpuQuad.img_height*2,
true,
"fclt_raw"); // , dbg_titles);
float [][] pfclt = gpuQuad.presentCltData(false);
ShowDoubleFloatArrays.showArrays(
pfclt,
gpuQuad.img_width*2,
gpuQuad.img_height*2,
true,
"fclt"); // , dbg_titles);
int mcorr_sel = Correlation2d.corrSelEncode(clt_parameters.img_dtt, getNumSensors());
if (test_execCorr2D) {
......
......@@ -18046,6 +18046,7 @@ public class QuadCLTCPU {
final CLTParameters clt_parameters,
double [] data,
double [] lla, // latitude, longitude, altitude (or null)
double [] xy_center, // X,Y of top left to vertical (negative meters)
LocalDateTime dt, // local date/time or null
double pix_in_meters,
int width,
......@@ -18097,6 +18098,7 @@ public class QuadCLTCPU {
imp,
image_path,
lla, // double [] lla, // latitude, longitude, altitude (or null)
xy_center, //double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
pix_in_meters, //double pix_in_meters, // resolution or Double.NaN
false, // imageJTags,
......@@ -18109,6 +18111,7 @@ public class QuadCLTCPU {
final CLTParameters clt_parameters,
double [] data,
double [] lla, // latitude, longitude, altitude (or null)
double [] xy_center, // X,Y of top left to vertical (negative meters)
LocalDateTime dt, // local date/time or null
double pix_in_meters,
int width,
......@@ -18141,6 +18144,7 @@ public class QuadCLTCPU {
imp,
image_path,
lla, // double [] lla, // latitude, longitude, altitude (or null)
xy_center, //double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
pix_in_meters, //double pix_in_meters, // resolution or Double.NaN
false, // imageJTags,
......
......@@ -261,7 +261,7 @@ public class TDCorrTile {
* @param neib_too_strong discard stronger neighbors from accumulating.
* @param process_all process tiles even if the center tile is null. False - process only
* the tiles around non-null ones.
* @return
* @return tile-mapped array of the combined transform-domain 2D correlations.
*/
public static TDCorrTile [] calcNeibs(
TDCorrTile [] tiles,
......@@ -318,6 +318,64 @@ public class TDCorrTile {
return rslt;
}
/**
* Average neighbors in TD primarily for rectilinear image matching
* @param tiles tile-mapped array of transform-domain 2D correlations and tile weights
* needed for correct application of fat zero for phase correlation and
* transform to pixel domain.
* @param tilesX number of tiles in a scan row.
* @param radius radius (in X and Y direction) for averaging neighbors using cosine
* for weights. Radius corresponds to PI/2, accumulation happens for
* integer values
* @param process_all process tiles even if the center tile is null. False - process only
* the tiles around non-null ones.
* @return same format as input tiles
*/
public static TDCorrTile [] calcNeibs(
TDCorrTile [] tiles,
final int tilesX,
final double radius,
final boolean process_all
) {
final int tilesY = tiles.length / tilesX;
final int irad = (int) Math.floor(radius);
final int size = 2*irad+1;
final double [][] wnd = new double [size][size];
for (int i = 0; i < size; i++) {
double wy = Math.cos((i-irad)*0.5*Math.PI/radius);
for (int j = 0; j < size; j++) {
wnd[i][j] =wy*Math.cos((j-irad)*0.5*Math.PI/radius);
}
}
final TDCorrTile [] rslt = new TDCorrTile [tiles.length];
final Thread[] threads = ImageDtt.newThreadArray(ImageDtt.THREADS_MAX);
final AtomicInteger ai = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
TileNeibs tn = new TileNeibs(tilesX,tilesY);
for (int iTile = ai.getAndIncrement(); iTile < tiles.length; iTile = ai.getAndIncrement()) if (process_all || (tiles[iTile] != null)) {
for (int dy = -irad; dy <= irad; dy++) {
for (int dx = -irad; dx <= irad; dx++) {
int iTile1 = tn.getNeibIndex(iTile, dx, dy);
if ((iTile1 >= 0) && (tiles[iTile1] != null)) {
if (rslt[iTile] == null) {
rslt[iTile] = tiles[iTile1].clone();
rslt[iTile].scale(wnd[dy+irad][dx+irad]);
} else {
rslt[iTile].accumulate(tiles[iTile1], wnd[dy+irad][dx+irad]);
}
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return rslt;
}
/**
* Convert Transform-domain 2D correlation to phase correlation,
......@@ -329,8 +387,7 @@ public class TDCorrTile {
* @param corr_type
* @param gpu_fat_zero
* @param debug_level
* @return
*
* @return sparse array in line-scan order. Each element either null or double[225]
*/
public static double [][] convertTDtoPD(
final GpuQuad gpuQuad,
......@@ -401,6 +458,64 @@ public class TDCorrTile {
return mapped_corrs;
}
public static double [][] getMismatchVector(
final double [][] tiles,
double rmax,
final double centroid_radius, // 0 - all same weight, > 0 cosine(PI/2*sqrt(dx^2+dy^2)/rad)
final int n_recenter){ // re-center window around new maximum. 0 -no refines (single-pass)
double [][] vector_field = new double [tiles.length][];
final int corr_size = 2 * GPUTileProcessor.DTT_SIZE - 1;
final Thread[] threads = ImageDtt.newThreadArray();
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger ati = new AtomicInteger(0);
final double [] th_max = new double [threads.length];
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
int thread_num = ati.getAndIncrement();
for (int iTile = ai.getAndIncrement(); iTile < tiles.length; iTile = ai.getAndIncrement()) if (tiles[iTile] != null) {
for (double d:tiles[iTile]) {
if (d > th_max[thread_num]) {
th_max[thread_num] = d;
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
double amax = th_max[0];
for (int i = 1; i < th_max.length; i++) {
if (th_max[i] > amax) {
amax = th_max[i];
}
}
final double min_str = rmax * amax;
ai.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
public void run() {
for (int iTile = ai.getAndIncrement(); iTile < tiles.length; iTile = ai.getAndIncrement()) if (tiles[iTile] != null) {
double [] mv = Correlation2d.getMaxXYCm( // last, average
tiles[iTile], // corrs.length-1], // double [] data,
corr_size, // int data_width, // = 2 * transform_size - 1;
centroid_radius, // double radius, // 0 - all same weight, > 0 cosine(PI/2*sqrt(dx^2+dy^2)/rad)
n_recenter, // int refine, // re-center window around new maximum. 0 -no refines (single-pass)
null, // boolean [] fpn_mask,
false, // boolean ignore_border, // only if fpn_mask != null - ignore tile if maximum touches fpn_mask
false); // boolean debug)
if (mv[2] > min_str) {
vector_field[iTile] = new double [] {mv[0], mv[1], mv[2]-min_str};
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return vector_field;
}
/**
* Get GPU TD data after interscene correlation of 2 scenes (only use
* combo of all channels)
......
......@@ -2472,6 +2472,7 @@ public class TexturedModel {
final int crop_extra = clt_parameters.gmap_crop_extra ; //20;
final int [] tex_pals = clt_parameters.gmap_tex_pals ; //{0,1,2};
final boolean gmap_save_alt = clt_parameters.gmap_save_alt; // true; // save height map (meters ASL)
final boolean gmap_gnss_vert = clt_parameters.gmap_gnss_vert; // true; // reference ll to the point below (false - top left corner)
final boolean gmap_save_tiff32= clt_parameters.gmap_save_tiff32; // save float TIFF (NaN for transparency) with geo metadata (top left corner)
final boolean gmap_save_tiff = clt_parameters.gmap_save_tiff; // true; // save transparent TIFF with geo metadata (top left corner)
final int gmap_tiff_pal = clt_parameters.gmap_tiff_pal; // 0; // LWIR palette for TIFF
......@@ -3240,11 +3241,16 @@ public class TexturedModel {
ref_lla = new double[3];
}
// correct GPS coordinates to top-left corner of the result (full) image
double [] top_left_lla_offset_ned = new double[] {
double [] top_left_lla_offset_ned = new double[3]; // use center
if (gmap_gnss_vert) {
suffix+="-VERT";
} else { // top left
top_left_lla_offset_ned = new double[] {
hdr_x0y0[1], // North // hdr_x0y0 - in meters !
hdr_x0y0[0], // East
0}; // no altitude offset here
double [] top_left_lla = Imx5.offsetLla(ref_lla,top_left_lla_offset_ned);
}
double [] corrected_lla = Imx5.offsetLla(ref_lla,top_left_lla_offset_ned);
int num_pix = 0;
double sum_z = 0.0;
for (int i = 0; i < cropped_z[0].length; i++) {
......@@ -3258,7 +3264,7 @@ public class TexturedModel {
}
double avg_z = sum_z/num_pix;
LocalDateTime dt = scenes[ref_index].getLocalDateTime();
top_left_lla[2] = avg_z; // average altitude. Maybe keep drone altitude?
corrected_lla[2] = avg_z; // average altitude. Maybe keep drone altitude?
if (gmap_save_alt) {
/*
scenes[ref_index].saveDoubleArrayInTopModelDirectory( // save with Z
......@@ -3271,7 +3277,8 @@ public class TexturedModel {
scenes[ref_index].writeLwirGeoTiff32( // Negative value supplied for TIFF_RATIONAL
clt_parameters, // final CLTParameters clt_parameters,
cropped_z[0], // double [] data,
top_left_lla, // double [] lla, // latitude, longitude, altitude (or null)
corrected_lla, // double [] lla, // latitude, longitude, altitude (or null)
hdr_x0y0, // double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
scaled_pixel_size, // double pix_in_meters,
hdr_whs[0], // int width,
......@@ -3283,7 +3290,8 @@ public class TexturedModel {
scenes[ref_index].writeLwirGeoTiff32(
clt_parameters, // final CLTParameters clt_parameters,
img_cropped[0], // double [] data,
top_left_lla, // double [] lla, // latitude, longitude, altitude (or null)
corrected_lla, // double [] lla, // latitude, longitude, altitude (or null)
hdr_x0y0, // double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
scaled_pixel_size, // double pix_in_meters,
hdr_whs[0], // int width,
......@@ -3338,7 +3346,8 @@ public class TexturedModel {
scenes[ref_index].writeLwirGeoTiffARGB(
clt_parameters, // final CLTParameters clt_parameters,
img_cropped[0], // double [] data,
top_left_lla, // double [] lla, // latitude, longitude, altitude (or null)
corrected_lla, // double [] lla, // latitude, longitude, altitude (or null)
hdr_x0y0, // double [] xy_center, // X,Y of top left to vertical (negative meters)
dt, // LocalDateTime dt, // local date/time or null
scaled_pixel_size, // double pix_in_meters,
hdr_whs[0], // int width,
......
......@@ -9376,6 +9376,7 @@ if (debugLevel > -100) return true; // temporarily !
// Does not need to specify reference scene - it is always the last even if out of timestamp order
OpticalFlow.intersceneExport(
clt_parameters, // CLTParameters clt_parameters,
false, // boolean compensate_dsi,
// ers_reference, // ErsCorrection ers_reference,
indx_ref, // ref_index, // int ref_index,
scenes, // QuadCLT [] scenes,
......
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