Commit 9b0ad10d authored by Andrey Filippov's avatar Andrey Filippov

Tiff writer, fixed bug in Z interpolation in plane render

parent beaa0851
......@@ -480,7 +480,8 @@ public class CLTParameters {
public double gmap_discard_adisp = 0.2; // discard above/below this fraction of average height
public double gmap_discard_rdisp = 0.02; // discard above/below this fraction of average height
public double gmap_pix_size = 0.005; // hdr_x0y0, // in meters
public int gmap_max_image_width = 4000; // 3200; // increase pixel size as a power of 2 until image fits
public int gmap_max_image_width = 4000; // 3200; // increase pixel size as a power of 2 until image fits
public double gmap_min_sfm = 10.0; // minimal SfM gain to keep ground map
public boolean gmap_crop_empty = true;
public int gmap_crop_extra = 20;
public int [] gmap_tex_pals = {0,1,2};
......@@ -1626,6 +1627,7 @@ public class CLTParameters {
properties.setProperty(prefix+"gmap_discard_rdisp", this.gmap_discard_rdisp+""); // double
properties.setProperty(prefix+"gmap_pix_size", this.gmap_pix_size+""); // double
properties.setProperty(prefix+"gmap_max_image_width", this.gmap_max_image_width+""); // int
properties.setProperty(prefix+"gmap_min_sfm", this.gmap_min_sfm+""); // double
properties.setProperty(prefix+"gmap_crop_empty", this.gmap_crop_empty+""); // boolean
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[]
......@@ -2644,6 +2646,7 @@ public class CLTParameters {
if (properties.getProperty(prefix+"gmap_discard_rdisp")!=null) this.gmap_discard_rdisp=Double.parseDouble(properties.getProperty(prefix+ "gmap_discard_rdisp"));
if (properties.getProperty(prefix+"gmap_pix_size")!=null) this.gmap_pix_size=Double.parseDouble(properties.getProperty(prefix+ "gmap_pix_size"));
if (properties.getProperty(prefix+"gmap_max_image_width")!=null) this.gmap_max_image_width=Integer.parseInt(properties.getProperty(prefix+ "gmap_max_image_width"));
if (properties.getProperty(prefix+"gmap_min_sfm")!=null) this.gmap_min_sfm=Double.parseDouble(properties.getProperty(prefix+ "gmap_min_sfm"));
if (properties.getProperty(prefix+"gmap_crop_empty")!=null) this.gmap_crop_empty=Boolean.parseBoolean(properties.getProperty(prefix+ "gmap_crop_empty"));
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"));
......@@ -3908,6 +3911,8 @@ public class CLTParameters {
"Rendered absolute pixel size in meters.");
gd.addNumericField("Maximal rendered image width", this.gmap_max_image_width, 0,3,"",
"Maximal output image size in pixels. Increase pixel size in the power-of-two ratio if calculated image width exceeds this value.");
gd.addNumericField("Minimal SfM gain", this.gmap_min_sfm, 4,6,"x",
"Minimal SfM gain to keep ground map, lower makes texture transparent.");
gd.addCheckbox ("Crop empty map areas", this.gmap_crop_empty, // true; // enable change FG pixel to opaque from transparent
"Crop the map output from four directions while only undefined pixels are removed.");
gd.addNumericField("Crop maps extra", this.gmap_crop_extra, 0,3,"pix", // minimal neighbors to keep alpha
......@@ -3915,7 +3920,6 @@ 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.addMessage ("Earlier 3D generation parameters");
gd.addCheckbox ("Generate background (infinity) image for 3D (not needed for view down)", this.generate_bg);
gd.addCheckbox ("Show generated textures", this.show_textures);
......@@ -5125,13 +5129,12 @@ public class CLTParameters {
this.gmap_discard_high= gd.getNextNumber();
this.gmap_discard_adisp= gd.getNextNumber();
this.gmap_discard_rdisp= gd.getNextNumber();
gmap_pix_size= gd.getNextNumber();
this.gmap_pix_size= gd.getNextNumber();
this.gmap_max_image_width= (int) gd.getNextNumber();
this.gmap_min_sfm= gd.getNextNumber();
this.gmap_crop_empty= gd.getNextBoolean();
this.gmap_crop_extra= (int) gd.getNextNumber();
this.gmap_tex_pals = CLTParameters.str_to_iarr(gd.getNextString());
this.generate_bg= gd.getNextBoolean();
this.show_textures= gd.getNextBoolean();
this.debug_filters= gd.getNextBoolean();
......
......@@ -69,114 +69,42 @@ public class ElphelTiffWriter {
public static void saveTiffARGB32(
ImagePlus imp,
String path,
boolean imageJTags,
int debugLevel
ImagePlus imp,
String path, // full path to save image
double [] lla, // latitude, longitude, altitude (or null)
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
int debugLevel
) {
// ImageWriter tiffWriter;
// ImageWriteParam tiffWriteParam;
IIOMetadata tiffStreamMetadata;
IIOMetadata primaryIFD;
BufferedImage bufferedImage = (BufferedImage) imp.getImage(); // properties=null
BufferedImage thumbnail;
File outputFile = new File(path);
System.out.println("saveTiffARGB32(): will write to "+outputFile);
System.out.println("ElphelTiffWriter.saveTiffARGB32");
// Write only the primary IFD and image data.
// Specify uncompressed output.
if (debugLevel > 0) {
System.out.println("saveTiffARGB32(): will write to "+outputFile);
System.out.println("ElphelTiffWriter.saveTiffARGB32");
}
ImageWriter tiffWriter = ImageIO.getImageWritersByFormatName("tiff").next();
ImageWriteParam tiffWriteParam = tiffWriter.getDefaultWriteParam();
// tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
// https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html
// tiffWriteParam.setCompressionType("Exif JPEG");
tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);
// tiffWriteParam.setSourceSubsampling(param.getSourceXSubsampling(), param.getSourceYSubsampling(), param.getSubsamplingXOffset(), param.getSubsamplingYOffset());
// tiffWriteParam.setSourceRegion(param.getSourceRegion());
// tiffWriteParam.setSourceBands(param.getSourceBands());
/*
* https://docs.oracle.com/javase%2F9%2Fdocs%2Fapi%2F%2F/javax/imageio/metadata/doc-files/tiff_metadata.html
Setting up the image metadata to write to a TIFF stream may be simplified by using
the TIFFDirectory class which represents a TIFF IFD. A field in a TIFF IFD is represented
by an instance of TIFFField. For each field to be written a TIFFField may be added to
the TIFFDirectory and the latter converted to an IIOMetadata object by invoking
TIFFDirectory.getAsMetadata. The IIOMetadata object so obtained may then be passed to
the TIFF writer.
ImageTypeSpecifier
ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel)
Constructs an ImageTypeSpecifier directly from a ColorModel and a SampleModel.
static long computeImageSize(RenderedImage image) {
long bits = 0;
final int bands = image.getSampleModel().getNumBands();
for (int i = 0; i < bands; i++) {
bits += image.getSampleModel().getSampleSize(i);
}
return (long) Math.ceil(bits / 8) * image.getWidth() * image.getHeight();
}
void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) and default sRGB color space, into a portion of the image data.
*/
// Raster raster = bufferedImage.getData(); // use pixels from IJ
/* ImagePlus image removes alpha, so we need to create a new ARGB BufferedImage
* and copy data (it is correct in imp.getImage() */
BufferedImage bufferedImage = (BufferedImage) imp.getImage(); // properties=null
BufferedImage bufferedImageAlpha = new BufferedImage(
bufferedImage.getWidth(),
bufferedImage.getHeight(),
BufferedImage.TYPE_INT_ARGB
);
BufferedImage.TYPE_INT_ARGB);
int [] ipixels = (int[])imp.getProcessor().getPixels();
final int[] bia_as_arr = ( (DataBufferInt) bufferedImageAlpha.getRaster().getDataBuffer() ).getData();
System.arraycopy(ipixels, 0, bia_as_arr, 0, bia_as_arr.length);
/*
bufferedImageAlpha.setRGB( // slow
0, // int startX,
0, // int startY,
bufferedImage.getWidth(), // int w,
bufferedImage.getHeight(), // int h,
ipixels, // int[] rgbArray,
0, // int offset,
bufferedImage.getWidth()); // int scansize);
*/
// bufferedImageAlpha.setData(raster);
//BufferedImage.TYPE_INT_ARGB
// ColorModel colorModel = ColorModel.getRGBdefault();
// SampleModel samleModel = bufferedImage.getSampleModel();
// ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(bufferedImage);
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(bufferedImageAlpha);
IIOMetadata imageMetadata = tiffWriter.getDefaultImageMetadata(imageType, tiffWriteParam);
// just for testing:
double [] lla = { 49.9476514222895,28.5547846609957,323.750316821841};
LocalDateTime dt = Did_ins.getLocalDateTime(2286, 491072.634526699);
double pix_in_meters = 0.01;
int cm_dig_after = 9;
// Here is a way adding tag sets through TIFFDirectory
/*
ExifGPSTagSet exif_tag_set = ExifGPSTagSet.getInstance();
TIFFTagSet [] tag_sets = {ExifGPSTagSet.getInstance()} ;
ExifParentTIFFTagSet eptts = ExifParentTIFFTagSet.getInstance();
TIFFDirectory gps_directory = new TIFFDirectory(
tag_sets, eptts.getTag(
ExifParentTIFFTagSet.TAG_GPS_INFO_IFD_POINTER));
TIFFTagSet tag_set = ExifGPSTagSet.getInstance();
TIFFField gps_ifd = null;
// int df = TIFFField.TIFF_IFD_POINTER; // 13
gps_ifd = new TIFFField(
eptts.getTag(
ExifParentTIFFTagSet.TAG_GPS_INFO_IFD_POINTER), // 'ExifIFDPointer', // TIFFTag tag,
13, // TIFFField.TIFF_IFD_POINTER, // int type,
(long) 0, // long offset,
(TIFFDirectory) gps_directory); // TIFFDirectory dir)
directory.addTIFFField(gps_ifd);
directory.addTagSet(tag_set); // ExifGPSTagSet.getInstance());
*/
/* */
TIFFDirectory directory = null;
try {
directory = TIFFDirectory.createFromMetadata(imageMetadata);
......@@ -191,122 +119,41 @@ Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) a
directory.addTagSet(eptts); // ExifParentTIFFTagSet.getInstance());
//ExifGPSTagSet
imageMetadata = directory.getAsMetadata();
/* */
*/
IIOMetadataNode root_new = (IIOMetadataNode) imageMetadata.getAsTree(TIFF_METADATA_FORMAT);//?
System.out.println("\n=== root_new ===:");
DumpImageMetadata.displayMetadataNode(root_new, 1);
// createGpsMetadata(double [] lla, LocalDateTime dt)
if (debugLevel > 0) {System.out.println("\n=== root_new ===:");DumpImageMetadata.displayMetadataNode(root_new, 1);}
IIOMetadataNode ifd = (IIOMetadataNode) root_new.getFirstChild();
String ifd_attr = ifd.getAttribute("tagSets");
// set it to ifd_attr "javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.ExifGPSTagSet,javax.imageio.plugins.tiff.ExifParentTIFFTagSet" (id=187)
// remove directory above and addTagSet
IIOMetadataNode gpsRootNode = createGpsMetadata(lla, dt);
/*
IIOMetadataNode gpsRootNode = new IIOMetadataNode("TIFFIFD");
gpsRootNode.setAttribute("parentTagNumber", "34853");
gpsRootNode.setAttribute("parentTagName", "GPSInfoIFDPointer");
gpsRootNode.setAttribute("tagSets", "javax.imageio.plugins.tiff.ExifGPSTagSet");
IIOMetadataNode childNode = new IIOMetadataNode(TIFF_FIELD_TAG);
childNode.setAttribute("number", "1");
childNode.setAttribute("name", "GPSLatitudeRef");
IIOMetadataNode asciiNode = new IIOMetadataNode(TIFF_ASCIIS_TAG);
IIOMetadataNode childAsciiNode = new IIOMetadataNode(TIFF_ASCII_TAG);
childAsciiNode.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, "N");
asciiNode.appendChild(childAsciiNode);
childNode.appendChild(asciiNode);
gpsRootNode.appendChild(childNode);
*/
System.out.println("\n=== gpsRootNode ===:");
DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);
addResolutionMetadata(ifd,pix_in_meters,cm_dig_after);
ifd.appendChild(gpsRootNode);
System.out.println("\n=== ifd ===:");
DumpImageMetadata.displayMetadataNode(ifd, 1);
/*
IIOMetadataNode childNode = new IIOMetadataNode(FileConstants.TIFF_FIELD_TAG);
childNode.setAttribute(FileConstants.TIFF_FIELD_NUMBER_ATTRIBUTE, "1");
childNode.setAttribute(FileConstants.TIFF_FIELD_NAME_ATTRIBUTE, "GPSLatitudeRef");
IIOMetadataNode asciiNode = new IIOMetadataNode("TIFFAsciis");
IIOMetadataNode childAsciiNode = new IIOMetadataNode("TIFFAscii");
childAsciiNode.setAttribute(FileConstants.TIFF_FIELD_VALUE_ATTRIBUTE, "N");
asciiNode.appendChild(childAsciiNode);
childNode.appendChild(asciiNode);
gpsRootNode.appendChild(childNode);
ifd.appendChild(gpsRootNode);
//Update metadata with new tree
metadata.setFromTree(FileConstants.TIFF_METADATA_FORMAT, root);
ImageOutputStream outstr = ImageIO.createImageOutputStream(writeTarget);
writer.setOutput(outstr);
//Write the image
IIOImage img = new IIOImage(renderedImage, Collections.<BufferedImage> emptyList(), metadata);
writer.write(img);
outstr.close();
public static String TIFF_METADATA_FORMAT = "javax_imageio_tiff_image_1.0";
public static String TIFF_FIELD_TAG = "TIFFField";
public static String TIFF_ASCIIS_TAG = "TIFFAsciis";
public static String TIFF_ASCII_TAG = "TIFFAscii";
public static String TIFF_RATIONALS_TAG = "TIFFRationals";
public static String TIFF_RATIONAL_TAG = "TIFFRational";
public static String TIFF_FIELD_VALUE_ATTRIBUTE = "value";
*/
// imageMetadata.appendChild(dimension);
ifd.setAttribute("tagSets",
"javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.ExifGPSTagSet,javax.imageio.plugins.tiff.ExifParentTIFFTagSet");
if ((lla != null) || (dt!=null)) {
IIOMetadataNode gpsRootNode = createGpsMetadata(lla, dt);
if (debugLevel > 0) {System.out.println("\n=== gpsRootNode ===:");DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);}
ifd.appendChild(gpsRootNode);
}
addResolutionMetadata(ifd,pix_in_meters,cm_dig_after); // NOP if pix_in_meters is NaN
//// IIOMetadataNode root_dimension = new IIOMetadataNode(TIFF_METADATA_FORMAT); // IIOMetadataFormatImpl.standardMetadataFormatName);
// root_dimension.appendChild(dimension);
//// root_dimension.appendChild(root_new);
//// System.out.println("\n=== root_new ===:"); // should have 2 tagSets, but has only baseline
/*
<javax_imageio_tiff_image_1.0>
<TIFFIFD tagSets='javax.imageio.plugins.tiff.BaselineTIFFTagSet,javax.imageio.plugins.tiff.GeoTIFFTagSet'>
*/
System.out.println("\n=== root_new ===:");
DumpImageMetadata.displayMetadataNode(root_new, 1);
System.out.println("\n=== imageMetadata - before merge ===:");
DumpImageMetadata.displayMetadataNode(imageMetadata.getAsTree(TIFF_METADATA_FORMAT), 1);
// lost GPS data after merge
if (debugLevel > 0) {
System.out.println("\n=== ifd ===:");DumpImageMetadata.displayMetadataNode(ifd, 1);
System.out.println("\n=== root_new ===:"); DumpImageMetadata.displayMetadataNode(root_new, 1);
System.out.println("\n=== imageMetadata - before merge ===:"); DumpImageMetadata.displayMetadataNode(imageMetadata.getAsTree(TIFF_METADATA_FORMAT), 1);
}
try {
imageMetadata.mergeTree(TIFF_METADATA_FORMAT, root_new); // dimension); // Root must have "TIFFIFD" child
// imageMetadata.setFromTree(TIFF_METADATA_FORMAT, root_dimension); // dimension);
} catch (IIOInvalidTreeException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return;
}
System.out.println("\n=== imageMetadata - after merge ===:");
DumpImageMetadata.displayMetadataNode(imageMetadata.getAsTree(TIFF_METADATA_FORMAT), 1);
System.out.println();
if (debugLevel > 0) {System.out.println("\n=== imageMetadata - after merge ===:");DumpImageMetadata.displayMetadataNode(imageMetadata.getAsTree(TIFF_METADATA_FORMAT), 1);}
FileImageOutputStream outputStream;
try {
outputStream = new FileImageOutputStream(outputFile);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return;
}
tiffWriter.setOutput(outputStream);
// IIOImage image_with_metadata = new IIOImage(bufferedImage, null, primaryIFD);
// IIOImage image_with_metadata = new IIOImage(bufferedImage, null, null);
IIOImage image_with_metadata = new IIOImage(bufferedImageAlpha, null, imageMetadata);
System.out.println();
try {
......@@ -315,12 +162,11 @@ outstr.close();
image_with_metadata,
tiffWriteParam);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println();
}
private static IIOMetadataNode createRationalDegrees(double d, int digits_after) { // 8
int denom = 1;
for (int i = 0; i < digits_after; i++) denom *= 10;
......@@ -380,7 +226,9 @@ outstr.close();
return node_date;
}
private static IIOMetadataNode createGpsMetadata(double [] lla, LocalDateTime dt) {
private static IIOMetadataNode createGpsMetadata(
double [] lla,
LocalDateTime dt) {
int ang_sec_after = 5;
int meters_after = 3;
int seconds_after = 3;
......@@ -390,71 +238,62 @@ outstr.close();
gpsRootNode.setAttribute("parentTagNumber", "34853");
gpsRootNode.setAttribute("parentTagName", "GPSInfoIFDPointer");
gpsRootNode.setAttribute("tagSets", "javax.imageio.plugins.tiff.ExifGPSTagSet");
boolean lat_south = lla[0] < 0;
double lat_abs = Math.abs(lla[0]);
boolean long_west = lla[1] < 0;
double long_abs = Math.abs(lla[1]);
boolean alt_down = lla[2] < 0;
double alt_abs = Math.abs(lla[2]);
// Latitude
IIOMetadataNode node_lat_ref = new IIOMetadataNode(TIFF_FIELD_TAG);
node_lat_ref.setAttribute("number", "1");
node_lat_ref.setAttribute("name", "GPSLatitudeRef");
IIOMetadataNode node_lat_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG);
IIOMetadataNode node_lat_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG);
node_lat_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, lat_south?"S":"N");
node_lat_ref_asciis.appendChild(node_lat_ref_ascii);
node_lat_ref.appendChild(node_lat_ref_asciis);
gpsRootNode.appendChild(node_lat_ref);
IIOMetadataNode node_lat = new IIOMetadataNode(TIFF_FIELD_TAG);
node_lat.setAttribute("number", "2");
node_lat.setAttribute("name", "GPSLatitude");
node_lat.appendChild(createRationalDegrees(lat_abs, ang_sec_after));
gpsRootNode.appendChild(node_lat);
System.out.println("\n=== gpsRootNode after latitude ===:");
DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);
// Longitude
IIOMetadataNode node_long_ref = new IIOMetadataNode(TIFF_FIELD_TAG);
node_long_ref.setAttribute("number", "3");
node_long_ref.setAttribute("name", "GPSLongitudeRef");
IIOMetadataNode node_long_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG);
IIOMetadataNode node_long_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG);
node_long_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, long_west?"W":"E");
node_long_ref_asciis.appendChild(node_long_ref_ascii);
node_long_ref.appendChild(node_long_ref_asciis);
gpsRootNode.appendChild(node_long_ref);
IIOMetadataNode node_long = new IIOMetadataNode(TIFF_FIELD_TAG);
node_long.setAttribute("number", "4");
node_long.setAttribute("name", "GPSLongitude");
node_long.appendChild(createRationalDegrees(long_abs, ang_sec_after));
gpsRootNode.appendChild(node_long);
System.out.println("\n=== gpsRootNode after longitude ===:");
DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);
// Altitude
IIOMetadataNode node_alt_ref = new IIOMetadataNode(TIFF_FIELD_TAG);
node_alt_ref.setAttribute("number", "5");
node_alt_ref.setAttribute("name", "GPSAltitudeRef");
IIOMetadataNode node_alt_ref_asciis = new IIOMetadataNode(TIFF_BYTES_TAG);
IIOMetadataNode node_alt_ref_ascii = new IIOMetadataNode(TIFF_BYTE_TAG);
node_alt_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, alt_down?"1":"0");
node_alt_ref_ascii.setAttribute(TIFF_FIELD_DESCRIPTION_ATTRIBUTE, "Sea level");
node_alt_ref_asciis.appendChild(node_alt_ref_ascii);
node_alt_ref.appendChild(node_alt_ref_asciis);
gpsRootNode.appendChild(node_alt_ref);
IIOMetadataNode node_alt = new IIOMetadataNode(TIFF_FIELD_TAG);
node_alt.setAttribute("number", "6");
node_alt.setAttribute("name", "GPSAltitude");
node_alt.appendChild(createRationalMeters(alt_abs, meters_after));
gpsRootNode.appendChild(node_alt);
System.out.println("\n=== gpsRootNode after altitude ===:");
DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);
boolean lat_south, long_west, alt_down;
double lat_abs, long_abs, alt_abs;
if (lla != null) {
lat_south = lla[0] < 0;
lat_abs = Math.abs(lla[0]);
long_west = lla[1] < 0;
long_abs = Math.abs(lla[1]);
alt_down = lla[2] < 0;
alt_abs = Math.abs(lla[2]);
// Latitude
IIOMetadataNode node_lat_ref = new IIOMetadataNode(TIFF_FIELD_TAG);
node_lat_ref.setAttribute("number", "1");
node_lat_ref.setAttribute("name", "GPSLatitudeRef");
IIOMetadataNode node_lat_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG);
IIOMetadataNode node_lat_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG);
node_lat_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, lat_south?"S":"N");
node_lat_ref_asciis.appendChild(node_lat_ref_ascii);
node_lat_ref.appendChild(node_lat_ref_asciis);
gpsRootNode.appendChild(node_lat_ref);
IIOMetadataNode node_lat = new IIOMetadataNode(TIFF_FIELD_TAG);
node_lat.setAttribute("number", "2");
node_lat.setAttribute("name", "GPSLatitude");
node_lat.appendChild(createRationalDegrees(lat_abs, ang_sec_after));
gpsRootNode.appendChild(node_lat);
// Longitude
IIOMetadataNode node_long_ref = new IIOMetadataNode(TIFF_FIELD_TAG);
node_long_ref.setAttribute("number", "3");
node_long_ref.setAttribute("name", "GPSLongitudeRef");
IIOMetadataNode node_long_ref_asciis = new IIOMetadataNode(TIFF_ASCIIS_TAG);
IIOMetadataNode node_long_ref_ascii = new IIOMetadataNode(TIFF_ASCII_TAG);
node_long_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, long_west?"W":"E");
node_long_ref_asciis.appendChild(node_long_ref_ascii);
node_long_ref.appendChild(node_long_ref_asciis);
gpsRootNode.appendChild(node_long_ref);
IIOMetadataNode node_long = new IIOMetadataNode(TIFF_FIELD_TAG);
node_long.setAttribute("number", "4");
node_long.setAttribute("name", "GPSLongitude");
node_long.appendChild(createRationalDegrees(long_abs, ang_sec_after));
gpsRootNode.appendChild(node_long);
// Altitude
IIOMetadataNode node_alt_ref = new IIOMetadataNode(TIFF_FIELD_TAG);
node_alt_ref.setAttribute("number", "5");
node_alt_ref.setAttribute("name", "GPSAltitudeRef");
IIOMetadataNode node_alt_ref_asciis = new IIOMetadataNode(TIFF_BYTES_TAG);
IIOMetadataNode node_alt_ref_ascii = new IIOMetadataNode(TIFF_BYTE_TAG);
node_alt_ref_ascii.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, alt_down?"1":"0");
node_alt_ref_ascii.setAttribute(TIFF_FIELD_DESCRIPTION_ATTRIBUTE, "Sea level");
node_alt_ref_asciis.appendChild(node_alt_ref_ascii);
node_alt_ref.appendChild(node_alt_ref_asciis);
gpsRootNode.appendChild(node_alt_ref);
IIOMetadataNode node_alt = new IIOMetadataNode(TIFF_FIELD_TAG);
node_alt.setAttribute("number", "6");
node_alt.setAttribute("name", "GPSAltitude");
node_alt.appendChild(createRationalMeters(alt_abs, meters_after));
gpsRootNode.appendChild(node_alt);
}
if (dt != null) {
// Time
IIOMetadataNode node_time = new IIOMetadataNode(TIFF_FIELD_TAG);
......@@ -462,8 +301,6 @@ outstr.close();
node_time.setAttribute("name", "GPSTimeStamp");
node_time.appendChild(createTimeStamp(dt,seconds_after));
gpsRootNode.appendChild(node_time);
System.out.println("\n=== gpsRootNode after time ===:");
DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);
// Date
IIOMetadataNode node_date = new IIOMetadataNode(TIFF_FIELD_TAG);
node_date.setAttribute("number", "29");
......@@ -471,31 +308,16 @@ outstr.close();
node_date.appendChild(createDateStamp(dt));
gpsRootNode.appendChild(node_date);
}
System.out.println("\n=== gpsRootNode after date ===:");
DumpImageMetadata.displayMetadataNode(gpsRootNode, 1);
return gpsRootNode;
}
private static IIOMetadataNode createResolutionMetadataStd(double resolutionPixelInMeters) {
// String pixelSize = Double.toString(25.4 / resolutionDPI);
String pixelSize = Double.toString(1000*resolutionPixelInMeters); // millimeters
IIOMetadataNode horizontal = new IIOMetadataNode("HorizontalPixelSize");
horizontal.setAttribute("value", pixelSize);
IIOMetadataNode vertical = new IIOMetadataNode("VerticalPixelSize");
vertical.setAttribute("value", pixelSize);
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
dimension.appendChild(horizontal);
dimension.appendChild(vertical);
return dimension;
// IIOMetadataNode root = new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName);
// root.appendChild(dimension);
// return root;
}
private static void addResolutionMetadata(
IIOMetadataNode ifd,
double resolutionPixelInMeters,
double resolutionPixelInMeters, // NaN for undefined
int digits_after) {
if (Double.isNaN(resolutionPixelInMeters)) {
return;
}
int denom = 1;
for (int i = 0; i < digits_after; i++) denom *= 10;
int fppcm = (int) Math.round(denom * 0.01/resolutionPixelInMeters); // pixels per cm
......@@ -532,41 +354,6 @@ outstr.close();
ifd.appendChild(node_y_resolution);
}
/*
*
IIOMetadataNode node_rationals = new IIOMetadataNode(TIFF_RATIONALS_TAG);
IIOMetadataNode node_hrs = new IIOMetadataNode(TIFF_RATIONAL_TAG);
node_hrs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getHour()+"/1");
IIOMetadataNode node_mins = new IIOMetadataNode(TIFF_RATIONAL_TAG);
node_mins.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, dt.getMinute()+"/1");
IIOMetadataNode node_secs = new IIOMetadataNode(TIFF_RATIONAL_TAG);
node_secs.setAttribute(TIFF_FIELD_VALUE_ATTRIBUTE, fsec+"/"+denom);
node_rationals.appendChild(node_hrs);
node_rationals.appendChild(node_mins);
node_rationals.appendChild(node_secs);
*
* The number of pixels per ResolutionUnit in the ImageWidth direction.
<TIFFField number='282' name='XResolution'>
<TIFFRationals>
<TIFFRational value='1/1'/>
</TIFFRationals>
</TIFFField>
<TIFFField number='283' name='YResolution'>
<TIFFRationals>
<TIFFRational value='1/1'/>
</TIFFRationals>
</TIFFField>
<TIFFField number='296' name='ResolutionUnit'>
<TIFFShorts>
<TIFFShort value='1' description='None'/>
</TIFFShorts>
</TIFFField>
public static String TIFF_SHORTS_TAG = "TIFFShorts";
public static String TIFF_SHORT_TAG = "TIFFShort";
*/
/*
*
FileImageOutputStream outputStream = new FileImageOutputStream(outputFile);
......
......@@ -39,6 +39,7 @@ import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;
......@@ -58,6 +59,7 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.elphel.imagej.correction.Eyesis_Correction;
import com.elphel.imagej.ims.Did_ins;
import com.elphel.imagej.tileprocessor.QuadCLTCPU;
//import org.apache.log4j.Logger;
......@@ -306,9 +308,20 @@ the type of pixel data in this file getPixelType()
boolean imageJTags,
int debugLevel
) throws IOException, FormatException, ServiceException, DependencyException{
double [] lla = { 49.9476514222895,28.5547846609957,323.750316821841};
LocalDateTime dt = Did_ins.getLocalDateTime(2286, 491072.634526699);
double pix_in_meters = 0.01;
if (imp.getType()==ImagePlus.COLOR_RGB) { // 4*8 bit - type = 0
if (debugLevel>1) System.out.println("Saving 8-bit TIFF with alpha-channel: "+path); // is it possible to just add alpha to high bytes?
ElphelTiffWriter.saveTiffARGB32(imp, path, imageJTags, debugLevel);
ElphelTiffWriter.saveTiffARGB32(
imp,
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
imageJTags,
debugLevel);
// saveTiffARGB32(imp, path, imageJTags, debugLevel);
return;
} else if (imp.getStackSize()==4) {
......@@ -341,7 +354,14 @@ the type of pixel data in this file getPixelType()
if (debugLevel>1) System.out.println("Saving 8-bit RGBA TIFF with alpha-channel: "+path); // is it possible to just add alpha to high bytes?
ElphelTiffWriter.saveTiffARGB32(imp_rgb, path, imageJTags, debugLevel);
ElphelTiffWriter.saveTiffARGB32(
imp_rgb,
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
imageJTags,
debugLevel);
// saveTiffARGB32(imp_rgb, path, imageJTags, debugLevel);
return;
}
......
......@@ -5351,6 +5351,11 @@ public class OpticalFlow {
quadCLTs[ref_index].saveInterProperties( // save properties for interscene processing (extrinsics, ers, ...)
null, // String path, // full name with extension or w/o path to use x3d directory
debugLevel+1);
} else {
if (debugLevel> -3) {
System.out.println("Failed to perform attitude correction with QuaternionLma.");
}
}
}
......@@ -5946,7 +5951,6 @@ public class OpticalFlow {
int [] whs = new int[3];
double [] x0y0 = new double[2];
if (export3d) { //combo_dsn_final had strength 1.0e-4 where it should not? Reset it?
boolean ok_3d = TexturedModel.output3d( // quadCLTs have same image name, and everything else
clt_parameters, // CLTParameters clt_parameters,
colorProcParameters, // ColorProcParameters colorProcParameters,
......
......@@ -696,6 +696,7 @@ public class QuadCLTCPU {
System.out.println("getGroundIns(): no INS data available.");
return null;
}
double min_sfm_gain = clt_parameters.gmap_min_sfm ; //10.0 minimal SfM gain to keep ground map
double [] ims_ortho = clt_parameters.imp.ims_ortho;
double [] ims_mount_atr = clt_parameters.imp.getImsMountATR(); // converts to radians
double [] ims_mount_xyz = clt_parameters.imp.ims_mount_xyz; // not yet used
......@@ -721,6 +722,14 @@ public class QuadCLTCPU {
}
double [] scene_abs_atr_enu = Imx5.quatToCamAtr(cam_quat_enu);
double [][] dls = getDLS();
if ((min_sfm_gain> 0) && (dls[3] != null)) {
dls[2]=dls[2].clone();
for (int i = 0; i <dls[2].length; i++) {
if (dls[3][i] < min_sfm_gain) {
dls[2][i] = 0; // zero strength if low SfM gain
}
}
}
if (dls==null) {
return null;
}
......@@ -941,15 +950,16 @@ public class QuadCLTCPU {
public double [][] getDLS(){ // get disparity, disparity_lma, strength
public double [][] getDLS(){ // get disparity, disparity_lma, strength, sfm_gain
if (dsi == null) {
// System.out.println("dsi== null, use spawnQuadCLT(), restoreFromModel(), ... to set it");
return null;
}
double [][] dls = new double[3][];
double [][] dls = new double[4][];
dls[0] = dsi[isAux()? TwoQuadCLT.DSI_DISPARITY_AUX : TwoQuadCLT.DSI_DISPARITY_MAIN];
dls[1] = dsi[isAux()? TwoQuadCLT.DSI_DISPARITY_AUX_LMA : TwoQuadCLT.DSI_DISPARITY_MAIN_LMA];
dls[2] = dsi[isAux()? TwoQuadCLT.DSI_STRENGTH_AUX : TwoQuadCLT.DSI_STRENGTH_MAIN];
dls[3] = dsi[isAux()? TwoQuadCLT.DSI_SFM_GAIN_AUX : TwoQuadCLT.DSI_SFM_GAIN_MAIN];
return dls;
}
......
......@@ -2464,6 +2464,7 @@ public class TexturedModel {
final double discard_rdisp = clt_parameters.gmap_discard_rdisp ; //0.02; // discard above/below this fraction of average height
final double pix_size = clt_parameters.gmap_pix_size ; //0.005; // hdr_x0y0, // in meters
final int max_image_width = clt_parameters.gmap_max_image_width ; //4000; // 3200; // increase pixel size as a power of 2 until image fits
final double min_sfm_gain = clt_parameters.gmap_min_sfm ; //10.0 minimal SfM gain to keep ground map
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};
......@@ -2559,7 +2560,7 @@ public class TexturedModel {
combo_dsn_final[OpticalFlow.COMBO_DSN_INDX_LMA],
combo_dsn_final[OpticalFlow.COMBO_DSN_INDX_STRENGTH]
};
double [] sfm_gain = (min_sfm_gain > 0.0) ? combo_dsn_final[OpticalFlow.COMBO_DSN_INDX_SFM_GAIN] : null;
// currently conditionInitialDS() zeroes disparity for blue_sky. TODO: allow some FG over blue_sky?
// gets Blue Sky from scene.dsi , not from the file!
double [][] ds_fg = OpticalFlow.conditionInitialDS(
......@@ -2584,9 +2585,17 @@ public class TexturedModel {
dls_bg, // double [][] dls
scenes[ref_index], // QuadCLT scene,
debugLevel); // int debug_level)
if (sfm_gain != null) {
for (int i = 0; i < ds_fg[0].length; i++) if (sfm_gain[i] < min_sfm_gain){
ds_fg[0][i] = Double.NaN;
ds_bg[0][i] = Double.NaN;
ds_fg[1][i] = 0.0;
ds_bg[1][i] = 0.0;
}
}
double[][] ds_fg_bg = {ds_fg[0], ds_bg[0].clone()};
double[][] ss_fg_bg = {ds_fg[1], ds_bg[1]};
if (show_bs_debug) {
String [] dbg_titles = {"FG","BG","BS"};
double [][] dbg_img = {ds_fg_bg[0], ds_fg_bg[1],combo_dsn_final[OpticalFlow.COMBO_DSN_INDX_BLUE_SKY].clone()};
......@@ -2612,10 +2621,10 @@ public class TexturedModel {
}
for (int i = 0; i < ss_fg_bg[0].length; i++) {
if (Double.isNaN(dls_fg[1][i])){
ss_fg_bg[0][i] = 0.0001;
ss_fg_bg[0][i] = Math.min(ss_fg_bg[0][i],0.0001); // do not increase if it was already 0
}
if (Double.isNaN(dls_bg[1][i])){
ss_fg_bg[1][i] = 0.0001;
ss_fg_bg[1][i] = Math.min(ss_fg_bg[1][i],0.0001); // do not increase if it was already 0
}
}
}
......@@ -2979,7 +2988,7 @@ public class TexturedModel {
}
// if (imp_textures[nslice] != null)
} // for (int nslice = 0; nslice < tileClusters.length; nslice++){
if (render_hdr) {
if (render_hdr) { //
int [] hdr_whs = new int[3];
double [] hdr_x0y0 = new double[2];
double [][] to_ground_xyzatr = scenes[ref_index].getGround(
......
......@@ -254,6 +254,7 @@ public class Render3D {
if ((tri_meshes == null) || tri_meshes.isEmpty() || (tri_meshes.get(0).getTexturePixels() == null)) {
return null;
}
final boolean export_z = true;
final int dbg_ipix=1673752;
// get total number of triangles
int num_tri=0;
......@@ -276,7 +277,7 @@ public class Render3D {
System.out.println("Prepare to render "+num_tri+" triangles in "+num_mesh+" meshes");
}
final int z_index = tri_meshes.get(0).getTexturePixels().length;
final double [][] full_rendered = new double[z_index][out_width * out_height];
final double [][] full_rendered = new double[z_index+ (export_z? 1:0)][out_width * out_height];
int alpha_index = last_is_alpha ? (z_index - 1) : z_index;
for (int chn = 0; chn < alpha_index; chn++) {
Arrays.fill(full_rendered[chn], Double.NaN);
......@@ -361,12 +362,12 @@ public class Render3D {
double kx = dot2(d0p, orto2[0]);
double ky = dot2(d0p, orto2[1]);
// interpolate z
double z_interp = tri_out2[0][2] + kx * (tri_out2[1][2]-tri_out2[0][2]) + ky*(tri_out2[1][2]-tri_out2[0][2]);
double z_interp = tri_out2[0][2] +
kx * (tri_out2[1][2]-tri_out2[0][2]) +
ky * (tri_out2[2][2]-tri_out2[0][2]);
if ((rend[ipix] != null ) && (rend[ipix][z_index] < z_interp)) {
continue;
}
// Get corresponding texture coordinates
double text_x = tri_text2[0][0] + kx * t01[0] + ky*t02[0]; // texture relative coordinates (0,1)
double text_y = tri_text2[0][1] + kx * t01[1] + ky*t02[1]; // y - up!
......@@ -426,7 +427,7 @@ public class Render3D {
for (int sub_render = 0; sub_render < rendered.length; sub_render++) if (rendered[sub_render][indx] != null){
if (!(rendered[sub_render][indx][z_index] <= z)) { // OK previous NaN
z = rendered[sub_render][indx][z_index];
for (int chn = 0; chn < z_index; chn++) {
for (int chn = 0; chn < full_rendered.length; chn++) { // z_index; chn++) {
full_rendered[chn][indx] = rendered[sub_render][indx][chn];
}
}
......@@ -549,12 +550,12 @@ public class Render3D {
double kx = dot2(d0p, orto2[0]);
double ky = dot2(d0p, orto2[1]);
// interpolate z
double z_interp = tri_out2[0][2] + kx * (tri_out2[1][2]-tri_out2[0][2]) + ky*(tri_out2[1][2]-tri_out2[0][2]);
double z_interp = tri_out2[0][2] +
kx * (tri_out2[1][2]-tri_out2[0][2]) +
ky * (tri_out2[2][2]-tri_out2[0][2]);
if ((rend[ipix] != null ) && (rend[ipix][z_index] < z_interp)) {
continue;
}
// Get corresponding texture coordinates
double text_x = tri_text2[0][0] + kx * t01[0] + ky*t02[0]; // texture relative coordinates (0,1)
double text_y = tri_text2[0][1] + kx * t01[1] + ky*t02[1]; // y - up!
......
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