Loading src/main/java/com/elphel/imagej/orthomosaic/FloatImageData.java +195 −23 Original line number Original line Diff line number Diff line package com.elphel.imagej.orthomosaic; package com.elphel.imagej.orthomosaic; import java.awt.Rectangle; import java.awt.Rectangle; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Arrays; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger; import com.elphel.imagej.common.PolynomialApproximation; import com.elphel.imagej.common.PolynomialApproximation; import com.elphel.imagej.readers.ElphelTiffReader; import com.elphel.imagej.tileprocessor.ImageDtt; import com.elphel.imagej.tileprocessor.ImageDtt; public class FloatImageData { import ij.ImagePlus; public class FloatImageData implements Serializable { private static final long serialVersionUID = 1L; public static boolean FIX_VERT_Y = false; // true; // temporarily fix vertical Y coordinate bug (use -GCORR in the filename?) public int width; public int width; public int height; public int height; public int zoom_lev; public int zoom_lev; private boolean zoom_valid; public String path; public Properties properties; // serializable private double [] lla; // lat/long/alt public LocalDateTime dt; private double [] vert = new double[2]; // x,y offset (in meters) of the point under the camera private double [] vert = new double[2]; // x,y offset (in meters) of the point under the camera public float[] data; private double pix_meters; private double averagePixel=Double.NaN; private transient float[] data; // make transient public FloatImageData ( public FloatImageData ( int width, String path) { int height, this.path = path; int zoom_lev, try { double [] vert, // x,y pixel offset of the point under the camera properties = ElphelTiffReader.getTiffMeta(path); float[] data) { } catch (IOException e) { this.width = width; // TODO Auto-generated catch block this.height = height; e.printStackTrace(); this.zoom_lev = zoom_lev; } this.vert = vert.clone(); try { this.data = data; lla = ElphelTiffReader.getLLA(properties); } catch (NullPointerException e) { System.out.println("No GPS data in "+path); // TODO Auto-generated catch block e.printStackTrace(); } dt = ElphelTiffReader.getLocalDateTime(properties); vert = ElphelTiffReader.getXYOffsetMeters(properties); pix_meters = ElphelTiffReader.getPixelSize(properties)[0]; if (FIX_VERT_Y) { int height_pix = ElphelTiffReader.getHeight(properties); double height_meters = height_pix * pix_meters; vert[1] = height_meters-vert[1]; } width = ElphelTiffReader.getWidth(properties); height = ElphelTiffReader.getHeight(properties); zoom_lev = getZoomLevel(pix_meters); zoom_valid = isZoomValid(pix_meters); } } public int getWidth() { private void writeObject(ObjectOutputStream oos) throws IOException { return width; oos.defaultWriteObject(); } } public int getHeight() { return height; private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); data = null; } } public double[] getVertMeters() { public void updateLLA() { return vert; try { properties = ElphelTiffReader.getTiffMeta(path); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { lla = ElphelTiffReader.getLLA(properties); } catch (NullPointerException e) { System.out.println("No GPS data in "+path); // TODO Auto-generated catch block e.printStackTrace(); } } float [] readFData() { if (data == null) { ImagePlus imp = new ImagePlus(path); int width = imp.getWidth(); int height = imp.getHeight(); if ((width != this.width) || (height != this.height)) { throw new IllegalArgumentException (String.format("IJ image size does not match Exif one: (%d,%d) != (%d,%d)", width,height, this.width,this.height)); } data = (float[]) (imp.getProcessor().getPixels()); } } return data; } public double [] getDData() { public double [] getDData() { if (data==null) { readFData(); if (data== null) { return null; } } final double [] ddata = new double [data.length]; final double [] ddata = new double [data.length]; final Thread[] threads = ImageDtt.newThreadArray(); final Thread[] threads = ImageDtt.newThreadArray(); final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ai = new AtomicInteger(0); Loading @@ -53,6 +124,103 @@ public class FloatImageData { return ddata; return ddata; } } public double [] getLLA() { return lla; // null if does not exist, saved with data file } public LocalDateTime getDT() { return dt; } public boolean isZoomValid() { if (!zoom_valid) { System.out.println("Original zoom level is invalid, need_extra_zoom = "+needZoomIn(pix_meters)); } return zoom_valid; } /** * Get vertical point offset from the top-left corner of the original orthoimage in pixels * of the original resolution * @return vertical point X,Y offset in pixels from the top-left image corner in original resolution */ public int [] getVertPixels() { double [] vm = getVertMeters(); return new int [] { (int) Math.round(vm[0]/pix_meters), (int) Math.round(vm[1]/pix_meters)}; } public double getPixMeters() { return pix_meters; } public FloatImageData ( FloatImageData master, int zoom_level, float[] data) { this.width = master.width; this.height = master.height; this.zoom_valid = master.zoom_valid; this.path = master.path; this.properties = master.properties; this.lla = master.lla; this.dt = master.dt; this.vert = master.vert; this.pix_meters = master.pix_meters; this.averagePixel = master.averagePixel; this.zoom_lev = zoom_level; this.data = data; } public double getAveragePixel() { if (Double.isNaN(averagePixel)) { final float [] pixels = readFData(); final Thread[] threads = ImageDtt.newThreadArray(); final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ati = new AtomicInteger(0); final double [] avg_arr = new double [threads.length]; final double [] npix_arr = 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 ipix = ai.getAndIncrement(); ipix < pixels.length; ipix = ai.getAndIncrement()) { float p = pixels[ipix]; if (!Float.isNaN(p)) { avg_arr[thread_num] += p; npix_arr[thread_num] +=1; } } } }; } ImageDtt.startAndJoin(threads); double avg=0, num=0; for (int i = 0; i < avg_arr.length; i++) { avg+=avg_arr[i]; // *npix_arr[i]; num+=npix_arr[i]; } averagePixel = avg/num; } return averagePixel; } public int getWidth() { return width; } public int getHeight() { return height; } public double[] getVertMeters() { return vert; } public static int getZoomLevel( public static int getZoomLevel( double pix_in_meters) { double pix_in_meters) { return getZoomLevel (pix_in_meters, null, null); return getZoomLevel (pix_in_meters, null, null); Loading @@ -70,6 +238,10 @@ public class FloatImageData { return extra_zoom[0]; return extra_zoom[0]; } } public int getZoomLevel() { return zoom_lev; } /** /** * Find scale level (0: 1pix/cm, 1 - 2pix/cm, -1 - 0.5 pix/cm) from pixel size in meters * 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] * If scale does not match, provide false in optional valid_zoom[0] Loading src/main/java/com/elphel/imagej/orthomosaic/ObjectLocation.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class ObjectLocation { OrthoMap [] ortho_maps=maps_collection.getMaps(); OrthoMap [] ortho_maps=maps_collection.getMaps(); final int width = ortho_maps[nmap].getImageData().width; final int width = ortho_maps[nmap].getImageData().width; final int height = ortho_maps[nmap].getImageData().height; final int height = ortho_maps[nmap].getImageData().height; final float [] src_img = ortho_maps[nmap].getImageData().data; final float [] src_img = ortho_maps[nmap].getImageData().readFData(); double [] dcrop = new double [size*size]; double [] dcrop = new double [size*size]; Arrays.fill(dcrop, Double.NaN); Arrays.fill(dcrop, Double.NaN); int hsize = size/2; int hsize = size/2; Loading Loading
src/main/java/com/elphel/imagej/orthomosaic/FloatImageData.java +195 −23 Original line number Original line Diff line number Diff line package com.elphel.imagej.orthomosaic; package com.elphel.imagej.orthomosaic; import java.awt.Rectangle; import java.awt.Rectangle; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Arrays; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger; import com.elphel.imagej.common.PolynomialApproximation; import com.elphel.imagej.common.PolynomialApproximation; import com.elphel.imagej.readers.ElphelTiffReader; import com.elphel.imagej.tileprocessor.ImageDtt; import com.elphel.imagej.tileprocessor.ImageDtt; public class FloatImageData { import ij.ImagePlus; public class FloatImageData implements Serializable { private static final long serialVersionUID = 1L; public static boolean FIX_VERT_Y = false; // true; // temporarily fix vertical Y coordinate bug (use -GCORR in the filename?) public int width; public int width; public int height; public int height; public int zoom_lev; public int zoom_lev; private boolean zoom_valid; public String path; public Properties properties; // serializable private double [] lla; // lat/long/alt public LocalDateTime dt; private double [] vert = new double[2]; // x,y offset (in meters) of the point under the camera private double [] vert = new double[2]; // x,y offset (in meters) of the point under the camera public float[] data; private double pix_meters; private double averagePixel=Double.NaN; private transient float[] data; // make transient public FloatImageData ( public FloatImageData ( int width, String path) { int height, this.path = path; int zoom_lev, try { double [] vert, // x,y pixel offset of the point under the camera properties = ElphelTiffReader.getTiffMeta(path); float[] data) { } catch (IOException e) { this.width = width; // TODO Auto-generated catch block this.height = height; e.printStackTrace(); this.zoom_lev = zoom_lev; } this.vert = vert.clone(); try { this.data = data; lla = ElphelTiffReader.getLLA(properties); } catch (NullPointerException e) { System.out.println("No GPS data in "+path); // TODO Auto-generated catch block e.printStackTrace(); } dt = ElphelTiffReader.getLocalDateTime(properties); vert = ElphelTiffReader.getXYOffsetMeters(properties); pix_meters = ElphelTiffReader.getPixelSize(properties)[0]; if (FIX_VERT_Y) { int height_pix = ElphelTiffReader.getHeight(properties); double height_meters = height_pix * pix_meters; vert[1] = height_meters-vert[1]; } width = ElphelTiffReader.getWidth(properties); height = ElphelTiffReader.getHeight(properties); zoom_lev = getZoomLevel(pix_meters); zoom_valid = isZoomValid(pix_meters); } } public int getWidth() { private void writeObject(ObjectOutputStream oos) throws IOException { return width; oos.defaultWriteObject(); } } public int getHeight() { return height; private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); data = null; } } public double[] getVertMeters() { public void updateLLA() { return vert; try { properties = ElphelTiffReader.getTiffMeta(path); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { lla = ElphelTiffReader.getLLA(properties); } catch (NullPointerException e) { System.out.println("No GPS data in "+path); // TODO Auto-generated catch block e.printStackTrace(); } } float [] readFData() { if (data == null) { ImagePlus imp = new ImagePlus(path); int width = imp.getWidth(); int height = imp.getHeight(); if ((width != this.width) || (height != this.height)) { throw new IllegalArgumentException (String.format("IJ image size does not match Exif one: (%d,%d) != (%d,%d)", width,height, this.width,this.height)); } data = (float[]) (imp.getProcessor().getPixels()); } } return data; } public double [] getDData() { public double [] getDData() { if (data==null) { readFData(); if (data== null) { return null; } } final double [] ddata = new double [data.length]; final double [] ddata = new double [data.length]; final Thread[] threads = ImageDtt.newThreadArray(); final Thread[] threads = ImageDtt.newThreadArray(); final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ai = new AtomicInteger(0); Loading @@ -53,6 +124,103 @@ public class FloatImageData { return ddata; return ddata; } } public double [] getLLA() { return lla; // null if does not exist, saved with data file } public LocalDateTime getDT() { return dt; } public boolean isZoomValid() { if (!zoom_valid) { System.out.println("Original zoom level is invalid, need_extra_zoom = "+needZoomIn(pix_meters)); } return zoom_valid; } /** * Get vertical point offset from the top-left corner of the original orthoimage in pixels * of the original resolution * @return vertical point X,Y offset in pixels from the top-left image corner in original resolution */ public int [] getVertPixels() { double [] vm = getVertMeters(); return new int [] { (int) Math.round(vm[0]/pix_meters), (int) Math.round(vm[1]/pix_meters)}; } public double getPixMeters() { return pix_meters; } public FloatImageData ( FloatImageData master, int zoom_level, float[] data) { this.width = master.width; this.height = master.height; this.zoom_valid = master.zoom_valid; this.path = master.path; this.properties = master.properties; this.lla = master.lla; this.dt = master.dt; this.vert = master.vert; this.pix_meters = master.pix_meters; this.averagePixel = master.averagePixel; this.zoom_lev = zoom_level; this.data = data; } public double getAveragePixel() { if (Double.isNaN(averagePixel)) { final float [] pixels = readFData(); final Thread[] threads = ImageDtt.newThreadArray(); final AtomicInteger ai = new AtomicInteger(0); final AtomicInteger ati = new AtomicInteger(0); final double [] avg_arr = new double [threads.length]; final double [] npix_arr = 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 ipix = ai.getAndIncrement(); ipix < pixels.length; ipix = ai.getAndIncrement()) { float p = pixels[ipix]; if (!Float.isNaN(p)) { avg_arr[thread_num] += p; npix_arr[thread_num] +=1; } } } }; } ImageDtt.startAndJoin(threads); double avg=0, num=0; for (int i = 0; i < avg_arr.length; i++) { avg+=avg_arr[i]; // *npix_arr[i]; num+=npix_arr[i]; } averagePixel = avg/num; } return averagePixel; } public int getWidth() { return width; } public int getHeight() { return height; } public double[] getVertMeters() { return vert; } public static int getZoomLevel( public static int getZoomLevel( double pix_in_meters) { double pix_in_meters) { return getZoomLevel (pix_in_meters, null, null); return getZoomLevel (pix_in_meters, null, null); Loading @@ -70,6 +238,10 @@ public class FloatImageData { return extra_zoom[0]; return extra_zoom[0]; } } public int getZoomLevel() { return zoom_lev; } /** /** * Find scale level (0: 1pix/cm, 1 - 2pix/cm, -1 - 0.5 pix/cm) from pixel size in meters * 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] * If scale does not match, provide false in optional valid_zoom[0] Loading
src/main/java/com/elphel/imagej/orthomosaic/ObjectLocation.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class ObjectLocation { OrthoMap [] ortho_maps=maps_collection.getMaps(); OrthoMap [] ortho_maps=maps_collection.getMaps(); final int width = ortho_maps[nmap].getImageData().width; final int width = ortho_maps[nmap].getImageData().width; final int height = ortho_maps[nmap].getImageData().height; final int height = ortho_maps[nmap].getImageData().height; final float [] src_img = ortho_maps[nmap].getImageData().data; final float [] src_img = ortho_maps[nmap].getImageData().readFData(); double [] dcrop = new double [size*size]; double [] dcrop = new double [size*size]; Arrays.fill(dcrop, Double.NaN); Arrays.fill(dcrop, Double.NaN); int hsize = size/2; int hsize = size/2; Loading