Commit ff164bbf authored by Andrey Filippov's avatar Andrey Filippov

More on output of geolocated TIFFs with transparency

parent 9b0ad10d
......@@ -486,6 +486,9 @@ public class CLTParameters {
public int gmap_crop_extra = 20;
public int [] gmap_tex_pals = {0,1,2};
public boolean gmap_save_alt = true; // save height map (meters ASL)
public boolean gmap_save_tiff = true; // save transparent TIFF with geo metadata (top left corner)
public int gmap_tiff_pal = 0; // LWIR palette for TIFF
public boolean generate_bg = true; // Generate background image for 3dmodels
......
......@@ -256,6 +256,16 @@ public class Imx5 {
};
return ned;
}
/*
* Offset Latitude, Longitude, Altitude by North, East, Up (in meters)
*/
public static double [] offsetLla(double [] lla, double [] ned) {
double [] offset_lla = new double [] {
lla[0] + (ned[0]/EARTH_RADIUS / Math.PI * 180 / Math.cos(lla[0])), // degrees
lla[1] + (ned[1]/EARTH_RADIUS / Math.PI * 180), // degrees
lla[2] - ned[2]
};
return offset_lla;
}
}
......@@ -78,9 +78,8 @@ public class ElphelTiffWriter {
int debugLevel
) {
File outputFile = new File(path);
if (debugLevel > 0) {
System.out.println("saveTiffARGB32(): will write to "+outputFile);
System.out.println("ElphelTiffWriter.saveTiffARGB32");
if (debugLevel > -3) {
System.out.println("ElphelTiffWriter.saveTiffARGB32(): will write to "+outputFile);
}
ImageWriter tiffWriter = ImageIO.getImageWritersByFormatName("tiff").next();
ImageWriteParam tiffWriteParam = tiffWriter.getDefaultWriteParam();
......
......@@ -38,6 +38,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -72,6 +73,7 @@ import com.elphel.imagej.ims.Did_ins_2;
import com.elphel.imagej.ims.Did_pimu;
import com.elphel.imagej.ims.EventLogger;
import com.elphel.imagej.ims.Imx5;
import com.elphel.imagej.readers.ElphelTiffWriter;
import com.elphel.imagej.readers.ImagejJp4Tiff;
import com.elphel.imagej.x3d.export.TriMesh;
import com.elphel.imagej.x3d.export.WavefrontExport;
......@@ -227,6 +229,13 @@ public class QuadCLTCPU {
return dxyzatyr;
}
public double [] getLla() {
return did_ins_2.lla;
}
public LocalDateTime getLocalDateTime() {
return did_ins_2.getLocalDateTime();
}
public static double [][] scaleDtToErs(
CLTParameters clt_parameters,
double [][] cam_dxyzatr){
......@@ -413,7 +422,7 @@ public class QuadCLTCPU {
double discard_rdisp, // discard above/below this fraction of average height
double pix_size, // in meters
int max_image_width,// increase pixel size as a power of 2 until image fits
double [] x0y0, // initialize to double[2] to return width, height
double [] x0y0, // top level offset in meters
int [] whs, // initialize to int[3] to return {width, height, scale reduction}
int debug_level
) {
......@@ -745,7 +754,7 @@ public class QuadCLTCPU {
max_disparity, // double max_disparity,
discard_low, // double discard_low, // fraction of all pixels
discard_high, // double discard_high, // fraction of all pixels
xy_range, // double [][] xy_range, // should be double[2][];
xy_range, // double [][] xy_range, // should be double[2][]; meters
debug_level); // int debug_level)
// camera position and orientation relative to the same lat/long on the ground below it
// double [][] scene_abs_xyzatr_enu = new double [][] {new double[] {0,0,-agl}, scene_abs_atr_enu};
......@@ -3247,6 +3256,25 @@ public class QuadCLTCPU {
return imp;
}
public ImagePlus saveDoubleArrayInTopModelDirectory(
String suffix,
String [] labels, // or null
double [][] data,
int width,
int height)
{
String x3d_path = getX3dTopDirectory();
String file_name = image_name + suffix;
String file_path = x3d_path + Prefs.getFileSeparator() + file_name + ".tiff";
ImageStack imageStack = ShowDoubleFloatArrays.makeStack(data, width, height, labels);
ImagePlus imp = new ImagePlus( file_name, imageStack);
FileSaver fs=new FileSaver(imp);
fs.saveAsTiff(file_path);
System.out.println("saveDoubleArrayInModelDirectory(): saved "+file_path);
return imp;
}
public ImagePlus saveDoubleArrayInModelDirectory(
String suffix,
double [] data,
......@@ -16299,6 +16327,7 @@ public class QuadCLTCPU {
suffix,
debugLevel);
}
public boolean writeLwirPreview(
final CLTParameters clt_parameters,
double [] data,
......@@ -16315,7 +16344,6 @@ public class QuadCLTCPU {
for (int i = 0; i < rendered_texture[0].length; i++) {
rendered_texture[1][i] = Double.isNaN(rendered_texture[0][i])? 0.0: 1.0;
}
// double [] minmax = scene.getColdHot(); // used in linearStackToColor (from this current scene)
if (!suffix.equals("")) {
if (minmax == null) { // to replace standard preview file name
minmax = scene.getColdHot(); // used in linearStackToColor (from this current scene)
......@@ -16324,7 +16352,6 @@ public class QuadCLTCPU {
suffix +="-RANGE"+(minmax[1]-minmax[0]);
}
}
// int width = getTileProcessor().getTilesX() *getTileProcessor().getTileSize();
int height = data.length/width;
String set_name = getImageName();
if (set_name == null ) {
......@@ -16366,6 +16393,68 @@ public class QuadCLTCPU {
(debugLevel > -2) ? debugLevel : 1); // int debugLevel (print what it saves)
return true;
}
public boolean writeLwirGeoTiffARGB(
final CLTParameters clt_parameters,
double [] data,
double [] lla, // latitude, longitude, altitude (or null)
LocalDateTime dt, // local date/time or null
double pix_in_meters,
int width,
double [] minmax, // null for auto
QuadCLT scene,
int tex_palette,
String suffix, // include "-geo"
int debugLevel) {
if (scene == null) {
scene = (QuadCLT) this;
}
double [][] rendered_texture = new double[][] {data, new double[data.length]};
for (int i = 0; i < rendered_texture[0].length; i++) {
rendered_texture[1][i] = Double.isNaN(rendered_texture[0][i])? 0.0: 1.0;
}
if (!suffix.equals("")) {
if (minmax == null) { // to replace standard preview file name
minmax = scene.getColdHot(); // used in linearStackToColor (from this current scene)
suffix +="-AUTORANGE";
} else {
suffix +="-RANGE"+(minmax[1]-minmax[0]);
}
}
int height = data.length/width;
String set_name = getImageName();
if (set_name == null ) {
QuadCLTCPU.SetChannels [] set_channels = setChannels(debugLevel);
set_name = set_channels[0].set_name;
}
String model_dir= correctionsParameters.selectX3dDirectory(
set_name, // quad timestamp. Will be ignored if correctionsParameters.use_x3d_subdirs is false
null,
true, // smart,
true); //newAllowed, // save\
String title = getImageName()+suffix;
ImagePlus imp = QuadCLTCPU.linearStackToColorLWIR(
clt_parameters, // CLTParameters clt_parameters,
tex_palette, // int lwir_palette, // <0 - do not convert
minmax, // double [] minmax,
title, // String name,
"", // String suffix, // such as disparity=...
true, // boolean toRGB,
rendered_texture, // faded_textures[nslice], // double [][] texture_data,
width, // int width, // int tilesX,
height, // int height, // int tilesY,
debugLevel); // int debugLevel )
String image_path = model_dir + Prefs.getFileSeparator() + title+".tiff";
ElphelTiffWriter.saveTiffARGB32(
imp,
image_path,
lla, // double [] lla, // latitude, longitude, altitude (or null)
dt, // LocalDateTime dt, // local date/time or null
pix_in_meters, //double pix_in_meters, // resolution or Double.NaN
false, // imageJTags,
debugLevel);
return true;
}
/** broke
......
......@@ -24,6 +24,7 @@ package com.elphel.imagej.tileprocessor;
//import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -39,6 +40,7 @@ import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.correction.EyesisCorrections;
import com.elphel.imagej.gpu.TpTask;
import com.elphel.imagej.ims.Imx5;
import com.elphel.imagej.x3d.export.GlTfExport;
import com.elphel.imagej.x3d.export.Render3D;
import com.elphel.imagej.x3d.export.TriMesh;
......@@ -2468,6 +2470,10 @@ public class TexturedModel {
final boolean crop_empty = clt_parameters.gmap_crop_empty ; //true;
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_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
final double range_disparity_offset = clt_parameters.imp.range_disparity_offset;// double range_disparity_offset
final boolean batch_mode = clt_parameters.multiseq_run; // batch_run;
......@@ -3046,15 +3052,15 @@ public class TexturedModel {
hdr_whs[0], // int out_width, // output rendered image width in pixels
hdr_whs[1]); // int out_height); // output rendered image height in pixels
boolean last_is_alpha = true; // last channel in textures slices is alpha
double [][] full_render;
double [][] full_render_z;
if (use_parallel_proj) {
full_render =render3D.render3dPlaneParallelProj(
full_render_z =render3D.render3dPlaneParallelProj(
tri_meshes, // final ArrayList<TriMesh> tri_meshes,
last_is_alpha, // final boolean last_is_alpha,
// scenes[ref_index], //final QuadCLT ref_scene, // all coordinates relative to this scene
debugLevel); //int debugLevel)
} else {
full_render =render3D.render3dPlaneCenterProj(
full_render_z =render3D.render3dPlaneCenterProj(
tri_meshes, // final ArrayList<TriMesh> tri_meshes,
last_is_alpha, // final boolean last_is_alpha,
// scenes[ref_index], //final QuadCLT ref_scene, // all coordinates relative to this scene
......@@ -3064,46 +3070,113 @@ public class TexturedModel {
String suffix ="-RECT";
if (clt_parameters.tex_um) {
suffix+="-UM"+(clt_parameters.tex_um_sigma)+"_"+(clt_parameters.tex_um_weight);
}
}
suffix +="-PIX"+pix_size * hdr_whs[2];
scenes[ref_index].saveDoubleArrayInModelDirectory(
suffix+"-FULL", // String suffix,
null, // String [] labels, // or null
full_render, // double [][] data,
full_render_z, // double [][] data, // including Z as it was
hdr_whs[0], // int width, // int tilesX,
hdr_whs[1]); // int height, // int tilesY,
double [][] img_cropped_z = full_render_z;
// int [] wh = hdr_whs.clone();
if (crop_empty || (crop_extra > 0)) {
int [] wh = new int[2];
double [][] img_cropped = Render3D.cropRectified(
int [] ltwh = new int[4];
img_cropped_z = Render3D.cropRectified(
crop_empty, // boolean crop_empty,
last_is_alpha, // boolean last_is_alpha,
// last_is_alpha, // boolean last_is_alpha,
full_render_z.length - 2, // last is Z, previous is alpha
crop_extra, // int crop_extra,
hdr_whs[0], // int width,
wh, // int [] wh, // should be initialized to int [2]
full_render); // double [][] img_src)
if (img_cropped != null) { // has NaN and alpha 0-1
scenes[ref_index].saveDoubleArrayInModelDirectory(
ltwh, // int [] wh, // should be initialized to int [2]
full_render_z); // double [][] img_src)
if (img_cropped_z != null) { // has NaN and alpha 0-1
hdr_whs[0] = ltwh[2]; // cropped width
hdr_whs[1] = ltwh[3]; // cropped height
hdr_x0y0[0] +=ltwh[0]* scaled_pixel_size; // meters corrected by pixels
hdr_x0y0[1] +=ltwh[1]* scaled_pixel_size; // meters corrected by pixels
scenes[ref_index].saveDoubleArrayInModelDirectory( // save with Z
suffix+"-CROP", // String suffix,
null, // String [] labels, // or null
img_cropped, // double [][] data,
wh[0], // int width, // int tilesX,
wh[1]); // int height, // int tilesY,
// for (int tex_palette = tex_palette_start; tex_palette <= tex_palette_end; tex_palette++) {
for (int tex_palette: tex_pals) {
// try with fixed range?
double [] minmax = tex_um_fixed ? (new double[] {-tex_um_range/2, tex_um_range/2}): null;
scenes[ref_index].writeLwirPreview(
clt_parameters, // final CLTParameters clt_parameters,
img_cropped[0], // double [] data,
wh[0], // int width, // int tilesX,
minmax, // double [] minmax, // null for auto
null, // QuadCLT scene,
tex_palette, // int tex_palette,
suffix+"-CROP"+"-PAL"+tex_palette, // +tex_palette, // String suffix,
debugLevel); // int debugLevel)
img_cropped_z, // double [][] data,
hdr_whs[0], // int width, // int tilesX,
hdr_whs[1]); // int height, // int tilesY,
} else {
img_cropped_z = full_render_z; // restore
}
}
// Here use cropped or full (non-cropped) if not calculated and save separately
// textures and altitude ASL
if (img_cropped_z != null) { // has NaN and alpha 0-1
double [][] img_cropped = new double [img_cropped_z.length - 1][];
for (int i = 0; i < img_cropped.length; i++) {
img_cropped[i] = img_cropped_z[i];
}
double [][] cropped_z = new double [][] {img_cropped_z[img_cropped_z.length-1].clone(), img_cropped_z[img_cropped_z.length-2]};
// scale units, add altitude, add NaNs
double [] ref_lla = scenes[ref_index].getLla();
if (ref_lla == null) {
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[] {
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);
int num_pix = 0;
double sum_z = 0.0;
for (int i = 0; i < cropped_z[0].length; i++) {
if (cropped_z[1][i] <= 0.0) {
cropped_z[0][i] = Double.NaN;
} else {
cropped_z[0][i] = ref_lla[2] - cropped_z[0][i] * scaled_pixel_size;
num_pix++;
sum_z += cropped_z[0][i];
}
}
double avg_z = sum_z/num_pix;
top_left_lla[2] = avg_z; // average altitude. Maybe keep drone altitude?
if (gmap_save_alt) {
scenes[ref_index].saveDoubleArrayInTopModelDirectory( // save with Z
suffix+"-ALT", // String suffix,
null, // String [] labels, // or null
new double[][] {cropped_z[0]}, // double [][] data,
hdr_whs[0], // int width, // int tilesX,
hdr_whs[1]); // int height, // int tilesY,
}
double [] minmax = tex_um_fixed ? (new double[] {-tex_um_range/2, tex_um_range/2}): null;
if (gmap_save_tiff && (gmap_tiff_pal >=0)) {
LocalDateTime dt = scenes[ref_index].getLocalDateTime();
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)
dt, // LocalDateTime dt, // local date/time or null
scaled_pixel_size, // double pix_in_meters,
hdr_whs[0], // int width,
minmax, // double [] minmax, // null for auto
null, // QuadCLT scene,
gmap_tiff_pal, // int tex_palette,
suffix+"-GEO"+"-PAL"+gmap_tiff_pal, // String suffix,
debugLevel); // int debugLevel)
}
for (int tex_palette: tex_pals) {
// try with fixed range?
// double [] minmax = tex_um_fixed ? (new double[] {-tex_um_range/2, tex_um_range/2}): null;
scenes[ref_index].writeLwirPreview(
clt_parameters, // final CLTParameters clt_parameters,
img_cropped[0], // double [] data,
hdr_whs[0], // int width,
minmax, // double [] minmax, // null for auto
null, // QuadCLT scene,
tex_palette, // int tex_palette,
suffix+"-CROP"+"-PAL"+tex_palette, // +tex_palette, // String suffix,
debugLevel); // int debugLevel)
}
}
}
}
}
......
......@@ -137,20 +137,25 @@ public class Render3D {
public static double [][] cropRectified(
boolean crop_empty,
boolean last_is_alpha,
// boolean last_is_alpha,
int indx_alpha,
int crop_extra,
int width,
int [] wh, // should be initialized to int [2]
int [] ltwh, // should be initialized to int [4] (left,top,width, height)
double [][] img_src){
int height = img_src[0].length/width;
int indx_alpha = img_src.length - 1;
// int indx_alpha = img_src.length - 1;
int marg_top=0,marg_left=0,marg_bottom=0,marg_right=0;
if (crop_empty) {
int [][] xy_min_max= null; // new int[2][2];
for (int iy = 0; iy<height; iy++) {
for (int ix=0; ix<width; ix++) {
int indx=iy * width +ix;
if (last_is_alpha? (img_src[indx_alpha][indx] > 0.0) : !Double.isNaN(img_src[0][indx])) {
// if (last_is_alpha? (img_src[indx_alpha][indx] > 0.0) : !Double.isNaN(img_src[0][indx])) {
if (!Double.isNaN(img_src[0][indx])) {
if ((indx_alpha >= 0) && (img_src[indx_alpha][indx] <= 0.0)) {
continue;
}
if (xy_min_max == null) {
xy_min_max=new int [][] {{ix,ix},{iy,iy}};
} else {
......@@ -176,8 +181,10 @@ public class Render3D {
marg_right += crop_extra;
int out_width = width - marg_left - marg_right;
int out_height = height - marg_top - marg_bottom;
wh[0] = out_width;
wh[1] = out_height;
ltwh[0] = marg_left;
ltwh[1] = marg_top;
ltwh[2] = out_width;
ltwh[3] = out_height;
double [][] img_cropped = new double [img_src.length][out_width*out_height];
for (int row = 0; row < out_height; row++) {
for (int chn = 0; chn < img_cropped.length; chn++) {
......
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