Commit 50de1233 authored by Andrey Filippov's avatar Andrey Filippov

preparing for the goniometer with LWIR

parent 47b15645
......@@ -60,25 +60,16 @@ import java.util.regex.Pattern;
// TODO: modify methods that depend on it, use class CalibrationFileManagement
import javax.swing.JFileChooser;
import com.elphel.imagej.calibration.CalibrationFileManagement.MultipleExtensionsFileFilter;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.CamerasInterface;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.FocusingMotors;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.GoniometerMotors;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.LaserPointers;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.PowerControl;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.UVLEDandLasers;
import com.elphel.imagej.calibration.Distortions.RefineParameters;
import com.elphel.imagej.calibration.SimulationPattern.SimulParameters;
import com.elphel.imagej.cameras.EyesisCameraParameters;
import com.elphel.imagej.cameras.SFEPhases;
import com.elphel.imagej.cameras.SFEPhases.Defect;
import com.elphel.imagej.cameras.SFEPhases.SensorDefects;
import com.elphel.imagej.common.DoubleFHT;
import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.PolynomialApproximation;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.jp4.JP46_Reader_camera;
import com.elphel.imagej.lwir.LwirReader;
import com.elphel.imagej.lwir.LwirReaderParameters;
import Jama.Matrix; // Download here: http://math.nist.gov/javanumerics/jama/
import ij.IJ;
......@@ -110,6 +101,7 @@ public class Aberration_Calibration extends PlugInFrame implements ActionListene
private Panel panelCurvature;
private Panel panelGoniometer;
private Panel panelPixelMapping, panelStereo,panelStereo1;
private Panel panelLWIR;
private ShowDoubleFloatArrays SDFA_INSTANCE; // just for debugging?
JP46_Reader_camera JP4_INSTANCE;
......@@ -271,6 +263,9 @@ public class Aberration_Calibration extends PlugInFrame implements ActionListene
);
public static LwirReader LWIR_READER = null;
public static ProcessCalibrationFilesParameters PROCESS_PARAMETERS = new ProcessCalibrationFilesParameters(
"jp46", // sourceFileExtension,
"tiff", // kernelFileExtension,
......@@ -614,6 +609,11 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
public static EyesisAberrations EYESIS_ABERRATIONS; // need Distortions to be set up
public static Goniometer GONIOMETER=null;
public static LwirReaderParameters LWIR_PARAMETERS=new LwirReaderParameters();
// new CalibrationHardwareInterface.LaserPointers();
public class SyncCommand{
public boolean isRunning= false;
......@@ -634,7 +634,7 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
addKeyListener(IJ.getInstance());
// setLayout(new GridLayout(ADVANCED_MODE?8:5, 1));
// setLayout(new GridLayout(ADVANCED_MODE?9:6, 1));
setLayout(new GridLayout(ADVANCED_MODE?20:20, 1));
setLayout(new GridLayout(ADVANCED_MODE?21:21, 1));
Color color_configure= new Color(200, 200,160);
Color color_process= new Color(180, 180, 240);
Color color_conf_process= new Color(180, 240, 240);
......@@ -983,9 +983,19 @@ if (MORE_BUTTONS) {
addButton("Create Ambiguity",panelStereo1);
addButton("Initial Resolve",panelStereo1);
addButton("Ambiguity Resolve",panelStereo1);
add(panelStereo1);
panelLWIR= new Panel();
panelLWIR.setLayout(new GridLayout(1, 0, 5, 5)); // rows, columns, vgap, hgap
addButton("LWIR Configure", panelLWIR,color_configure);
addButton("LWIR_TEST", panelLWIR, color_conf_process);
addButton("LWIR_ACQUIRE", panelLWIR, color_conf_process);
addButton("Configure Goniometer", panelLWIR,color_configure);
addButton("Goniometer Move", panelLWIR,color_debug);
addButton("LWIR Goniometer", panelLWIR,color_conf_process);
add(panelLWIR);
pack();
GUI.center(this);
setVisible(true);
......@@ -1094,6 +1104,23 @@ if (MORE_BUTTONS) {
if (DEBUG_LEVEL>0) System.out.println("--- Free memory="+runtime.freeMemory()+" (of "+runtime.totalMemory()+")");
if (label==null) return;
String LOG_LEVEL;
switch (MASTER_DEBUG_LEVEL) {
case -2: LOG_LEVEL = "FATAL"; break;
case -1: LOG_LEVEL = "ERROR"; break;
case 0: LOG_LEVEL = "WARN"; break;
case 1: LOG_LEVEL = "INFO"; break;
case 2: LOG_LEVEL = "DEBUG"; break;
default: LOG_LEVEL = "OFF";
}
boolean LOG_LEVEL_SET = loci.common.DebugTools.enableLogging(LOG_LEVEL);
if (!LOG_LEVEL_SET) { // only first time true
loci.common.DebugTools.setRootLevel(LOG_LEVEL);
}
System.out.println("DEBUG_LEVEL = "+DEBUG_LEVEL+", MASTER_DEBUG_LEVEL = "+MASTER_DEBUG_LEVEL+
" LOG_LEVEL="+LOG_LEVEL+"LOG_LEVEL_SET="+LOG_LEVEL_SET);
if (FOCUSING_FIELD!=null) FOCUSING_FIELD.setThreads(THREADS_MAX);
/* ======================================================================== */
if (label.equals("Configure Globals")) {
......@@ -1172,334 +1199,11 @@ if (MORE_BUTTONS) {
return;
/* ======================================================================== */
} else if (label.equals("Restore") || label.equals("Restore no autoload")) {
boolean noAuto=label.equals("Restore no autoload");
ABERRATIONS_PARAMETERS.autoRestore=false;
String confPath=loadProperties(null,PROCESS_PARAMETERS.kernelsDirectory,PROCESS_PARAMETERS.useXML, PROPERTIES);
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (ABERRATIONS_PARAMETERS.autoRestore && !noAuto){
if (DEBUG_LEVEL>0)System.out.println("Auto-loading configuration files");
if (LENS_DISTORTIONS==null) {
LENS_DISTORTIONS=new Distortions(LENS_DISTORTION_PARAMETERS,PATTERN_PARAMETERS,REFINE_PARAMETERS,this.SYNC_COMMAND.stopRequested);
}
LENS_DISTORTIONS.debugLevel=DEBUG_LEVEL;
boolean dcdUpdated=autoLoadFiles(
ABERRATIONS_PARAMETERS,
LENS_DISTORTIONS, // should be initialized, after update DISTORTION_CALIBRATION_DATA from this
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS, //EyesisCameraParameters eyesisCameraParameters,
UPDATE_STATUS,
DEBUG_LEVEL
);
if (dcdUpdated) DISTORTION_CALIBRATION_DATA=LENS_DISTORTIONS.fittingStrategy.distortionCalibrationData;
if (ABERRATIONS_PARAMETERS.autoReCalibrate){
if (LENS_DISTORTIONS.fittingStrategy==null) {
IJ.showMessage("Can not recalibrate grids - LENS_DISTORTION.fittingStrategy is not set");
return;
}
if (DEBUG_LEVEL>0)System.out.println("=== Re-calibrating grids ===");
int numMatched=LENS_DISTORTIONS.applyHintedGrids(
LASER_POINTERS, // MatchSimulatedPattern.LaserPointer laserPointer, // LaserPointer object that specifies actual laser poiners on the target
DISTORTION_PROCESS_CONFIGURATION.removeOutOfGridPointers, // boolean removeOutOfGridPointers,
5.0, //double hintGridTolerance, // alllowed mismatch (fraction of period) or 0 - orientation only
true, //boolean processAll, // if true - process all images, false - only disabeld
false, //?
false, //processBlind,
-1, // imageNumber,
true, // useSetData - use imageSets data if available (false - use camera data)
THREADS_MAX, //int threadsMax,
UPDATE_STATUS, // boolean updateStatus,
DISTORTION.loop_debug_level, // int mspDebugLevel,
MASTER_DEBUG_LEVEL, //int global_debug_level, // DEBUG_LEVEL
MASTER_DEBUG_LEVEL //int debug_level // debug level used inside loops
);
System.out.println("Number of matched images: "+numMatched);
LENS_DISTORTIONS.debugLevel=DEBUG_LEVEL;
LENS_DISTORTIONS.updateStatus=UPDATE_STATUS;
LENS_DISTORTIONS.fittingStrategy.debugLevel=DEBUG_LEVEL;
LENS_DISTORTIONS.markBadNodces(
-1,// series - all images
DEBUG_LEVEL);
}
if ((LENS_DISTORTIONS.fittingStrategy != null) && ABERRATIONS_PARAMETERS.autoFilter) { // trying to fix restore
if (DEBUG_LEVEL>0) System.out.println("LENS_DISTORTIONS.fittingStrategy != null -> Extra after loading");
int minGridsNoPointer=1000;
int [] numImages=DISTORTION_CALIBRATION_DATA.filterImages(
false, // resetHinted,
0, // 2, // minPointers,
0.4, // minGridPeriod,
true, // disableNoVignetting,
minGridsNoPointer); //minGridsNoPointer);
System.out.println("Number of enabled grid images: "+numImages[0]+
", of them new: "+numImages[1]+
", disabled without vignetting info: "+numImages[2]+
", disabled having less than "+minGridsNoPointer+" nodes and no matched pointers: "+numImages[3]+
", disabled with no lasers and enableNoLaser==false (like 2 bottom cameras - check all stations):" +numImages[4]);
if (DISTORTION_CALIBRATION_DATA.gIS==null) {
int numImageSets=DISTORTION_CALIBRATION_DATA.buildImageSets(false); // from scratch
if (DEBUG_LEVEL>0) System.out.println("Image set was empty, built a new one with "+numImageSets+" image sets (\"panoramas\"): ");
DISTORTION_CALIBRATION_DATA.updateSetOrientation(null); // restore orientation from (enabled) image files
if (DEBUG_LEVEL>0) System.out.println("Setting sets orientation from per-grid image data");
}
}
restoreFocusingHistory(false);
}
restore(label.equals("Restore no autoload"));
return;
/* ======================================================================== */
} else if (label.equals("Process Calibration Files")) {
if (!showProcessCalibrationFilesDialog(PROCESS_PARAMETERS)) return;
boolean noMessageBoxes=false; //TODO: move to configuration
long startTime=System.nanoTime();
long tmpTime;
String resultPath;
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
int loop_debug_level=1;
String [][][] filePaths=null;
int dirNum, fileNum;
ImageStack stack;
ImagePlus imp_psf;
File file;
String fileName;
if (PROCESS_PARAMETERS.processSourceImages) {
if ((PROCESS_PARAMETERS.sourceSuperDirectory==null) || (PROCESS_PARAMETERS.sourceSuperDirectory.length()==0)) {
fileName= selectSourceDirectory(PROCESS_PARAMETERS.sourceSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.sourceSuperDirectory=fileName;
}
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
filePaths=prepareCalibrationFilesList(PROCESS_PARAMETERS);
if (filePaths==null) {
IJ.showMessage("Error","No files to process\nProcess canceled");
return;
}
startTime=System.nanoTime(); // restart timer after possible interactive dialogs
for (dirNum=0;dirNum<filePaths.length; dirNum++) {
if (filePaths[dirNum]!=null){
if (DEBUG_LEVEL>1) System.out.println("======= directory number="+dirNum+", number of files="+filePaths[dirNum].length+" ========");
for (fileNum=0;fileNum<filePaths[dirNum].length; fileNum++) {
if (DEBUG_LEVEL>1) System.out.println(filePaths[dirNum][fileNum][0] +" ==> "+filePaths[dirNum][fileNum][1]);
imp_sel=JP4_INSTANCE.open(
"", // path,
filePaths[dirNum][fileNum][0],
"", //arg - not used in JP46 reader
true, // un-apply camera color gains
imp_sel); // reuse the same image window
// Remove for old method?
matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize);
matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
null, // LaserPointer laserPointer, // LaserPointer object or null
true, // don't care -removeOutOfGridPointers
null, // double [][][] hintGrid, // predicted grid array (or null)
0, // double hintGridTolerance, // alllowed mismatch (fraction of period) or 0 - orientation only
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level, // debug level
noMessageBoxes);
SIM_ARRAY= (new SimulationPattern(SIMUL)).simulateGridAll (
imp_sel.getWidth(),
imp_sel.getHeight(),
matchSimulatedPattern,
2, // gridFrac, // number of grid steps per pattern full period
SIMUL,
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level); // debug level
createPSFMap(
matchSimulatedPattern,
matchSimulatedPattern.applyFlatField (imp_sel), // if grid is flat-field calibrated, apply it
null, // int [][][] sampleList, // optional (or null) 2-d array: list of coordinate pairs (2d - to match existent PSF_KERNEL_MAP structure)
MULTIFILE_PSF.overexposedMaxFraction,
SIMUL, //simulation parameters
MAP_FFT_SIZE, // scanImageForPatterns:FFT size
PATTERN_DETECT,
FFT_OVERLAP, // scanImageForPatterns:high-pass gaussian filter sigma when correlating power spectrum
FFT_SIZE, // maximal distance between maximum on spectrum and predicted maximum on autocorrelation of gamma(|spectrum|)
COMPONENTS,
PSF_SUBPIXEL, // maximal iterations when looking for local maximum
OTF_FILTER,
PSF_PARS, // step of the new map (should be multiple of map step)
PSF_PARS.minDefinedArea,
INVERSE.dSize, // size of square used in the new map (should be multiple of map step)
THREADS_MAX,
UPDATE_STATUS,
loop_debug_level);// debug level used inside loops
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
stack=mergeKernelsToStack(PSF_KERNEL_MAP);
if (stack!=null) {
imp_psf = new ImagePlus(filePaths[dirNum][fileNum][1], stack);
// if (DEBUG_LEVEL>1) imp_psf.show();
if (DEBUG_LEVEL>1) System.out.println("Saving result to"+filePaths[dirNum][fileNum][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[dirNum][fileNum][1]);
} else {
System.out.println("File "+filePaths[dirNum][fileNum][1]+ " has no useful PSF kernels - at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
}
}
}
}
}
if (PROCESS_PARAMETERS.combinePSFfiles) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
filePaths=preparePartialKernelsFilesList(PROCESS_PARAMETERS);
startTime-=(System.nanoTime()-tmpTime); // do not count time used for selection of files
if (filePaths==null) {
IJ.showMessage("Error","No partila kernel files to process, finished in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+ " seconds");
return;
}
String [] filenames;
for (dirNum=0;dirNum<filePaths.length; dirNum++) {
if ((filePaths[dirNum]!=null) && (filePaths[dirNum].length!=0)){
resultPath=filePaths[dirNum][0][1];
filenames=new String[filePaths[dirNum].length];
for (fileNum=0;fileNum<filenames.length;fileNum++) filenames[fileNum]=filePaths[dirNum][fileNum][0];
if (!combinePSFKernels (
INTERPOLATE,
MULTIFILE_PSF,
filenames,
resultPath,
SDFA_INSTANCE,
imp_sel, // re-use global
true, // saveResult,
false, // showResult,
UPDATE_STATUS,
DEBUG_LEVEL)) continue; // return; // no overlap, bad result kernel
}
}
}
if (PROCESS_PARAMETERS.interpolatePSFkernel) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
IJ.showMessage("Notice","partialKernelsSuperDirectory="+PROCESS_PARAMETERS.partialKernelsSuperDirectory);
startTime-=(System.nanoTime()-tmpTime); // do not count time used for selection of files
filePaths=prepareInterpolateKernelsList(PROCESS_PARAMETERS);
for (fileNum=0;fileNum<filePaths.length;fileNum++) if ((filePaths[fileNum]!=null) && (filePaths[fileNum].length>0)) {
file=new File(filePaths[fileNum][0][0]);
if (!file.exists()) {
if (DEBUG_LEVEL>1) System.out.println("Raw PSF kernel stack file "+filePaths[fileNum][0][0]+" does not exist");
continue;
}
imp_psf=new ImagePlus(filePaths[fileNum][0][0]);
if (imp_psf.getStackSize()<3) {
System.out.println("Need a 3-layer stack with raw PSF kernels");
continue;
}
stack= interpolateKernelStack(imp_psf.getStack(), // Image stack, each slice consists of square kernels of one channel
INTERPOLATE,
UPDATE_STATUS); // update status info
imp_psf = new ImagePlus(filePaths[fileNum][0][1], stack);
if (DEBUG_LEVEL>2) {
imp_psf.getProcessor().resetMinAndMax(); // imp_psf will be reused
imp_psf.show();
}
if (DEBUG_LEVEL>1) System.out.println("Saving interpolation result to"+filePaths[fileNum][0][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[fileNum][0][1]);
}
}
if (PROCESS_PARAMETERS.invertKernels) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
if ((PROCESS_PARAMETERS.kernelsDirectory==null) || (PROCESS_PARAMETERS.kernelsDirectory.length()==0)) {
fileName= selectKernelsDirectory(PROCESS_PARAMETERS.kernelsDirectory);
if (fileName!=null) PROCESS_PARAMETERS.kernelsDirectory=fileName;
}
startTime-=(System.nanoTime()-tmpTime); // do not count time used fro selection of files
filePaths=prepareInvertGaussianKernelsList(PROCESS_PARAMETERS, PROCESS_PARAMETERS.rpsfPrefix );
for (fileNum=0;fileNum<filePaths.length;fileNum++) if ((filePaths[fileNum]!=null) && (filePaths[fileNum].length>0)) {
file=new File(filePaths[fileNum][0][0]);
if (!file.exists()) {
if (DEBUG_LEVEL>0) System.out.println("Interpolated PSF kernel stack file "+filePaths[fileNum][0][0]+" does not exist");
continue;
}
imp_psf=new ImagePlus(filePaths[fileNum][0][0]);
if (imp_psf.getStackSize()<3) {
System.out.println("Need a 3-layer stack with interpolated PSF kernels");
continue;
}
stack= reversePSFKernelStack(imp_psf.getStack(), // stack of 3 32-bit (float) images, made of square kernels
INVERSE,
THREADS_MAX, // size (side of square) of reverse PSF kernel
UPDATE_STATUS); // update status info
imp_psf = new ImagePlus(filePaths[fileNum][0][1], stack);
if (DEBUG_LEVEL>2) {
imp_psf.getProcessor().resetMinAndMax(); // imp_psf will be reused
imp_psf.show();
}
if (DEBUG_LEVEL>0) System.out.println("Saving PSF inversion result to"+filePaths[fileNum][0][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[fileNum][0][1]);
}
}
if (PROCESS_PARAMETERS.gaussianKernels) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
if ((PROCESS_PARAMETERS.kernelsDirectory==null) || (PROCESS_PARAMETERS.kernelsDirectory.length()==0)) {
fileName= selectKernelsDirectory(PROCESS_PARAMETERS.kernelsDirectory);
if (fileName!=null) PROCESS_PARAMETERS.kernelsDirectory=fileName;
}
startTime-=(System.nanoTime()-tmpTime); // do not count time used fro selection of files
filePaths=prepareInvertGaussianKernelsList(PROCESS_PARAMETERS, PROCESS_PARAMETERS.gaussianPrefix);
for (fileNum=0;fileNum<filePaths.length;fileNum++) if ((filePaths[fileNum]!=null) && (filePaths[fileNum].length>0)) {
file=new File(filePaths[fileNum][0][0]);
if (!file.exists()) {
if (DEBUG_LEVEL>0) System.out.println("Interpolated PSF kernel stack file "+filePaths[fileNum][0][0]+" does not exist");
continue;
}
imp_psf=new ImagePlus(filePaths[fileNum][0][0]);
if (imp_psf.getStackSize()<3) {
System.out.println("Need a 3-layer stack with interpolated PSF kernels");
continue;
}
stack= generateGaussianStackFromDirect(imp_psf.getStack(), // stack of 3 32-bit (float) images, made of square kernels
INVERSE,
UPDATE_STATUS); // update status info
imp_psf = new ImagePlus(filePaths[fileNum][0][1], stack);
if (DEBUG_LEVEL>2) {
imp_psf.getProcessor().resetMinAndMax(); // imp_psf will be reused
imp_psf.show();
}
if (DEBUG_LEVEL>0) System.out.println("Saving Gaussian kernels result to"+filePaths[fileNum][0][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[fileNum][0][1]);
}
}
System.out.println("Processing done in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+ " seconds");
if (PROCESS_PARAMETERS.saveSettings) saveProperties(PROCESS_PARAMETERS.kernelsDirectory+Prefs.getFileSeparator()+"calibration_settings",null,PROCESS_PARAMETERS.useXML, PROPERTIES);
processCalibrationFiles();
return;
/* ======================================================================== */
......@@ -9697,6 +9401,110 @@ if (MORE_BUTTONS) {
}
return;
}
/* ======================================================================== */
if (label.equals("LWIR Configure")) {
LWIR_PARAMETERS.showJDialog();
return;
}
/* ======================================================================== */
//
if (label.equals("LWIR_TEST")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
// public static LwirReader LWIR_READER = null;
if (LWIR_READER == null) {
LWIR_READER = new LwirReader(LWIR_PARAMETERS);
}
ImagePlus [][] imps = LWIR_READER.readAllMultiple(
10, // final int num_frames,
// true, // use LWIR telemetry
true, // final boolean show,
false); // true); // final boolean scale)
for (ImagePlus imp: imps[0]) {
imp.show();
}
System.out.println("LWIR_TEST: got "+imps.length+" image sets");
ImagePlus [][] imps_sync = LWIR_READER.matchSets(imps, 0.001, 3); // double max_mismatch)
if (imps_sync != null) {
ImagePlus [] imps_avg = LWIR_READER.averageMultiFrames(imps_sync);
for (ImagePlus imp: imps_avg) {
imp.show();
}
}
return;
}
/* ======================================================================== */
if (label.equals("LWIR_ACQUIRE")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
// public static LwirReader LWIR_READER = null;
if (LWIR_READER == null) {
LWIR_READER = new LwirReader(LWIR_PARAMETERS);
}
ImagePlus [] imps = LWIR_READER.acquire("/data_ssd/imagej-elphel/attic/camera_img/test-calib"); // directory to save
if (imps != null) {
// for (ImagePlus imp: imps) {
// imp.show();
// }
}
return;
}
/* ======================================================================== */
if (label.equals("Goniometer LWIR")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
// CAMERAS.setNumberOfThreads(THREADS_MAX);
// CAMERAS.debugLevel=DEBUG_LEVEL;
if (GONIOMETER==null) {
GONIOMETER= new Goniometer(
LWIR_READER,
// CAMERAS, // CalibrationHardwareInterface.CamerasInterface cameras,
DISTORTION, //MatchSimulatedPattern.DistortionParameters distortion,
PATTERN_DETECT, //MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
EYESIS_CAMERA_PARAMETERS, //EyesisCameraParameters eyesisCameraParameters,
LASER_POINTERS, // MatchSimulatedPattern.LaserPointer laserPointers
SIMUL, //SimulationPattern.SimulParameters simulParametersDefault,
GONIOMETER_PARAMETERS, //LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
DISTORTION_PROCESS_CONFIGURATION
);
if (DEBUG_LEVEL>1){
System.out.println("Initiaslizing Goniometer class");
}
} else if (DEBUG_LEVEL>1){
System.out.println("GONIOMETER was initialized");
}
// calculate angular size of the target as visible from the camera
double distanceToTarget=GONIOMETER_PARAMETERS.targetDistance;
double patternWidth= PATTERN_PARAMETERS.patternWidth;
double patternHeight=PATTERN_PARAMETERS.patternHeight;
double targetAngleHorizontal=360*Math.atan(patternWidth/2/distanceToTarget)/Math.PI;
double targetAngleVertical= 360*Math.atan(patternHeight/2/distanceToTarget)/Math.PI;
if (DEBUG_LEVEL>0) System.out.println(
"Using:\n"+
"Distance from target: "+IJ.d2s(distanceToTarget,1)+" mm\n"+
" Taget width: "+IJ.d2s(patternWidth,1)+" mm\n"+
" Taget height: "+IJ.d2s(patternHeight,1)+" mm\n"+
"Taget angular size horizontal: "+IJ.d2s(targetAngleHorizontal,1)+" degrees\n"+
"Taget angular size vertical: "+IJ.d2s(targetAngleVertical,1)+" degrees\n"
);
GONIOMETER.debugLevel=DEBUG_LEVEL;
/// POWER_CONTROL.lightsOnWithDelay();
boolean goniometerScanOK=GONIOMETER.scanAndAcquire(
targetAngleHorizontal,
targetAngleVertical,
this.SYNC_COMMAND.stopRequested,
UPDATE_STATUS);
System.out.println ("GONIOMETER.scanAndAcquireI() "+(goniometerScanOK?"finished OK":"failed"));
/// POWER_CONTROL.lightsOff();
return;
}
/* ======================================================================== */
......@@ -9706,6 +9514,347 @@ if (MORE_BUTTONS) {
}
/* ===== Other methods ==================================================== */
/* ======================================================================== */
/* ======================================================================== */
/* ======================================================================== */
/* ======================================================================== */
public void processCalibrationFiles() {
if (!showProcessCalibrationFilesDialog(PROCESS_PARAMETERS)) return;
boolean noMessageBoxes=false; //TODO: move to configuration
long startTime=System.nanoTime();
long tmpTime;
String resultPath;
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
int loop_debug_level=1;
String [][][] filePaths=null;
int dirNum, fileNum;
ImageStack stack;
ImagePlus imp_psf;
File file;
String fileName;
if (PROCESS_PARAMETERS.processSourceImages) {
if ((PROCESS_PARAMETERS.sourceSuperDirectory==null) || (PROCESS_PARAMETERS.sourceSuperDirectory.length()==0)) {
fileName= selectSourceDirectory(PROCESS_PARAMETERS.sourceSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.sourceSuperDirectory=fileName;
}
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
filePaths=prepareCalibrationFilesList(PROCESS_PARAMETERS);
if (filePaths==null) {
IJ.showMessage("Error","No files to process\nProcess canceled");
return;
}
startTime=System.nanoTime(); // restart timer after possible interactive dialogs
for (dirNum=0;dirNum<filePaths.length; dirNum++) {
if (filePaths[dirNum]!=null){
if (DEBUG_LEVEL>1) System.out.println("======= directory number="+dirNum+", number of files="+filePaths[dirNum].length+" ========");
for (fileNum=0;fileNum<filePaths[dirNum].length; fileNum++) {
if (DEBUG_LEVEL>1) System.out.println(filePaths[dirNum][fileNum][0] +" ==> "+filePaths[dirNum][fileNum][1]);
imp_sel=JP4_INSTANCE.open(
"", // path,
filePaths[dirNum][fileNum][0],
"", //arg - not used in JP46 reader
true, // un-apply camera color gains
imp_sel); // reuse the same image window
//Remove for old method?
matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize);
matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
null, // LaserPointer laserPointer, // LaserPointer object or null
true, // don't care -removeOutOfGridPointers
null, // double [][][] hintGrid, // predicted grid array (or null)
0, // double hintGridTolerance, // alllowed mismatch (fraction of period) or 0 - orientation only
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level, // debug level
noMessageBoxes);
SIM_ARRAY= (new SimulationPattern(SIMUL)).simulateGridAll (
imp_sel.getWidth(),
imp_sel.getHeight(),
matchSimulatedPattern,
2, // gridFrac, // number of grid steps per pattern full period
SIMUL,
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level); // debug level
createPSFMap(
matchSimulatedPattern,
matchSimulatedPattern.applyFlatField (imp_sel), // if grid is flat-field calibrated, apply it
null, // int [][][] sampleList, // optional (or null) 2-d array: list of coordinate pairs (2d - to match existent PSF_KERNEL_MAP structure)
MULTIFILE_PSF.overexposedMaxFraction,
SIMUL, //simulation parameters
MAP_FFT_SIZE, // scanImageForPatterns:FFT size
PATTERN_DETECT,
FFT_OVERLAP, // scanImageForPatterns:high-pass gaussian filter sigma when correlating power spectrum
FFT_SIZE, // maximal distance between maximum on spectrum and predicted maximum on autocorrelation of gamma(|spectrum|)
COMPONENTS,
PSF_SUBPIXEL, // maximal iterations when looking for local maximum
OTF_FILTER,
PSF_PARS, // step of the new map (should be multiple of map step)
PSF_PARS.minDefinedArea,
INVERSE.dSize, // size of square used in the new map (should be multiple of map step)
THREADS_MAX,
UPDATE_STATUS,
loop_debug_level);// debug level used inside loops
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
stack=mergeKernelsToStack(PSF_KERNEL_MAP);
if (stack!=null) {
imp_psf = new ImagePlus(filePaths[dirNum][fileNum][1], stack);
// if (DEBUG_LEVEL>1) imp_psf.show();
if (DEBUG_LEVEL>1) System.out.println("Saving result to"+filePaths[dirNum][fileNum][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[dirNum][fileNum][1]);
} else {
System.out.println("File "+filePaths[dirNum][fileNum][1]+ " has no useful PSF kernels - at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
}
}
}
}
}
if (PROCESS_PARAMETERS.combinePSFfiles) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
filePaths=preparePartialKernelsFilesList(PROCESS_PARAMETERS);
startTime-=(System.nanoTime()-tmpTime); // do not count time used for selection of files
if (filePaths==null) {
IJ.showMessage("Error","No partila kernel files to process, finished in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+ " seconds");
return;
}
String [] filenames;
for (dirNum=0;dirNum<filePaths.length; dirNum++) {
if ((filePaths[dirNum]!=null) && (filePaths[dirNum].length!=0)){
resultPath=filePaths[dirNum][0][1];
filenames=new String[filePaths[dirNum].length];
for (fileNum=0;fileNum<filenames.length;fileNum++) filenames[fileNum]=filePaths[dirNum][fileNum][0];
if (!combinePSFKernels (
INTERPOLATE,
MULTIFILE_PSF,
filenames,
resultPath,
SDFA_INSTANCE,
imp_sel, // re-use global
true, // saveResult,
false, // showResult,
UPDATE_STATUS,
DEBUG_LEVEL)) continue; // return; // no overlap, bad result kernel
}
}
}
if (PROCESS_PARAMETERS.interpolatePSFkernel) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
IJ.showMessage("Notice","partialKernelsSuperDirectory="+PROCESS_PARAMETERS.partialKernelsSuperDirectory);
startTime-=(System.nanoTime()-tmpTime); // do not count time used for selection of files
filePaths=prepareInterpolateKernelsList(PROCESS_PARAMETERS);
for (fileNum=0;fileNum<filePaths.length;fileNum++) if ((filePaths[fileNum]!=null) && (filePaths[fileNum].length>0)) {
file=new File(filePaths[fileNum][0][0]);
if (!file.exists()) {
if (DEBUG_LEVEL>1) System.out.println("Raw PSF kernel stack file "+filePaths[fileNum][0][0]+" does not exist");
continue;
}
imp_psf=new ImagePlus(filePaths[fileNum][0][0]);
if (imp_psf.getStackSize()<3) {
System.out.println("Need a 3-layer stack with raw PSF kernels");
continue;
}
stack= interpolateKernelStack(imp_psf.getStack(), // Image stack, each slice consists of square kernels of one channel
INTERPOLATE,
UPDATE_STATUS); // update status info
imp_psf = new ImagePlus(filePaths[fileNum][0][1], stack);
if (DEBUG_LEVEL>2) {
imp_psf.getProcessor().resetMinAndMax(); // imp_psf will be reused
imp_psf.show();
}
if (DEBUG_LEVEL>1) System.out.println("Saving interpolation result to"+filePaths[fileNum][0][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[fileNum][0][1]);
}
}
if (PROCESS_PARAMETERS.invertKernels) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
if ((PROCESS_PARAMETERS.kernelsDirectory==null) || (PROCESS_PARAMETERS.kernelsDirectory.length()==0)) {
fileName= selectKernelsDirectory(PROCESS_PARAMETERS.kernelsDirectory);
if (fileName!=null) PROCESS_PARAMETERS.kernelsDirectory=fileName;
}
startTime-=(System.nanoTime()-tmpTime); // do not count time used fro selection of files
filePaths=prepareInvertGaussianKernelsList(PROCESS_PARAMETERS, PROCESS_PARAMETERS.rpsfPrefix );
for (fileNum=0;fileNum<filePaths.length;fileNum++) if ((filePaths[fileNum]!=null) && (filePaths[fileNum].length>0)) {
file=new File(filePaths[fileNum][0][0]);
if (!file.exists()) {
if (DEBUG_LEVEL>0) System.out.println("Interpolated PSF kernel stack file "+filePaths[fileNum][0][0]+" does not exist");
continue;
}
imp_psf=new ImagePlus(filePaths[fileNum][0][0]);
if (imp_psf.getStackSize()<3) {
System.out.println("Need a 3-layer stack with interpolated PSF kernels");
continue;
}
stack= reversePSFKernelStack(imp_psf.getStack(), // stack of 3 32-bit (float) images, made of square kernels
INVERSE,
THREADS_MAX, // size (side of square) of reverse PSF kernel
UPDATE_STATUS); // update status info
imp_psf = new ImagePlus(filePaths[fileNum][0][1], stack);
if (DEBUG_LEVEL>2) {
imp_psf.getProcessor().resetMinAndMax(); // imp_psf will be reused
imp_psf.show();
}
if (DEBUG_LEVEL>0) System.out.println("Saving PSF inversion result to"+filePaths[fileNum][0][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[fileNum][0][1]);
}
}
if (PROCESS_PARAMETERS.gaussianKernels) {
tmpTime=System.nanoTime();
if ((PROCESS_PARAMETERS.partialKernelsSuperDirectory==null) || (PROCESS_PARAMETERS.partialKernelsSuperDirectory.length()==0)) {
fileName= selectPartialKernelsDirectory(PROCESS_PARAMETERS.partialKernelsSuperDirectory);
if (fileName!=null) PROCESS_PARAMETERS.partialKernelsSuperDirectory=fileName;
}
if ((PROCESS_PARAMETERS.kernelsDirectory==null) || (PROCESS_PARAMETERS.kernelsDirectory.length()==0)) {
fileName= selectKernelsDirectory(PROCESS_PARAMETERS.kernelsDirectory);
if (fileName!=null) PROCESS_PARAMETERS.kernelsDirectory=fileName;
}
startTime-=(System.nanoTime()-tmpTime); // do not count time used fro selection of files
filePaths=prepareInvertGaussianKernelsList(PROCESS_PARAMETERS, PROCESS_PARAMETERS.gaussianPrefix);
for (fileNum=0;fileNum<filePaths.length;fileNum++) if ((filePaths[fileNum]!=null) && (filePaths[fileNum].length>0)) {
file=new File(filePaths[fileNum][0][0]);
if (!file.exists()) {
if (DEBUG_LEVEL>0) System.out.println("Interpolated PSF kernel stack file "+filePaths[fileNum][0][0]+" does not exist");
continue;
}
imp_psf=new ImagePlus(filePaths[fileNum][0][0]);
if (imp_psf.getStackSize()<3) {
System.out.println("Need a 3-layer stack with interpolated PSF kernels");
continue;
}
stack= generateGaussianStackFromDirect(imp_psf.getStack(), // stack of 3 32-bit (float) images, made of square kernels
INVERSE,
UPDATE_STATUS); // update status info
imp_psf = new ImagePlus(filePaths[fileNum][0][1], stack);
if (DEBUG_LEVEL>2) {
imp_psf.getProcessor().resetMinAndMax(); // imp_psf will be reused
imp_psf.show();
}
if (DEBUG_LEVEL>0) System.out.println("Saving Gaussian kernels result to"+filePaths[fileNum][0][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(imp_psf);
fs.saveAsTiffStack(filePaths[fileNum][0][1]);
}
}
System.out.println("Processing done in "+IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+ " seconds");
if (PROCESS_PARAMETERS.saveSettings) saveProperties(PROCESS_PARAMETERS.kernelsDirectory+Prefs.getFileSeparator()+"calibration_settings",null,PROCESS_PARAMETERS.useXML, PROPERTIES);
return;
}
public void restore(boolean noAuto)
{
// boolean noAuto=label.equals("Restore no autoload");
ABERRATIONS_PARAMETERS.autoRestore=false;
String confPath=loadProperties(null,PROCESS_PARAMETERS.kernelsDirectory,PROCESS_PARAMETERS.useXML, PROPERTIES);
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (ABERRATIONS_PARAMETERS.autoRestore && !noAuto){
if (DEBUG_LEVEL>0)System.out.println("Auto-loading configuration files");
if (LENS_DISTORTIONS==null) {
LENS_DISTORTIONS=new Distortions(LENS_DISTORTION_PARAMETERS,PATTERN_PARAMETERS,REFINE_PARAMETERS,this.SYNC_COMMAND.stopRequested);
}
LENS_DISTORTIONS.debugLevel=DEBUG_LEVEL;
boolean dcdUpdated=autoLoadFiles(
ABERRATIONS_PARAMETERS,
LENS_DISTORTIONS, // should be initialized, after update DISTORTION_CALIBRATION_DATA from this
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS, //EyesisCameraParameters eyesisCameraParameters,
UPDATE_STATUS,
DEBUG_LEVEL
);
if (dcdUpdated) DISTORTION_CALIBRATION_DATA=LENS_DISTORTIONS.fittingStrategy.distortionCalibrationData;
if (ABERRATIONS_PARAMETERS.autoReCalibrate){
if (LENS_DISTORTIONS.fittingStrategy==null) {
IJ.showMessage("Can not recalibrate grids - LENS_DISTORTION.fittingStrategy is not set");
return;
}
if (DEBUG_LEVEL>0)System.out.println("=== Re-calibrating grids ===");
int numMatched=LENS_DISTORTIONS.applyHintedGrids(
LASER_POINTERS, // MatchSimulatedPattern.LaserPointer laserPointer, // LaserPointer object that specifies actual laser poiners on the target
DISTORTION_PROCESS_CONFIGURATION.removeOutOfGridPointers, // boolean removeOutOfGridPointers,
5.0, //double hintGridTolerance, // alllowed mismatch (fraction of period) or 0 - orientation only
true, //boolean processAll, // if true - process all images, false - only disabeld
false, //?
false, //processBlind,
-1, // imageNumber,
true, // useSetData - use imageSets data if available (false - use camera data)
THREADS_MAX, //int threadsMax,
UPDATE_STATUS, // boolean updateStatus,
DISTORTION.loop_debug_level, // int mspDebugLevel,
MASTER_DEBUG_LEVEL, //int global_debug_level, // DEBUG_LEVEL
MASTER_DEBUG_LEVEL //int debug_level // debug level used inside loops
);
System.out.println("Number of matched images: "+numMatched);
LENS_DISTORTIONS.debugLevel=DEBUG_LEVEL;
LENS_DISTORTIONS.updateStatus=UPDATE_STATUS;
LENS_DISTORTIONS.fittingStrategy.debugLevel=DEBUG_LEVEL;
LENS_DISTORTIONS.markBadNodces(
-1,// series - all images
DEBUG_LEVEL);
}
if ((LENS_DISTORTIONS.fittingStrategy != null) && ABERRATIONS_PARAMETERS.autoFilter) { // trying to fix restore
if (DEBUG_LEVEL>0) System.out.println("LENS_DISTORTIONS.fittingStrategy != null -> Extra after loading");
int minGridsNoPointer=1000;
int [] numImages=DISTORTION_CALIBRATION_DATA.filterImages(
false, // resetHinted,
0, // 2, // minPointers,
0.4, // minGridPeriod,
true, // disableNoVignetting,
minGridsNoPointer); //minGridsNoPointer);
System.out.println("Number of enabled grid images: "+numImages[0]+
", of them new: "+numImages[1]+
", disabled without vignetting info: "+numImages[2]+
", disabled having less than "+minGridsNoPointer+" nodes and no matched pointers: "+numImages[3]+
", disabled with no lasers and enableNoLaser==false (like 2 bottom cameras - check all stations):" +numImages[4]);
if (DISTORTION_CALIBRATION_DATA.gIS==null) {
int numImageSets=DISTORTION_CALIBRATION_DATA.buildImageSets(false); // from scratch
if (DEBUG_LEVEL>0) System.out.println("Image set was empty, built a new one with "+numImageSets+" image sets (\"panoramas\"): ");
DISTORTION_CALIBRATION_DATA.updateSetOrientation(null); // restore orientation from (enabled) image files
if (DEBUG_LEVEL>0) System.out.println("Setting sets orientation from per-grid image data");
}
}
restoreFocusingHistory(false);
}
return;
}
public void viewCSVFile(){
String [] extensions={".csv","CSV"};
CalibrationFileManagement.MultipleExtensionsFileFilter parFilter = new CalibrationFileManagement.MultipleExtensionsFileFilter("",extensions,"CSV table *.csv files");
......@@ -14819,6 +14968,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
boolean select_ABERRATIONS_PARAMETERS=!select;
boolean select_FOCUSING_FIELD=!select;
boolean select_POWER_CONTROL=!select;
boolean select_LWIR=!select;
if (select) {
GenericDialog gd = new GenericDialog("Select parameters to save");
gd.addMessage("===== Individual parameters ======");
......@@ -14859,6 +15009,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
gd.addCheckbox("ABERRATIONS_PARAMETERS",select_ABERRATIONS_PARAMETERS);
gd.addCheckbox("FOCUSING_FIELD",select_FOCUSING_FIELD);
gd.addCheckbox("POWER_CONTROL",select_POWER_CONTROL);
gd.addCheckbox("LWIR",select_LWIR);
WindowTools.addScrollBars(gd);
gd.showDialog();
......@@ -14900,6 +15051,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
select_ABERRATIONS_PARAMETERS=gd.getNextBoolean();
select_FOCUSING_FIELD=gd.getNextBoolean();
select_POWER_CONTROL=gd.getNextBoolean();
select_LWIR=gd.getNextBoolean();
}
if (select_MASTER_DEBUG_LEVEL) properties.setProperty("MASTER_DEBUG_LEVEL", MASTER_DEBUG_LEVEL+"");
......@@ -14939,6 +15091,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
if (select_ABERRATIONS_PARAMETERS) ABERRATIONS_PARAMETERS.setProperties("ABERRATIONS_PARAMETERS.", properties);
if ((select_FOCUSING_FIELD) && (FOCUSING_FIELD!=null)) FOCUSING_FIELD.setProperties("FOCUSING_FIELD.", properties);
if (select_POWER_CONTROL) POWER_CONTROL.setProperties("POWER_CONTROL.", properties);
if (select_LWIR) LWIR_PARAMETERS.setProperties("LWIR.", properties);
if (select) properties.remove("selected");
}
......@@ -14981,6 +15134,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
ABERRATIONS_PARAMETERS.getProperties("ABERRATIONS_PARAMETERS.", properties);
if (FOCUSING_FIELD!=null) FOCUSING_FIELD.getProperties("FOCUSING_FIELD.", properties,false); // false -> overwrite distortions center
POWER_CONTROL.getProperties("POWER_CONTROL.", properties);
LWIR_PARAMETERS.getProperties("LWIR.", properties);
}
private String selectSourceDirectory(String defaultPath) {
......@@ -3,13 +3,13 @@ package com.elphel.imagej.calibration;
** -----------------------------------------------------------------------------**
** Goniometer.java
**
** Measurements in the "goniometer" machine
**
** Measurements in the "goniometer" machine
**
**
** Copyright (C) 2010 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
**
** Goniometer.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
......@@ -29,12 +29,10 @@ package com.elphel.imagej.calibration;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.CamerasInterface;
import com.elphel.imagej.calibration.CalibrationHardwareInterface.GoniometerMotors;
import com.elphel.imagej.calibration.SimulationPattern.SimulParameters;
import com.elphel.imagej.cameras.EyesisCameraParameters;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.lwir.LwirReader;
import ij.IJ;
import ij.ImagePlus;
......@@ -53,6 +51,7 @@ horizontal axis:
// for
// debugging
public CalibrationHardwareInterface.CamerasInterface cameras = null;
LwirReader lwirReader = null;
// public CalibrationHardwareInterface.LaserPointers lasers = null;
// public static CalibrationHardwareInterface.FocusingMotors motorsS=null;
// public DistortionProcessConfiguration
......@@ -81,7 +80,6 @@ horizontal axis:
public Goniometer(CalibrationHardwareInterface.CamerasInterface cameras,
MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
// MatchSimulatedPattern.DistortionParameters distortion,
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
EyesisCameraParameters eyesisCameraParameters,
MatchSimulatedPattern.LaserPointer laserPointers,
......@@ -98,9 +96,34 @@ horizontal axis:
this.simulParametersDefault=simulParametersDefault;
this.goniometerParameters=goniometerParameters;
this.distortionProcessConfiguration=distortionProcessConfiguration;
}
public Goniometer(
LwirReader lwirReader,
// CalibrationHardwareInterface.CamerasInterface cameras,
MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
EyesisCameraParameters eyesisCameraParameters,
MatchSimulatedPattern.LaserPointer laserPointers,
SimulationPattern.SimulParameters simulParametersDefault,
Goniometer.GoniometerParameters goniometerParameters,
DistortionProcessConfiguration distortionProcessConfiguration
) {
this.lwirReader= lwirReader;
// this.cameras = cameras;
this.distortionParametersDefault = distortionParametersDefault;
// this.distortion = distortion;
this.patternDetectParameters=patternDetectParameters;
this.eyesisCameraParameters = eyesisCameraParameters;
this.laserPointers = laserPointers;
this.simulParametersDefault=simulParametersDefault;
this.goniometerParameters=goniometerParameters;
this.distortionProcessConfiguration=distortionProcessConfiguration;
}
//goniometerMotors
private enum MOT_ACT {
MOVE_SPEC,
......@@ -118,7 +141,7 @@ horizontal axis:
"Rotate to clockwise 200 degrees",
"Rotate to counter-clockwise 200 degrees",
"set current position as new home"};
public boolean manualMove(
AtomicInteger stopRequested, // 1 - stop now, 2 - when convenient
......@@ -126,7 +149,7 @@ horizontal axis:
int tiltMotor=2; // 0-1-2
int axialMotor=1; // 0-1-2
boolean needsInit=false;
int [] currentMotors=this.goniometerParameters.goniometerMotors.getCurrentPositions();
double currentTilt=currentMotors[tiltMotor]/this.goniometerParameters.goniometerMotors.stepsPerDegreeTilt;
double currentAxial=currentMotors[axialMotor]/this.goniometerParameters.goniometerMotors.stepsPerDegreeAxial;
......@@ -137,7 +160,7 @@ horizontal axis:
"Current position:\n"+
"Tilt: "+IJ.d2s(currentTilt,1)+" degrees ("+currentMotors[tiltMotor]+" steps)\n"+
"Axial: "+IJ.d2s(currentAxial,1)+" degrees ("+currentMotors[axialMotor]+" steps)\n");
GenericDialog gd = new GenericDialog("User interrupt");
gd.addRadioButtonGroup("Select action", options, 7, 1, options[0]);
......@@ -222,13 +245,15 @@ horizontal axis:
if (!OK) System.out.println("motorsMove()->false");
return true; // OK; // So will re-open dialog even after abort
}
public boolean scanAndAcquire(
double targetAngleHorizontal,
double targetAngleVertical,
AtomicInteger stopRequested, // 1 - stop now, 2 - when convenient
boolean updateStatus
){
int tiltMotor=2; // 0-1-2
int axialMotor=1; // 0-1-2
int [] motors=this.goniometerParameters.goniometerMotors.updateMotorsPosition();
......@@ -236,28 +261,28 @@ horizontal axis:
double thisAxial=motors[axialMotor]/this.goniometerParameters.goniometerMotors.stepsPerDegreeAxial;
double scanOverlapVertical=this.goniometerParameters.scanOverlapVertical;
double scanOverlapHorizontal=this.goniometerParameters.scanOverlapHorizontal;
boolean reverseAxial=(this.goniometerParameters.scanLimitAxialStart>this.goniometerParameters.scanLimitAxialEnd);
double scanLimitAxialLow= reverseAxial?this.goniometerParameters.scanLimitAxialEnd:this.goniometerParameters.scanLimitAxialStart;
double scanLimitAxialHigh= reverseAxial?this.goniometerParameters.scanLimitAxialStart:this.goniometerParameters.scanLimitAxialEnd;
double scanLimitAxialLow= reverseAxial?this.goniometerParameters.scanLimitAxialEnd:this.goniometerParameters.scanLimitAxialStart;
double scanLimitAxialHigh= reverseAxial?this.goniometerParameters.scanLimitAxialStart:this.goniometerParameters.scanLimitAxialEnd;
boolean zenithToNadir=this.goniometerParameters.scanLatitudeHigh<this.goniometerParameters.scanLatitudeLow;
double scanLatitudeHigh=zenithToNadir? this.goniometerParameters.scanLatitudeLow: this.goniometerParameters.scanLatitudeHigh;
double scanLatitudeLow= zenithToNadir? this.goniometerParameters.scanLatitudeHigh:this.goniometerParameters.scanLatitudeLow;
double scanStepTilt= targetAngleVertical* (1.0-scanOverlapVertical);
double scanStepAxial=targetAngleHorizontal*(1.0-scanOverlapHorizontal); // valid at equator
if (this.debugLevel>1) System.out.println("scanStepTilt="+IJ.d2s(scanStepTilt,2)+", scanStepAxial="+IJ.d2s(scanStepAxial,2));
int numTiltSteps=(int) Math.ceil((scanLatitudeHigh-scanLatitudeLow)/scanStepTilt); // includes first and last
if (numTiltSteps>0){ // increase vertical overlap to make it same for all images
scanStepTilt=(scanLatitudeHigh-scanLatitudeLow)/numTiltSteps;
scanOverlapVertical=1.0-(scanStepTilt/targetAngleVertical);
}
if (this.debugLevel>1) System.out.println("Updated scanStepTilt="+IJ.d2s(scanStepTilt,2)+", scanOverlapVertical="+IJ.d2s(scanOverlapVertical,2));
double [] tilts=new double [numTiltSteps];
double [][] rots= new double [numTiltSteps][];
......@@ -276,11 +301,10 @@ horizontal axis:
double cosMinAbsTilt=Math.cos(minAbsTilt*Math.PI/180.0);
if (this.debugLevel>2) System.out.println("tilt="+IJ.d2s(tilt,2)+"tiltL="+IJ.d2s(tiltL,2)+", tiltH="+IJ.d2s(tiltH,2)+
", minAbsTilt="+IJ.d2s(minAbsTilt,2)+", cosMinAbsTilt="+IJ.d2s(cosMinAbsTilt,2));
// double axialRange=
double scanStep=scanStepAxial;
double overlap=scanOverlapHorizontal;
int numAxialSteps=(int) Math.ceil((scanLimitAxialHigh-scanLimitAxialLow)*cosMinAbsTilt/scanStepAxial);
// Correction for bottom rollers that block view - if tilt is above 60degrees (positive - looking higher). The clear angle is ~36%
if (tilts[i]>this.bottomRollerTilt){
int numForRollers=(int) Math.ceil((scanLimitAxialHigh-scanLimitAxialLow)/(this.bottomRollersClearance*(1.0-scanOverlapHorizontal)));
......@@ -292,12 +316,10 @@ horizontal axis:
numAxialSteps=numForRollers;
}
}
// spread evenly
if (numAxialSteps>0){ // increase vertical overlap to make it same for all images
// scanStep=(scanLimitAxialHigh-scanLimitAxialLow)*cosMinAbsTilt/numAxialSteps;
// overlap=1.0-(scanStep/targetAngleHorizontal);
scanStep=(scanLimitAxialHigh-scanLimitAxialLow)/numAxialSteps;
overlap=1.0-(scanStep*cosMinAbsTilt/targetAngleHorizontal);
}
......@@ -322,14 +344,8 @@ horizontal axis:
System.out.println();
}
}
// return true;
// motorsSimultaneous
// show current tilt/axial
// double absTiltRange=Math.abs(this.goniometerParameters.scanLimitTiltStart-this.goniometerParameters.scanLimitTiltStart);
GenericDialog gd = new GenericDialog("Start scanning");
// this.serialNumber, // camera serial number string
gd.addMessage("About to start scanning and recording images, parameters are set in the \"Configure Goniometer\" dialog");
gd.addMessage("Please make sure goniometer motors are set that 0,0 corresponds to the camera in the initial position -");
gd.addMessage("vertical and cables are not entangled, camera exposure is set correctly.");
......@@ -343,7 +359,7 @@ horizontal axis:
if (this.lastScanStep>=0){
gd.addMessage("Last scan finished at stop "+this.lastScanStep);
if (this.lastScanStep<(numStops-1)) startStep= this.lastScanStep+1;
}
gd.addMessage("");
gd.addMessage("Current position is:");
......@@ -364,7 +380,7 @@ horizontal axis:
}
// overwrite some distortionProcessConfiguration parameters (show, save, ...?) from GoniometerParameters
this.distortionProcessConfiguration.sourceDirectory=src_dir;
// just for now - setting motor debug 1 higher than this
// just for now - setting motor debug 1 higher than this
this.goniometerParameters.goniometerMotors.debugLevel=this.debugLevel+1;
long startTime = System.nanoTime();
String status;
......@@ -389,7 +405,6 @@ horizontal axis:
if (this.debugLevel>0) System.out.println(status);
if (updateStatus) IJ.showStatus(status);
this.goniometerParameters.motorsSimultaneous=false; // not yet implemented
// if (!this.goniometerParameters.motorsSimultaneous){
OK= this.goniometerParameters.goniometerMotors.moveMotorSetETA(tiltMotor, tiltMotorPosition);
if (!OK) {
String msg="Could not set motor "+(tiltMotor+1)+" to move to "+tiltMotorPosition+" - may be out of limit";
......@@ -432,11 +447,20 @@ horizontal axis:
return false;
}
// update motor positions in the image properties, acquire and save images.
// TODO: Make acquisition/decoding/laser identification multi-threaded
this.cameras.setMotorsPosition(this.goniometerParameters.goniometerMotors.getTargetPositions()); // Used target, not current to prevent minor variations
this.cameras.reportTiming=debugTiming;
// TODO: Make acquisition/decoding/laser identification multi-threaded
if (cameras != null) {
this.cameras.setMotorsPosition(this.goniometerParameters.goniometerMotors.getTargetPositions()); // Used target, not current to prevent minor variations
this.cameras.reportTiming=debugTiming;
this.cameras.acquire(this.distortionProcessConfiguration.sourceDirectory,true, updateStatus); // true - use lasers, updateStatus - make false?
} else if (lwirReader != null) {
this.lwirReader.setMotorsPosition(this.goniometerParameters.goniometerMotors.getTargetPositions()); // Used target, not current to prevent minor variations
this.lwirReader.reportTiming=debugTiming;
this.lwirReader.acquire(this.distortionProcessConfiguration.sourceDirectory); // true - use lasers, updateStatus - make false?
} else {
System.out.println("Neignter traditional camera/rig, no LWIR rig are initialized, dry run");
}
this.cameras.acquire(this.distortionProcessConfiguration.sourceDirectory,true, updateStatus); // true - use lasers, updateStatus - make false?
this.lastScanStep++;
if (stopRequested.get()>1){
if (this.debugLevel>0) System.out.println("User interrupt");
......@@ -523,7 +547,7 @@ horizontal axis:
return true;
}
public boolean testHintedTarget (
ImagePlus[] images,
Distortions lensDistortions, // should not be null
......@@ -551,7 +575,7 @@ horizontal axis:
// String imgTitle=images[nImg].getTitle();
pointersArray[nImg]=0;
if (images[nImg].getProperty("POINTERS")!=null) pointersArray[nImg]=Integer.parseInt((String) (images[nImg].getProperty("POINTERS")));
choices[index]=index+" sub-camera:"+subCam+" "+images[nImg].getTitle()+" - "+pointersArray[nImg]+" pointers";
// if (this.debugLevel>1)System.out.println ("Adding image, nImg="+nImg);
// if (this.debugLevel>1)System.out.println ("Adding image "+images[nImg].getTitle()+": "+choices[index]);
......@@ -564,7 +588,7 @@ horizontal axis:
if (distortionCalibrationData.getNumStations()>1) {
gd.addNumericField("Station number (0.."+(distortionCalibrationData.getNumStations()-1)+")", stationNumber, 0);
}
gd.showDialog();
if (gd.wasCanceled()) return false;
index= gd.getNextChoiceIndex();
......@@ -576,7 +600,7 @@ horizontal axis:
}
int nImg=indices[index];
int subCam= distortionCalibrationData.getImageChannel(images[nImg]);
// int stationNumber= distortionCalibrationData.getImageStation(numGridImage), // station number
double timeStamp= distortionCalibrationData.getImageTimestamp(images[nImg]);
......@@ -600,7 +624,7 @@ horizontal axis:
IJ.showMessage("Warning",msg);
}
if ((Double.isNaN(goniometerTiltAxial[0])) || (Double.isNaN(goniometerTiltAxial[1]))) return false;
double [][][] hintGrid=lensDistortions.estimateGridOnSensor(
stationNumber, // station number
subCam,
......@@ -617,8 +641,8 @@ horizontal axis:
return false;
}
if (this.debugLevel>1) lensDistortions.showHintGrid(hintGrid);
MatchSimulatedPattern matchSimulatedPattern = new MatchSimulatedPattern(this.distortionParametersDefault.FFTSize); // new instance, all reset
// next 2 lines are not needed for the new instance, but can be
// used alternatively if keeping it
......@@ -626,8 +650,8 @@ horizontal axis:
matchSimulatedPattern.invalidateFocusMask();
matchSimulatedPattern.debugLevel = debug_level;
ImagePlus imp_eq = matchSimulatedPattern.applyFlatField(images[nImg]); // current image with grid flat-field correction
//TODO: it shows always 4 pointers (if>0) - the array is sparse
//TODO: it shows always 4 pointers (if>0) - the array is sparse
// public int getNumberOfPointers (int sensorNum){
// public int getNumberOfPointers (ImagePlus imp){
......@@ -667,11 +691,11 @@ horizontal axis:
if (debug_level > 0) System.out.println("Warning: " + msg);
if (debug_level > 2) IJ.showMessage("Warning", msg);
}
return true;
}
/*
* private showDoubleFloatArrays SDFA_INSTANCE= new showDoubleFloatArrays(); // just for debugging?
this.SDFA_INSTANCE.showArrays(gridXYZCorr, getGridWidth(), getGridHeight(), true, "Grid corrections", titles);
......@@ -684,7 +708,7 @@ horizontal axis:
(this.distortionCalibrationData.isSubcameraParameter(parIndex)?(" s"+subCam):"com "),
this.definedModes, this.definedModes[this.parameterMode[numSeries][i]]);
*
*
* this.parameterMode[numSeries][i]=gd.getNextChoiceIndex();
PatternParameters patternParameters, // should not be null
boolean equalizeGreens,
......@@ -692,7 +716,7 @@ horizontal axis:
boolean updateStatus,
int debug_level) {// debug level used inside loops
*
*
*
*/
public MatchSimulatedPattern.DistortionParameters modifyDistortionParameters(){
......@@ -715,7 +739,7 @@ horizontal axis:
distortionParameters.searchOverlap=this.goniometerParameters.searchOverlap;
return distortionParameters;
}
public SimulationPattern.SimulParameters modifySimulParameters(){
SimulationPattern.SimulParameters simulParameters = this.simulParametersDefault.clone();
simulParameters.smallestSubPix = this.goniometerParameters.smallestSubPix;
......@@ -723,7 +747,7 @@ horizontal axis:
simulParameters.subdiv = this.goniometerParameters.subdiv;
return simulParameters;
}
public double[] estimateOrientation(
ImagePlus[] images, // last acquire images with number of pointers
// detected>0
......@@ -799,8 +823,8 @@ horizontal axis:
}
this.matchSimulatedPatterns[numSensor].debugLevel = debug_level;
ImagePlus imp_eq = this.matchSimulatedPatterns[numSensor].applyFlatField(images[numSensor]); // current image with grid flat-field correction
//TODO: it shows always 4 pointers (if>0) - the array is sparse
//TODO: it shows always 4 pointers (if>0) - the array is sparse
// public int getNumberOfPointers (int sensorNum){
// public int getNumberOfPointers (ImagePlus imp){
numPointers[numSensor]=0;
......@@ -812,7 +836,7 @@ horizontal axis:
", initial number of pointers was "+numPointers[numSensor]);
}
// matchSimulatedPatterns[numSensor].getChannel(images[numSensor])+" ");
int numAbsolutePoints = this.matchSimulatedPatterns[numSensor].calculateDistortions(
// allow more of grid around pointers?
distortionParameters, //
......@@ -825,7 +849,7 @@ horizontal axis:
true, // don't care -removeOutOfGridPointers
null, // double [][][] hintGrid, // predicted grid array (or null)
0, // double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only
threadsMax,
updateStatus,
debug_level,
......@@ -906,14 +930,14 @@ horizontal axis:
distortionCalibrationData.setImages(imp_calibrated, // ImagePlus [] images, // imagesin the memory
patternParameters); // PatternParameters patternParameters);
distortionCalibrationData.initImageSet(eyesisCameraParameters);
// Set initial azimuth and elevation
// Set initial heading and elevation
double [] initialHeadEl=distortionCalibrationData.getHeadEl(imgWithMaxPointers);
// set goniometer horizontal axis angle and goniometer axial angles in all images
// set goniometer horizontal axis angle and goniometer axial angles in all images
distortionCalibrationData.setGHGA(-initialHeadEl[1], -initialHeadEl[0]);
if (debug_level > 1) System.out.println("Initial Heading and Elevation are set to heading="+IJ.d2s(-initialHeadEl[0],2)+", elvation="+IJ.d2s(-initialHeadEl[1],2));
if (debug_level > 1) System.out.println("Initial Heading and Elevation are set to heading="+IJ.d2s(-initialHeadEl[0],2)+", elvation="+IJ.d2s(-initialHeadEl[1],2));
lensDistortions.copySensorConstants(eyesisCameraParameters); // copy from the first channel
// lensDistortions.fittingStrategy will be defined later, no need to
// update it with a reference to distortionCalibrationData now
......@@ -932,19 +956,19 @@ horizontal axis:
IJ.showMessage("Error", "Failed to open fitting strategy file: "+this.goniometerParameters.strategyFile);
return null;
}
if (debug_level > 1) System.out.println("Using fitting strategy template file: "+ lensDistortions.fittingStrategy.pathName);
if (debug_level > 1) System.out.println("Using fitting strategy template file: "+ lensDistortions.fittingStrategy.pathName);
// TODO: modify fitting strategy to include all grid images
lensDistortions.fittingStrategy.adjustNumberOfImages(imp_calibrated.length);
this.goniometerParameters.strategyFile = lensDistortions.fittingStrategy.pathName;
// saved fitting strategy maybe for different number of subcameras.
// it will be adjusted here - that works only for simple strategies that use all subcameras at each step.
// TODO: fix repeating subcamera parameters for all subcameras in each strategy
lensDistortions.fittingStrategy.updateNumberOfSubcameras();
// enable azimuth adjust for all but the first camera? not here, later
// enable azimuth adjust for all but the first camera? not here, later
// Calculate Sensor Masks
distortionCalibrationData.debugLevel = debug_level;
distortionCalibrationData.updateStatus = updateStatus;
......@@ -1001,24 +1025,24 @@ horizontal axis:
public double psf_cutoffLevel= 0.2; // disregard pixels below this fraction of the maximal value
public int psf_minArea = 10; // continue increasing the selected area, even if beyound psf_cutoffEnergy and psf_cutoffLevel,
public double psf_blurSigma = 0.0; // optionally blur the calculated mask
// the following overwrite SimulParameters members
//TODO: Make initial pattern search more robust - if it first gets false positive, and number of detected cells is too low - increase threshold and re-try
//TODO: Make initial pattern search more robust - if it first gets false positive, and number of detected cells is too low - increase threshold and re-try
public double correlationMinInitialContrast=3.0; // minimal contrast for the pattern of the center (initial point)
public int minimalPatternCluster=150; // minimal pattern cluster size (0 - disable retries)
public double scaleMinimalInitialContrast=2.0; // increase/decrease minimal contrast if initial cluster is >0 but less than minimalPatternCluster
public double searchOverlap=0.25; // when searching for grid, step this amount of the FFTSize
public double smallestSubPix=0.3; // subdivide pixels down to that fraction when simulating
public double bitmapNonuniforityThreshold=0.1 ; // subdivide pixels until difference between the corners is below this value
public int subdiv=4;
public int subdiv=4;
// overwrites public static class MultiFilePSF.overexposedMaxFraction
public double overexposedMaxFraction=0.1; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
public double overexposedMaxFraction=0.1; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
// overwrites public static class PSFParameters.minDefinedArea
public double minDefinedArea=0.75; // minimal (weighted) fraction of the defined patter pixels in the FFT area
public int PSFKernelSize=32; // size of the detected PSF kernel
public boolean approximateGrid=true; // approximate grid with polynomial
public boolean approximateGrid=true; // approximate grid with polynomial
public boolean centerPSF=true; // Center PSF by modifying phase
public double mask1_sigma= 1.0;
public double mask1_threshold=0.25;
public double gaps_sigma= 1.0;
......@@ -1031,8 +1055,8 @@ horizontal axis:
public double minUVSpan; // Minimal u/v span in correlation window that triggers increase of the correlation FFT size
public boolean flatFieldCorrection=true;
public double flatFieldExpand=4.0;
public double thresholdFinish=0.001; // Stop iterations if 2 last steps had less improvement (but not worsening )
public double thresholdFinish=0.001; // Stop iterations if 2 last steps had less improvement (but not worsening )
public int numIterations= 100; // maximal number of iterations
......@@ -1044,7 +1068,7 @@ horizontal axis:
64 - pulses per revolution
5682.48889 per degree
*/
// motors rotate positive - look down, positive - CCW
// motors rotate positive - look down, positive - CCW
CalibrationHardwareInterface.GoniometerMotors goniometerMotors=null;
// public double stepsPerDegreeTilt=-5682.48889; // minus that positive steps make negative elevation
// public double stepsPerDegreeAxial=-36.0; // minus that positive steps make rotate CCW when looking from Eyesis top
......@@ -1053,26 +1077,26 @@ horizontal axis:
// public double scanLimitTiltStart= 30.0; // scan around horizontal axis from that angle
// public double scanLimitTiltEnd= -80.0; // scan around horizontal axis to that angle
public double targetDistance= 5817; //mm - foer overlap calculation
public double scanLatitudeLow=-90; // lowest camera latitude to calibrate (nadir=-90)
public double scanLatitudeHigh=90; // highest camera latitude to calibrate (zenith=90)
public double scanOverlapHorizontal= 0.5;
public double scanOverlapVertical= 0.5;
public double scanLimitAxialStart= -200.0; // scan around camera axis from that angle
public double scanLimitAxialEnd= 200.0; // scan around camera axis to that angle
public boolean scanBidirectional= true; // false - always move axial in the same direction, true - optimize movements
public boolean motorsSimultaneous= true; // true - move motors simultaneously, false - one at a time
public boolean scanBidirectional= true; // false - always move axial in the same direction, true - optimize movements
public boolean motorsSimultaneous= true; // true - move motors simultaneously, false - one at a time
public GoniometerParameters(CalibrationHardwareInterface.GoniometerMotors goniometerMotors){
this.goniometerMotors=goniometerMotors;
}
public GoniometerParameters(
CalibrationHardwareInterface.GoniometerMotors goniometerMotors,
CalibrationHardwareInterface.GoniometerMotors goniometerMotors,
String gridGeometryFile,
String initialCalibrationFile, // not needed
String strategyFile,
......@@ -1099,8 +1123,8 @@ horizontal axis:
double searchOverlap, // when searching for grid, step this amount of the FFTSize
double smallestSubPix, // subdivide pixels down to that fraction when simulating
double bitmapNonuniforityThreshold, // subdivide pixels until difference between the corners is below this value
int subdiv,
double overexposedMaxFraction, // allowed fraction of the overexposed pixels in the PSF kernel measurement area
int subdiv,
double overexposedMaxFraction, // allowed fraction of the overexposed pixels in the PSF kernel measurement area
double minDefinedArea, // minimal (weighted) fraction of the defined patter pixels in the FFT area
int PSFKernelSize,
boolean approximateGrid, // approximate grid with polynomial
......@@ -1115,7 +1139,7 @@ horizontal axis:
double minUVSpan, // Minimal u/v span in correlation window that triggers increase of the correlation FFT size
boolean flatFieldCorrection,
double flatFieldExpand,
double thresholdFinish,// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
double thresholdFinish,// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
int numIterations, // maximal number of iterations
// double stepsPerDegreeTilt, // minus that positive steps make negative elevation
// double stepsPerDegreeAxial, // minus that positive steps make rotate CCW when looking from Eyesis top
......@@ -1154,12 +1178,12 @@ horizontal axis:
this.searchOverlap=searchOverlap; // when searching for grid, step this amount of the FFTSize
this.smallestSubPix=smallestSubPix;
this.bitmapNonuniforityThreshold=bitmapNonuniforityThreshold;
this.subdiv=subdiv;
this.overexposedMaxFraction=overexposedMaxFraction;
this.subdiv=subdiv;
this.overexposedMaxFraction=overexposedMaxFraction;
this.minDefinedArea=minDefinedArea;
this.PSFKernelSize=PSFKernelSize;
this.approximateGrid = approximateGrid; // approximate grid with polynomial
this.centerPSF = centerPSF; // approximate grid with polynomial
this.centerPSF = centerPSF; // approximate grid with polynomial
this.mask1_sigma = mask1_sigma;
this.mask1_threshold = mask1_threshold;
this.gaps_sigma=gaps_sigma;
......@@ -1170,7 +1194,7 @@ horizontal axis:
this.minUVSpan=minUVSpan;
this.flatFieldCorrection=flatFieldCorrection;
this.flatFieldExpand=flatFieldExpand;
this.thresholdFinish=thresholdFinish;// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
this.thresholdFinish=thresholdFinish;// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
this.numIterations=numIterations; // maximal number of iterations
this.goniometerMotors=goniometerMotors;
// this.goniometerMotors.stepsPerDegreeTilt=stepsPerDegreeTilt; // minus that positive steps make negative elevation
......@@ -1185,7 +1209,8 @@ horizontal axis:
this.scanBidirectional=scanBidirectional;
this.motorsSimultaneous=motorsSimultaneous;
}
public GoniometerParameters clone(){
@Override
public GoniometerParameters clone(){
return new GoniometerParameters(
this.goniometerMotors,
this.gridGeometryFile,
......@@ -1213,8 +1238,8 @@ horizontal axis:
this.searchOverlap, // when searching for grid, step this amount of the FFTSize
this.smallestSubPix,
this.bitmapNonuniforityThreshold,
this.subdiv,
this.overexposedMaxFraction,
this.subdiv,
this.overexposedMaxFraction,
this.minDefinedArea,
this.PSFKernelSize,
this.approximateGrid,
......@@ -1229,7 +1254,7 @@ horizontal axis:
this.minUVSpan,
this.flatFieldCorrection,
this.flatFieldExpand,
this.thresholdFinish,
this.thresholdFinish,
this.numIterations,
this.targetDistance,
this.scanLatitudeLow,
......@@ -1290,20 +1315,20 @@ horizontal axis:
properties.setProperty(prefix+"goniometerMotors_stepsPerSecond", this.goniometerMotors.stepsPerSecond+"");
properties.setProperty(prefix+"goniometerMotors_stepsPerDegreeTilt", this.goniometerMotors.stepsPerDegreeTilt+"");
properties.setProperty(prefix+"goniometerMotors_stepsPerDegreeAxial",this.goniometerMotors.stepsPerDegreeAxial+"");
properties.setProperty(prefix+"targetDistance",this.targetDistance+"");
properties.setProperty(prefix+"scanLatitudeLow",this.scanLatitudeLow+"");
properties.setProperty(prefix+"scanLatitudeHigh",this.scanLatitudeHigh+"");
properties.setProperty(prefix+"scanOverlapHorizontal",this.scanOverlapHorizontal+"");
properties.setProperty(prefix+"scanOverlapVertical",this.scanOverlapVertical+"");
properties.setProperty(prefix+"scanLimitAxialStart",this.scanLimitAxialStart+"");
properties.setProperty(prefix+"scanLimitAxialEnd",this.scanLimitAxialEnd+"");
properties.setProperty(prefix+"scanBidirectional",this.scanBidirectional+"");
properties.setProperty(prefix+"motorsSimultaneous",this.motorsSimultaneous+"");
}
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"gridGeometryFile")!=null)
this.gridGeometryFile=properties.getProperty(prefix+"gridGeometryFile");
......@@ -1316,7 +1341,7 @@ horizontal axis:
if (properties.getProperty(prefix+"serialNumber")!=null)
this.serialNumber=properties.getProperty(prefix+"serialNumber");
// this.serialNumber is only written, but never read from the configuration file (only from device)
if (properties.getProperty(prefix+"sensorTemperature")!=null) this.sensorTemperature=Double.parseDouble(properties.getProperty(prefix+"sensorTemperature"));
else this.sensorTemperature=Double.NaN;
if (properties.getProperty(prefix+"EEPROM_channel")!=null)
......@@ -1327,7 +1352,7 @@ horizontal axis:
this.showResults=Boolean.parseBoolean(properties.getProperty(prefix+"showResults"));
if (properties.getProperty(prefix+"comment")!=null)
this.comment=properties.getProperty(prefix+"comment");
if ((this.comment.length()>10) && this.comment.substring(0,9).equals("<![CDATA[")) this.comment=this.comment.substring(9,this.comment.length()-3);
if ((this.comment.length()>10) && this.comment.substring(0,9).equals("<![CDATA[")) this.comment=this.comment.substring(9,this.comment.length()-3);
if (properties.getProperty(prefix+"maxCorr")!=null)
this.maxCorr=Double.parseDouble(properties.getProperty(prefix+"maxCorr"));
if (properties.getProperty(prefix+"showHistoryDetails")!=null)
......@@ -1402,7 +1427,7 @@ horizontal axis:
this.goniometerMotors.stepsPerDegreeTilt=Double.parseDouble(properties.getProperty(prefix+"goniometerMotors_stepsPerDegreeTilt"));
if (properties.getProperty(prefix+"goniometerMotors_stepsPerDegreeAxial")!=null)
this.goniometerMotors.stepsPerDegreeAxial=Double.parseDouble(properties.getProperty(prefix+"goniometerMotors_stepsPerDegreeAxial"));
if (properties.getProperty(prefix+"targetDistance")!=null)
this.targetDistance=Double.parseDouble(properties.getProperty(prefix+"targetDistance"));
if (properties.getProperty(prefix+"scanLatitudeLow")!=null)
......@@ -1421,9 +1446,9 @@ horizontal axis:
this.scanBidirectional=Boolean.parseBoolean(properties.getProperty(prefix+"scanBidirectional"));
if (properties.getProperty(prefix+"motorsSimultaneous")!=null)
this.motorsSimultaneous=Boolean.parseBoolean(properties.getProperty(prefix+"motorsSimultaneous"));
}
public boolean showDialog(String title) {
}
public boolean showDialog(String title) {
GenericDialog gd = new GenericDialog(title);
// this.serialNumber, // camera serial number string
gd.addMessage("Sensor board serial number is "+(((this.serialNumber==null)||(this.serialNumber==""))?"not specified":this.serialNumber));
......@@ -1453,7 +1478,7 @@ horizontal axis:
gd.addNumericField("Smallest fraction to subdivide pixels at simulation", this.smallestSubPix, 3,5,"sensor pix");
gd.addNumericField("Maximal difference of the pattern value in the corners that triggers subdivision", this.bitmapNonuniforityThreshold, 3);
gd.addNumericField("Subdivide simulated pattern by:", this.subdiv, 0);
gd.addNumericField("Allowed overexposed pixels (fraction of the area) ",this.overexposedMaxFraction,3); // 0.005; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
gd.addNumericField("Allowed overexposed pixels (fraction of the area) ",this.overexposedMaxFraction,3); // 0.005; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
gd.addNumericField("Min fraction of the FFT square (weighted) to have defined pattern", this.minDefinedArea, 3);
gd.addNumericField ("PSF kernel size", this.PSFKernelSize, 0);
gd.addCheckbox ("Approximate pattern grid with a polynomial",this.approximateGrid); // true; // ignore lateral chromatic aberration (center OTF to 0,0)
......@@ -1470,19 +1495,19 @@ horizontal axis:
gd.addNumericField("Expand during extrapolation (relative to the average grid period)", this.flatFieldExpand, 3);
gd.addNumericField("Threshold RMS to exit LMA", this.thresholdFinish, 7,9,"pix");
gd.addNumericField("Maximal number of LMA iterations per series",this.numIterations, 0);
gd.addMessage("Parameters for scanning/acquisition");
gd.addMessage("Parameters for scanning/acquisition");
gd.addStringField ("Goniometer motors IP address", this.goniometerMotors.ipAddress,40);
gd.addNumericField("Motors rotation speed ", this.goniometerMotors.stepsPerSecond,6,12,"steps/second");
gd.addNumericField("Motor steps per tilt angular degree (currently negative) ",this.goniometerMotors.stepsPerDegreeTilt,6,12,"steps");
gd.addNumericField("Motor steps per axial angular degree (currently negative) ",this.goniometerMotors.stepsPerDegreeAxial,6,12,"steps");
// gd.addNumericField("Tilt scan step (not larger than)", this.scanStepTilt,2,6,"degrees");
// gd.addNumericField("Axial scan step (not larger than)", this.scanStepAxial,2,6,"degrees");
gd.addNumericField("Distance to target (for overlap calculation)", this.targetDistance,2,7,"mm");
gd.addNumericField("Horizontal overlap", 100*this.scanOverlapHorizontal,2,5,"%");
gd.addNumericField("Vertical overlap", 100*this.scanOverlapVertical,2,5,"%");
gd.addNumericField("Lowest camera view latitude to calibrate (nadir=-90)", this.scanLatitudeLow,2,6,"degrees");
......@@ -1491,10 +1516,10 @@ horizontal axis:
// gd.addNumericField("Tilt scan end angle", this.scanLimitTiltEnd,2,6,"degrees");
gd.addNumericField("Axial scan start angle", this.scanLimitAxialStart,2,6,"degrees");
gd.addNumericField("Axial scan end angle", this.scanLimitAxialEnd,2,6,"degrees");
gd.addCheckbox ("Axial scan bidirectional", this.scanBidirectional);
gd.addCheckbox ("Allow simultaneous operation of motors", this.motorsSimultaneous);
gd.addCheckbox ("Axial scan bidirectional", this.scanBidirectional);
gd.addCheckbox ("Allow simultaneous operation of motors", this.motorsSimultaneous);
if (!Double.isNaN(this.sensorTemperature)) gd.addMessage("Last measured sensor temperature is "+this.sensorTemperature+" C");
WindowTools.addScrollBars(gd);
gd.showDialog();
......@@ -1524,7 +1549,7 @@ horizontal axis:
this.smallestSubPix= gd.getNextNumber();
this.bitmapNonuniforityThreshold=gd.getNextNumber();
this.subdiv= (int) gd.getNextNumber();
this.overexposedMaxFraction= gd.getNextNumber();
this.overexposedMaxFraction= gd.getNextNumber();
this.minDefinedArea= gd.getNextNumber();
this.PSFKernelSize= (int) gd.getNextNumber();
this.approximateGrid= gd.getNextBoolean();
......
......@@ -4873,10 +4873,10 @@ private Panel panel1,
if (LWIR_READER == null) {
LWIR_READER = new LwirReader(CLT_PARAMETERS.lwir);
}
ImagePlus [] imps = LWIR_READER.acquire();
ImagePlus [] imps = LWIR_READER.acquire("/data_ssd/imagej-elphel/attic/camera_img/test"); // directory to save
if (imps != null) {
for (ImagePlus imp: imps) {
imp.show();
// imp.show();
}
}
......
......@@ -26,6 +26,7 @@
*/
package com.elphel.imagej.lwir;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Properties;
......@@ -40,9 +41,13 @@ import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.elphel.imagej.readers.ImagejJp4Tiff;
import com.elphel.imagej.readers.ImagejJp4TiffMulti;
import ij.IJ;
import ij.ImagePlus;
import ij.Prefs;
import ij.io.FileSaver;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import loci.formats.FormatException;
......@@ -68,7 +73,7 @@ public class LwirReader {
public static final int LWIR_HEIGHT = 120;
public static final int LWIR_TELEMETRY_LINES = 2;
public static final int FRAMES_SKIP = 3;
public static final int FRAMES_SKIP = 4;
public static final int MAX_THREADS = 100; // combine from all classes?
/** Logger for this class. */
......@@ -82,6 +87,10 @@ public class LwirReader {
private LwirReaderParameters lwirReaderParameters = null;
private LwirReaderParameters last_programmed = null;
private int [] motorsPosition = null;
public boolean reportTiming=false;
// -- constructors
public LwirReader() {
......@@ -99,6 +108,15 @@ public class LwirReader {
}
public void setMotorsPosition (int [] position) {
this.motorsPosition=position;
}
public int [] getMotorsPosition() {
return this.motorsPosition; // may be null
}
// TODO: create
public boolean reSyncNeeded() {
return out_of_sync;
......@@ -220,6 +238,10 @@ public class LwirReader {
imps_avg[chn].setProperty(key, properties0.getProperty(key));
}
imps_avg[chn].setProperty("average", ""+num_frames);
if (motorsPosition!=null) for (int m=0;m<motorsPosition.length;m++ ) {
imps_avg[chn].setProperty("MOTOR"+(m+1), ""+motorsPosition[m]);
}
ImagejJp4Tiff.encodeProperiesToInfo(imps_avg[chn]);
// TODO: Overwrite some properties?
}
......@@ -333,10 +355,12 @@ public class LwirReader {
for (int c : lrp.lwir_channels) {
channels |= 1 << c;
}
String hex_chan = String.format("%x", channels);
String hex_chan = String.format("0x%x", channels);
String url = "http://"+lrp.lwir_ip+"/parsedit.php?immediate&sensor_port="+chn+
"&SENSOR_REGS67=0!"+hex_chan;
// String url = "http://"+lrp.lwir_ip+"/parsedit.php?immediate&sensor_port="+chn+
// "&SENSOR_REGS67=0&*SENSOR_REGS67="+hex_chan;
Document dom=null;
LOGGER.warn("calibrate(): Perform calibration (instead of 15 frames), url="+url);
try {
......@@ -415,12 +439,12 @@ public class LwirReader {
return true;
}
public ImagePlus [] acquire() {
return acquire(lwirReaderParameters);
public ImagePlus [] acquire(String dirpath) {
return acquire(lwirReaderParameters, dirpath);
}
public ImagePlus [] acquire(LwirReaderParameters lrp) {
public ImagePlus [] acquire(LwirReaderParameters lrp, String dirpath) {
if (!condProgramLWIRCamera(lrp)) {
LOGGER.error("acquire(): failed to program cameras");
return null;
......@@ -439,6 +463,20 @@ public class LwirReader {
return null;
}
LOGGER.debug("LWIR_ACQUIRE: got "+imps.length+" image sets");
// Verify fresh FFC for all channels
double [] after_ffc = new double [lrp.lwir_channels.length];
for (int chn = 0; chn < after_ffc.length; chn++) {
double uptime = Double.NaN, ffctime = Double.NaN;
try {
uptime = Double.parseDouble(((String) imps[0][chn].getProperty("TLM_UPTIME")));
ffctime = Double.parseDouble(((String) imps[0][chn].getProperty("TLM_FFC_TIME")));
after_ffc[chn] = uptime-ffctime;
} catch (Exception e) {
LOGGER.warn("acquire(): TLM_UPTIME and/or TLM_FFC_TIME properties are not available for"+imps[0][chn].getTitle());
}
LOGGER.warn(String.format("LWIR channel %d time from FFC: %.3f", chn, after_ffc[chn]));
}
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;
......@@ -464,6 +502,27 @@ public class LwirReader {
}
}
ImagePlus [] imps_avg = averageMultiFrames(imps_sync);
if (dirpath != null) {
File f_dir = new File(dirpath);
// get series path from the first channel file title
String first_name = imps_sync[0][0].getTitle();
String set_name = first_name.substring(0, first_name.lastIndexOf('_'));
String set_path = dirpath+Prefs.getFileSeparator()+set_name;
File set_dir = new File(set_path);
set_dir.mkdirs(); // including parent
for (ImagePlus imp:imps_avg) {
String fname = imp.getTitle();
fname = fname.substring(0, fname.lastIndexOf('_')) + ".tiff"; // remove _average
FileSaver fs=new FileSaver(imp);
String path=set_path+Prefs.getFileSeparator()+fname;
IJ.showStatus("Saving "+path);
LOGGER.debug("LWIR_ACQUIRE: 'Saving "+path+ " (and other with the same timestamp)" );
fs.saveAsTiff(path);
}
}
return imps_avg;
}
......
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