Commit 66cd4b7e authored by Andrey Filippov's avatar Andrey Filippov

Simultaneous LWIR/VNIR acquisition: added configurable parameters

parent 3649ef29
...@@ -107,6 +107,17 @@ ...@@ -107,6 +107,17 @@
<resource> <resource>
<directory>${project.build.sourceDirectory}</directory> <directory>${project.build.sourceDirectory}</directory>
</resource> </resource>
<!-- trying to copy deep classes to top for the imageJ to see as plugins-->
<!--
<resource>
<filtering>true</filtering>
<directory>${basedir}/target/classes/com/elphel/imagej/jp4</directory>
<targetPath>${basedir}/target/classes</targetPath>
<includes>
<include>JP46_Reader_camera.class</include>
</includes>
</resource>
-->
</resources> </resources>
<testResources> <testResources>
<testResource> <testResource>
......
/**
** -----------------------------------------------------------------------------**
** JP46_Reader_camera0.java
**
** Reads Elphel Camera JP46 files into ImageJ, un-applying gamma and gains
**
** Copyright (C) 2010 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** JP46_Reader.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import ij.IJ;
import ij.ImageJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.Prefs;
import ij.WindowManager;
import ij.gui.GUI;
import ij.gui.GenericDialog;
import ij.io.FileInfo;
import ij.io.OpenDialog;
import ij.plugin.frame.PlugInFrame;
import ij.process.ImageConverter;
import ij.process.ImageProcessor;
import ij.text.TextWindow;
/* This plugin opens images in Elphel JP4/JP46 format (opens as JPEG, reads MakerNote and converts). */
public class JP46_Reader_camera0 extends PlugInFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 390855361964415147L;
Panel panel1;
Panel confpanel;
Frame instance;
String arg;
static File dir;
public String camera_url = "http://192.168.0.236:8081/";
public String camera_img = "bimg";
public String camera_img_new = "towp/wait/bimg"; // will always wait for the next image (repetitive acquisitions get new images)
public String camera_jp46settings = "";
public boolean IS_SILENT=true;
public boolean ABSOLUTELY_SILENT=false;
public boolean demux=true;
public String imageTitle="cameraImage";
private int ExifOffset=0x0c;
public JP46_Reader_camera0() {
super("JP46 Reader Camera");
if (IJ.versionLessThan("1.39t")) return;
if (instance!=null) {
instance.toFront();
return;
}
instance = this;
addKeyListener(IJ.getInstance());
panel1 = new Panel();
panel1.setLayout(new GridLayout(6, 1, 50, 5));
addButton("Open JP4/JP46...",panel1);
addButton("Open JP4/JP46 from camera",panel1);
addButton("Configure...",panel1);
addButton("Show image properties",panel1);
addButton("Decode image info to properties",panel1);
addButton("Split Bayer",panel1);
add(panel1);
pack();
GUI.center(this);
setVisible(true);
}
public JP46_Reader_camera0(boolean showGUI) {
super("JP46 Reader Camera");
if (IJ.versionLessThan("1.39t")) return;
if (instance!=null) {
instance.toFront();
return;
}
instance = this;
addKeyListener(IJ.getInstance());
panel1 = new Panel();
panel1.setLayout(new GridLayout(6, 1, 50, 5));
addButton("Open JP4/JP46...",panel1);
addButton("Open JP4/JP46 from camera",panel1);
addButton("Configure...",panel1);
addButton("Show image properties",panel1);
addButton("Decode image info to properties",panel1);
addButton("Split Bayer",panel1);
add(panel1);
pack();
GUI.center(this);
setVisible(showGUI);
if (!showGUI) {
this.ABSOLUTELY_SILENT = true;
}
}
void addButton(String label, Panel panel) {
Button b = new Button(label);
b.addActionListener(this);
b.addKeyListener(IJ.getInstance());
panel.add(b);
}
@Override
public void actionPerformed(ActionEvent e) {
String label = e.getActionCommand();
/* nothing */
if (label==null) return;
/* button */
if (label.equals("Open JP4/JP46...")) {
read_jp46(arg,true);
}else if (label.equals("Open JP4/JP46 (no scale)...")) {
read_jp46(arg,false);
}else if (label.equals("Configure...")) {
showConfigDialog(); // open configure dialog
}else if (label.equals("Open JP4/JP46 from camera")) {
openURL(camera_url + camera_img_new + camera_jp46settings, arg, true);
}else if (label.equals("Open JP4/JP46 from camera (no scale)")) {
openURL(camera_url + camera_img_new + camera_jp46settings, arg, false);
}else if (label.equals("Show image properties")) {
ImagePlus imp_sel = WindowManager.getCurrentImage();
if (imp_sel==null){
IJ.showMessage("Error","No images selected");
return;
}
listImageProperties (imp_sel);
}
else if (label.equals("Decode image info to properties")) {
ImagePlus imp_sel = WindowManager.getCurrentImage();
if (imp_sel==null){
IJ.showMessage("Error","No images selected");
return;
}
decodeProperiesFromInfo(imp_sel);
listImageProperties (imp_sel);
}
else if (label.equals("Split Bayer")) {
ImagePlus imp_sel = WindowManager.getCurrentImage();
if (imp_sel==null){
IJ.showMessage("Error","No images selected");
return;
}
splitShowBayer(imp_sel);
}
IJ.showStatus("DONE");
}
public void splitShowBayer(ImagePlus imp){
float [] pixels= (float[]) imp.getProcessor().getPixels();
int height=imp.getHeight();
int width= imp.getWidth();
int halfHeight=height/2;
int halfWidth=width/2;
float [][] bayerPixels=new float[4][halfHeight * halfWidth];
for (int iy=0;iy<halfHeight;iy++) for (int ix=0;ix<halfWidth;ix++){
int oIndex=iy*halfWidth+ix;
int iIndex=iy*2*width+ix*2;
bayerPixels[0][oIndex]=pixels[iIndex];
bayerPixels[1][oIndex]=pixels[iIndex+1];
bayerPixels[2][oIndex]=pixels[iIndex+width];
bayerPixels[3][oIndex]=pixels[iIndex+width+1];
}
ImageStack array_stack=new ImageStack(halfWidth,halfHeight);
for (int i=0;i<4;i++) array_stack.addSlice("chn-"+i, bayerPixels[i]);
ImagePlus imp_stack = new ImagePlus(imp.getTitle()+"-BAYER", array_stack);
imp_stack.getProcessor().resetMinAndMax();
imp_stack.show();
}
public void read_jp46(String arg, boolean scale) {
JFileChooser fc=null;
//try {fc = new JFileChooser();}
fc = new JFileChooser();
//catch (Throwable e) {IJ.error("This plugin requires Java 2 or Swing."); return;}
fc.setMultiSelectionEnabled(true);
if (dir==null) {
String sdir = OpenDialog.getDefaultDirectory();
if (sdir!=null)
dir = new File(sdir);
}
if (dir!=null)
fc.setCurrentDirectory(dir);
int returnVal = fc.showOpenDialog(IJ.getInstance());
if (returnVal!=JFileChooser.APPROVE_OPTION)
return;
File[] files = fc.getSelectedFiles();
if (files.length==0) { // getSelectedFiles does not work on some JVMs
files = new File[1];
files[0] = fc.getSelectedFile();
}
String path = fc.getCurrentDirectory().getPath()+Prefs.getFileSeparator();
dir = fc.getCurrentDirectory();
for (int i=0; i<files.length; i++) {
open(path, files[i].getName(), arg, scale);
}
}
public boolean showConfigDialog() {
GenericDialog gd = new GenericDialog("Configure");
gd.addStringField ("Image title: ", getTitle(), 20);
gd.addStringField("Camera Address: ", getURL(), 20);
gd.addStringField("Image: ", camera_img, 20);
gd.addStringField("Image (new): ", camera_img_new, 20);
gd.addStringField("JP46 Parameters: ", camera_jp46settings, 50);
gd.addCheckbox("Demux composite frame? ", demux);
gd.addCheckbox("Silent? ", IS_SILENT);
// gd.addCheckbox("JP4 (not JP46)? ", IS_JP4);
confpanel = new Panel();
gd.addPanel(confpanel);
addButton("Open JP4/JP46 (no scale)...", confpanel);
addButton("Open JP4/JP46 from camera (no scale)", confpanel);
//Vector textfields = gd.getStringFields();
//((TextField)fields.elementAt(0)).SetWidth = 20;
gd.showDialog();
if (gd.wasCanceled()) return false;
setTitle(gd.getNextString());
setURL (gd.getNextString());
camera_img = gd.getNextString();
camera_img_new = gd.getNextString();
camera_jp46settings = gd.getNextString();
demux=gd.getNextBoolean();
IS_SILENT=gd.getNextBoolean();
return true;
}
public ImagePlus open(String directory, String fileName, String arg, boolean scale) {
return open(directory, fileName, arg, scale, null,true);
}
public ImagePlus open(String directory, String fileName, String arg, boolean scale, ImagePlus imp_src) {
return open(directory, fileName, arg, scale, imp_src,true);
}
public ImagePlus open(
String directory,
String fileName,
String arg,
boolean scale,
ImagePlus imp_src,
boolean showImage) {
long[] ElphelMakerNote=null;
ImagePlus imp = null;
boolean reuse_imp=false;
boolean showDemux=showImage && demux;
if (demux) showImage=false;
double [] xtraExif=new double[1]; // ExposureTime
double [] lla = null;
try {
imp = openJpegOrGif(directory, fileName);
if (imp == null) {
IJ.showMessage("JP46 Reader Error", "Could not open "+directory+"" + fileName + " as JPEG/JP46");
} else {
if ((imp_src==null)&& showImage) imp.show(); /* Shows before re-ordering*/
ElphelMakerNote = readElphelMakerNote(directory, fileName, 16,xtraExif); /* after or 8.2.2 */
if (ElphelMakerNote==null) ElphelMakerNote = readElphelMakerNote(directory, fileName, 14,xtraExif); /* after or 8.0.8.32 */
if (ElphelMakerNote==null) ElphelMakerNote = readElphelMakerNote(directory, fileName, 12,xtraExif); /* after or 8.0.7.3 */
if (ElphelMakerNote==null) ElphelMakerNote = readElphelMakerNote(directory, fileName, 8 ,xtraExif); /* before 8.0.7.3 */
lla = readGpsLLA(directory, fileName);
if (lla != null) {
imp.setProperty("LATITUDE", String.format("%f",lla[0]));
imp.setProperty("LONGITUDE", String.format("%f",lla[1]));
imp.setProperty("ALTITUDE", String.format("%f",lla[2]));
}
}
} catch (IOException e) {
IJ.showStatus("");
String error = e.getMessage();
if (error==null || error.equals("")) error = ""+e;
IJ.showMessage("JP46 Reader", ""+error);
return null;
}
if (imp!=null) {
reuse_imp=jp46Reorder(imp, ElphelMakerNote, scale, imp_src);
if (reuse_imp) {
imp=imp_src;
} else if ((imp_src!=null)&& showImage) { /* tried to reuse, but wrong size */
imp.show(); /* never did that before */
}
if ((xtraExif!=null) && !Double.isNaN(xtraExif[0])){
imp.setProperty("EXPOSURE", String.format("%f",xtraExif[0]));
}
if (showImage) imp.updateAndDraw(); /* Redisplays final image*/
if (showDemux) {
if (!this.ABSOLUTELY_SILENT) System.out.println("demuxing...");
ImagePlus imp_0 = demuxImage(imp, 0); if (imp_0!=null) imp_0.show();
ImagePlus imp_1 = demuxImage(imp, 1); if (imp_1!=null) imp_1.show();
ImagePlus imp_2 = demuxImage(imp, 2); if (imp_2!=null) imp_2.show();
if ((imp_0==null) && (imp_0==null) && (imp_0==null)) imp.show(); // Show original image if demux failed (single original)
}
return imp;
}
return null;
}
public ImagePlus openURL(ImagePlus imp_src) {
if (imp_src==null) return openURL(camera_url + camera_img_new + camera_jp46settings, arg, true);
return openURL(camera_url + camera_img_new + camera_jp46settings, arg, true, imp_src,true);
}
public ImagePlus openURL() {
return openURL(camera_url + camera_img_new + camera_jp46settings, arg, true);
}
public ImagePlus openURL(String url, String arg, boolean scale) {
return openURL(url, arg, scale, null,true);
}
public ImagePlus openURL(
String url,
String arg,
boolean scale,
ImagePlus imp_src,
boolean showImage) {
long[] ElphelMakerNote=null;
ImagePlus imp = null;
boolean reuse_imp=false;
boolean showDemux=showImage && demux;
if (demux) showImage=false;
double [] xtraExif=new double[1]; // ExposureTime
// System.out.println("imp_src is "+((imp_src!=null)?"not ":"")+"null");
try {
imp = openJpegOrGifUsingURL(url);
if (imp == null) {
IJ.showMessage("JP46 Reader Error", "Could not open the URL: " + url + " as JPEG/JP46");
} else {
if ((imp_src==null) && showImage) {
// System.out.println("show() 1");
imp.show(); /* Shows before re-ordering*/
}
/// get rid of the "/towp/wait" if any - there is a chance to re-read the same image
ElphelMakerNote = readElphelMakerNoteURL(url.replaceFirst("/towp/wait",""), 16,xtraExif); /* after or 8.2.2 */
if (ElphelMakerNote==null) ElphelMakerNote = readElphelMakerNoteURL(url.replaceFirst("/towp/wait",""), 14,xtraExif); /* after or 8.0.8.32 */
if (ElphelMakerNote==null) ElphelMakerNote = readElphelMakerNoteURL(url.replaceFirst("/towp/wait",""), 12,xtraExif); /* after or 8.0.7.3 */
if (ElphelMakerNote==null) ElphelMakerNote = readElphelMakerNoteURL(url.replaceFirst("/towp/wait",""), 8 ,xtraExif ); /* before 8.0.7.3 */
}
} catch (IOException e) {
IJ.showStatus("");
String error = e.getMessage();
if (error==null || error.equals(""))
error = ""+e;
IJ.showMessage("JP46 Reader", ""+error);
return null;
}
if (imp!=null) {
reuse_imp=jp46Reorder(imp, ElphelMakerNote, scale, imp_src);
if (reuse_imp) {
imp=imp_src;
} else if ((imp_src!=null) && showImage) { /* tried to reuse, but wrong size */
// System.out.println("show() 2");
imp.show(); /* never did that before */
}
if ((xtraExif!=null) && !Double.isNaN(xtraExif[0])){
imp.setProperty("EXPOSURE", String.format("%f",xtraExif[0]));
}
if (showImage) imp.updateAndDraw(); /* Redisplays final image*/
if (showDemux) {
if (!this.ABSOLUTELY_SILENT) System.out.println("demuxing...");
ImagePlus imp_0 = demuxImage(imp, 0); if (imp_0!=null) imp_0.show();
ImagePlus imp_1 = demuxImage(imp, 1); if (imp_1!=null) imp_1.show();
ImagePlus imp_2 = demuxImage(imp, 2); if (imp_2!=null) imp_2.show();
if ((imp_0==null) && (imp_0==null) && (imp_0==null)) imp.show(); // Show original image if demux failed (single original)
}
return imp;
}
return null;
}
boolean jp46Reorder(ImagePlus imp, long[] MakerNote, boolean scale) {
return jp46Reorder(imp, MakerNote, scale, null);
}
void swapArrayElements (double[]arr,int i, int j) {
double tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
void swapArrayElements (long[]arr,int i, int j) {
long tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
boolean jp46Reorder(ImagePlus imp, long[] MakerNote, boolean scale, ImagePlus imp_src) {
// int MARGIN=2; // 2 pixels in JP4/JP46 mode around WOI
double[] gains= new double[4];
double[] blacks= new double[4];
double[] blacks256= new double[4];
double[] gammas= new double[4];
long [] gamma_scales= new long[4]; /* now not used, was scale _after_ gamma is applied, 0x400(default) corresponds to 1.0 */
int i;
double[][] rgammas=new double[4][];
double min_gain;
long WOI_LEFT,WOI_WIDTH,WOI_TOP,WOI_HEIGHT,BAYER_MODE,DCM_HOR,DCM_VERT,BIN_HOR,BIN_VERT;
long COLOR_MODE=0;
long FLIPH=0;
long FLIPV=0;
long HEIGHT1=0;
long HEIGHT2=0;
long HEIGHT3=0;
long BLANK1=0;
long BLANK2=0;
boolean FLIPH1=false;
boolean FLIPV1=false;
boolean FLIPH2=false;
boolean FLIPV2=false;
boolean FLIPH3=false;
boolean FLIPV3=false;
boolean COMPOSITE=false;
boolean PORTRAIT=false;
boolean YTABLEFORC=false;
long QUALITY=0;
long CQUALITY=0;
long CORING_INDEX_Y=0;
long CORING_INDEX_C=0;
double [] satValue={255.0, 255.0, 255.0, 255.0};
if (MakerNote !=null) {
for (i=0;i<4;i++) { /* r,g,gb,b */
gains[i]= MakerNote[i]/65536.0;
blacks[i]=(MakerNote[i+4]>>24)/256.0;
gammas[i]=((MakerNote[i+4]>>16)&0xff)/100.0;
gamma_scales[i]=MakerNote[i+4] & 0xffff;
imp.setProperty("gains_"+i,String.format("%f",gains[i]));
imp.setProperty("blacks_"+i,String.format("%f",blacks[i]));
imp.setProperty("gammas_"+i,String.format("%f",gammas[i]));
imp.setProperty("gamma_scales_"+i,String.format("%d",gamma_scales[i]));
}
IJ.showStatus("R=" +(0.001*((int)(1000*gains[0])))+
" G=" +IJ.d2s(gains[1],3)+
" Gb="+IJ.d2s(gains[2],3)+
" B=" +IJ.d2s(gains[3],3)+
" Gamma[0]="+IJ.d2s(gammas[0],3)+
" Black[0]="+((int) (256*blacks[0])));
String info=new String();
info+="Gain\t"+ IJ.d2s(gains[0],3) + "\t"+ IJ.d2s(gains[1],3) + "\t"+ IJ.d2s(gains[2],3) + "\t"+ IJ.d2s(gains[3],3) + "\n"+
"Gamma\t"+IJ.d2s(gammas[0],3) + "\t"+IJ.d2s(gammas[1],3) + "\t"+IJ.d2s(gammas[2],3) + "\t"+IJ.d2s(gammas[3],3) + "\n"+
"Black\t"+IJ.d2s(blacks[0],3) + "\t"+IJ.d2s(blacks[1],3) + "\t"+IJ.d2s(blacks[2],3) + "\t"+IJ.d2s(blacks[3],3) + "\n";
if (MakerNote.length>=14) {
COMPOSITE= ((MakerNote[10] & 0xc0000000)!=0);
if (COMPOSITE) {
HEIGHT1= MakerNote[11] & 0xffff;
BLANK1= (MakerNote[11]>>16) & 0xffff;
HEIGHT2= MakerNote[12] & 0xffff;
BLANK2= (MakerNote[12]>>16) & 0xffff;
// HEIGHT3=(( MakerNote[9]>>16)+2*MARGIN) - HEIGHT1-BLANK1-HEIGHT2-BLANK2;
HEIGHT3=( MakerNote[9]>>16) - HEIGHT1-BLANK1-HEIGHT2-BLANK2;
FLIPH1= (((MakerNote[10] >> 24) & 1)!=0); // Same value as FLIP_H
FLIPV1= (((MakerNote[10] >> 25) & 1)!=0); // Same value as FLIP_V
FLIPH2= (((MakerNote[10] >> 26) & 1)!=0);
FLIPV2= (((MakerNote[10] >> 27) & 1)!=0);
FLIPH3= (((MakerNote[10] >> 28) & 1)!=0);
FLIPV3= (((MakerNote[10] >> 29) & 1)!=0);
}
PORTRAIT= (((MakerNote[13] >> 7) & 1)!=0);
YTABLEFORC=(((MakerNote[13] >> 15) & 1)!=0);
QUALITY= (MakerNote[13] & 0x7f);
CQUALITY= ((MakerNote[13]>>8) & 0x7f);
if (CQUALITY==0) CQUALITY=QUALITY;
CORING_INDEX_Y= ((MakerNote[13]>>16) & 0x7f);
CORING_INDEX_C= ((MakerNote[13]>>24) & 0x7f);
if (CORING_INDEX_C==0) CORING_INDEX_C=CORING_INDEX_Y;
}
if (MakerNote.length>=12) {
WOI_LEFT= MakerNote[8]&0xffff;
WOI_WIDTH= MakerNote[8]>>16;
WOI_TOP= MakerNote[9]&0xffff;
WOI_HEIGHT= MakerNote[9]>>16;
FLIPH= MakerNote[10] & 1;
FLIPV= (MakerNote[10]>> 1) & 1;
BAYER_MODE=(MakerNote[10]>> 2) & 3;
COLOR_MODE=(MakerNote[10]>> 4) & 0x0f;
DCM_HOR= (MakerNote[10]>> 8) & 0x0f;
DCM_VERT= (MakerNote[10]>>12) & 0x0f;
BIN_HOR= (MakerNote[10]>>16) & 0x0f;
BIN_VERT= (MakerNote[10]>>20) & 0x0f;
info+="WOI_LEFT\t" + WOI_LEFT+"\t\t\t\n"+
"WOI_WIDTH\t"+ WOI_WIDTH+"\t\t\t\n"+
"WOI_TOP\t" + WOI_TOP+"\t\t\t\n"+
"WOI_HEIGHT\t"+ WOI_HEIGHT+"\t\t\t\n"+
"FLIP_HOR\t"+ (FLIPH!=0)+"\t\t\t\n"+
"FLIP_VERT\t"+ (FLIPV!=0)+"\t\t\t\n"+
"BAYER_MODE\t"+ BAYER_MODE+"\t\t\t\n"+
"COLOR_MODE\t"+ COLOR_MODE+"\t"+ ((COLOR_MODE==2)?"JP46":((COLOR_MODE==5)?"JP4":((COLOR_MODE==0)?"MONO":"OTHER"))) +"\t\t\n"+
"DECIM_HOR\t"+ DCM_HOR+"\t\t\t\n"+
"DECIM_VERT\t"+ DCM_VERT+"\t\t\t\n"+
"BIN_HOR\t"+ BIN_HOR+"\t\t\t\n"+
"BIN_VERT\t"+ BIN_VERT+"\t\t\t\n";
imp.setProperty("WOI_LEFT", String.format("%d",WOI_LEFT));
imp.setProperty("WOI_WIDTH", String.format("%d",WOI_WIDTH));
imp.setProperty("WOI_TOP", String.format("%d",WOI_TOP));
imp.setProperty("WOI_HEIGHT",String.format("%d",WOI_HEIGHT));
imp.setProperty("FLIPH", String.format("%d",FLIPH));
imp.setProperty("FLIPV", String.format("%d",FLIPV));
imp.setProperty("BAYER_MODE",String.format("%d",BAYER_MODE));
imp.setProperty("COLOR_MODE",((COLOR_MODE==2)?"JP46":((COLOR_MODE==5)?"JP4":((COLOR_MODE==0)?"MONO":"OTHER"))));
imp.setProperty("DCM_HOR", String.format("%d",DCM_HOR));
imp.setProperty("DCM_VERT", String.format("%d",DCM_VERT));
imp.setProperty("BIN_HOR", String.format("%d",BIN_HOR));
imp.setProperty("BIN_VERT", String.format("%d",BIN_VERT));
}
if (MakerNote.length>=14) {
info+="COMPOSITE\t" + COMPOSITE+"\t\t\t\n";
info+="ORIENTATION\t" + (PORTRAIT?"PORTRAIT":"LANDSCAPE" )+"\t\t\t\n";
info+="JPEG quality\t" + QUALITY+"\t"+((CQUALITY!=QUALITY)?("("+CQUALITY+")"):"")+"\t"+(YTABLEFORC? "Color use Y table":"")+"\t\n";
info+="Coring index\t" + CORING_INDEX_Y+"\t"+((CORING_INDEX_C!=CORING_INDEX_Y)?("("+CORING_INDEX_C+")"):"")+"\t\t\n";
imp.setProperty("COMPOSITE",String.format("%d",COMPOSITE?1:0));
imp.setProperty("ORIENTATION",(PORTRAIT?"PORTRAIT":"LANDSCAPE" ));
imp.setProperty("QUALITY",String.format("%d",QUALITY)); //not full
imp.setProperty("CORING_INDEX_Y",String.format("%d",CORING_INDEX_Y));
imp.setProperty("CORING_INDEX_C",String.format("%d",CORING_INDEX_C));
}
if (MakerNote.length>=16) {
long [] iTemps={
(MakerNote[14]>> 0) & 0xffff,
(MakerNote[14]>>16) & 0xffff,
(MakerNote[15]>> 0) & 0xffff,
(MakerNote[15]>>16) & 0xffff};
for (i=0;i<iTemps.length;i++) if (iTemps[i]!=0xffff){
double temperature=(iTemps[i]&0xfff)/16.0;
if (i==0) info+="SYSTEM TEMPERATURE\t" + temperature+"\t\t\t\n";
else info+="SFE "+i+" TEMPERATURE\t" + temperature+"\t\t\t\n";
imp.setProperty("TEMPERATURE_"+i,""+temperature);
}
}
if (COMPOSITE) {
info+="SUB_FRAMES\t- 1 -\t- 2 -\t- 3 -\t\n";
info+="HEIGHTS\t"+HEIGHT1+"\t"+HEIGHT2+"\t"+HEIGHT3+"\t\n";
info+="BLANK_ROWS\t" +BLANK1+"\t"+BLANK2+"\t\t\n";
info+="FLIPH\t"+FLIPH1+"\t"+FLIPH2+"\t"+FLIPH3+"\t\n";
info+="FLIPV\t"+FLIPV1+"\t"+FLIPV2+"\t"+FLIPV3+"\t\n";
imp.setProperty("HEIGHT1",String.format("%d",HEIGHT1));
imp.setProperty("HEIGHT2",String.format("%d",HEIGHT2));
imp.setProperty("HEIGHT3",String.format("%d",HEIGHT3));
imp.setProperty("BLANK_ROWS1",String.format("%d",BLANK1));
imp.setProperty("BLANK_ROWS2",String.format("%d",BLANK2));
imp.setProperty("FLIPH1",FLIPH1?"1":"0");
imp.setProperty("FLIPH2",FLIPH2?"1":"0");
imp.setProperty("FLIPH3",FLIPH3?"1":"0");
imp.setProperty("FLIPV1",FLIPV1?"1":"0");
imp.setProperty("FLIPV2",FLIPV2?"1":"0");
imp.setProperty("FLIPV3",FLIPV3?"1":"0");
}
if (!IS_SILENT) new TextWindow(imp.getTitle()+" info", "Parameter\tRed\tGreen(R)\tGreen(B)\tBlue",info, 400, COMPOSITE?(600):((MakerNote.length>=12)?600:160));
//tw.setLocation(0,0);
// If there are FLIPH, FLIPV - swap gains, gammas, blacks accordingly. later the images will be also flipped
if (FLIPV!=0) {
swapArrayElements (gains, 1, 3);
swapArrayElements (gains, 0, 2);
swapArrayElements (blacks, 1, 3);
swapArrayElements (blacks, 0, 2);
swapArrayElements (gammas, 1, 3);
swapArrayElements (gammas, 0, 2);
swapArrayElements (gamma_scales,1, 3);
swapArrayElements (gamma_scales,0, 2);
}
if (FLIPH!=0) {
swapArrayElements (gains, 1, 0);
swapArrayElements (gains, 3, 2);
swapArrayElements (blacks, 1, 0);
swapArrayElements (blacks, 3, 2);
swapArrayElements (gammas, 1, 0);
swapArrayElements (gammas, 3, 2);
swapArrayElements (gamma_scales,1, 0);
swapArrayElements (gamma_scales,3, 2);
}
for (i=0;i<4;i++) rgammas[i]=elphel_gamma_calc (gammas[i], blacks[i], gamma_scales[i]);
} else {
IJ.showMessage("WARNING", "MakerNote not found");
}
/**adjusting gains to have the result picture in the range 0..256 */
min_gain=2.0*gains[0];
for (i=0;i<4;i++) {
if (min_gain > gains[i]*(1.0-blacks[i])) min_gain = gains[i]*(1.0-blacks[i]);
if (!this.ABSOLUTELY_SILENT) System.out.println("gains["+i+"]="+gains[i]+" min_gain="+min_gain);
}
imp.setProperty("GAIN",String.format("%f",min_gain)); // common gain
for (i=0;i<4;i++) gains[i]/=min_gain;
for (i=0;i<4;i++) blacks256[i]=256.0*blacks[i];
for (i=0;i<4;i++) {
if (!this.ABSOLUTELY_SILENT) System.out.println("scaled gains["+i+"]="+gains[i]);
}
for (i=0;i<4;i++) {
if (MakerNote !=null) {
if (scale) satValue[i]=((rgammas[i][255])-blacks256[i])/gains[i];
else satValue[i]=((rgammas[i][255])-blacks256[i]);
} else satValue[i]=255.0;
imp.setProperty("saturation_"+i,String.format("%f",satValue[i]));
if (!this.ABSOLUTELY_SILENT) System.out.println("scaled gains["+i+"]="+gains[i]+" satValue["+i+"]="+satValue[i]);
}
// swap satValue to match FLIPH,FLIPV again
if (FLIPV!=0) {
swapArrayElements (satValue, 1, 3);
swapArrayElements (satValue, 0, 2);
}
if (FLIPH!=0) {
swapArrayElements (satValue, 1, 0);
swapArrayElements (satValue, 3, 2);
}
for (i=0;i<4;i++) {
imp.setProperty("saturation_"+i,String.format("%f",satValue[i]));
//System.out.println("saturation_"+i+"\t"+String.format("%f",satValue[i]));
}
ImageProcessor ip = imp.getProcessor();
// if (FLIPH!=0) ip.flipHorizontal(); /* To correct Bayer */
// if (FLIPV!=0) ip.flipVertical(); /* To correct Bayer */
int width = ip.getWidth();
int height = ip.getHeight();
int yb,y,xb,x,offset,nb,xbyr,ybyr;
float [] pixels = (float[])ip.getPixels();
float [][] macroblock=new float[16][16];
float [] pixels1= null;
boolean IS_JP4=(COLOR_MODE==5);
boolean IS_JP46=(COLOR_MODE==2);
if (IS_JP4) pixels1= pixels.clone(); ///JP4 mode
boolean use_imp_src= (imp_src!=null) && (imp_src.getWidth()==imp.getWidth()) && (imp_src.getHeight()==imp.getHeight());
ImageProcessor ip_src= use_imp_src? imp_src.getProcessor():ip;
if (ip_src==null) {
ip_src=ip;
use_imp_src=false;
}
for (yb=0;yb<(height>>4); yb++) for (xb=0;xb<(width>>4); xb++) { /* iterating macroblocks */
if (IS_JP4) {
for (nb=0; nb<4;nb++) {
xbyr=nb & 1;
ybyr=(nb>>1) & 1;
for (y=0;y<8;y++) {
offset=((yb<<4)+y)*width+ (nb<<3) +((xb>=(width>>5))?(((xb<<5)-width)+(width<<3)):(xb<<5));
for (x=0;x<8;x++) {
macroblock[(y<<1) | ybyr][(x<<1) | xbyr]=pixels1[offset+x];
}
}
}
} else if (IS_JP46) {
for (y=0;y<16;y++) {
offset=((yb<<4)+y)*width+(xb<<4);
for (x=0;x<16;x++) {
macroblock[((y<<1)&0xe) | ((y>>3) & 0x1)][((x<<1)&0xe) | ((x>>3) & 0x1)]=pixels[offset+x];
}
}
} else { /// mono and other non-processed
for (y=0;y<16;y++) {
offset=((yb<<4)+y)*width+(xb<<4);
for (x=0;x<16;x++) {
macroblock[y][x]=pixels[offset+x];
}
}
}
/* apply gammas here */
if (MakerNote !=null) {
if (scale) {
for (y=0;y<16;y+=2) for (x=0;x<16;x+=2) {
i=(int) macroblock[y ][x ]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y ][x ]= (float) (((rgammas[1][i])-blacks256[1])/gains[1]);
i=(int) macroblock[y ][x+1]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y ][x+1]= (float) (((rgammas[0][i])-blacks256[0])/gains[0]);
i=(int) macroblock[y+1][x ]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y+1][x ]= (float) (((rgammas[3][i])-blacks256[3])/gains[3]);
i=(int) macroblock[y+1][x+1]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y+1][x+1]= (float) (((rgammas[2][i])-blacks256[2])/gains[2]);
}
} else {
for (y=0;y<16;y+=2) for (x=0;x<16;x+=2) {
i=(int) macroblock[y ][x ]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y ][x ]= (float) ((rgammas[1][i])-blacks256[1]);
i=(int) macroblock[y ][x+1]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y ][x+1]= (float) ((rgammas[0][i])-blacks256[0]);
i=(int) macroblock[y+1][x ]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y+1][x ]= (float) ((rgammas[3][i])-blacks256[3]);
i=(int) macroblock[y+1][x+1]; if (i<0) i=0 ; else if (i>255) i=255;
macroblock[y+1][x+1]= (float) ((rgammas[2][i])-blacks256[2]);
}
}
}
if (ip_src==null) System.out.println("ip_src is null");
// else if (ip_src.setf==null) System.out.println("ip_src.setf is null");
for (y=0;y<16;y++) {
offset=(yb<<4)+y;
for (x=0;x<16;x++) {
ip_src.setf((xb<<4)+ x, offset, macroblock[y][x]); // here null pointer if image was closed
}
}
}
if (FLIPH!=0) ip_src.flipHorizontal(); /* To correct Bayer */
if (FLIPV!=0) ip_src.flipVertical(); /* To correct Bayer */
/* Is it needed here ? */
/* imp.draw();
imp.show(); **/
if (use_imp_src) copyProperties (imp, imp_src);
return use_imp_src;
}
/* reverses gamma calculations in the camera
returns double[] table , in the range 0.0..255.996
*/
double [] elphel_gamma_calc (double gamma, double black, long gamma_scale) {
int i;
double x, black256 ,k;
int[] gtable = new int[257];
double[] rgtable =new double[256];
int ig;
black256=black*256.0;
k=1.0/(256.0-black256);
if (gamma < 0.13) gamma=0.13;
if (gamma >10.0) gamma=10.0;
for (i=0; i<257; i++) {
x=k*(i-black256);
if (x < 0.0 ) x=0.0;
ig= (int) (0.5+65535.0*Math.pow(x,gamma));
ig=(ig* (int) gamma_scale)/0x400;
if (ig > 0xffff) ig=0xffff;
gtable[i]=ig;
}
/* now gtable[] is the same as was used in the camera */
/* FPGA was using linear interpolation between elements of the gamma table, so now we'll reverse that process */
// double[] rgtable =new double[256];
int indx=0;
double outValue;
for (i=0; i<256; i++ ) {
outValue=128+(i<<8);
while ((gtable[indx+1]<outValue) && (indx<256)) indx++;
if (indx>=256) rgtable[i]=65535.0/256;
else if (gtable[indx+1]==gtable[indx]) rgtable[i]=i;
else rgtable[i]=indx+(1.0*(outValue-gtable[indx]))/(gtable[indx+1] - gtable[indx]);
}
return rgtable;
}
long[] readElphelMakerNote(String directory, String fileName, int len, double [] xtraExif) throws IOException {
byte [] sig= {(byte) 0x92 ,0x7c, /* MakerNote*/
0x00 ,0x04, /* type (long)*/
0x00 ,0x00 ,0x00 ,0x08 }; /* number*/
/* should always read all MakerNote - verify that format did not change (edit here when it does). */
sig[7]=(byte) (len & 0xff);
sig[6]=(byte) ((len>>8) & 0xff);
sig[5]=(byte) ((len>>16) & 0xff);
sig[4]=(byte) ((len>>24) & 0xff);
RandomAccessFile in = new RandomAccessFile(directory + fileName, "r");
byte[] head = new byte[4096]; /* just read the beginning of the file */
in.readFully(head);
in.close(); // was no close()! -? "too many open files"
if ((head[this.ExifOffset]!=0x4d) || (head[this.ExifOffset+1]!=0x4d)) {
IJ.showMessage("JP46 Reader", "Exif Header not found in " + directory + fileName);
return null;
}
/* search for MakerNote */
long [] note=getExifData (sig, head, len);
if (xtraExif!=null){
if (xtraExif.length>0){ // get exposure time
byte [] exposureTime={
(byte) 0x82,(byte) 0x9a,0x00,0x05,
0x00,0x00,0x00,0x01};
long [] nomDenom=getExifData (exposureTime, head, 2);
if (nomDenom==null) xtraExif[0]=Double.NaN;
else {
xtraExif[0]=(1.0*nomDenom[0])/nomDenom[1];
}
}
}
return note;
}
double [] readGpsLLA(String directory, String fileName) throws IOException
{
RandomAccessFile in = new RandomAccessFile(directory + fileName, "r");
byte[] head = new byte[4096]; /* just read the beginning of the file */
in.readFully(head);
in.close(); // was no close()! -? "too many open files"
if ((head[this.ExifOffset]!=0x4d) || (head[this.ExifOffset+1]!=0x4d)) {
IJ.showMessage("JP46 Reader", "Exif Header not found in " + directory + fileName);
return null;
}
// skip to gps header
byte [] sig = {0x2, 0x2, 0x0, 0x0};
int i = this.ExifOffset + 2;
boolean match=false;
for (i = this.ExifOffset + 2; i < (head.length - sig.length); i++ ) {
match=true;
for (int j=0;j<sig.length;j++)if (head[i+j]!=sig[j]){
match=false;
break;
}
if (match) break;
}
i += sig.length;
if (i >= (head.length-4)) {
/* IJ.showMessage("JP46 Reader", "MakerNote tag not found in "+directory + fileName+ ", finished at offset="+i); // re-enable with DEBUG_LEVEL*/
return null;
}
// System.out.println(String.format("offset=0x%04x", i));
double [] lla = new double[3];
boolean [] lla_sign = new boolean[3];
for (int ntag = 0; ntag < 10; ntag++) {
// read 2 big endian bytesof tag, and 2 - type
int tag = ((head[i+0] << 8) & 0xff00) + ((head[i+1] << 0) & 0x00ff);
int typ = ((head[i+2] << 8) & 0xff00) + ((head[i+3] << 0) & 0x00ff);
int len = ((head[i+4] <<24) & 0xff000000) + ((head[i+5] <<16) & 0x00ff0000) + ((head[i+ 6] << 8) & 0x0000ff00) + ((head[i+ 7] << 0) & 0x000000ff);
int val = ((head[i+8] <<24) & 0xff000000) + ((head[i+9] <<16) & 0x00ff0000) + ((head[i+10] << 8) & 0x0000ff00) + ((head[i+11] << 0) & 0x000000ff);
// System.out.println(String.format("ntag=%2d tag = 0x%04x type = 0x%04x len = 0x%08x value = 0x%08x", ntag, tag, typ, len, val));
i+=12;
switch (tag) {
case 1: lla_sign[0] = ((val >> 24) & 0xff) == 0x53; break; // S GPSLatitudeRef
case 2: int [] lat_arr = readExifBE(head, this.ExifOffset + val , 2 * len); //GPSLatitude
lla[0] = 1.0*lat_arr[0]/lat_arr[1] + (1.0/60)* lat_arr[2]/lat_arr[3] + (1.0/3600)* lat_arr[4]/lat_arr[5];
break;
case 3: lla_sign[1] = ((val >> 24) & 0xff) == 0x57; break; // W GPSLongitudeRef
case 4: int [] long_arr = readExifBE(head, this.ExifOffset + val , 2 * len); // GPSLongitude
lla[1] = 1.0*long_arr[0]/long_arr[1] + (1.0/60)* long_arr[2]/long_arr[3] + (1.0/3600)* long_arr[4]/long_arr[5];
break;
case 5: lla_sign[2] = ((val >> 24) & 0xff) != 0x0; break; // GPSAltitudeRef
case 6: int [] alt_arr = readExifBE(head, this.ExifOffset + val , 2 * len); // GPSLongitude
lla[2] = 1.0*alt_arr[0]/alt_arr[1];
break;
}
}
for (int j = 0; j < lla.length; j++) {
if (lla_sign[j]) lla[j] *= -1;
}
// System.out.println("Lat = "+lla[0]+" Long = "+lla[1]+ " alt = "+lla[2]+"m");
return lla;
}
int [] readExifBE(byte [] head, int offset, int len) {
int [] data = new int [len];
for (int i = 0; i < len; i++) {
int offs = offset + 4*i;
data[i] = ((head[offs + 0] << 24) & 0xff000000) +
((head[offs + 1] << 16) & 0x00ff0000) +
((head[offs + 2] << 8) & 0x0000ff00) +
((head[offs + 3] << 0) & 0x000000ff);
}
return data;
}
long[] readElphelMakerNoteURL(String url, int len, double [] xtraExif) throws IOException {
URL camURL = null;
URLConnection urlConn = null;
byte[] data = new byte[4096];
// System.out.println("loading exif from: " + url);
try {
camURL = new URL(url);
urlConn = camURL.openConnection();
int contentLength = 4096; /* just read the beginning of the file */ //urlConn.getContentLength();
//inStream = new InputStreamReader(urlConn.getInputStream());
int bytesRead = 0;
int offset = 0;
InputStream raw = urlConn.getInputStream();
InputStream in = new BufferedInputStream(raw);
while (offset < contentLength) {
bytesRead = in.read(data, offset, data.length - offset);
if (bytesRead == -1)
break;
offset += bytesRead;
}
in.close();
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
} catch(IOException e1){
System.out.println("Can't read from the Internet: "+ e1.toString() );
}
byte [] sig= {(byte) 0x92 ,0x7c, /* MakerNote*/
0x00 ,0x04, /* type (long)*/
0x00 ,0x00 ,0x00 ,0x08 }; /* number*/
/* should always read all MakerNote - verify that format did not change (edit here when it does). */
sig[7]=(byte) (len & 0xff);
sig[6]=(byte) ((len>>8) & 0xff);
sig[5]=(byte) ((len>>16) & 0xff);
sig[4]=(byte) ((len>>24) & 0xff);
//in = new RandomAccess(RandomAccessFactory.createRO(camURL), "r");
byte[] head = new byte[4096]; /* just read the beginning of the file */
head = data;
//in.readFully(head);
if ((head[this.ExifOffset] != 0x4d) || (head[this.ExifOffset+1] != 0x4d)) {
IJ.showMessage("JP46 Reader", "Exif Header not found in " + url);
return null;
}
/* search for MakerNote */
// return getExifData (sig, head, len);
long [] note=getExifData (sig, head, len);
if (xtraExif!=null){
if (xtraExif.length>0){ // get exposure time
byte [] exposureTime={
(byte) 0x82,(byte) 0x9a,0x00,0x05,
0x00,0x00,0x00,0x01};
long [] nomDenom=getExifData (exposureTime, head, 2);
if (nomDenom==null) xtraExif[0]=Double.NaN;
else {
xtraExif[0]=(1.0*nomDenom[0])/nomDenom[1];
}
}
}
return note;
}
long [] getExifData (byte [] sig, byte [] head, int len){
/* search for sig array */
int i = this.ExifOffset + 2;
boolean match=false;
for (i = this.ExifOffset + 2; i < (head.length - sig.length); i++ ) {
match=true;
for (int j=0;j<sig.length;j++)if (head[i+j]!=sig[j]){
match=false;
break;
}
if (match) break;
}
i += sig.length;
if (i >= (head.length-4)) {
/* IJ.showMessage("JP46 Reader", "MakerNote tag not found in "+directory + fileName+ ", finished at offset="+i); // re-enable with DEBUG_LEVEL*/
return null;
}
int offs=this.ExifOffset+(((head[i]<<24) & 0xff000000) |((head[i+1]<<16) & 0xff0000)| ((head[i+2]<<8) & 0xff00) | (head[i+3] & 0xff));
// IJ.showMessage("JP46 Reader Debug", "MakerNote starts at offset "+offs);
if (offs > (head.length-len) ) {
IJ.showMessage("JP46 Reader", "Error: data (i.e.MakerNote) starts too far - at offset "+offs+", while we read only "+ head.length+ "bytes");
return null;
}
long[] note=new long[len];
for (i=0; i<len; i++) note[i]=((head[offs+(i<<2)]&0xff) << 24) | ((head[offs+(i<<2)+1]&0xff) << 16) | ((head[offs+(i<<2)+2]&0xff) << 8) | (head[offs+(i<<2)+3]&0xff);
return note;
}
/* Modified from Opener.java */
ImagePlus openJpegOrGif(String dir, String name) {
ImagePlus imp = null;
Image img = Toolkit.getDefaultToolkit().createImage(dir+name);
if (img!=null) {
try {
imp = new ImagePlus(name, img);
} catch (IllegalStateException e) {
return null; // error loading image
}
if (imp.getType()==ImagePlus.COLOR_RGB) {
checkGrayJpegTo32Bits(imp);
}
IJ.showStatus("Converting to 32-bits");
new ImageConverter(imp).convertToGray32();
FileInfo fi = new FileInfo();
fi.fileFormat = FileInfo.GIF_OR_JPG;
fi.fileName = name;
fi.directory = dir;
imp.setFileInfo(fi);
}
return imp;
}
@Override
public void setTitle (String title) {
imageTitle=title;
}
@Override
public String getTitle () {
return imageTitle;
}
public void setURL (String url) {
camera_url=url;
}
public String getURL () {
return camera_url;
}
ImagePlus openJpegOrGifUsingURL (String cameraurl) {
URL url = null;
ImagePlus imp = null;
Image img = null;
/* Validate URL */
try {
url = new URL(cameraurl);
} catch (MalformedURLException e) {
System.out.println("Bad URL: " + cameraurl);
return null;
}
img = Toolkit.getDefaultToolkit().createImage(url);
if (!this.ABSOLUTELY_SILENT) System.out.println("loading image from: " + url);
// imp = new ImagePlus("test", img);
imp = new ImagePlus(imageTitle, img);
if (imp.getType() == ImagePlus.COLOR_RGB) {
checkGrayJpegTo32Bits(imp);
}
IJ.showStatus("Converting to 32-bits");
new ImageConverter(imp).convertToGray32();
FileInfo fi = new FileInfo();
fi.fileFormat = FileInfo.GIF_OR_JPG;
fi.fileName = "aquired from camera";
fi.directory = cameraurl;
imp.setFileInfo(fi);
return imp;
}
public static void checkGrayJpegTo32Bits(ImagePlus imp) {
ImageProcessor ip = imp.getProcessor();
int width = ip.getWidth();
int height = ip.getHeight();
int[] pixels = (int[])ip.getPixels();
int c,r,g,b,offset;
for (int y=0; y<(height-8); y++) {
offset = y*width;
for (int x=0; x<(width-8); x++) {
c = pixels[offset+x];
r = (c&0xff0000)>>16;
g = (c&0xff00)>>8;
b = c&0xff;
if (!((r==g)&&(g==b))) {
IJ.error("Warning: color image");
return;
}
}
}
IJ.showStatus("Converting to 32-bits");
new ImageConverter(imp).convertToGray32();
}
/* =====Other methods =================================================================== */
/* ======================================================================== */
public void listImageProperties (ImagePlus imp) {
listImageProperties (imp,false);
}
public void listImageProperties (ImagePlus imp, boolean toConsole) {
StringBuffer sb = new StringBuffer();
Set<Object> jp4_set;
Properties jp4_prop;
Iterator<Object> itr;
String str;
jp4_prop=imp.getProperties();
if (jp4_prop!=null) {
jp4_set=jp4_prop.keySet();
itr=jp4_set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
sb.append(str+"\t"+jp4_prop.getProperty(str)+"\n");
// System.out.println(str + "=\t" +jp4_prop.getProperty(str));
}
}
if (toConsole){
System.out.println(imp.getTitle()+" properties\n"+sb.toString());
} else {
new TextWindow(imp.getTitle()+" properties", "name\tvalue", sb.toString(),400,800);
}
}
/* ======================================================================== */
public double fracOverExposed(double [] map, // map of overexposed pixels 0.0 - 0K, >0 (==1.0) - overexposed
int mapWidth, // width of the map
int x0, // X of the top left corner of the selection
int y0, // Y of the top left corner of the selection
int width, // selection width
int height){ // selection height
int index,i,j;
int y1=y0+height;
int over=0;
for (i=y0;i<y1;i++) {
index=i*mapWidth+x0;
for (j=0;j<width;j++) if (map[index++]>0.0) over++;
}
return (1.0*over)/width/height;
}
// returns 1.0 if there is overexposed pixel, 0.0 - if OK
/* ======================================================================== */
public double [] overexposedMap (ImagePlus imp) {
return overexposedMap (imp, 0.999);
}
public double [] overexposedMap (ImagePlus imp, double relativeThreshold) {
double [] satValues=new double[4];
boolean noProperties=false;
int i,j,index;
for (i=0;i<4;i++) {
//protect from Double.valueOf(null), move to a function
if (imp.getProperty("saturation_"+i)!=null) satValues[i]= Double.valueOf((String) imp.getProperty("saturation_"+i)).doubleValue();
else {
noProperties=true;
break;
}
}
if (noProperties) return null;
//0 - red, 1,2 - green (use Math.min()), 3 - blue
for (i=0;i<4;i++) satValues[i]*=relativeThreshold;
ImageProcessor ip=imp.getProcessor();
int width=imp.getWidth();
float []pixels=(float[]) ip.getPixels();
double [] overexposed= new double [pixels.length];
for (index=0;index<overexposed.length;index++){
i=(index / width) % 2;
j=1-((index % width) % 2);
overexposed[index]=(pixels[index]>=satValues[i*2+j])?1.0:0.0;
}
return overexposed;
}
public ImagePlus demuxImageOrClone(ImagePlus imp, int numImg) {
ImagePlus imp_new=demuxImage(imp, numImg);
if (imp_new!=null) return imp_new;
return demuxClone(imp);
}
public ImagePlus demuxClone(ImagePlus imp) {
ImageProcessor ip=imp.getProcessor().duplicate();
ImagePlus imp_new=new ImagePlus(imp.getTitle()+"-dup",ip);
Set<Object> jp4_set;
Properties jp4_prop;
Iterator<Object> itr;
String str;
jp4_prop=imp.getProperties();
if (jp4_prop!=null) {
jp4_set=jp4_prop.keySet();
itr=jp4_set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
imp_new.setProperty(str,jp4_prop.getProperty(str));
}
}
return imp_new;
}
public ImagePlus demuxImage(ImagePlus imp, int numImg) {
int width= imp.getWidth();
// int height=imp.getHeight();
int FLIPGV,FLIPGH;
int [] FLIPV= new int[3];
int [] FLIPH= new int[3];
int [] HEIGHTS=new int[3];
int [] BLANKS= new int[2];
Object timestamp=null;
if (imp.getProperty("FLIPV")!=null) FLIPGV= Integer.valueOf((String) imp.getProperty("FLIPV")).intValue(); else return null;
if (imp.getProperty("FLIPH")!=null) FLIPGH= Integer.valueOf((String) imp.getProperty("FLIPH")).intValue(); else return null;
int i;
for (i=1;i<=3;i++) {
if (imp.getProperty("FLIPV"+i)!=null) FLIPV[i-1]= Integer.valueOf((String) imp.getProperty("FLIPV"+i)).intValue(); else return null;
if (imp.getProperty("FLIPH"+i)!=null) FLIPH[i-1]= Integer.valueOf((String) imp.getProperty("FLIPH"+i)).intValue(); else return null;
if (imp.getProperty("HEIGHT"+i)!=null) HEIGHTS[i-1]= Integer.valueOf((String) imp.getProperty("HEIGHT"+i)).intValue(); else return null;
}
for (i=1;i<=2;i++) {
if (imp.getProperty("BLANK_ROWS"+i)!=null) BLANKS[i-1]= Integer.valueOf((String) imp.getProperty("BLANK_ROWS"+i)).intValue(); else return null;
}
timestamp=imp.getProperty("timestamp");
if (timestamp!=null);
/*
System.out.println("FLIPV="+FLIPGV+" FLIPH="+FLIPGH);
for (i=0;i<3;i++) System.out.println("FLIPV["+i+"]= "+FLIPV[i]+" FLIPH["+i+"]= "+FLIPH[i]);
for (i=0;i<3;i++) System.out.println("HEIGHTS["+i+"]="+HEIGHTS[i]);
for (i=0;i<2;i++) System.out.println("BLANKS["+i+"]= "+BLANKS[i]);
*/
Rectangle [] r = new Rectangle[3];
r[0]=new Rectangle(0, 0, width,HEIGHTS[0]);
r[1]=new Rectangle(0, HEIGHTS[0]+BLANKS[0], width,HEIGHTS[1]);
r[2]=new Rectangle(0, HEIGHTS[0]+BLANKS[0]+HEIGHTS[1]+BLANKS[1],width,HEIGHTS[2]);
// assuming that (HEIGHTS[1]==0) && (HEIGHTS[2]!=0) == false
if (FLIPGV!=0){
if (HEIGHTS[1]>0) {
if (HEIGHTS[2]>0) {
Rectangle r_tmp=r[0];
r[0]=r[2];
r[2]=r_tmp;
} else {
Rectangle r_tmp=r[0];
r[0]=r[1];
r[1]=r_tmp;
}
}
}
if (FLIPGV>0) for (i=0;i<3;i++) FLIPV[i]=1-FLIPV[i];
if (FLIPGH>0) for (i=0;i<3;i++) FLIPH[i]=1-FLIPH[i];
// for (i=0;i<3;i++) System.out.println("Final: FLIPV["+i+"]= "+FLIPV[i]+" FLIPH["+i+"]= "+FLIPH[i]);
// if needed, we'll cut one pixel line. later can modify to add one extra, but then we need to duplicate the pre-last one (same Bayer),
// not just add zeros - later before sliding FHT the two border lines are repeated for 16 times to reduce border effects.
for (i=0;i<3;i++) {
// System.out.println("before r["+i+"].x= "+r[i].x+" r["+i+"].width= "+r[i].width);
// System.out.println("before r["+i+"].y= "+r[i].y+" r["+i+"].height= "+r[i].height);
if (((r[i].height & 1)==0 ) & (((r[i].y+FLIPV[i])&1)!=0)) r[i].height-=2;
r[i].height &=~1;
if (((r[i].y+FLIPV[i])&1)!=0) r[i].y+=1;
if (((r[i].width & 1)==0 ) & (((r[i].x+FLIPH[i])&1)!=0)) r[i].width-=2;
r[i].width &=~1;
if (((r[i].x+FLIPH[i])&1)!=0) r[i].x+=1;
// System.out.println("after r["+i+"].x= "+r[i].x+" r["+i+"].width= "+r[i].width);
// System.out.println("after r["+i+"].y= "+r[i].y+" r["+i+"].height= "+r[i].height);
}
if (r[numImg].height<=0) return null;
// ImageProcessor ip=imp.getProcessor();
// ip.setRoi(r[numImg]);
// ImageProcessor ip_individual=ip.crop().duplicate(); //java.lang.NegativeArraySizeException
/*
* When using in multithreaded with (probably) the same composite image
Exception in thread "Thread-3564" java.lang.ArrayIndexOutOfBoundsException: 8970912
at ij.process.FloatProcessor.crop(FloatProcessor.java:706)
at JP46_Reader_camera0.demuxImage(JP46_Reader_camera0.java:1104)
at CalibrationHardwareInterface$CamerasInterface$4.run(CalibrationHardwareInterface.java:1101)
*/
// ImageProcessor ip=imp.getProcessor();
// ip.setRoi(r[numImg]);
ImageProcessor ip_individual=imp.getProcessor().duplicate(); //java.lang.NegativeArraySizeException
ip_individual.setRoi(r[numImg]);
ip_individual=ip_individual.crop();
if (FLIPH[numImg]!=0) ip_individual.flipHorizontal();
if (FLIPV[numImg]!=0) ip_individual.flipVertical();
ImagePlus imp_result=new ImagePlus(imp.getTitle()+"-"+numImg,ip_individual);
//copy all defined properties of the composite image
Set<Object> jp4_set;
Properties jp4_prop;
Iterator<Object> itr;
String str;
jp4_prop=imp.getProperties();
if (jp4_prop!=null) {
jp4_set=jp4_prop.keySet();
itr=jp4_set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
imp_result.setProperty(str,jp4_prop.getProperty(str));
}
}
// Replaced by copying all properties from the composite image
/*
for (i=0;i<4;i++) {
//protect from Double.valueOf(null), move to a function
if (imp.getProperty("saturation_"+i)!=null) {
imp_result.setProperty("saturation_"+i, imp.getProperty("saturation_"+i));
}
}
if (timestamp!=null)imp_result.setProperty("timestamp", timestamp);
*/
// fill in meta data
return imp_result;
}
public void copyProperties (ImagePlus imp_src,ImagePlus imp_dst){
// copy all the properties to the new image
Set<Object> set;
Properties prop;
Iterator<Object> itr;
String str;
prop=imp_src.getProperties();
if (prop!=null) {
set=prop.keySet();
itr=set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
imp_dst.setProperty(str,prop.getProperty(str));
}
}
}
public ImagePlus encodeProperiesToInfo(ImagePlus imp){
String info="<?xml version=\"1.0\" encoding=\"UTF-8\"?><properties>";
Set<Object> jp4_set;
Properties jp4_prop;
Iterator<Object> itr;
String str;
jp4_prop=imp.getProperties();
if (jp4_prop!=null) {
jp4_set=jp4_prop.keySet();
itr=jp4_set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
// if (!str.equals("Info")) info+="<"+str+">\""+jp4_prop.getProperty(str)+"\"</"+str+">";
if (!str.equals("Info")) info+="<"+str+">"+jp4_prop.getProperty(str)+"</"+str+">";
}
}
info+="</properties>\n";
imp.setProperty("Info", info);
return imp;
}
public boolean decodeProperiesFromInfo(ImagePlus imp){
if (imp.getProperty("Info")==null) return false;
String xml= (String) imp.getProperty("Info");
DocumentBuilder db=null;
try {
db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException e) {
return false;
}
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
Document doc = null;
try {
doc = db.parse(is);
} catch (SAXException e) {
return false;
} catch (IOException e) {
return false;
}
NodeList allNodes=doc.getDocumentElement().getElementsByTagName("*");
for (int i=0;i<allNodes.getLength();i++) {
String name= allNodes.item(i).getNodeName();
String value=allNodes.item(i).getFirstChild().getNodeValue();
imp.setProperty(name, value);
}
return true;
}
/**
* Main method for debugging.
*
* For debugging, it is convenient to have a method that starts ImageJ, loads an
* image and calls the plugin, e.g. after setting breakpoints.
* Grabbed from https://github.com/imagej/minimal-ij1-plugin
* @param args unused
*/
public static void main(String[] args) {
// set the plugins.dir property to make the plugin appear in the Plugins menu
Class<?> clazz = JP46_Reader_camera0.class;
String url = clazz.getResource("/" + clazz.getName().replace('.', '/') + ".class").toString();
String pluginsDir = url.substring(5, url.length() - clazz.getName().length() - 6);
System.out.println(System.getProperty("plugins.dir"));
System.setProperty("plugins.dir", pluginsDir);
// System.setProperty("plugins.dir", "/data_ssd/imagej-elphel/ijplugins");
// System.setProperty("plugins.dir", "/data_ssd/imagej-elphel/target/classes/com/elphel/imagej/jp4/");
System.out.println(System.getProperty("plugins.dir"));
// start ImageJ
new ImageJ();
// run the plugin
IJ.runPlugIn(clazz.getName(), "");
}
}
/**
**
** TileAssignment - handle tile surfaces
**
** Copyright (C) 2017 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** TileAssignment.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
import java.awt.Point;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
//import ij.IJ;
public class TileAssignment {
private TileSurface ts;
private CLTPass3d p3d; // last/ combined FPGA data
private EyesisCorrectionParameters.CLTParameters clt_parameters;
private double [][][] dispStrength; // indexed as a surface (full supertiles), not as image
private boolean [] valid_ml;
private double [][] tile_tones;
private double [][][] tone_diff_weight; // for each surface (not image) tile, for each of 8 directions,
//a pair of normalized tone difference and weight (both weight and diff == 0.0 for connections to/from undefined tiles
private double kR = 1.0; // relative weight of red to green ratio
private double kB = 1.0; // relative weight of blue to green ratio
private double fatZero = 0.01; // for colors, normalized to 0..1.0 range
private int surfTilesX;
private int surfTilesY;
private int imgTilesX;
private int imgTilesY;
private TileNeibs tnImage;
private TileNeibs tnSurface;
private boolean [][][] valid_surf; // per measured layer, per surface tile, per surface layer
// from clt_parameters
private double dispNorm;
private TACosts cost_coeff;
private double minFgBg; // = 0.1; // Minimal foreground/ background separation to look for weak FG edge
private double minFgEdge; // = 0.2; // Minimal foreground edge strength (stronger edges will have proportionally smaller costs)
private double minColSep; // = 0.05; // Minimal surface separation that requires color change
private double minColDiff; // = 0.01; // Minimal color variation (larger proportionally reduces cost)
private double dispOutlier; // = 1.0; // Disparity difference limit (to handle outliers)
private double strengthDiffPwr; // = 0.25; // Strength power when calculating disparity error
private double strengthBestPwr; // = 0.0; // Strength power when calculating disparity error over best
private double strengthDiff9Pwr; // = 0.5; // Strength power when calculating disparity error for group of 9
private double taColSigma; // = 1.5; // Gaussian sigma to blur color difference between tiles along each direction
private double taColFraction; // = 0.3; // Relative amount of the blurred color difference in the mixture
private double shrinkWeakFgnd = 0.5; // 0.5; //reduce cost of multiple weak_fgnd links of the same tile
private double shrinkColor = 0.5; // 0.0; //reduce cost of surface transitions w/o color change
static double [] NEIB_WEIGHTS = {0.5,0.25, 0.5, 0.25, 0.5,0.25, 0.5, 0.25, 1.0};
static int INDEX_R = 0;
static int INDEX_B = 1;
static int INDEX_G = 2;
static int INDEX_A = 3;
public boolean mutual_weak_fgnd = false; // set to true when using 3x3 grid, false for 5x5;
public class TACosts{
public double empty; // Cost of a tile that is not assigned
public double nolink; // Cost of a tile not having any neighbor in particular direction
public double swtch; // Cost of a tile switching to a neighbor that does not have a link
public double color; // Cost of a tile switching to a disconnected neighbor divided by a color mismatch
public double diff; // Cost of a weighted normalized tile disparity error
public double diff_best; // Cost of a weighted normalized tile disparity error above best surface
public double diff9; // Cost of a weighted normalized tile disparity error for tile and 8 neighbors (DC)
public double weak_fgnd; // Cost of a weak foreground edge
public double flaps; // Cost of using supertile "flaps" (not in the center 8x8 tiles area)
public double ml_mismatch; // Cost of a measurement layer not having same layer in the same location or near
public TACosts (int mode)
{
this.empty = 1.0/0.35833; // 0.71715;
this.nolink = 1.0/0.83739; // 0.95952; // 1.50705;
this.swtch = 1.0/0.07604; // 0.05172; // 0.59474;
this.color = 1.0/6.69936; // 3.34968; // 0.21458; // 0.19294; // 2.25763;
this.diff = 1.0/0.11879; // 0.11039; // 1.94213;
this.diff_best = 1.0/0.02831; // 0.00628; // 0.06731;
this.diff9 = 1.0/0.04064; // 0.01350; // 1.09087;
this.weak_fgnd = 1.0/2.355492; // 1.177746; // 0.02172; // 0.01726; // 0.22250;
this.flaps = 1.0/0.1; // 0.00056; // 0.07229;
this.ml_mismatch = 1.0;
// ml_mismatch not yet implemented - is it needed - maybe some see-through data appears on one layer only
}
/*
empty= 0.00000 nolink= 1.50705 swtch= 0.59474 color= 2.25763 diff= 1.94213
diff_best= 0.06731 diff9= 1.09087 weak_fgnd= 0.22250 flaps= 0.07229 ml_mismatch= 0.00000
*/
public TACosts (EyesisCorrectionParameters.CLTParameters clt_parameters)
{
this.empty = clt_parameters.taEnEmpty? clt_parameters.taCostEmpty : 0.0;
this.nolink = clt_parameters.taEnNoLink? clt_parameters.taCostNoLink : 0.0;
this.swtch = clt_parameters.taEnSwitch? clt_parameters.taCostSwitch : 0.0;
this.color = clt_parameters.taEnColor? clt_parameters.taCostColor : 0.0;
this.diff = clt_parameters.taEnDiff? clt_parameters.taCostDiff : 0.0;
this.diff_best = clt_parameters.taEnDiffBest? clt_parameters.taCostDiffBest : 0.0;
this.diff9 = clt_parameters.taEnDiff9? clt_parameters.taCostDiff9 : 0.0;
this.weak_fgnd = clt_parameters.taEnWeakFgnd? clt_parameters.taCostWeakFgnd : 0.0;
this.flaps = clt_parameters.taEnFlaps? clt_parameters.taCostFlaps : 0.0;
this.ml_mismatch = clt_parameters.taEnMismatch? clt_parameters.taCostMismatch : 0.0;
// ml_mismatch not yet implemented - is it needed - maybe some see-through data appears on one layer only
}
public TACosts(){}
public TACosts(double [] vals)
{
set(vals);
}
public void set(double [] vals)
{
this.empty = vals[0];
this.nolink = vals[1];
this.swtch = vals[2];
this.color = vals[3];
this.diff = vals[4];
this.diff_best = vals[5];
this.diff9 = vals[6];
this.weak_fgnd = vals[7];
this.flaps = vals[8];
this.ml_mismatch = vals[9];
}
public double [] toArray(){
double [] rslt = {
this.empty,
this.nolink,
this.swtch,
this.color,
this.diff,
this.diff_best,
this.diff9,
this.weak_fgnd,
this.flaps,
this.ml_mismatch
};
return rslt;
}
public String [] getTitles()
{
String [] titles = {
"empty",
"nolink",
"swtch",
"color",
"diff",
"diff_best",
"diff9",
"weak_fgnd",
"flaps",
"ml_mismatch"};
return titles;
}
@Override
public String toString()
{
String s = "";
s+= String.format("empty= %8.5f nolink=%8.5f swtch= %8.5f color=%8.5f diff= %8.5f\n",empty, nolink, swtch, color, diff);
s+= String.format("diff_best=%8.5f diff9= %8.5f weak_fgnd=%8.5f flaps=%8.5f ml_mismatch=%8.5f\n",diff_best, diff9, weak_fgnd, flaps, ml_mismatch);
return s;
}
public double dotProd (TACosts costs){
double [] these = toArray();
double [] other = costs.toArray();
double prod = 0.0;
for (int i = 0; i < these.length; i++){
prod += these[i]*other[i];
}
return prod;
}
public void add (TACosts costs){
double [] these = toArray();
double [] other = costs.toArray();
for (int i = 0; i < these.length; i++){
these[i] += other[i];
}
set (these);
}
public void mul (TACosts costs){
double [] these = toArray();
double [] other = costs.toArray();
for (int i = 0; i < these.length; i++){
these[i] *= other[i];
}
set (these);
}
public void max (TACosts costs){
double [] these = toArray();
double [] other = costs.toArray();
for (int i = 0; i < these.length; i++){
these[i] = Math.max(these[i],other[i]);
}
set (these);
}
public void scale (double a){
double [] these = toArray();
for (int i = 0; i < these.length; i++){
these[i] *= a;
}
set (these);
}
}
/**
*
* @param ts
* @param p3d
* @param tile_sel
* @param dispStrength per measurement layer, combined disparity and strength array ([num_ml [2][])
* @param kR
* @param kB
* @param fatZero
*/
public TileAssignment (
EyesisCorrectionParameters.CLTParameters clt_parameters,
TileSurface ts,
CLTPass3d p3d,
double [][][] dispStrength,
double kR,
double kB,
double fatZero)
{
this.ts = ts;
this.p3d = p3d;
copyParams(clt_parameters);
this.clt_parameters = clt_parameters; // replace with copying specific ones
valid_ml = new boolean [dispStrength.length];
for (int ml = 0; ml < dispStrength.length; ml++){
valid_ml[ml] = dispStrength[ml] != null;
}
if (!Double.isNaN(kR)) this.kR = kR;
if (!Double.isNaN(kB)) this.kB = kB;
if (!Double.isNaN(fatZero)) this.fatZero = fatZero;
this.surfTilesX = ts.getSTilesX() * ts.getSuperTileSize();
this.surfTilesY = ts.getSTilesY() * ts.getSuperTileSize();
this.imgTilesX = ts.getImageTilesX();
this.imgTilesY = ts.getImageTilesY();
this.tnImage = new TileNeibs(imgTilesX, imgTilesY);
this.tnSurface = new TileNeibs(surfTilesX, surfTilesY);
setDispStrength(dispStrength);
setTones(p3d);
}
public void copyParams(EyesisCorrectionParameters.CLTParameters clt_parameters)
{
this.dispNorm = clt_parameters.plDispNorm;
this.minFgBg = clt_parameters.taMinFgBg;
this.minFgEdge = clt_parameters.taMinFgEdge;
this.minColSep = clt_parameters.taMinColSep;
this.minColDiff = clt_parameters.taMinColDiff;
this.dispOutlier = clt_parameters.taOutlier;
this.strengthDiffPwr = clt_parameters.taDiffPwr;
this.strengthBestPwr = clt_parameters.taBestPwr;
this.strengthDiff9Pwr = clt_parameters.taDiff9Pwr;
this.taColSigma = clt_parameters.taColSigma;
this.taColFraction = clt_parameters.taColFraction;
this.cost_coeff = new TACosts (clt_parameters);
this.cost_coeff.mul(new TACosts (0)); // make average ~=1.0 for each used component
}
public void setDispStrength(
double [][][] ds)
{
this.dispStrength = new double [ds.length][][];
for (int ml = 0; ml < ds.length; ml++) if (ds[ml] != null){
this.dispStrength[ml] = new double [ surfTilesX * surfTilesY][];
for (int nTile = 0; nTile < ds[ml][0].length; nTile++){
int nSurfTile = ts.getSurfaceTileIndex(nTile);
this.dispStrength[ml][nSurfTile] = new double[2]; // ds[ml][nTile];
this.dispStrength[ml][nSurfTile][0] = ds[ml][0][nTile];
this.dispStrength[ml][nSurfTile][1] = ds[ml][1][nTile];
}
}
}
public int getSurfTilesX(){
return surfTilesX;
}
public int getSurfTilesY(){
return surfTilesY;
}
// private int surfTilesX;
// private int surfTilesY;
public void setTones(CLTPass3d p3d)
{
double [][] tt = p3d.getTileRBGA(4);
this.tile_tones = new double [surfTilesX * surfTilesY][tt.length];
for (int nTile = 0; nTile < tt[0].length; nTile++){
int nSurfTile = ts.getSurfaceTileIndex(nTile);
for (int j = 0; j < tt.length; j++){
this.tile_tones[nSurfTile][j] = tt[j][nTile];
}
}
this.tone_diff_weight = new double [surfTilesX * surfTilesY][8][2];
// final int numTiles = imgTilesX * imgTilesY;
final Thread[] threads = ImageDtt.newThreadArray(ts.getThreadsMax());
final AtomicInteger ai = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int nSurfTile = ai.getAndIncrement(); nSurfTile < tone_diff_weight.length; nSurfTile = ai.getAndIncrement()) {
if (nSurfTile >= 0){
for (int dir = 0; dir < 4; dir++){
int nSurfTile1 = tnSurface.getNeibIndex(nSurfTile, dir);
if (nSurfTile1 >= 0){
tone_diff_weight[nSurfTile][dir] =
getDiffWeight (
tile_tones[nSurfTile],
tile_tones[nSurfTile1]);
tone_diff_weight[nSurfTile1][(dir + 4) % 8] = tone_diff_weight[nSurfTile][dir];
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
}
public void blurMixTones(
final boolean use_sqrt,
final boolean weighted) // blur weighted
{
this.tone_diff_weight = blurMixTones(
this.tone_diff_weight, // final double [][][] tone_diffs,
this.taColSigma, // final double sigma,
this.taColFraction, // final double fraction,
use_sqrt,
weighted); // final boolean weighted)
}
public double [][][] blurMixTones(
final double [][][] tone_diffs,
final double sigma,
final double fraction,
final boolean use_sqrt,
final boolean weighted) // blur weighted
{
final int num_tiles = surfTilesX * surfTilesY;
final double [][] dir_blur = new double [4][num_tiles];
final double [][] dir_weight = new double [4][num_tiles];
final Thread[] threads = ImageDtt.newThreadArray(ts.getThreadsMax());
final AtomicInteger ai = new AtomicInteger(0);
final double [][][] mixed_diff_weight = new double [surfTilesX * surfTilesY][8][2];
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int dir = ai.getAndIncrement(); dir < 4; dir = ai.getAndIncrement()) {
for (int nSurfTile = 0; nSurfTile < num_tiles; nSurfTile++){
double w = tone_diffs[nSurfTile][dir][1];
double dw = tone_diffs[nSurfTile][dir][0] ;
if (use_sqrt) dw = Math.sqrt(dw);
if (weighted) dw *= w;
dir_blur[dir][nSurfTile] = dw;
dir_weight[dir][nSurfTile] = w;
}
DoubleGaussianBlur gb =new DoubleGaussianBlur();
gb.blurDouble(dir_blur[dir], surfTilesX, surfTilesY, sigma, sigma, 0.01);
gb.blurDouble(dir_weight[dir], surfTilesX, surfTilesY, sigma, sigma, 0.01);
if (weighted){
for (int nSurfTile = 0; nSurfTile < num_tiles; nSurfTile++){
if (dir_weight[dir][nSurfTile] != 0.0) dir_blur[dir][nSurfTile] /= dir_weight[dir][nSurfTile];
}
}
int rdir = (dir + 4) % 8;
double rfract = 1.0 - fraction;
for (int nSurfTile = 0; nSurfTile < num_tiles; nSurfTile++){
int nSurfTile1 = tnSurface.getNeibIndex(nSurfTile, dir);
if (nSurfTile1 >= 0){
double d;
if (use_sqrt){
d = rfract * Math.sqrt(tone_diffs[nSurfTile][dir][0]) + fraction * dir_blur[dir][nSurfTile];
d *= d;
} else {
d =rfract * tone_diffs[nSurfTile][dir][0] + fraction * dir_blur[dir][nSurfTile];
}
mixed_diff_weight[nSurfTile][dir][0] = d;
mixed_diff_weight[nSurfTile][dir][1] = rfract * tone_diffs[nSurfTile][dir][1] + fraction * dir_weight[dir][nSurfTile];
mixed_diff_weight[nSurfTile1][rdir][0] = mixed_diff_weight[nSurfTile][dir][0];
mixed_diff_weight[nSurfTile1][rdir][1] = mixed_diff_weight[nSurfTile][dir][1];
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
return mixed_diff_weight;
}
public void showToneDiffWeights3(String prefix){
String [] titles = {"diffs","sqrt","centers","weights"};
double [][] img_data = new double[titles.length][9 * surfTilesX * surfTilesY];
TileNeibs tnSurface3 = new TileNeibs( 3 * surfTilesX, 3 * surfTilesY);
for (int nSurfTile = 0; nSurfTile < tone_diff_weight.length; nSurfTile++){
int [] txy = tnSurface.getXY(nSurfTile);
int [] txy3 = {3 * txy[0] + 1, 3 * txy[1] + 1};
double sdw = 0.0, sw = 0.0;
int num_neibs = 0;
for (int dir = 0; dir < 8; dir++){
sw += tone_diff_weight[nSurfTile][dir][1];
sdw += tone_diff_weight[nSurfTile][dir][0] * tone_diff_weight[nSurfTile][dir][1];
int nSurfTile3 = tnSurface3.getNeibIndex(tnSurface3.getIndex(txy3[0],txy3[1]),dir);
img_data[0][nSurfTile3] = tone_diff_weight[nSurfTile][dir][0];
img_data[1][nSurfTile3] = Math.sqrt(tone_diff_weight[nSurfTile][dir][0]);
img_data[3][nSurfTile3] = tone_diff_weight[nSurfTile][dir][1];
if (tone_diff_weight[nSurfTile][dir][1] > 0.0) num_neibs ++;
}
if (sw > 0.0){
sdw /= sw;
}
if (num_neibs > 0){
sw /= num_neibs;
}
int nSurfTile3 = tnSurface3.getIndex(txy3[0],txy3[1]);
img_data[0][nSurfTile3] = sdw;
img_data[1][nSurfTile3] = Math.sqrt(sdw);
img_data[2][nSurfTile3] = sdw;
img_data[3][nSurfTile3] = sw;
}
(new showDoubleFloatArrays()).showArrays(img_data, 3 * surfTilesX, 3 * surfTilesY, true, prefix+"tone_diffs3", titles);
}
public void showToneDiffWeights1(String prefix){
double [][] img_data = new double[2][surfTilesX * surfTilesY];
for (int nSurfTile = 0; nSurfTile < tone_diff_weight.length; nSurfTile++){
double sdw = 0.0, sw = 0.0;
int num_neibs = 0;
for (int dir = 0; dir < 8; dir++){
sw += tone_diff_weight[nSurfTile][dir][1];
sdw += tone_diff_weight[nSurfTile][dir][0] * tone_diff_weight[nSurfTile][dir][1];
if (tone_diff_weight[nSurfTile][dir][1] > 0.0) num_neibs ++;
}
if (sw > 0.0){
sdw /= sw;
}
if (num_neibs > 0){
sw /= num_neibs;
}
img_data[0][nSurfTile] = sdw;
img_data[1][nSurfTile] = sw;
}
String [] titles = {"diffs","weights"};
(new showDoubleFloatArrays()).showArrays(img_data, surfTilesX, surfTilesY, true, prefix+"tone_diffs1", titles);
}
private double [] getDiffWeight(
double [] tone1,
double [] tone2)
{
double [] tone_weight = {0.0, Math.max(tone1[INDEX_A] * tone2[INDEX_A], 0.0)};
if (tone_weight[1] > 0.0){
double [][] scaled = {
{(Math.max(tone1[INDEX_R], 0.0) + fatZero) * kR, (Math.max(tone1[INDEX_B], 0.0) + fatZero) * kB, (Math.max(tone1[INDEX_G], 0.0) + fatZero) },
{(Math.max(tone2[INDEX_R], 0.0) + fatZero) * kR, (Math.max(tone2[INDEX_B], 0.0) + fatZero) * kB, (Math.max(tone2[INDEX_G], 0.0) + fatZero)}};
double rdiff2 = 0.0;
for (int i = 0; i < 3; i++){
double rd = (scaled[0][i] - scaled[1][i])/(scaled[0][i] + scaled[1][i]);
rdiff2 += rd*rd;
}
tone_weight[0] = rdiff2/3.0;
}
return tone_weight;
}
public void intValidSurf()
{
TileSurface.TileData [][] tileData = ts.getTileData();
int nSurfTiles = surfTilesX * surfTilesY;
valid_surf = new boolean [valid_ml.length][][]; // surfTilesX * surfTilesY][];
for (int ml = 0; ml < valid_ml.length; ml++) if (valid_ml[ml]) {
valid_surf[ml] = new boolean [nSurfTiles][];
}
for (int nSurfTile = 0; nSurfTile < nSurfTiles; nSurfTile++) if (tileData[nSurfTile] != null){
boolean [] surf_en = new boolean [tileData[nSurfTile].length];
for (int i = 0; i < surf_en.length; i++) {
surf_en[i] = true;
}
for (int ml = 0; ml < valid_ml.length; ml++) if (valid_surf[ml] != null){
valid_surf[ml][nSurfTile] = surf_en.clone();
}
}
}
/**
* limit layer options for assigned cells to a single (selected) option, disable all negative ones
* @param tileLayers
*/
public void restrictSingle (
final int [][] tileLayers)
{
for (int ml = 0; ml < valid_ml.length; ml++) if ((valid_surf[ml] != null) && (tileLayers[ml] != null)){
for (int nTile = 0; nTile < tileLayers[ml].length; nTile++) if (tileLayers[ml][nTile] != 0){
int nSurfTile = ts.getSurfaceTileIndex(nTile);
for (int ns = 0; ns < valid_surf[ml][nSurfTile].length; ns++){
valid_surf[ml][nSurfTile][ns] = false;
}
if (tileLayers[ml][nTile] > 0) valid_surf[ml][nSurfTile][tileLayers[ml][nTile] - 1] = true;
}
}
}
/**
* Limit layer options for assigned cells to a multiple options per tile cell
* @param options
*/
public void restrictMulti (
final int [][][] options)
{
for (int ml = 0; ml < valid_ml.length; ml++) if ((valid_surf[ml] != null) && (options[ml] != null)){
for (int nTile = 0; nTile < options[ml].length; nTile++) if ((options[ml][nTile] != null) && (options[ml][nTile].length > 0)){
int nSurfTile = ts.getSurfaceTileIndex(nTile);
for (int ns = 0; ns < valid_surf[ml][nSurfTile].length; ns++){
valid_surf[ml][nSurfTile][ns] = false;
}
for (int i = 0; i < options[ml][nTile].length; i++) {
valid_surf[ml][nSurfTile][options[ml][nTile][i] - 1] = true;
}
}
}
}
/**
* Get signed normalized difference from the measured disparity to the selected surface,
* limit it to +/-dispOutlier to reduce cost of the outliers
* @param ml measured layer (combo, quad, hor, vert)
* @param nSurfTile tile index in surface array (includes full supertiles)
* @param ns number of the surface
* @return signed disparity error, scaled down for large disparities
*/
public double dispDiff(
int ml,
int nSurfTile,
int ns,
boolean debug)
{
if (debug && ((dispStrength[ml] == null) || (dispStrength[ml][nSurfTile] == null))) {
String msg="dispDiff(): no data for ml="+ml+", nSurfTile="+nSurfTile+", ns="+ns;
System.out.println(msg);
return Double.NaN;
// IJ.showMessage(msg);
// throw new IllegalArgumentException (msg);
}
double dm = dispStrength[ml][nSurfTile][0];
double ds = ts.getTileData()[nSurfTile][ns].getDisparity();
double diff = dm - ds;
double d_av = 0.5 * (dm + ds);
if (d_av > dispNorm){
diff *= dispNorm/d_av;
}
if (diff > dispOutlier) diff = dispOutlier;
else if (diff < -dispOutlier) diff = -dispOutlier;
return diff;
}
/**
* Get absolute value of the normalized disparity difference from the measured value to the nearest surface
* @param ml measured layer (combo, quad, hor, vert)
* @param nSurfTile tile index in surface array (includes full supertiles)
* @return absolute value of the disparity error (scaled down for large disparities) to the nearest surface
*/
public double dispDiffBest(
int ml,
int nSurfTile,
boolean debug)
{
double best = Double.NaN;
if ((ts.getTileData() == null) || (ts.getTileData()[nSurfTile] == null)){
// System.out.println("dispDiffBest("+ml+","+nSurfTile+")");
return best;
}
for (int ns = 0; ns < ts.getTileData()[nSurfTile].length; ns++){
double diff = dispDiff(ml, nSurfTile, ns, debug);
double adiff = Math.abs(diff);
if (Double.isNaN(best) || (adiff < best)) {
best = adiff;
}
}
return best;
}
/**
* Get absolute value of the normalized disparity difference from the measured value to the farthest surface
* Used to estimate cost of un-assigned tiles
* @param ml measured layer (combo, quad, hor, vert)
* @param nSurfTile tile index in surface array (includes full supertiles)
* @return absolute value of the disparity error (scaled down for large disparities) to the farthest surface
*/
public double dispDiffWorst(
int ml,
int nSurfTile,
boolean debug)
{
double worst = Double.NaN;
if ((ts.getTileData() == null) || (ts.getTileData()[nSurfTile] == null)){
// System.out.println("dispDiffWorst("+ml+","+nSurfTile+")");
return worst;
}
for (int ns = 0; ns < ts.getTileData()[nSurfTile].length; ns++){
double diff = dispDiff(ml, nSurfTile, ns,debug);
double adiff = Math.abs(diff);
if (Double.isNaN(worst) || (adiff < worst)) {
worst = adiff;
}
}
return worst;
}
public TACosts [] getTileCosts(
boolean all_tiles,
int [][] tileLayers,
boolean debug)
{
TACosts [] ta_costs = new TACosts [surfTilesX * surfTilesY];
for (int nSurfTile = 0; nSurfTile < ta_costs.length; nSurfTile++){
boolean has_tile = false;
boolean has_block = false;
for (int ml = 0; ml < tileLayers.length; ml++) if(tileLayers[ml] != null) {
if (tileLayers[ml][nSurfTile] < 0) {
has_block = true;
break;
}
if (tileLayers[ml][nSurfTile] > 0) {
has_tile = true;
}
}
if (!has_block && (all_tiles || has_tile)){
ta_costs[nSurfTile] = getTileCosts(
nSurfTile, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, debug); // HashMap<Point,Integer> replacements)
}
} //for (int nSurfTile)
return ta_costs;
}
public double [] calcTileCosts(
int [][] tileLayers,
boolean debug)
{
double [] costs = new double [surfTilesX * surfTilesY];
for (int nSurfTile = 0; nSurfTile < costs.length; nSurfTile++){
boolean has_tile = false;
boolean has_block = false;
for (int ml = 0; ml < tileLayers.length; ml++) if(tileLayers[ml] != null) {
if (tileLayers[ml][nSurfTile] < 0) {
has_block = true;
break;
}
if (tileLayers[ml][nSurfTile] > 0) {
has_tile = true;
}
}
if (!has_block && has_tile){
TACosts ta_cost = getTileCosts(
nSurfTile, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, debug); // HashMap<Point,Integer> replacements)
costs[nSurfTile] = cost_coeff.dotProd(ta_cost);
}
}
return costs;
}
public void showTileCost(
String prefix,
int [][] tileLayers,
boolean debug)
{
double [] composite_costs = calcTileCosts(tileLayers, debug);
(new showDoubleFloatArrays()).showArrays(composite_costs, surfTilesX, surfTilesY, prefix+"composite_costs");
}
public void showTileCosts(
String prefix,
int [][] tileLayers,
boolean debug)
{
String [] titles = (new TACosts()).getTitles();
int num_stiles = surfTilesX*surfTilesY;
double [][] cost_components = new double[titles.length][surfTilesX * surfTilesY];
double [] NaNs = new double[titles.length];
for (int i = 0; i < NaNs.length; i++) NaNs[i] = Double.NaN;
for (int nSurfTile = 0; nSurfTile < num_stiles; nSurfTile++){
boolean has_tile = false;
boolean has_block = false;
for (int ml = 0; ml < tileLayers.length; ml++) if(tileLayers[ml] != null) {
if (tileLayers[ml][nSurfTile] < 0) {
has_block = true;
break;
}
if (tileLayers[ml][nSurfTile] > 0) {
has_tile = true;
}
}
double [] costs = NaNs;
if (!has_block) { // && has_tile){
TACosts ta_cost = getTileCosts(
nSurfTile, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, debug); // HashMap<Point,Integer> replacements)
ta_cost.mul(cost_coeff);
costs = ta_cost.toArray();
}
for (int i =0; i < cost_components.length; i++){
cost_components[i][nSurfTile] = costs[i];
}
}
(new showDoubleFloatArrays()).showArrays(cost_components, surfTilesX, surfTilesY, true, prefix+"cost_components", titles);
}
public TACosts [] statTileCosts(
int [][] tileLayers,
boolean debug)
{
TACosts [] ta_stats = {new TACosts(), new TACosts()}; // average, max
int num_tiles = 0;
int numSurfTiles =surfTilesX * surfTilesY;
for (int nSurfTile = 0; nSurfTile < numSurfTiles; nSurfTile++){
if (nSurfTile == 47459){
System.out.println("statTileCosts() nSurfTile="+nSurfTile);
}
boolean has_tile = false;
boolean has_block = false;
for (int ml = 0; ml < tileLayers.length; ml++) if(tileLayers[ml] != null) {
if (tileLayers[ml][nSurfTile] < 0) {
has_block = true;
break;
}
if (tileLayers[ml][nSurfTile] > 0) {
has_tile = true;
}
}
if (!has_block) { // && has_tile){
TACosts ta_cost = getTileCosts(
nSurfTile, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null,debug); // HashMap<Point,Integer> replacements)
ta_stats[0].max(ta_cost);
ta_stats[1].add(ta_cost);
num_tiles++;
}
}
if (num_tiles > 0){
ta_stats[1].scale(1.0/num_tiles);
}
return ta_stats;
}
/**
* Get costs (not scaled) for the particular tile, add for all defined layers
* @param nSurfTile tile index in surface array (includes full supertiles)
* @param tileLayers current assignment
* @param replacements optional assignment modification (or null)
* @return TACosts instance with assigned values
*/
public TACosts getTileCosts(
int nSurfTile,
int [][] tileLayers,
HashMap<Point,Integer> replacements,
boolean debug)
{
TACosts costs = new TACosts();
int debugLevel = 0;
if (nSurfTile == -51360) { // 44831) { // 47459){
System.out.println("getTileCosts() nSurfTile="+nSurfTile);
debugLevel = 1;
}
int [][] around = new int [valid_ml.length][]; // contains layer + 1
for (int ml = 0; ml < valid_ml.length; ml++) if(valid_ml[ml]) {
around[ml] = new int [9];
}
int [] nSurfTiles = new int[9];
for (int dir = 0; dir < 9; dir++){
nSurfTiles[dir] = tnSurface.getNeibIndex(nSurfTile, dir);
if (nSurfTiles[dir] < 0) {
for (int ml = 0; ml < around.length; ml++) if (around[ml] != null){
around[ml][dir] = TileSurface.PROHOBITED;
}
} else {
for (int ml = 0; ml < around.length; ml++) if (around[ml] != null){
around[ml][dir] = tileLayers[ml][nSurfTiles[dir]];
if (replacements != null){
Integer isurf = replacements.get(new Point(ml, nSurfTiles[dir]));
if (isurf != null) {
around[ml][dir] = isurf; // substitute
}
}
}
}
}
//
// public double empty; // Cost of a tile that is not assigned
for (int ml = 0; ml < around.length; ml++) if (around[ml] != null){
if (around[ml][8] == 0) costs.empty +=1.0; // Cost of a tile that is not assigned
}
// public double nolink; // Cost of a tile not having any neighbor in particular direction
int num_weak_fgnd = 0; // to reduce multiple for teh same tile
int num_color_sep = 0; // to reduce multiple for teh same tile
for (int ml = 0; ml < around.length; ml++) if ((around[ml] != null) && (around[ml][8] > 0)){
if ((around[ml][8] - 1) >= ts.getTileData()[nSurfTile].length){
System.out.println("getTileCosts() BUG: nSurfTile="+nSurfTile);
}
int [] neibs = ts.getTileData()[nSurfTile][around[ml][8] - 1].getNeighbors();
for (int dir = 0; dir < 8; dir++) if (neibs[dir] >= 0){ // do not count non-existing connections
boolean link_this = false;
boolean link_other = false;
int ml1 = ml;
int neibp1 = neibs[dir] + 1;
if (around[ml][dir] > 0) {
if (around[ml][dir] == neibp1) {
link_this = true;
} else {
link_other = true;
}
} else if (around[ml][dir] == 0){
// see if some other ml contains this surface (ignore other surfaces
for (ml1 = 0; ml1 < around.length; ml1++) if ((ml1 != ml) && (around[ml1] != null)) {
if (around[ml1][dir] == neibp1){
link_this = true;
break; // ml1 will keep other ml
}
}
} else { // negative/prohibited
continue;
}
if (!link_this && !link_other){
costs.nolink +=1.0;
} else if (link_other) {
costs.swtch += 1.0; // cost for any switch
// check if it is fb->bg transition and fg is weak
double d_this = ts.getTileData()[nSurfTiles[dir]][neibs[dir]].getDisparity();
double d_other = ts.getTileData()[nSurfTiles[dir]][around[ml][dir] -1].getDisparity();
double disp_diff = d_this - d_other;
double d_av = 0.5 * (d_this + d_other);
if (d_av > dispNorm){
disp_diff *= dispNorm/d_av;
}
// disp_diff here is signed, positive if center is FG, other is BG
if (disp_diff > minFgBg) {
double strength = dispStrength[ml][nSurfTile][1];
strength = Math.max(strength, minFgEdge);
costs.weak_fgnd += minFgEdge / strength;
num_weak_fgnd++;
} else if (mutual_weak_fgnd && (disp_diff < -minFgBg)) {
double [] dsmeas_other = dispStrength[ml][nSurfTiles[dir]];
double strength = (dsmeas_other != null)? dsmeas_other[1]: 0.0; // measured strength on the other end or 0.0 if nothing there
strength = Math.max(strength, minFgEdge);
costs.weak_fgnd += minFgEdge / strength;
num_weak_fgnd++;
}
if (Math.abs(disp_diff) > minColSep){
double col_diff = tone_diff_weight[nSurfTile][dir][0];
col_diff= Math.max(col_diff,minColDiff);
costs.color += tone_diff_weight[nSurfTile][dir][1] * minColSep/col_diff;
num_color_sep++;
}
} else { // v, both can not coexist
// Anything to cost here?
}
}
// if (around[ml][8] == 0) costs.empty +=1.0; // each existing measurement layer that is not assigned
} //for (int ml = 0; ml < around.length; ml++) if ((around[ml] != null) && (around[ml][8] > 0))
// using /4.0 to maintain same value (==1.0) for half neighbors (straight edge)
if ((num_weak_fgnd > 0) && (shrinkWeakFgnd > 0.0)){
costs.weak_fgnd /= Math.pow(num_weak_fgnd/4.0, shrinkWeakFgnd);
}
if ((num_color_sep > 0) && (shrinkColor > 0.0)){
costs.color /= Math.pow(num_color_sep/4.0, shrinkColor);
}
double disp_diff_lpf = 0.0, disp_diff_weight = 0.0; // calculate LPF of the disparity signed error over all ML and 9 cells
double disp_diff2 = 0.0, disp_weight = 0.0; // calculate disparity error in the center, weighted
double disp_diff_over_best = 0.0; // , disp_weight_best = 0.0; // calculate disparity error in the center, weighted
for (int ml = 0; ml < around.length; ml++) if (around[ml] != null){
double diff=0.0, weight=0.0;
for (int dir = 0; dir < 9; dir++){
if (around[ml][dir] > 0){ // assigned
diff = dispDiff(
ml, // int ml,
nSurfTiles[dir], // int nSurfTile,
around[ml][dir] - 1, // int ns)
debug);
} else if ((dir == 8) && (around[ml][dir] == 0) ) { //no assigned (not prohibited) - center only, because worst does not have sign
diff = dispDiffWorst( // worst for all surfaces
ml, // int ml,
nSurfTiles[dir], // int nSurfTile,
debug);
}
if (dispStrength[ml][nSurfTile] != null) { // not a bug
if (strengthDiff9Pwr > 0.0) {
weight = dispStrength[ml][nSurfTile][1];
if (strengthDiff9Pwr != 1.0) {
weight = Math.pow(weight, strengthDiff9Pwr);
}
} else {
weight = 1.0;
}
weight *= NEIB_WEIGHTS[dir];
disp_diff_lpf += diff * weight;
disp_diff_weight += weight;
if (debugLevel > 0){
System.out.println("getTileCosts() nSurfTile = "+nSurfTile+"->"+dir+" disp_diff_lpf="+disp_diff_lpf+
" disp_diff_weight="+disp_diff_weight+" weight="+weight+ " diff="+diff+" around["+ml+"]["+dir+"]="+around[ml][dir]);
}
}
}
// now diff is for the center, weight needs to be re-calculated
if (strengthDiffPwr > 0.0) {
if ((dispStrength[ml] == null) || (dispStrength[ml][nSurfTile] == null)){
if (debug) {
System.out.println("getTileCosts() nSurfTile = "+nSurfTile+" ml = "+ml+" is it really a BUG - null pointer here?");
}
weight = 1.0;
} else {
weight = dispStrength[ml][nSurfTile][1]; // null pointer
if (strengthDiffPwr != 1.0) {
weight = Math.pow(weight, strengthDiffPwr);
}
}
} else {
weight = 1.0;
}
disp_diff2 += diff * diff * weight;
disp_weight += weight;
// and once more for the disparity over best
if (strengthBestPwr > 0.0) {
weight = dispStrength[ml][nSurfTile][1];
if (strengthBestPwr != 1.0) {
weight = Math.pow(weight, strengthBestPwr);
}
} else {
weight = 1.0;
}
disp_diff_over_best += (Math.abs(diff) - dispDiffBest( ml, nSurfTiles[8], debug)) * weight; // this one - not squared
}
if (disp_diff_weight > 0.0) {
disp_diff_lpf /= disp_diff_weight;
costs.diff9 += disp_diff_lpf * disp_diff_lpf;
if (debugLevel > 0){
System.out.println("getTileCosts() nSurfTile = "+nSurfTile+" disp_diff_lpf="+disp_diff_lpf+
" disp_diff_weight="+disp_diff_weight+" costs.diff9="+costs.diff9);
}
}
if (disp_weight > 0.0) {
costs.diff += disp_diff2 / disp_weight;
costs.diff_best += disp_diff_over_best / disp_weight;
}
int [] txy = tnSurface.getXY(nSurfTile);
int nSTile = (txy[0] / ts.getSuperTileSize()) + (txy[1] / ts.getSuperTileSize()) * ts.getSTilesX();
for (int ml = 0; ml < around.length; ml++) if ((around[ml] != null) && (around[ml][8] > 0)){
int parentSTile =ts.getTileData()[nSurfTile][around[ml][8] -1].getParentNsTile();
if (parentSTile != nSTile){
costs.flaps += 1.0;
}
}
return costs;
}
public int [][] imgToSurf (
int [][] tileLayersImg)
{
int [][] tileLayersSurf = new int[tileLayersImg.length][];
for (int ml = 0; ml < tileLayersImg.length; ml++) if (tileLayersImg[ml] != null){
tileLayersSurf[ml] = new int [tnSurface.getLength()];
for (int i = 0; i < tileLayersSurf[ml].length; i++){
tileLayersSurf[ml][i] = -1;
}
for (int nTile = 0; nTile < tileLayersImg[ml].length; nTile++){
int nSurfTile = tnSurface.getIndex(tnImage.getXY(nTile));
if (nSurfTile >= 0) {
tileLayersSurf[ml][nSurfTile] = tileLayersImg[ml][nTile];
}
}
}
return tileLayersSurf;
}
public int [][] surfToImg (
int [][] tileLayersSurf)
{
int [][] tileLayersImg = new int[tileLayersSurf.length][];
for (int ml = 0; ml < tileLayersSurf.length; ml++) if (tileLayersSurf[ml] != null){
tileLayersImg[ml] = new int [tnImage.getLength()];
for (int i = 0; i < tileLayersImg[ml].length; i++){
tileLayersImg[ml][i] = -1;
}
for (int nSurfTile = 0; nSurfTile < tileLayersSurf[ml].length; nSurfTile++){
int nImgTile = tnImage.getIndex(tnSurface.getXY(nSurfTile));
if (nImgTile >= 0) {
tileLayersImg[ml][nImgTile] = tileLayersSurf[ml][nSurfTile];
}
}
}
return tileLayersImg;
}
public void optimizeAssignment9(
final boolean noEdge,
final int [][] tileLayers,
final int debugLevel,
final int dbg_X,
final int dbg_Y)
{
mutual_weak_fgnd = true;
final int step = 3;
final int tries = 1000;
// final int dbg_tile = dbg_X + dbg_Y * surfTilesX;
final int dbg_tile = 47779; // 27083; // 44493;
final int num_tiles = surfTilesX * surfTilesY;
final int [][] tile_indices = new int [step*step][];
for (int sty = 0; sty < step; sty ++){
int num_y = (surfTilesY + step -1 - sty) / step;
for (int stx = 0; stx < step; stx ++){
int num_x = (surfTilesX + step -1 - stx) / step;
int indx1 = sty * step + stx;
int l = num_y * num_x;
tile_indices[indx1] = new int [l];
int indx2 = 0;
for (int y = 0; y < num_y; y++){
for (int x = 0; x < num_x; x++){
tile_indices[indx1][indx2++] = (sty + step * y) * surfTilesX + (stx + step * x);
}
}
}
}
final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : ts.getThreadsMax());
final int numThreads = threads.length;
final int [] improved = new int [numThreads];
final AtomicInteger ai_numThread = new AtomicInteger(0);
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger ai_series = new AtomicInteger(0);
final AtomicBoolean [] dirty = new AtomicBoolean[surfTilesX * surfTilesY];
for (int nSurfTile = 0; nSurfTile < dirty.length; nSurfTile++){
boolean valid_tile = false; // bad may be only some ml?
for (int ml = 0; ml < tileLayers.length; ml++) if ((tileLayers[ml] != null) && (tileLayers[ml][nSurfTile] >= 0)){
valid_tile = true;
break;
}
if (valid_tile) dirty[nSurfTile] = new AtomicBoolean(true);
}
final boolean [][] bad_surface = new boolean[num_tiles][];
final TileSurface.TileData [][] tileData = ts.getTileData();
if (noEdge) {
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int nSurfTile = ai.getAndIncrement(); nSurfTile < num_tiles; nSurfTile = ai.getAndIncrement()) {
if (tileData[nSurfTile] != null){
bad_surface[nSurfTile] = new boolean [tileData[nSurfTile].length];
for (int ns = 0; ns < tileData[nSurfTile].length; ns++) {
int []neibs = tileData[nSurfTile][ns].getNeighbors();
for (int i = 0; i < neibs.length; i++){
if (neibs[i] < 0){
bad_surface[nSurfTile][ns] = true;
}
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
}
for (int nTry = 0 ; nTry < tries; nTry++) {
for (int i = 0; i < improved.length; i++) improved[i] = 0;
int this_improved = 0;
for (int nSeries = 0; nSeries < tile_indices.length; nSeries++) {
final int fnSeries = nSeries;
ai.set(0);
ai_numThread.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
int numThread = ai_numThread.getAndIncrement(); // unique number of thread to write to rslt_diffs[numThread]
for (int iTile = ai.getAndIncrement(); iTile < tile_indices[fnSeries].length; iTile = ai.getAndIncrement()) {
int nSurfTile = tile_indices[fnSeries][iTile];
int dl = ((debugLevel > 1) && (nSurfTile == dbg_tile)) ? 3: debugLevel;
if (dl > 2){
System.out.println("optimizeAssignment9(), nSurfTile = "+nSurfTile+" dl = "+dl);
}
// if (dirty[nSurfTile].get()) {
if ((dirty[nSurfTile] != null) && dirty[nSurfTile].getAndSet(false)) {
int num_surf = tileData[nSurfTile].length;
int lowest_surf = 0;
for (; lowest_surf < num_surf; lowest_surf ++){
if ((bad_surface[nSurfTile] != null) && !bad_surface[nSurfTile][lowest_surf]) {
break;
}
}
if (lowest_surf >= num_surf) {
continue; // no valid surfaces at this location
}
double best_cost = cost_coeff.dotProd(getTileCosts(
nSurfTile, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, (dl > 1))); // HashMap<Point,Integer> replacements);
// int [] initial_indices = tileLayers[nSurfTile].clone();
int [] initial_indices = new int [valid_ml.length]; // 1-based
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
initial_indices[ml] = tileLayers[ml][nSurfTile]; // 1-based
}
}
int [] best_surf = null;
int [] surfaces = null; // new int [valid_ml.length];
int max_reset = 0; // = valid_ml.length; // maximal ml to reset
while (true) {
if (surfaces == null) {
surfaces = new int [valid_ml.length];
for (int ml = 0; ml < valid_ml.length; ml ++){
if (!valid_ml[ml] || (tileLayers[ml][nSurfTile] < 0)) {
surfaces[ml] = -1;
}
}
max_reset = valid_ml.length;
} else { // find ml to increase surface
for (max_reset = 0; max_reset < surfaces.length; max_reset++) if (surfaces[max_reset] >= 0){
for (surfaces[max_reset]++; surfaces[max_reset] < num_surf; surfaces[max_reset]++) {
if ((bad_surface[nSurfTile] == null) || !bad_surface[nSurfTile][surfaces[max_reset]]) {
break;
}
}
if (surfaces[max_reset] < num_surf) break;
}
if (max_reset >= surfaces.length){
break; // while (true) {
}
}
// reset all surfaces[] with indices < max_reset to lowest
for (int ml = 0; ml < max_reset; ml++ ) if (valid_ml[ml] && (surfaces[ml] >= 0)){
surfaces[ml] = lowest_surf;
}
// now surfaces[] contain next combination of surfaces to try
// tileLayers[nSurfTile] = surfaces;
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
tileLayers[ml][nSurfTile] = surfaces[ml] + 1; // 1-based from 0-based
}
}
double cost = cost_coeff.dotProd(getTileCosts( //
nSurfTile, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, (dl > 1))); // HashMap<Point,Integer> replacements);
if (cost < best_cost) {
best_cost = cost;
best_surf = surfaces.clone();
}
} // while (true)
if (best_surf != null){ // update
// tileLayers[nSurfTile] = best_surf;
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
tileLayers[ml][nSurfTile] = best_surf[ml] + 1; // 1-based from 0-based
}
}
for (int dir = 0; dir <8; dir++) {
int nSurfTile1 = tnSurface.getNeibIndex(nSurfTile, dir);
if ((nSurfTile1 >= 0) && (dirty[nSurfTile1] != null)){
dirty[nSurfTile1].set(true);
}
}
improved[numThread]++;
} else { // restore initial data
// tileLayers[nSurfTile] = initial_indices;
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
tileLayers[ml][nSurfTile] = initial_indices[ml]; // 1-based from 1-based
}
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
if (debugLevel > -1){
int num_better = 0;
for (int i = 0; i < improved.length; i++){
num_better += improved[i];
}
System.out.println("optimizeAssignment9(): pass = "+nTry+ ":"+nSeries+" improved:" + (num_better - this_improved));
this_improved = num_better;
}
} // for (int nSeries = 0; nSeries < tile_indices.length; nSeries++) {
// should be checked only after all series (now 9 passes) are finished - if anything was added - continue
int num_improved = 0;
for (int i = 0; i < improved.length; i++){
num_improved += improved[i];
}
if (debugLevel > -1){
System.out.println("optimizeAssignment9(): pass = "+nTry+ " improved:"+num_improved);
}
if (num_improved == 0) break;
}
}
public void optimizeAssignment25(
final boolean noEdge,
final int [][] tileLayers,
final int debugLevel,
final int dbg_X,
final int dbg_Y)
{
final int step = 5;
mutual_weak_fgnd = false;
final int tries = 1000;
// final int dbg_tile = dbg_X + dbg_Y * surfTilesX;
final int dbg_tile = 51360; // 51; // 44831; // 27083; // 44493;
final int num_tiles = surfTilesX * surfTilesY;
final int [][] tile_indices = new int [step*step][];
for (int sty = 0; sty < step; sty ++){
int num_y = (surfTilesY + step -1 - sty) / step;
for (int stx = 0; stx < step; stx ++){
int num_x = (surfTilesX + step -1 - stx) / step;
int indx1 = sty * step + stx;
int l = num_y * num_x;
tile_indices[indx1] = new int [l];
int indx2 = 0;
for (int y = 0; y < num_y; y++){
for (int x = 0; x < num_x; x++){
tile_indices[indx1][indx2++] = (sty + step * y) * surfTilesX + (stx + step * x);
}
}
}
}
final Thread[] threads = ImageDtt.newThreadArray((debugLevel > 1)? 1 : ts.getThreadsMax());
final int numThreads = threads.length;
final int [] improved = new int [numThreads];
final AtomicInteger ai_numThread = new AtomicInteger(0);
final AtomicInteger ai = new AtomicInteger(0);
final AtomicInteger ai_series = new AtomicInteger(0);
final AtomicBoolean [] dirty = new AtomicBoolean[surfTilesX * surfTilesY];
for (int nSurfTile = 0; nSurfTile < dirty.length; nSurfTile++){
boolean valid_tile = false; // bad may be only some ml?
for (int ml = 0; ml < tileLayers.length; ml++) if ((tileLayers[ml] != null) && (tileLayers[ml][nSurfTile] >= 0)){
valid_tile = true;
break;
}
if (valid_tile) dirty[nSurfTile] = new AtomicBoolean(true);
}
final boolean [][] bad_surface = new boolean[num_tiles][];
final TileSurface.TileData [][] tileData = ts.getTileData();
if (noEdge) {
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int nSurfTile = ai.getAndIncrement(); nSurfTile < num_tiles; nSurfTile = ai.getAndIncrement()) {
if (tileData[nSurfTile] != null){
bad_surface[nSurfTile] = new boolean [tileData[nSurfTile].length];
for (int ns = 0; ns < tileData[nSurfTile].length; ns++) {
int []neibs = tileData[nSurfTile][ns].getNeighbors();
for (int i = 0; i < neibs.length; i++){
if (neibs[i] < 0){
bad_surface[nSurfTile][ns] = true;
}
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
}
for (int nTry = 0 ; nTry < tries; nTry++) {
for (int i = 0; i < improved.length; i++) improved[i] = 0;
int this_improved = 0;
for (int nSeries = 0; nSeries < tile_indices.length; nSeries++) {
final int fnSeries = nSeries;
ai.set(0);
ai_numThread.set(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
int numThread = ai_numThread.getAndIncrement(); // unique number of thread to write to rslt_diffs[numThread]
for (int iTile = ai.getAndIncrement(); iTile < tile_indices[fnSeries].length; iTile = ai.getAndIncrement()) {
int nSurfTile = tile_indices[fnSeries][iTile];
int dl = ((debugLevel > 1) && (nSurfTile == dbg_tile)) ? 3: debugLevel;
if (dl > 2){
System.out.println("optimizeAssignment25(), nSurfTile = "+nSurfTile+" dl = "+dl);
}
// if (dirty[nSurfTile].get()) {
if ((dirty[nSurfTile] != null) && dirty[nSurfTile].getAndSet(false)) {
int num_surf = tileData[nSurfTile].length;
int lowest_surf = 0;
for (; lowest_surf < num_surf; lowest_surf ++){
if ((bad_surface[nSurfTile] != null) && !bad_surface[nSurfTile][lowest_surf]) {
break;
}
}
if (lowest_surf >= num_surf) {
continue; // no valid surfaces at this location
}
double best_cost = 0.0;
if (dl > 2) {
System.out.println("optimizeAssignment25(), tileLayers[0]["+nSurfTile+"] = " + tileLayers[0][nSurfTile]);
// int [] dbg_layers = new int [tileLayers.length];
// for (int ml = 0; ml < tileLayers.length; ml++){
// dbg_layers[ml] = (tileLayers[ml] == null) ? -0: tileLayers[ml][nSurfTile];
// }
// System.out.println("optimizeAssignment25(), tileLayers["+nSurfTile+"] = " + dbg_layers);
}
for (int dir = 0; dir < 9; dir++) {
int nSurfTile1 = tnSurface.getNeibIndex(nSurfTile, dir);
if (nSurfTile1 >= 0){
// best_cost += cost_coeff.dotProd(getTileCosts(
// nSurfTile1, // int nSurfTile,
// tileLayers, // int [][] tileLayers,
// null)); // HashMap<Point,Integer> replacements);
TACosts ta_costs = getTileCosts(
nSurfTile1, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, (dl > 1)); // HashMap<Point,Integer> replacements);
double ccost = cost_coeff.dotProd(ta_costs);
best_cost += ccost;
if (dl > 2){
System.out.println("optimizeAssignment25(), nSurfTile = "+nSurfTile+" dir = "+dir +
" nSurfTile1="+nSurfTile1+" ccost = "+ccost+" best_cost="+best_cost);
System.out.println("ta_costs["+nSurfTile1+"]="+ta_costs.toString());
}
}
}
// int [] initial_indices = tileLayers[nSurfTile].clone();
int [] initial_indices = new int [valid_ml.length]; // 1-based
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
initial_indices[ml] = tileLayers[ml][nSurfTile]; // 1-based
}
}
int [] best_surf = null;
int [] surfaces = null; // new int [valid_ml.length];
int max_reset = 0; // = valid_ml.length; // maximal ml to reset
while (true) {
if (surfaces == null) {
surfaces = new int [valid_ml.length];
for (int ml = 0; ml < valid_ml.length; ml ++){
if (!valid_ml[ml] || (tileLayers[ml][nSurfTile] < 0)) {
surfaces[ml] = -1;
}
}
max_reset = valid_ml.length;
} else { // find ml to increase surface
for (max_reset = 0; max_reset < surfaces.length; max_reset++) if (surfaces[max_reset] >= 0){
for (surfaces[max_reset]++; surfaces[max_reset] < num_surf; surfaces[max_reset]++) {
if ((bad_surface[nSurfTile] == null) || !bad_surface[nSurfTile][surfaces[max_reset]]) {
break;
}
}
if (surfaces[max_reset] < num_surf) break;
}
if (max_reset >= surfaces.length){
break; // while (true) {
}
}
// reset all surfaces[] with indices < max_reset to lowest
for (int ml = 0; ml < max_reset; ml++ ) if (valid_ml[ml] && (surfaces[ml] >= 0)){
surfaces[ml] = lowest_surf;
}
// now surfaces[] contain next combination of surfaces to try
// tileLayers[nSurfTile] = surfaces;
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
tileLayers[ml][nSurfTile] = surfaces[ml] + 1; // 1-based from 0-based
}
}
double cost = 0.0;
if (dl > 2) {
System.out.println("optimizeAssignment25(), surfaces[0]= " + surfaces[0]);
}
for (int dir = 0; dir < 9; dir++) {
int nSurfTile1 = tnSurface.getNeibIndex(nSurfTile, dir);
if (nSurfTile1 >= 0){
TACosts ta_costs = getTileCosts(
nSurfTile1, // int nSurfTile,
tileLayers, // int [][] tileLayers,
null, (dl > 1)); // HashMap<Point,Integer> replacements);
double ccost = cost_coeff.dotProd(ta_costs);
cost+=ccost;
if (dl > 2){
System.out.println("optimizeAssignment25(), nSurfTile = "+nSurfTile+" dir = "+dir +
" nSurfTile1="+nSurfTile1+" ccost = "+ccost+" cost="+cost);
System.out.println("ta_costs["+nSurfTile1+"]="+ta_costs.toString());
}
}
}
if (cost < best_cost) {
best_cost = cost;
best_surf = surfaces.clone();
}
} // while (true)
if (best_surf != null){ // update
// tileLayers[nSurfTile] = best_surf;
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
tileLayers[ml][nSurfTile] = best_surf[ml] + 1; // 1-based from 0-based
}
}
for (int dir = 0; dir <8; dir++) {
int nSurfTile1 = tnSurface.getNeibIndex(nSurfTile, dir);
if ((nSurfTile1 >= 0) && (dirty[nSurfTile1] != null)){
dirty[nSurfTile1].set(true);
}
}
improved[numThread]++;
} else { // restore initial data
// tileLayers[nSurfTile] = initial_indices;
for (int ml = 0; ml < valid_ml.length; ml ++ ){
if (tileLayers[ml] != null) {
tileLayers[ml][nSurfTile] = initial_indices[ml]; // 1-based from 1-based
}
}
}
}
}
}
};
}
ImageDtt.startAndJoin(threads);
if (debugLevel > -1){
int num_better = 0;
for (int i = 0; i < improved.length; i++){
num_better += improved[i];
}
System.out.println("optimizeAssignment25(): pass = "+nTry+ ":"+nSeries+" improved:" + (num_better - this_improved));
this_improved = num_better;
}
} // for (int nSeries = 0; nSeries < tile_indices.length; nSeries++) {
// should be checked only after all series (now 9 passes) are finished - if anything was added - continue
int num_improved = 0;
for (int i = 0; i < improved.length; i++){
num_improved += improved[i];
}
if (debugLevel > -1){
System.out.println("optimizeAssignment25(): pass = "+nTry+ " improved:"+num_improved);
}
if (num_improved == 0) break;
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -37,6 +37,7 @@ import java.util.Set; ...@@ -37,6 +37,7 @@ import java.util.Set;
import com.elphel.imagej.calibration.CalibrationFileManagement; import com.elphel.imagej.calibration.CalibrationFileManagement;
import com.elphel.imagej.common.GenericJTabbedDialog; import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.common.WindowTools; import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.lwir.LwirReaderParameters;
import com.elphel.imagej.tileprocessor.BiQuadParameters; import com.elphel.imagej.tileprocessor.BiQuadParameters;
import com.elphel.imagej.tileprocessor.ImageDtt; import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.ImageDttParameters; import com.elphel.imagej.tileprocessor.ImageDttParameters;
...@@ -3252,6 +3253,8 @@ public class EyesisCorrectionParameters { ...@@ -3252,6 +3253,8 @@ public class EyesisCorrectionParameters {
public BiQuadParameters rig = new BiQuadParameters(); public BiQuadParameters rig = new BiQuadParameters();
public PoleProcessorParameters poles = new PoleProcessorParameters(); public PoleProcessorParameters poles = new PoleProcessorParameters();
public MeasuredLayersFilterParameters mlfp = new MeasuredLayersFilterParameters(); public MeasuredLayersFilterParameters mlfp = new MeasuredLayersFilterParameters();
public LwirReaderParameters lwir = new LwirReaderParameters();
public HashMap<String,Double> z_corr_map = new HashMap<String,Double>(); //old one public HashMap<String,Double> z_corr_map = new HashMap<String,Double>(); //old one
public HashMap<String,Double> infinity_distace_map = new HashMap<String,Double>(); //new one public HashMap<String,Double> infinity_distace_map = new HashMap<String,Double>(); //new one
...@@ -3945,6 +3948,7 @@ public class EyesisCorrectionParameters { ...@@ -3945,6 +3948,7 @@ public class EyesisCorrectionParameters {
mlfp.setProperties (prefix+"_mlfp", properties); mlfp.setProperties (prefix+"_mlfp", properties);
rig.setProperties (prefix+"_rig", properties); rig.setProperties (prefix+"_rig", properties);
poles.setProperties (prefix+"_poles", properties); poles.setProperties (prefix+"_poles", properties);
lwir.setProperties (prefix+"_lwir", properties);
} }
public void setPropertiesInfinityDistance(String prefix,Properties properties){ public void setPropertiesInfinityDistance(String prefix,Properties properties){
...@@ -4653,6 +4657,7 @@ public class EyesisCorrectionParameters { ...@@ -4653,6 +4657,7 @@ public class EyesisCorrectionParameters {
mlfp.getProperties (prefix+"_mlfp", properties); mlfp.getProperties (prefix+"_mlfp", properties);
rig.getProperties (prefix+"_rig", properties); rig.getProperties (prefix+"_rig", properties);
poles.getProperties (prefix+"_poles", properties); poles.getProperties (prefix+"_poles", properties);
lwir.getProperties (prefix+"_lwir", properties);
} }
public boolean showJDialog() { public boolean showJDialog() {
...@@ -5467,9 +5472,13 @@ public class EyesisCorrectionParameters { ...@@ -5467,9 +5472,13 @@ public class EyesisCorrectionParameters {
gd.addCheckbox ("Show 'flaps-dirs'", this.show_flaps_dirs); gd.addCheckbox ("Show 'flaps-dirs'", this.show_flaps_dirs);
gd.addCheckbox ("Show 'first_N_clusters'", this.show_first_clusters); gd.addCheckbox ("Show 'first_N_clusters'", this.show_first_clusters);
gd.addCheckbox ("Show planes", this.show_planes); gd.addCheckbox ("Show planes", this.show_planes);
gd.addMessage ("Unity up vector in camera coordinate system (x - right, y - up, z - to camera): {"+ gd.addMessage ("Unity up vector in camera coordinate system (x - right, y - up, z - to camera): {"+
this.vertical_xyz[0]+","+this.vertical_xyz[1]+","+this.vertical_xyz[2]+"}"); this.vertical_xyz[0]+","+this.vertical_xyz[1]+","+this.vertical_xyz[2]+"}");
gd.addTab ("LWIR", "parameters for LWIR/VNIR 8-camera rig");
this.lwir.dialogQuestions(gd);
// gd.buildDialog(); // gd.buildDialog();
gd.showDialog(); gd.showDialog();
// System.out.println("gd.wasCanceled="+gd.wasCanceled()); // System.out.println("gd.wasCanceled="+gd.wasCanceled());
...@@ -6150,6 +6159,9 @@ public class EyesisCorrectionParameters { ...@@ -6150,6 +6159,9 @@ public class EyesisCorrectionParameters {
this.show_flaps_dirs= gd.getNextBoolean(); this.show_flaps_dirs= gd.getNextBoolean();
this.show_first_clusters= gd.getNextBoolean(); this.show_first_clusters= gd.getNextBoolean();
this.show_planes= gd.getNextBoolean(); this.show_planes= gd.getNextBoolean();
this.lwir.dialogAnswers(gd);
return true; return true;
} }
......
package com.elphel.imagej.tileprocessor; package com.elphel.imagej.correction;
/** /**
** -----------------------------------------------------------------------------** ** -----------------------------------------------------------------------------**
** Eyesis_Correction.java ** Eyesis_Correction.java
...@@ -80,12 +80,6 @@ import com.elphel.imagej.common.DoubleGaussianBlur; ...@@ -80,12 +80,6 @@ import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.GenericJTabbedDialog; import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.common.ShowDoubleFloatArrays; import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.common.WindowTools; import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.correction.BlueLeak;
import com.elphel.imagej.correction.CorrectionColorProc;
import com.elphel.imagej.correction.EyesisCorrections;
import com.elphel.imagej.correction.EyesisDCT;
import com.elphel.imagej.correction.PostProcessing;
import com.elphel.imagej.correction.CorrectionColorProc.ColorGainsParameters;
import com.elphel.imagej.dct.FactorConvKernel; import com.elphel.imagej.dct.FactorConvKernel;
import com.elphel.imagej.gpu.GPUTileProcessor; import com.elphel.imagej.gpu.GPUTileProcessor;
import com.elphel.imagej.gpu.JCuda_ImageJ_Example_Plugin; import com.elphel.imagej.gpu.JCuda_ImageJ_Example_Plugin;
...@@ -93,6 +87,11 @@ import com.elphel.imagej.jp4.JP46_Reader_camera; ...@@ -93,6 +87,11 @@ import com.elphel.imagej.jp4.JP46_Reader_camera;
import com.elphel.imagej.lwir.LwirReader; import com.elphel.imagej.lwir.LwirReader;
import com.elphel.imagej.readers.EyesisTiff; import com.elphel.imagej.readers.EyesisTiff;
import com.elphel.imagej.tensorflow.TensorflowInferModel; import com.elphel.imagej.tensorflow.TensorflowInferModel;
import com.elphel.imagej.tileprocessor.DttRad2;
import com.elphel.imagej.tileprocessor.ImageDtt;
import com.elphel.imagej.tileprocessor.MLStats;
import com.elphel.imagej.tileprocessor.QuadCLT;
import com.elphel.imagej.tileprocessor.TwoQuadCLT;
import ij.CompositeImage; import ij.CompositeImage;
import ij.IJ; import ij.IJ;
...@@ -675,7 +674,8 @@ private Panel panel1, ...@@ -675,7 +674,8 @@ private Panel panel1,
if (LWIR_MODE) { if (LWIR_MODE) {
panelLWIR = new Panel(); panelLWIR = new Panel();
panelLWIR.setLayout(new GridLayout(1, 0, 5, 5)); // rows, columns, vgap, hgap panelLWIR.setLayout(new GridLayout(1, 0, 5, 5)); // rows, columns, vgap, hgap
addButton("LWIR_ACQUIRE", panelLWIR, color_conf_process); addButton("LWIR_TEST", panelLWIR, color_conf_process);
addButton("LWIR_ACQUIRE", panelLWIR, color_conf_process);
add(panelLWIR); add(panelLWIR);
} }
// //
...@@ -897,6 +897,9 @@ private Panel panel1, ...@@ -897,6 +897,9 @@ private Panel panel1,
if (DEBUG_LEVEL>0) System.out.println("--- Free memory="+runtime.freeMemory()+" (of "+runtime.totalMemory()+")"); if (DEBUG_LEVEL>0) System.out.println("--- Free memory="+runtime.freeMemory()+" (of "+runtime.totalMemory()+")");
CLT_PARAMETERS.batch_run = false; CLT_PARAMETERS.batch_run = false;
if (label==null) return; if (label==null) return;
System.out.println("DEBUG_LEVEL = "+DEBUG_LEVEL+", MASTER_DEBUG_LEVEL = "+MASTER_DEBUG_LEVEL);
loci.common.DebugTools.enableLogging((MASTER_DEBUG_LEVEL > 1)?"DEBUG":((MASTER_DEBUG_LEVEL > 0)?"INFO":"ERROR")); // INFO"); // ERROR");
/* ======================================================================== */ /* ======================================================================== */
if (label.equals("Configure spilt")) { if (label.equals("Configure spilt")) {
showSplitBayerToStackDialog(SPLIT_PARAMETERS); showSplitBayerToStackDialog(SPLIT_PARAMETERS);
...@@ -4826,12 +4829,12 @@ private Panel panel1, ...@@ -4826,12 +4829,12 @@ private Panel panel1,
TENSORFLOW_INFER_MODEL.test_tensorflow(keep_empty); TENSORFLOW_INFER_MODEL.test_tensorflow(keep_empty);
return; return;
/* ======================================================================== */ /* ======================================================================== */
} else if (label.equals("LWIR_ACQUIRE")) { } else if (label.equals("LWIR_TEST")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL; DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
loci.common.DebugTools.enableLogging((DEBUG_LEVEL > 1)?"DEBUG":((DEBUG_LEVEL > 0)?"INFO":"ERROR")); // INFO"); // ERROR"); // loci.common.DebugTools.enableLogging((DEBUG_LEVEL > 1)?"DEBUG":((DEBUG_LEVEL > 0)?"INFO":"ERROR")); // INFO"); // ERROR");
// public static LwirReader LWIR_READER = null; // public static LwirReader LWIR_READER = null;
if (LWIR_READER == null) { if (LWIR_READER == null) {
LWIR_READER = new LwirReader(); LWIR_READER = new LwirReader(CLT_PARAMETERS.lwir);
} }
ImagePlus [][] imps = LWIR_READER.readAllMultiple( ImagePlus [][] imps = LWIR_READER.readAllMultiple(
10, // final int num_frames, 10, // final int num_frames,
...@@ -4841,7 +4844,7 @@ private Panel panel1, ...@@ -4841,7 +4844,7 @@ private Panel panel1,
imp.show(); imp.show();
} }
System.out.println("LWIR_ACQUIRE: got "+imps.length+" image sets"); System.out.println("LWIR_TEST: got "+imps.length+" image sets");
ImagePlus [][] imps_sync = LWIR_READER.matchSets(imps, 0.001, 3); // double max_mismatch) ImagePlus [][] imps_sync = LWIR_READER.matchSets(imps, 0.001, 3); // double max_mismatch)
if (imps_sync != null) { if (imps_sync != null) {
ImagePlus [] imps_avg = LWIR_READER.averageMultiFrames(imps_sync); ImagePlus [] imps_avg = LWIR_READER.averageMultiFrames(imps_sync);
...@@ -4849,6 +4852,20 @@ private Panel panel1, ...@@ -4849,6 +4852,20 @@ private Panel panel1,
imp.show(); imp.show();
} }
} }
/* ======================================================================== */
} else if (label.equals("LWIR_ACQUIRE")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
// loci.common.DebugTools.enableLogging((DEBUG_LEVEL > 1)?"DEBUG":((DEBUG_LEVEL > 0)?"INFO":"ERROR")); // INFO"); // ERROR");
// public static LwirReader LWIR_READER = null;
if (LWIR_READER == null) {
LWIR_READER = new LwirReader(CLT_PARAMETERS.lwir);
}
ImagePlus [] imps = LWIR_READER.acquire();
if (imps != null) {
for (ImagePlus imp: imps) {
imp.show();
}
}
//JTabbedTest //JTabbedTest
// End of buttons code // End of buttons code
...@@ -7675,6 +7692,7 @@ private Panel panel1, ...@@ -7675,6 +7692,7 @@ private Panel panel1,
PSF_SUBPIXEL_SHOULD_BE_4=Integer.parseInt(properties.getProperty("PSF_SUBPIXEL_SHOULD_BE_4")); PSF_SUBPIXEL_SHOULD_BE_4=Integer.parseInt(properties.getProperty("PSF_SUBPIXEL_SHOULD_BE_4"));
if (QUAD_CLT != null) QUAD_CLT.getProperties(QuadCLT.PREFIX); if (QUAD_CLT != null) QUAD_CLT.getProperties(QuadCLT.PREFIX);
if (QUAD_CLT_AUX != null) QUAD_CLT_AUX.getProperties(QuadCLT.PREFIX_AUX); if (QUAD_CLT_AUX != null) QUAD_CLT_AUX.getProperties(QuadCLT.PREFIX_AUX);
} }
/* ======================================================================== */ /* ======================================================================== */
......
...@@ -1434,7 +1434,13 @@ Exception in thread "Thread-3564" java.lang.ArrayIndexOutOfBoundsException: 8970 ...@@ -1434,7 +1434,13 @@ Exception in thread "Thread-3564" java.lang.ArrayIndexOutOfBoundsException: 8970
Class<?> clazz = JP46_Reader_camera.class; Class<?> clazz = JP46_Reader_camera.class;
String url = clazz.getResource("/" + clazz.getName().replace('.', '/') + ".class").toString(); String url = clazz.getResource("/" + clazz.getName().replace('.', '/') + ".class").toString();
String pluginsDir = url.substring(5, url.length() - clazz.getName().length() - 6); String pluginsDir = url.substring(5, url.length() - clazz.getName().length() - 6);
System.out.println(System.getProperty("plugins.dir"));
System.setProperty("plugins.dir", pluginsDir); System.setProperty("plugins.dir", pluginsDir);
// System.setProperty("plugins.dir", "/data_ssd/imagej-elphel/ijplugins");
// System.setProperty("plugins.dir", "/data_ssd/imagej-elphel/target/classes/com/elphel/imagej/jp4/");
System.out.println(System.getProperty("plugins.dir"));
// start ImageJ // start ImageJ
new ImageJ(); new ImageJ();
// run the plugin // run the plugin
......
...@@ -27,10 +27,18 @@ ...@@ -27,10 +27,18 @@
package com.elphel.imagej.lwir; package com.elphel.imagej.lwir;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.elphel.imagej.readers.ImagejJp4TiffMulti; import com.elphel.imagej.readers.ImagejJp4TiffMulti;
...@@ -51,26 +59,47 @@ public class LwirReader { ...@@ -51,26 +59,47 @@ public class LwirReader {
"http://192.168.0.38:2326/bchn4", "http://192.168.0.38:2326/bchn4",
}; };
public static String IMAGE_URL_FIRST="/towp/wait/img/save"; // next image name, same image number/time public static final int [] IMGSRV_PORTS = {2323,2324,2325,2326};
public static String IMAGE_URL_NEXT= "/torp/next/wait/img/save"; // same image name, same image number/time public static final String IMAGE_URL_FIRST="/towp/wait/img/save"; // next image name, same image number/time
public static final String IMAGE_URL_NEXT= "/torp/next/wait/img/save"; // same image name, same image number/time
// public static String IMAGE_URL_FIRST="/towp/wait/bimg/save"; // next image name, same image number/time public static final String SKIP_FRAME_URL= "/towp/wait/meta"; // Wit for the next frame, return meta data
// public static String IMAGE_URL_NEXT= "/torp/next/wait/bimg/save"; // same image name, same image number/time public static final int COLOR_JP4 = 5;
public static final int COLOR_RAW = 15;
public static final int FRAMES_SKIP = 3;
public static final int MAX_THREADS = 100; // combine from all classes?
/** Logger for this class. */ /** Logger for this class. */
private static final Logger LOGGER = private static final Logger LOGGER =
LoggerFactory.getLogger(LwirReader.class); LoggerFactory.getLogger(LwirReader.class);
private ImagejJp4TiffMulti imagejJp4TiffMulti; private ImagejJp4TiffMulti imagejJp4TiffMulti;
private boolean out_of_sync = false;
/** Configuration parameters */
private LwirReaderParameters lwirReaderParameters = null;
private LwirReaderParameters last_programmed = null;
// -- constructors
public LwirReader() { public LwirReader() {
this.lwirReaderParameters = new LwirReaderParameters(); // default
imagejJp4TiffMulti = null; imagejJp4TiffMulti = null;
} }
public LwirReader(LwirReaderParameters lwirReaderParameters) {
if (lwirReaderParameters == null) {
this.lwirReaderParameters = new LwirReaderParameters(); // default
} else {
this.lwirReaderParameters = lwirReaderParameters;
}
imagejJp4TiffMulti = null;
}
// TODO: create
public boolean reSyncNeeded() {
return out_of_sync;
}
public ImagePlus[][] readAllMultiple( public ImagePlus[][] readAllMultiple(
final int num_frames, final int num_frames,
...@@ -181,14 +210,17 @@ public class LwirReader { ...@@ -181,14 +210,17 @@ public class LwirReader {
for (String key:properties0.stringPropertyNames()) { for (String key:properties0.stringPropertyNames()) {
imps_avg[chn].setProperty(key, properties0.getProperty(key)); imps_avg[chn].setProperty(key, properties0.getProperty(key));
} }
imps_avg[chn].setProperty("average", ""+num_frames);
// TODO: Overwrite some properties? // TODO: Overwrite some properties?
} }
return imps_avg; return imps_avg;
} }
public ImagePlus [][] matchSets(ImagePlus [][] sets, double max_mismatch, int max_frame_diff){ public ImagePlus [][] matchSets(ImagePlus [][] sets, double max_mismatch, int max_frame_diff){
return matchSets(sets, max_mismatch, max_frame_diff, null);
}
public ImagePlus [][] matchSets(ImagePlus [][] sets, double max_mismatch, int max_frame_diff, int [] lags){
int num_frames = sets.length; int num_frames = sets.length;
int num_channels = sets[0].length; int num_channels = sets[0].length;
double [][] img_seconds = new double [num_frames][num_channels]; double [][] img_seconds = new double [num_frames][num_channels];
...@@ -196,6 +228,7 @@ public class LwirReader { ...@@ -196,6 +228,7 @@ public class LwirReader {
double [] time_offsets = new double [num_channels]; double [] time_offsets = new double [num_channels];
boolean some_notsynced = false; boolean some_notsynced = false;
int fr_min = 0, fr_max = 0; int fr_min = 0, fr_max = 0;
frame_offsets[0] = 0;
for (int n = 0; n < num_frames; n++) { for (int n = 0; n < num_frames; n++) {
for (int i = 0; i < num_channels; i++) { for (int i = 0; i < num_channels; i++) {
String dt = (String) sets[n][i].getProperty("DATE_TIME"); String dt = (String) sets[n][i].getProperty("DATE_TIME");
...@@ -208,7 +241,7 @@ public class LwirReader { ...@@ -208,7 +241,7 @@ public class LwirReader {
time_offsets[i] = secOffs(img_seconds[0][0], img_seconds[0][i]); time_offsets[i] = secOffs(img_seconds[0][0], img_seconds[0][i]);
if (num_frames > max_frame_diff) { if (num_frames > max_frame_diff) {
if (time_offsets[i] > max_mismatch) { if (time_offsets[i] > max_mismatch) {
for (int fr_diff = 1; fr_diff < max_frame_diff; fr_diff++) { for (int fr_diff = 1; fr_diff <= max_frame_diff; fr_diff++) {
double aoff = secOffs(img_seconds[fr_diff][0], img_seconds[0][i]); double aoff = secOffs(img_seconds[fr_diff][0], img_seconds[0][i]);
if (aoff < time_offsets[i]) { if (aoff < time_offsets[i]) {
time_offsets[i] = aoff; time_offsets[i] = aoff;
...@@ -227,36 +260,49 @@ public class LwirReader { ...@@ -227,36 +260,49 @@ public class LwirReader {
if (time_offsets[i] > max_mismatch) { if (time_offsets[i] > max_mismatch) {
some_notsynced = true; some_notsynced = true;
} }
if (frame_offsets[i] > 0) { if (frame_offsets[i] > fr_max) fr_max = frame_offsets[i];
fr_max = frame_offsets[i]; if (frame_offsets[i] < fr_min) fr_min = frame_offsets[i];
}
if (frame_offsets[i] < 0) {
fr_min = frame_offsets[i];
}
} }
if (some_notsynced) { if (some_notsynced) {
LOGGER.error("*** Some channels are not synchronized, reboot or sensors re-start is needed ***"); LOGGER.error("*** Some channels are not synchronized, reboot or sensors re-start is needed ***");
out_of_sync = true;
for (int i = 0; i < num_channels; i++) { for (int i = 0; i < num_channels; i++) {
LOGGER.error("Channel "+ i+" frame offset="+frame_offsets[i]+ ", time offset = "+time_offsets[i]+" sec"); LOGGER.error("Channel "+ i+" frame offset="+frame_offsets[i]+ ", time offset = "+time_offsets[i]+" sec");
} }
return null; return null;
} }
if (((fr_max - fr_min) > max_frame_diff) || ((fr_max - fr_min) > (num_frames - 1))) { if (((fr_max - fr_min) > max_frame_diff) || ((fr_max - fr_min) > (num_frames - 1))) {
LOGGER.error("*** Earliest/latest channels differ by more than 1 frame, that should not happen! ***"); out_of_sync = true;
LOGGER.error("*** Earliest/latest channels differ by more than "+max_frame_diff+" frames, that should not happen! ***");
for (int i = 0; i < num_channels; i++) { for (int i = 0; i < num_channels; i++) {
LOGGER.error("Channel "+ i+" frame offset="+frame_offsets[i]+ ", time offset = "+time_offsets[i]+" sec"); LOGGER.error("Channel "+ i+" frame offset="+frame_offsets[i]+ ", time offset = "+time_offsets[i]+" sec");
} }
return null; return null;
} }
out_of_sync = false;
for (int i = 0; i < num_channels; i++) { for (int i = 0; i < num_channels; i++) {
// change to info later: // change to info later:
LOGGER.info("Channel "+ i+" frame offset="+frame_offsets[i]+ ", time offset = "+time_offsets[i]+" sec"); LOGGER.info("Channel "+ i+" frame offset="+frame_offsets[i]+ ", time offset = "+time_offsets[i]+" sec");
} }
ImagePlus [][] imps_synced = new ImagePlus [num_frames - fr_max + fr_min][num_channels]; // if (lags == null) lags = new int [num_channels];
// recalculate frame_offsets, fr_max, fr_min considering provided lags (>0 - channel images are acquired later)
if (lags != null) {
fr_max = lags[0];
fr_min = lags[0];
for (int i = 0; i < num_channels; i++ ) {
frame_offsets[i] += lags[i];
if (frame_offsets[i] > fr_max) fr_max = frame_offsets[i];
if (frame_offsets[i] < fr_min) fr_min = frame_offsets[i];
}
}
ImagePlus [][] imps_synced = null;
imps_synced = new ImagePlus [num_frames - fr_max + fr_min][num_channels];
for (int n = 0; n < imps_synced.length; n++) { for (int n = 0; n < imps_synced.length; n++) {
imps_synced[n][0]= sets[n+fr_max][0]; for (int i = 0; i < num_channels; i++) {
for (int i = 1; i < num_channels; i++) { imps_synced[n][i]= sets[n + fr_max -frame_offsets[i]][i];
imps_synced[n][i]= sets[n - fr_min][i];
} }
} }
return imps_synced; return imps_synced;
...@@ -269,5 +315,272 @@ public class LwirReader { ...@@ -269,5 +315,272 @@ public class LwirReader {
} }
return aoff; return aoff;
} }
public boolean skipFrame() {
return skipFrame(lwirReaderParameters);
}
public boolean skipFrame(LwirReaderParameters lrp) {
if (lrp.lwir_channels.length == 0) {
LOGGER.error("skipFrame(): No LWIR channels are configured");
return false;
}
int chn = lrp.lwir_channels[0];
String url = "http://"+lrp.lwir_ip+":"+IMGSRV_PORTS[chn]+SKIP_FRAME_URL;
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("meta")) {
LOGGER.error("skipFrame() in " + url+
": Root element: expected 'me3ta', got \"" + dom.getDocumentElement().getNodeName()+"\"");
return false;
}
} catch(MalformedURLException e){
LOGGER.error("skipFrame() in " + url+ ": " + e.toString());
return false;
} catch(IOException e1){
LOGGER.error("skipFrame() in " + url+ " - camera did not respond: " + e1.toString());
return false;
}catch(ParserConfigurationException pce) {
LOGGER.error("skipFrame() in " + url+ " - PCE error: " + pce.toString());
return false;
}catch(SAXException se) {
LOGGER.error("skipFrame() in " + url+ " - SAX error: " + se.toString());
return false;
}
return true;
}
public ImagePlus [] acquire() {
return acquire(lwirReaderParameters);
}
public ImagePlus [] acquire(LwirReaderParameters lrp) {
if (!condProgramLWIRCamera(lrp)) {
LOGGER.error("acquire(): failed to program cameras");
return null;
}
int num_frames = lrp.avg_number + lrp.vnir_lag + 2 * lrp.max_frame_diff;
ImagePlus [][] imps = readAllMultiple(
num_frames,
false, // final boolean show,
lrp.vnir_scale);
if (imps == null) {
LOGGER.error("acquire(): failed to acquire images");
return null;
}
LOGGER.debug("LWIR_ACQUIRE: got "+imps.length+" image sets");
int [] lags = new int [lrp.lwir_channels.length + lrp.vnir_channels.length];
for (int i = 0; i < lags.length; i++) {
lags[i] = (i >= lrp.lwir_channels.length) ? lrp.vnir_lag : 0;
}
ImagePlus [][] imps_sync = matchSets(
imps,
lrp.max_mismatch_ms * 0.001, // 0.001,
lrp.max_frame_diff,// 3); // double max_mismatch)
lags);
if (imps_sync == null) {
return null;
}
int num_keep = imps_sync.length;
if (!lrp.avg_all && (lrp.avg_number < imps_sync.length)) {
num_keep = lrp.avg_number;
}
LOGGER.debug("LWIR_ACQUIRE: got "+imps_sync.length+", requested "+lrp.avg_number+", keeping " + num_keep);
if (num_keep < imps_sync.length) {
ImagePlus [][] imps_sync0 = imps_sync;
imps_sync = new ImagePlus[num_keep][];
for (int i = 0; i < num_keep; i++) {
imps_sync[i] = imps_sync0[i];
}
}
ImagePlus [] imps_avg = averageMultiFrames(imps_sync);
return imps_avg;
}
// TODO: Implement LWIR restart
// Program cameras only if parameters had changed (including those, that do not actually need to be programmed)
public boolean condProgramLWIRCamera() {
return condProgramLWIRCamera(lwirReaderParameters);
}
public boolean condProgramLWIRCamera(LwirReaderParameters lrp) {
boolean ok = true;
if ((last_programmed == null) || !last_programmed.equals(lrp)) {
ok = programLWIRCamera(lrp);
if (ok) {
last_programmed = lrp.clone();
}
}
return ok;
}
//actually (unconditionally) program cameras parameters
public boolean programLWIRCamera() {
return programLWIRCamera(lwirReaderParameters);
}
public boolean programLWIRCamera(LwirReaderParameters lrp) {
int lwir_master_port = 0;
int vnir_master_port = 0;
int num_lwir = lrp.lwir_channels.length;
int num_vnir = lrp.vnir_channels.length;
final String [] urls = new String [num_lwir + num_vnir];
for (int chn:lrp.lwir_channels) {
urls[chn] = "http://"+lrp.lwir_ip+"/parsedit.php?immediate&sensor_port="+chn+
"&BITS=16"+
"&COLOR="+COLOR_RAW; // +"*0"; // raw mode - delay 0 - breaks compressor
if (chn == lwir_master_port) {
urls[chn] +="&TRIG=0*0"+
"&TRIG_DELAY="+lrp.lwir_trig_dly+"*0"+
"&TRIG_OUT=419157*0"+
"&TRIG_BITLENGTH=31*0"+
"&EXTERN_TIMESTAMP=1*0"+
"&XMIT_TIMESTAMP=1*0";
}
}
for (int chn:lrp.vnir_channels) {
int minExposure=10; // usec
int maxExposure=1000000; //usec
int minGain=(int) (0x10000*1.0);
int maxGain=(int) (0x10000*15.75);
int minScale=0;
int maxScale=(int) (0x10000*4.0);
int exposure= (int) (Math.round(1000*lrp.vnir_exposure_ms * lrp.vnir_exp_corr[chn]));
int autoExposureMax= (int) (Math.round(1000*lrp.vnir_max_autoexp_ms));
int gain= (int) (Math.round(0x10000*lrp.vnir_gain_g));
int rScale= (int) (Math.round(0x10000*lrp.vnir_gain_rg*lrp.vnir_gcorr_rbgb[3*chn+0]));
int bScale= (int) (Math.round(0x10000*lrp.vnir_gain_bg*lrp.vnir_gcorr_rbgb[3*chn+1]));
int gScale= (int) (Math.round(0x10000* lrp.vnir_gcorr_rbgb[3*chn+2]));
int autoExp= lrp.vnir_autoexp?1:0;
int autoWB= lrp.vnir_whitebal?1:0;
if (exposure<minExposure) exposure=minExposure; else if (exposure>maxExposure) exposure=maxExposure;
if (autoExposureMax<minExposure) autoExposureMax=minExposure; else if (autoExposureMax>maxExposure) autoExposureMax=maxExposure;
if (gain<minGain) gain= minGain ; else if (gain> maxGain) gain= maxGain;
if (rScale<minScale) rScale= minScale ; else if (rScale> maxScale) rScale= maxScale;
if (bScale<minScale) bScale= minScale ; else if (bScale> maxScale) bScale= maxScale;
if (gScale<minScale) gScale= minScale ; else if (gScale> maxScale) gScale= maxScale;
urls[num_lwir+chn] = "http://"+lrp.vnir_ip+"/parsedit.php?immediate&sensor_port="+chn+
"&COLOR="+COLOR_JP4+ // "*1"+ // JP4 always
"&QUALITY="+lrp.vnir_quality+ // "*0"+
"&EXPOS="+exposure+ // "*0"+
"&AUTOEXP_EXP_MAX="+autoExposureMax+//"*0"+
"&AUTOEXP_ON="+autoExp+//"*0"+
"&GAING="+gain+//"*0"+
"&RSCALE="+rScale+//"*0"+
"&BSCALE="+bScale+//"*0"+
"&GSCALE="+gScale+//"*0"+ // GB/G ratio
"&WB_EN="+autoWB+//"*0"+
"&DAEMON_EN_TEMPERATURE=1";//"*0";
if (chn == vnir_master_port) {
urls[num_lwir+chn] += "&TRIG=4*0"+
"&TRIG_CONDITION=611669*0"+ // external input
"&TRIG_BITLENGTH=31*0"+
"&EXTERN_TIMESTAMP=1*0";
}
}
for (int i = 0; i < urls.length; i++) {
LOGGER.debug("programLWIRCamera(): reading url " + urls[i]);
}
// multithreaded camera access:
final Thread[] threads = newThreadArray(MAX_THREADS);
final AtomicInteger indxAtomic = new AtomicInteger(0);
final boolean [] get_success = new boolean [urls.length];
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int indx = indxAtomic.getAndIncrement(); indx < urls.length; indx = indxAtomic.getAndIncrement()) {
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(urls[indx]);
if (!dom.getDocumentElement().getNodeName().equals("parameters")) {
LOGGER.error("programLWIRCamera() in " + urls[indx]+
": Root element: expected 'parameters', got \"" + dom.getDocumentElement().getNodeName()+"\"");
get_success[indx] = false;
continue;
}
} catch(MalformedURLException e){
LOGGER.error("programLWIRCamera() in " + urls[indx]+ ": " + e.toString());
get_success[indx] = false;
continue;
} catch(IOException e1){
LOGGER.error("programLWIRCamera() in " + urls[indx]+ " - camera did not respond: " + e1.toString());
get_success[indx] = false;
continue;
}catch(ParserConfigurationException pce) {
LOGGER.error("programLWIRCamera() in " + urls[indx]+ " - PCE error: " + pce.toString());
get_success[indx] = false;
continue;
}catch(SAXException se) {
LOGGER.error("programLWIRCamera() in " + urls[indx]+ " - SAX error: " + se.toString());
get_success[indx] = false;
continue;
}
get_success[indx] = true;
}
}
};
}
startAndJoin(threads);
// See if there are any errors
boolean allOK = true;
for (boolean OK:get_success) {
allOK &= OK;
}
if (allOK){
lrp.reset_updated();
for (int i = 0; i < FRAMES_SKIP; i++) {
if (!skipFrame(lrp)) {
LOGGER.error("programLWIRCamera():Failed to skip frame");
}
}
}
return allOK;
}
/* Create a Thread[] array as large as the number of processors available.
* From Stephan Preibisch's Multithreading.java class. See:
* http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
*/
private Thread[] newThreadArray(int maxCPUs) {
int n_cpus = Runtime.getRuntime().availableProcessors();
if (n_cpus>maxCPUs)n_cpus=maxCPUs;
return new Thread[n_cpus];
}
/* Start all given threads and wait on each of them until all are done.
* From Stephan Preibisch's Multithreading.java class. See:
* http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
*/
private static void startAndJoin(Thread[] threads)
{
for (int ithread = 0; ithread < threads.length; ++ithread)
{
threads[ithread].setPriority(Thread.NORM_PRIORITY);
threads[ithread].start();
}
try
{
for (int ithread = 0; ithread < threads.length; ++ithread)
threads[ithread].join();
} catch (InterruptedException ie)
{
throw new RuntimeException(ie);
}
}
} }
/**
** -----------------------------------------------------------------------------**
** LwirReaderParameters.java
**
** Parameters handling for LwirReader class
**
**
** Copyright (C) 2019 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** LwirReaderParameters.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
package com.elphel.imagej.lwir;
import java.util.Properties;
import com.elphel.imagej.common.GenericJTabbedDialog;
public class LwirReaderParameters {
private boolean parameters_updated = false;
protected int avg_number = 4; // number of measurements to average
public boolean avg_all = true;
protected String lwir_ip = "192.168.0.36";
protected String vnir_ip = "192.168.0.38";
protected int [] lwir_channels = {0, 1, 2 ,3};
protected int [] vnir_channels = {0, 1, 2 ,3};
protected double vnir_quality = 98.0;
protected boolean vnir_scale = false; // restore sensor pixel values, undo camera white balancing
protected boolean vnir_autoexp = false;
protected double vnir_max_autoexp_ms = 20.0;
protected double vnir_exposure_ms = 5.0;
protected boolean vnir_whitebal = false;
protected double vnir_gain_g = 2.0;
protected double vnir_gain_rg = 0.7705; // 1.116; halogen/fluorescent
protected double vnir_gain_bg = 2.401; // 1.476;
/*
protected double [] vnir_exp_corr = {1.0, 1.0, 1.0, 1.0};
protected double [] vnir_gcorr_rbgb = {
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0};
*/
protected double [] vnir_exp_corr = {
1.0, 1.0026, 0.9868, 1.0211};
protected double [] vnir_gcorr_rbgb = { // example after autobalance for 192.168.0.38 with halogen lamps
1.0, 1.0, 0.9743,
1.0668, 1.1055, 1.0006,
1.1533, 1.0780, 1.0015,
0.9966, 1.0445, 1.0023};
protected int lwir_trig_dly = 1000; //in 100MHz clock cycle, current FPGA requires >0 (used 1000)
protected int vnir_lag = 1; // frames
protected double max_mismatch_ms = 0.05;
protected int max_frame_diff = 1; // 2;
// --- interface methods
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"avg_number", this.avg_number+"");
properties.setProperty(prefix+"avg_all", this.avg_all+"");
properties.setProperty(prefix+"lwir_ip", this.lwir_ip+"");
properties.setProperty(prefix+"vnir_ip", this.vnir_ip+"");
properties.setProperty(prefix+"lwir_channels", arr_to_str(this.lwir_channels));
properties.setProperty(prefix+"vnir_channels", arr_to_str(this.vnir_channels));
properties.setProperty(prefix+"vnir_quality", this.vnir_quality+"");
properties.setProperty(prefix+"vnir_scale", this.vnir_scale+"");
properties.setProperty(prefix+"vnir_autoexp", this.vnir_autoexp+"");
properties.setProperty(prefix+"vnir_max_autoexp_ms", this.vnir_max_autoexp_ms+"");
properties.setProperty(prefix+"vnir_exposure_ms", this.vnir_exposure_ms+"");
properties.setProperty(prefix+"vnir_whitebal", this.vnir_whitebal+"");
properties.setProperty(prefix+"vnir_gain_g", this.vnir_gain_g+"");
properties.setProperty(prefix+"vnir_gain_rg", this.vnir_gain_rg+"");
properties.setProperty(prefix+"vnir_gain_bg", this.vnir_gain_bg+"");
properties.setProperty(prefix+"vnir_exp_corr", arr_to_str(this.vnir_exp_corr));
properties.setProperty(prefix+"vnir_gcorr_rbgb", arr_to_str(this.vnir_gcorr_rbgb));
properties.setProperty(prefix+"lwir_trig_dly", this.lwir_trig_dly+"");
properties.setProperty(prefix+"vnir_lag", this.vnir_lag+"");
properties.setProperty(prefix+"max_mismatch_ms", this.max_mismatch_ms+"");
properties.setProperty(prefix+"max_frame_diff", this.max_frame_diff+"");
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"avg_number")!=null) this.avg_number=Integer.parseInt(properties.getProperty(prefix+"avg_number"));
if (properties.getProperty(prefix+"avg_all")!=null) this.avg_all= Boolean.parseBoolean(properties.getProperty(prefix+"avg_all"));
if (properties.getProperty(prefix+"lwir_ip")!=null) this.lwir_ip= properties.getProperty(prefix+"lwir_ip");
if (properties.getProperty(prefix+"vnir_ip")!=null) this.vnir_ip= properties.getProperty(prefix+"vnir_ip");
if (properties.getProperty(prefix+"lwir_channels")!=null) this.lwir_channels=str_to_iarr(properties.getProperty(prefix+"lwir_channels"));
if (properties.getProperty(prefix+"vnir_channels")!=null) this.vnir_channels=str_to_iarr(properties.getProperty(prefix+"vnir_channels"));
if (properties.getProperty(prefix+"vnir_quality")!=null) this.vnir_quality=Double.parseDouble(properties.getProperty(prefix+"vnir_quality"));
if (properties.getProperty(prefix+"vnir_scale")!=null) this.vnir_scale= Boolean.parseBoolean(properties.getProperty(prefix+"vnir_scale"));
if (properties.getProperty(prefix+"vnir_autoexp")!=null) this.vnir_autoexp= Boolean.parseBoolean(properties.getProperty(prefix+"vnir_autoexp"));
if (properties.getProperty(prefix+"vnir_max_autoexp_ms")!=null) this.vnir_max_autoexp_ms=Double.parseDouble(properties.getProperty(prefix+"vnir_max_autoexp_ms"));
if (properties.getProperty(prefix+"vnir_exposure_ms")!=null) this.vnir_exposure_ms=Double.parseDouble(properties.getProperty(prefix+"vnir_exposure_ms"));
if (properties.getProperty(prefix+"vnir_whitebal")!=null) this.vnir_whitebal= Boolean.parseBoolean(properties.getProperty(prefix+"vnir_whitebal"));
if (properties.getProperty(prefix+"vnir_gain_g")!=null) this.vnir_gain_g=Double.parseDouble(properties.getProperty(prefix+"vnir_gain_g"));
if (properties.getProperty(prefix+"vnir_gain_rg")!=null) this.vnir_gain_rg=Double.parseDouble(properties.getProperty(prefix+"vnir_gain_rg"));
if (properties.getProperty(prefix+"vnir_gain_bg")!=null) this.vnir_gain_bg=Double.parseDouble(properties.getProperty(prefix+"vnir_gain_bg"));
if (properties.getProperty(prefix+"vnir_exp_corr")!=null) this.vnir_exp_corr=str_to_darr(properties.getProperty(prefix+"vnir_exp_corr"));
if (properties.getProperty(prefix+"vnir_gcorr_rbgb")!=null) this.vnir_gcorr_rbgb=str_to_darr(properties.getProperty(prefix+"vnir_gcorr_rbgb"));
if (properties.getProperty(prefix+"lwir_trig_dly")!=null) this.lwir_trig_dly=Integer.parseInt(properties.getProperty(prefix+"lwir_trig_dly"));
if (properties.getProperty(prefix+"vnir_lag")!=null) this.vnir_lag=Integer.parseInt(properties.getProperty(prefix+"vnir_lag"));
if (properties.getProperty(prefix+"max_mismatch_ms")!=null) this.max_mismatch_ms=Double.parseDouble(properties.getProperty(prefix+"max_mismatch_ms"));
if (properties.getProperty(prefix+"max_frame_diff")!=null) this.max_frame_diff=Integer.parseInt(properties.getProperty(prefix+"max_frame_diff"));
parameters_updated = true;
}
@Override
public LwirReaderParameters clone() { // throws CloneNotSupportedException {
LwirReaderParameters lrp = new LwirReaderParameters();
lrp.avg_number= this.avg_number;
lrp.avg_all= this.avg_all;
lrp.lwir_ip= this.lwir_ip;
lrp.vnir_ip= this.vnir_ip;
lrp.lwir_channels= this.lwir_channels.clone();
lrp.vnir_channels= this.vnir_channels.clone();
lrp.vnir_quality= this.vnir_quality;
lrp.vnir_scale= this.vnir_scale;
lrp.vnir_autoexp= this.vnir_autoexp;
lrp.vnir_max_autoexp_ms= this.vnir_max_autoexp_ms;
lrp.vnir_exposure_ms= this.vnir_exposure_ms;
lrp.vnir_whitebal= this.vnir_whitebal;
lrp.vnir_gain_g= this.vnir_gain_g;
lrp.vnir_gain_rg= this.vnir_gain_rg;
lrp.vnir_gain_bg= this.vnir_gain_bg;
lrp.vnir_exp_corr= this.vnir_exp_corr.clone();
lrp.vnir_gcorr_rbgb= this.vnir_gcorr_rbgb.clone();
lrp.lwir_trig_dly= this.lwir_trig_dly;
lrp.vnir_lag= this.vnir_lag;
lrp.max_mismatch_ms= this.max_mismatch_ms;
lrp.max_frame_diff= this.max_frame_diff;
return lrp;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof LwirReaderParameters)) {
return false;
}
LwirReaderParameters lrp = (LwirReaderParameters) o;
return (lrp.avg_number == this.avg_number) &&
(lrp.avg_all == this.avg_all) &&
(lrp.lwir_ip.equals(this.lwir_ip)) &&
(lrp.vnir_ip.equals(this.vnir_ip)) &&
(java.util.Arrays.equals(lrp.lwir_channels, this.lwir_channels)) &&
(java.util.Arrays.equals(lrp.vnir_channels, this.vnir_channels)) &&
(lrp.vnir_quality == this.vnir_quality) &&
(lrp.vnir_scale == this.vnir_scale) &&
(lrp.vnir_autoexp == this.vnir_autoexp) &&
(lrp.vnir_max_autoexp_ms == this.vnir_max_autoexp_ms) &&
(lrp.vnir_exposure_ms == this.vnir_exposure_ms) &&
(lrp.vnir_whitebal == this.vnir_whitebal) &&
(lrp.vnir_gain_g == this.vnir_gain_g) &&
(lrp.vnir_gain_rg == this.vnir_gain_rg) &&
(lrp.vnir_gain_bg == this.vnir_gain_bg) &&
(java.util.Arrays.equals(lrp.vnir_exp_corr, this.vnir_exp_corr)) &&
(java.util.Arrays.equals(lrp.vnir_gcorr_rbgb, this.vnir_gcorr_rbgb)) &&
(lrp.lwir_trig_dly == this.lwir_trig_dly) &&
(lrp.vnir_lag == this.vnir_lag) &&
(lrp.max_mismatch_ms == this.max_mismatch_ms) &&
(lrp.max_frame_diff == this.max_frame_diff);
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + (new Integer(avg_number)).hashCode();
result = prime * result + (avg_all?1:0);
result = prime * result + lwir_ip.hashCode();
result = prime * result + vnir_ip.hashCode();
result = prime * result + arr_to_str(lwir_channels).hashCode();
result = prime * result + arr_to_str(vnir_channels).hashCode();
result = prime * result + (new Double(vnir_quality)).hashCode();
result = prime * result + (vnir_scale?1:0);
result = prime * result + (vnir_autoexp?1:0);
result = prime * result + (new Double(vnir_max_autoexp_ms)).hashCode();
result = prime * result + (new Double(vnir_exposure_ms)).hashCode();
result = prime * result + (vnir_whitebal?1:0);
result = prime * result + (new Double(vnir_gain_g)).hashCode();
result = prime * result + (new Double(vnir_gain_rg)).hashCode();
result = prime * result + (new Double(vnir_gain_bg)).hashCode();
result = prime * result + arr_to_str(vnir_exp_corr).hashCode();
result = prime * result + arr_to_str(vnir_gcorr_rbgb).hashCode();
result = prime * result + (new Integer(lwir_trig_dly)).hashCode();
// next are not needed to be programmed to the cameras
// result = prime * result + (new Integer(vnir_lag)).hashCode();
// result = prime * result + (new Double(max_mismatch_ms)).hashCode();
// result = prime * result + (new Integer(max_frame_diff)).hashCode();
return 0;
}
public void dialogQuestions(GenericJTabbedDialog gd) {
gd.addNumericField("Number to average",this.avg_number, 0,3,"","Number of acquired consecutive images to average");
gd.addCheckbox ("Average all", this.avg_all, "Average all simultaneously acquired images (unchecked - only requested number to average)");
gd.addStringField ("LWIR IP", this.lwir_ip, 20, "LWIR camera IP address");
gd.addStringField ("VNIR IP", this.vnir_ip, 20, "Visible range high resolution camera IP address");
gd.addStringField ("LWIR channels", arr_to_str(this.lwir_channels), 20, "Space-separated list of used LWIR camera channels, such as '0 1 2 3'");
gd.addStringField ("VNIR channels", arr_to_str(this.vnir_channels), 20, "Space-separated list of used visible range camera channels, such as '0 1 2 3'");
gd.addNumericField("VNIR quality", this.vnir_quality, 3,6,"ms", "Visible range camera JPEG compression quality (all channels)");
gd.addCheckbox ("VNIR undo white balance", this.vnir_scale, "Undo in-camera white balancing");
gd.addCheckbox ("VNIR autoexposure", this.vnir_autoexp, "Enable autoexposure for the visible range camera");
gd.addNumericField("VNIR vnir_max_autoexp_ms", this.vnir_max_autoexp_ms, 3,6,"ms", "Visible range camera maximal exposure in autoexposure mode");
gd.addNumericField("VNIR exposure", this.vnir_exposure_ms, 3,6,"ms", "Visible range camera exposure time (all channels)");
gd.addCheckbox ("VNIR white balance", this.vnir_whitebal, "Enable automatic white balancing for the visible range camera");
gd.addNumericField("VNIR gain G", this.vnir_gain_g, 3,6,"","Analog gain for green channel for all visible range camera channels (normally 2.0)");
gd.addNumericField("VNIR gain R/G", this.vnir_gain_rg, 3,6,"","Red to green gain ratio for all visible range camera channels");
gd.addNumericField("VNIR gain B/G", this.vnir_gain_bg, 3,6,"","Blue to green gain ratio for all visible range camera channels");
gd.addStringField ("VNIR exposuere corrections", arr_to_str(this.vnir_exp_corr), 50, "Fine corrections of channel exposures (4 channel relative exposures)");
gd.addStringField ("VNIR gain corrections", arr_to_str(this.vnir_gcorr_rbgb), 100, "Fine corrections to per channel, per color gains:'r0 b0 gb0 r1 b1 gb1 ...'");
gd.addNumericField("LWIR trig dly", this.lwir_trig_dly, 0,3,"x10ns","Output trigger delay, should eventually match Lepton+FPGA latency to trigger VNIR exactly 1 frame after LWIR. 0 does not work with current FPGA - usec do not match sec in transmitted timestamp");
gd.addNumericField("VNIR lag", this.vnir_lag, 0,3,"","Visible camera lag (in frames) relative to LWIR one");
gd.addNumericField("Max mismatch", this.max_mismatch_ms, 3,6,"ms","Maximal mismatch between image timestamps. Larger mismatch requires LWIR sinsor reinitialization");
gd.addNumericField("Max frame diff",this.max_frame_diff, 0,3,"","Maximal difference in frames between simultaneously acquired channels as calculated from the timestamps");
}
public void dialogAnswers(GenericJTabbedDialog gd) {
this.avg_number = (int) gd.getNextNumber();
this.avg_all = gd.getNextBoolean();
this.lwir_ip = gd.getNextString();
this.vnir_ip = gd.getNextString();
this.lwir_channels = str_to_iarr(gd.getNextString());
this.vnir_channels = str_to_iarr(gd.getNextString());
this.vnir_quality = gd.getNextNumber();
this.vnir_scale = gd.getNextBoolean();
this.vnir_autoexp = gd.getNextBoolean();
this.vnir_max_autoexp_ms = gd.getNextNumber();
this.vnir_exposure_ms = gd.getNextNumber();
this.vnir_whitebal = gd.getNextBoolean();
this.vnir_gain_g = gd.getNextNumber();
this.vnir_gain_rg = gd.getNextNumber();
this.vnir_gain_bg = gd.getNextNumber();
this.vnir_exp_corr = str_to_darr(gd.getNextString());
this.vnir_gcorr_rbgb = str_to_darr(gd.getNextString());
this.lwir_trig_dly = (int) gd.getNextNumber();
this.vnir_lag = (int) gd.getNextNumber();
this.max_mismatch_ms = gd.getNextNumber();
this.max_frame_diff = (int) gd.getNextNumber();
parameters_updated = true;
}
public boolean showJDialog() {
GenericJTabbedDialog gd = new GenericJTabbedDialog("Set CLT parameters",800,900);
// gd.addTab ("General", "General parameters");
dialogQuestions(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
dialogAnswers(gd);
return true;
}
public boolean is_updated() {
return parameters_updated;
}
public void reset_updated() {
parameters_updated = false;
}
// --- internal methods
private String arr_to_str(int [] arr) {
String s = "";
for (int c:arr) s+=c+" ";
return s.trim();
}
private String arr_to_str(double [] arr) {
String s = "";
for (double c:arr) s+=c+" ";
return s.trim();
}
private int [] str_to_iarr(String s) {
String [] sa;
if (s.indexOf(",") >= 0) {
sa = s.trim().split(",");
} else {
sa = s.trim().split(" ");
}
int [] iarr = new int [sa.length];
for (int i = 0; i < sa.length; i++) {
iarr[i]=Integer.parseInt(sa[i].trim());
}
return iarr;
}
private double [] str_to_darr(String s) {
String [] sa;
if (s.indexOf(",") >= 0) {
sa = s.trim().split(",");
} else {
sa = s.trim().split(" ");
}
double [] darr = new double [sa.length];
for (int i = 0; i < sa.length; i++) {
darr[i]=Double.parseDouble(sa[i].trim());
}
return darr;
}
}
...@@ -105,7 +105,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -105,7 +105,7 @@ public class ElphelJp4Reader extends ImageIOReader{
// or these readers are combined with all other readers in readers.txt // or these readers are combined with all other readers in readers.txt
suffixNecessary = true; // false suffixNecessary = true; // false
suffixSufficient = true; // false; suffixSufficient = true; // false;
LOGGER.info("ElphelTiffReader(), after super()"); LOGGER.debug("ElphelTiffReader(), after super()");
if (REPLACEMENT_TAG_MAP == null) { if (REPLACEMENT_TAG_MAP == null) {
REPLACEMENT_TAG_MAP = new HashMap<String,String>(); REPLACEMENT_TAG_MAP = new HashMap<String,String>();
for (String [] line: REPLACEMENT_TAGS) { for (String [] line: REPLACEMENT_TAGS) {
...@@ -162,7 +162,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -162,7 +162,7 @@ public class ElphelJp4Reader extends ImageIOReader{
LOGGER.debug("id '"+id+"' is already mapped" ); LOGGER.debug("id '"+id+"' is already mapped" );
content_fileName = id; // id; // maybe set to null to handle externally? content_fileName = id; // id; // maybe set to null to handle externally?
mapped_externally = true; mapped_externally = true;
LOGGER.info("Starting initFile() method, read file directly"); LOGGER.debug("Starting initFile() method, read file directly");
super.setId(id); super.setId(id);
} else { } else {
// If URL, then read to memory, if normal file - use direct access // If URL, then read to memory, if normal file - use direct access
...@@ -175,7 +175,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -175,7 +175,7 @@ public class ElphelJp4Reader extends ImageIOReader{
LOGGER.warn("Bad URL: " + id); LOGGER.warn("Bad URL: " + id);
} }
if (url != null) { if (url != null) {
LOGGER.info("Starting initFile() method, read "+ id +" to memory first"); LOGGER.debug("Starting initFile() method, read "+ id +" to memory first");
//https://www.rgagnon.com/javadetails/java-0487.html //https://www.rgagnon.com/javadetails/java-0487.html
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
...@@ -192,20 +192,20 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -192,20 +192,20 @@ public class ElphelJp4Reader extends ImageIOReader{
content_fileName = "unknown." + suffix; content_fileName = "unknown." + suffix;
} }
// currentId = fileName; //??? // currentId = fileName; //???
// LOGGER.info("Mime type = "+mime); // LOGGER.debug("Mime type = "+mime);
// https://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests // https://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests
//https://stackoverflow.com/questions/2295221/java-net-url-read-stream-to-byte //https://stackoverflow.com/questions/2295221/java-net-url-read-stream-to-byte
InputStream is = url.openStream (); // InputStream is = url.openStream (); //
byte[] inBytes = IOUtils.toByteArray(is); byte[] inBytes = IOUtils.toByteArray(is);
if (is != null) is.close(); if (is != null) is.close();
LOGGER.info("Bytes read: "+ inBytes.length); LOGGER.debug("Bytes read: "+ inBytes.length);
Location.mapFile(content_fileName, new ByteArrayHandle(inBytes)); Location.mapFile(content_fileName, new ByteArrayHandle(inBytes));
// HashMap<String,Object> dbg_loc = Location.getIdMap(); // HashMap<String,Object> dbg_loc = Location.getIdMap();
super.setId(content_fileName); super.setId(content_fileName);
} else { // read file normally } else { // read file normally
content_fileName = id; content_fileName = id;
LOGGER.info("read file directly"); LOGGER.debug("read file directly");
super.setId(id); super.setId(id);
} }
} }
...@@ -229,7 +229,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -229,7 +229,7 @@ public class ElphelJp4Reader extends ImageIOReader{
LOGGER.debug("initFile("+id+"), currentId="+currentId+", after super" ); LOGGER.debug("initFile("+id+"), currentId="+currentId+", after super" );
// Below needs to be modified - EXIFService does not work with mapFile // Below needs to be modified - EXIFService does not work with mapFile
MetadataStore store = makeFilterMetadata(); MetadataStore store = makeFilterMetadata();
LOGGER.info("Parsing JPEG EXIF data"); LOGGER.debug("Parsing JPEG EXIF data");
HashMap<String, String> tags = null; HashMap<String, String> tags = null;
try { try {
// Reimplementing ExifServiceImpl as original does not have ExifIFD0Directory // Reimplementing ExifServiceImpl as original does not have ExifIFD0Directory
...@@ -307,14 +307,14 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -307,14 +307,14 @@ public class ElphelJp4Reader extends ImageIOReader{
int bytes_per_pixel = 1; int bytes_per_pixel = 1;
Hashtable<String, String> property_table = ElphelMeta.getMeta( Hashtable<String, String> property_table = ElphelMeta.getMeta(
null, maker_note, exposure, date_time, bytes_per_pixel, true ); null, maker_note, exposure, date_time, bytes_per_pixel, true );
LOGGER.info("Created elphelMeta table, size="+property_table.size()); LOGGER.debug("Created elphelMeta table, size="+property_table.size());
for (String key:property_table.keySet()) { for (String key:property_table.keySet()) {
addGlobalMeta(ELPHEL_PROPERTY_PREFIX+key,property_table.get(key)); addGlobalMeta(ELPHEL_PROPERTY_PREFIX+key,property_table.get(key));
} }
MetadataLevel level = getMetadataOptions().getMetadataLevel(); MetadataLevel level = getMetadataOptions().getMetadataLevel();
if (level != MetadataLevel.MINIMUM) { if (level != MetadataLevel.MINIMUM) {
// Integer[] tags = ifds.get(0).keySet().toArray(new Integer[0]); // Integer[] tags = ifds.get(0).keySet().toArray(new Integer[0]);
// LOGGER.info("initStandardMetadata() - got "+tags.length+" tags"); // LOGGER.debug("initStandardMetadata() - got "+tags.length+" tags");
} }
addGlobalMeta(ELPHEL_PROPERTY_PREFIX+CONTENT_FILENAME,content_fileName); addGlobalMeta(ELPHEL_PROPERTY_PREFIX+CONTENT_FILENAME,content_fileName);
...@@ -328,9 +328,9 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -328,9 +328,9 @@ public class ElphelJp4Reader extends ImageIOReader{
// HashMap<String,Object> dbg_loc = Location.getIdMap(); // HashMap<String,Object> dbg_loc = Location.getIdMap();
String saveCurrentId = currentId; String saveCurrentId = currentId;
currentId = null; currentId = null;
LOGGER.info("close("+fileOnly+") before super"); LOGGER.debug("close("+fileOnly+") before super");
super.close(fileOnly); // curerent_id == null only during actual close? super.close(fileOnly); // curerent_id == null only during actual close?
LOGGER.info("close("+fileOnly+") after super"); LOGGER.debug("close("+fileOnly+") after super");
currentId = saveCurrentId; currentId = saveCurrentId;
// if ((content_fileName != null) && file_initialized){ // if ((content_fileName != null) && file_initialized){
if (!mapped_externally && file_initialized){ // will try to unmap non-mapped file, OK if (!mapped_externally && file_initialized){ // will try to unmap non-mapped file, OK
...@@ -370,7 +370,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -370,7 +370,7 @@ public class ElphelJp4Reader extends ImageIOReader{
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException throws FormatException, IOException
{ {
LOGGER.info("openBytes() - before super()"); LOGGER.debug("openBytes() - before super()");
FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h); FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
if (image_bytes == null) { if (image_bytes == null) {
jp4Decode(no); jp4Decode(no);
...@@ -386,7 +386,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -386,7 +386,7 @@ public class ElphelJp4Reader extends ImageIOReader{
w); w);
dest += w; dest += w;
} }
LOGGER.info("openBytes() - after super()"); LOGGER.debug("openBytes() - after super()");
return buf; return buf;
} }
public void jp4Decode(int no) throws FormatException, IOException { public void jp4Decode(int no) throws FormatException, IOException {
...@@ -421,7 +421,7 @@ public class ElphelJp4Reader extends ImageIOReader{ ...@@ -421,7 +421,7 @@ public class ElphelJp4Reader extends ImageIOReader{
} else { } else {
image_bytes = ib; // temporary image_bytes = ib; // temporary
} }
LOGGER.info("jp4Decode()"); LOGGER.debug("jp4Decode()");
} }
} }
...@@ -130,7 +130,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -130,7 +130,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
suffixNecessary = true; // false suffixNecessary = true; // false
suffixSufficient = true; // false; suffixSufficient = true; // false;
/// mergeSubIFDs = true; // false; /// mergeSubIFDs = true; // false;
LOGGER.info("ElphelTiffReader(), after supper(), mergeSubIFDs = true;"); LOGGER.debug("ElphelTiffReader(), after supper(), mergeSubIFDs = true;");
} }
// -- IFormatReader API methods -- // -- IFormatReader API methods --
...@@ -177,7 +177,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -177,7 +177,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
LOGGER.debug("id '"+id+"' is already mapped" ); LOGGER.debug("id '"+id+"' is already mapped" );
content_fileName = id; // id; // maybe set to null to handle externally? content_fileName = id; // id; // maybe set to null to handle externally?
mapped_externally = true; mapped_externally = true;
LOGGER.info("Starting setId() method, read file directly"); LOGGER.debug("Starting setId() method, read file directly");
super.setId(id); super.setId(id);
} else { } else {
// If URL, then read to memory, if normal file - use direct access // If URL, then read to memory, if normal file - use direct access
...@@ -193,7 +193,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -193,7 +193,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
LOGGER.warn("Bad URL: " + id); LOGGER.warn("Bad URL: " + id);
} }
if (url != null) { if (url != null) {
LOGGER.info("Starting initFile() method, read "+ id +" to memory first"); LOGGER.debug("Starting initFile() method, read "+ id +" to memory first");
//https://www.rgagnon.com/javadetails/java-0487.html //https://www.rgagnon.com/javadetails/java-0487.html
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
...@@ -210,20 +210,20 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -210,20 +210,20 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
content_fileName = "unknown." + suffix; content_fileName = "unknown." + suffix;
} }
// currentId = fileName; //??? // currentId = fileName; //???
// LOGGER.info("Mime type = "+mime); // LOGGER.debug("Mime type = "+mime);
// https://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests // https://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests
//https://stackoverflow.com/questions/2295221/java-net-url-read-stream-to-byte //https://stackoverflow.com/questions/2295221/java-net-url-read-stream-to-byte
InputStream is = url.openStream (); // InputStream is = url.openStream (); //
byte[] inBytes = IOUtils.toByteArray(is); byte[] inBytes = IOUtils.toByteArray(is);
if (is != null) is.close(); if (is != null) is.close();
LOGGER.info("Bytes read: "+ inBytes.length); LOGGER.debug("Bytes read: "+ inBytes.length);
Location.mapFile(content_fileName, new ByteArrayHandle(inBytes)); Location.mapFile(content_fileName, new ByteArrayHandle(inBytes));
// HashMap<String,Object> dbg_loc = Location.getIdMap(); // HashMap<String,Object> dbg_loc = Location.getIdMap();
super.setId(content_fileName); super.setId(content_fileName);
} else { // read file normally } else { // read file normally
content_fileName = id; content_fileName = id;
LOGGER.info("read file directly"); LOGGER.debug("read file directly");
super.setId(id); super.setId(id);
} }
} }
...@@ -241,9 +241,9 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -241,9 +241,9 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
{ {
// Trying ServiceFactory before it is going to be initialized, so static defaultFactory will be initialized // Trying ServiceFactory before it is going to be initialized, so static defaultFactory will be initialized
// with small set of services - only needed for Elphel // with small set of services - only needed for Elphel
LOGGER.info("Starting initFile() method"); LOGGER.debug("Starting initFile() method");
super.initFile(id); super.initFile(id);
LOGGER.info("Ending initFile() method"); LOGGER.debug("Ending initFile() method");
} }
...@@ -262,9 +262,9 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -262,9 +262,9 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
/* @see loci.formats.IFormatReader#close(boolean) */ /* @see loci.formats.IFormatReader#close(boolean) */
@Override @Override
public void close(boolean fileOnly) throws IOException { public void close(boolean fileOnly) throws IOException {
LOGGER.info("close("+fileOnly+") before super"); LOGGER.debug("close("+fileOnly+") before super");
super.close(fileOnly); // curerent_id == null only during actual close? super.close(fileOnly); // curerent_id == null only during actual close?
LOGGER.info("close("+fileOnly+") after super"); LOGGER.debug("close("+fileOnly+") after super");
// if ((content_fileName != null) && file_initialized){ // if ((content_fileName != null) && file_initialized){
if (!mapped_externally && file_initialized){ // will try to unmap non-mapped file, OK if (!mapped_externally && file_initialized){ // will try to unmap non-mapped file, OK
Location.mapFile(content_fileName, null); Location.mapFile(content_fileName, null);
...@@ -288,10 +288,10 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -288,10 +288,10 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
/* @see BaseTiffReader#initStandardMetadata() */ /* @see BaseTiffReader#initStandardMetadata() */
@Override @Override
protected void initStandardMetadata() throws FormatException, IOException { protected void initStandardMetadata() throws FormatException, IOException {
LOGGER.info("initStandardMetadata() - before super()"); LOGGER.debug("initStandardMetadata() - before super()");
super.initStandardMetadata(); super.initStandardMetadata();
String comment = ifds.get(0).getComment(); // IMAGE_DESCRIPTION String comment = ifds.get(0).getComment(); // IMAGE_DESCRIPTION
LOGGER.info("initStandardMetadata() - after super()"); LOGGER.debug("initStandardMetadata() - after super()");
long[] maker_note = null; long[] maker_note = null;
double exposure = Double.NaN; double exposure = Double.NaN;
String date_time = null; String date_time = null;
...@@ -330,14 +330,14 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -330,14 +330,14 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
null, maker_note, exposure, date_time, bytes_per_pixel, true ); null, maker_note, exposure, date_time, bytes_per_pixel, true );
LOGGER.info("Created elphelMeta table, size="+property_table.size()); LOGGER.debug("Created elphelMeta table, size="+property_table.size());
for (String key:property_table.keySet()) { for (String key:property_table.keySet()) {
addGlobalMeta(ELPHEL_PROPERTY_PREFIX+key,property_table.get(key)); addGlobalMeta(ELPHEL_PROPERTY_PREFIX+key,property_table.get(key));
} }
MetadataLevel level = getMetadataOptions().getMetadataLevel(); MetadataLevel level = getMetadataOptions().getMetadataLevel();
if (level != MetadataLevel.MINIMUM) { if (level != MetadataLevel.MINIMUM) {
Integer[] tags = ifds.get(0).keySet().toArray(new Integer[0]); Integer[] tags = ifds.get(0).keySet().toArray(new Integer[0]);
LOGGER.info("initStandardMetadata() - got "+tags.length+" tags"); LOGGER.debug("initStandardMetadata() - got "+tags.length+" tags");
} }
addGlobalMeta(ELPHEL_PROPERTY_PREFIX+CONTENT_FILENAME,content_fileName); addGlobalMeta(ELPHEL_PROPERTY_PREFIX+CONTENT_FILENAME,content_fileName);
// convert MAKER_NOTE to the same text format as in com.drew.metadata // convert MAKER_NOTE to the same text format as in com.drew.metadata
...@@ -410,9 +410,9 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader { ...@@ -410,9 +410,9 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException throws FormatException, IOException
{ {
LOGGER.info("openBytes() - before super()"); LOGGER.debug("openBytes() - before super()");
super.openBytes(no, buf, x, y, w, h); super.openBytes(no, buf, x, y, w, h);
LOGGER.info("openBytes() - after super()"); LOGGER.debug("openBytes() - after super()");
return buf; return buf;
} }
......
...@@ -66,6 +66,7 @@ public class ImagejJp4Tiff { ...@@ -66,6 +66,7 @@ public class ImagejJp4Tiff {
private static final Logger LOGGER = LoggerFactory.getLogger(ClassList.class); private static final Logger LOGGER = LoggerFactory.getLogger(ClassList.class);
private static final boolean BYPASS_SERVICES = false; // true; private static final boolean BYPASS_SERVICES = false; // true;
private static final String SERVICES_PATH = "services.properties.forelphel"; private static final String SERVICES_PATH = "services.properties.forelphel";
private static final boolean KEEP_EXTENSION = false; // remove extension for ImagePlus title
// -- Fields -- // -- Fields --
...@@ -151,7 +152,7 @@ public class ImagejJp4Tiff { ...@@ -151,7 +152,7 @@ public class ImagejJp4Tiff {
if (url != null) { if (url != null) {
LOGGER.error("Read "+ path_url +" to memory first"); LOGGER.error("Read "+ path_url +" to memory first");
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
// Wrong - waits forever
String content_disposition = connection.getHeaderField("Content-Disposition"); // reads file String content_disposition = connection.getHeaderField("Content-Disposition"); // reads file
// raw = "attachment; filename=abc.jpg" // raw = "attachment; filename=abc.jpg"
if(content_disposition != null && content_disposition.indexOf("=") != -1) { if(content_disposition != null && content_disposition.indexOf("=") != -1) {
...@@ -217,6 +218,12 @@ public class ImagejJp4Tiff { ...@@ -217,6 +218,12 @@ public class ImagejJp4Tiff {
if (meta_hash.containsKey(imageNameKey)) { if (meta_hash.containsKey(imageNameKey)) {
imageName = meta_hash.get(imageNameKey).toString(); imageName = meta_hash.get(imageNameKey).toString();
} }
if (!KEEP_EXTENSION) {
int dot_indx = imageName.lastIndexOf(".");
if (dot_indx >= 0) {
imageName = imageName.substring(0, dot_indx);
}
}
imp = new ImagePlus(imageName, ip); // original jp46 reader had full path as title imp = new ImagePlus(imageName, ip); // original jp46 reader had full path as title
// first - save all as properties, later - only ELPHEL_* // first - save all as properties, later - only ELPHEL_*
......
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