Commit 52884d5b authored by Andrey Filippov's avatar Andrey Filippov

refactored, continue grid import

parent 047fdb5e
......@@ -60,6 +60,11 @@ import java.util.regex.Pattern;
// TODO: modify methods that depend on it, use class CalibrationFileManagement
import javax.swing.JFileChooser;
import com.elphel.imagej.calibration.hardware.CamerasInterface;
import com.elphel.imagej.calibration.hardware.FocusingMotors;
import com.elphel.imagej.calibration.hardware.GoniometerMotors;
import com.elphel.imagej.calibration.hardware.LaserPointersHardware;
import com.elphel.imagej.calibration.hardware.PowerControl;
import com.elphel.imagej.cameras.EyesisCameraParameters;
import com.elphel.imagej.cameras.SFEPhases;
import com.elphel.imagej.common.DoubleFHT;
......@@ -526,7 +531,7 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
{-27.5,26.5}, // bottom left
{32.5,20.5}}; // bottom right
public static MatchSimulatedPattern.LaserPointer LASER_POINTERS= new MatchSimulatedPattern.LaserPointer (
public static LaserPointer LASER_POINTERS= new LaserPointer (
1.06, // public double headLasersTilt= 1.06; // degrees, right laser lower than left laser
0.05, // minimalIntensity
1.5, // maximalIntensity
......@@ -602,15 +607,15 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
SyncCommand SYNC_COMMAND=new SyncCommand();
public float [][] SIM_ARRAY=null; // first index - 0 - main, 1 - shifted by 0.5 pixel diagonally (to extract checker greens)
public static CalibrationHardwareInterface.LaserPointers LASERS=new CalibrationHardwareInterface.LaserPointers(LASER_POINTERS);
public static CalibrationHardwareInterface.PowerControl POWER_CONTROL=new CalibrationHardwareInterface.PowerControl();
public static CalibrationHardwareInterface.CamerasInterface CAMERAS=new CalibrationHardwareInterface.CamerasInterface(26,LASERS);
public static CalibrationHardwareInterface.FocusingMotors MOTORS=new CalibrationHardwareInterface.FocusingMotors();
public static LaserPointersHardware LASERS=new LaserPointersHardware(LASER_POINTERS);
public static PowerControl POWER_CONTROL=new PowerControl();
public static CamerasInterface CAMERAS=new CamerasInterface(26,LASERS);
public static FocusingMotors MOTORS=new FocusingMotors();
public static DistortionProcessConfiguration DISTORTION_PROCESS_CONFIGURATION=new DistortionProcessConfiguration();
public static LensAdjustment.FocusMeasurementParameters FOCUS_MEASUREMENT_PARAMETERS= new LensAdjustment.FocusMeasurementParameters(MOTORS.curpos);
public static CalibrationHardwareInterface.GoniometerMotors GONIOMETER_MOTORS= new CalibrationHardwareInterface.GoniometerMotors();
public static GoniometerMotors GONIOMETER_MOTORS= new GoniometerMotors();
public static FocusingField FOCUSING_FIELD=null;
// public String FOCUSING_FIELD_HISTORY_PATH=null;
//GoniometerParameters
......@@ -618,7 +623,7 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
public static CalibrationHardwareInterface.UVLEDandLasers UV_LED_LASERS=new CalibrationHardwareInterface.UVLEDandLasers(FOCUS_MEASUREMENT_PARAMETERS);
public static UVLEDandLasers UV_LED_LASERS=new UVLEDandLasers(FOCUS_MEASUREMENT_PARAMETERS);
public static LensAdjustment LENS_ADJUSTMENT = new LensAdjustment();
......@@ -1012,7 +1017,9 @@ if (MORE_BUTTONS) {
addButton("Goniometer Move", panelLWIR,color_debug);
addButton("LWIR Goniometer", panelLWIR,color_conf_process);
addButton("LWIR grids", panelLWIR,color_process);
addButton("Import Subsystem", panelLWIR,color_configure);
addButton("Select LWIR grids", panelLWIR,color_configure);
addButton("Manual hint", panelLWIR,color_configure);
add(panelLWIR);
pack();
......@@ -2111,17 +2118,6 @@ if (MORE_BUTTONS) {
numStation--;
}
}
/*
String [] gridFiles=CalibrationFileManagement.selectFiles(false,
"Select Calibrated Grid Files",
"Select",
gridFilter,
null); // String [] defaultPaths);
if ((gridFiles==null) || (gridFiles.length==0)) {
IJ.showMessage("No files selected");
return;
}
*/
PATTERN_PARAMETERS.debugLevel=MASTER_DEBUG_LEVEL;
EYESIS_CAMERA_PARAMETERS.updateNumstations (numStations);
//if (MASTER_DEBUG_LEVEL==0) return; //TODO: Remove - just debugging
......@@ -2129,6 +2125,7 @@ if (MORE_BUTTONS) {
gridFiles,
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS,
LASER_POINTERS,
MASTER_DEBUG_LEVEL);
LENS_DISTORTIONS.initImageSet(
DISTORTION_CALIBRATION_DATA,
......@@ -2140,20 +2137,6 @@ if (MORE_BUTTONS) {
return;
}
/* ======================================================================== */
/*
if (label.equals("Use Current Images")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
LENS_DISTORTIONS=new Distortions(LENS_DISTORTION_PARAMETERS,PATTERN_PARAMETERS,REFINE_PARAMETERS);
DISTORTION_CALIBRATION_DATA=new DistortionCalibrationData(gridFiles,PATTERN_PARAMETERS,EYESIS_CAMERA_PARAMETERS);
LENS_DISTORTIONS.initImageSet(
DISTORTION_CALIBRATION_DATA,
EYESIS_CAMERA_PARAMETERS
);
return;
}
*/
/* ======================================================================== */
if (label.equals("Edit Calibration")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
......@@ -2187,6 +2170,7 @@ if (MORE_BUTTONS) {
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS,
ABERRATIONS_PARAMETERS,
LASER_POINTERS,
null); // gridImages null - use specified files
if (DISTORTION_CALIBRATION_DATA.pathName== null){ // failed to select/open the file
DISTORTION_CALIBRATION_DATA=oldDISTORTION_CALIBRATION_DATA;
......@@ -2844,7 +2828,7 @@ if (MORE_BUTTONS) {
}
LENS_DISTORTIONS.debugLevel=DEBUG_LEVEL;
LENS_DISTORTIONS.resetSensorCorrection();
LENS_DISTORTIONS.initSensorCorrection(); // set zero corerctions (to be able to save sensor correction files)
LENS_DISTORTIONS.initSensorCorrection(); // set zero corrections (to be able to save sensor correction files)
return;
}
/* ======================================================================== */
......@@ -2875,8 +2859,19 @@ if (MORE_BUTTONS) {
if (allFiles) numSensor=-1;
boolean overwriteExtrinsic=gd.getNextBoolean();
boolean overwriteDistortion=gd.getNextBoolean();
if (numSensor<0) LENS_DISTORTIONS.setDistortionFromImageStack(pathname,overwriteExtrinsic,overwriteDistortion); // requires fitting strategy to be set?
else LENS_DISTORTIONS.setDistortionFromImageStack(pathname, numSensor,true,overwriteExtrinsic,overwriteDistortion); // report missing files
if (numSensor<0) LENS_DISTORTIONS.setDistortionFromImageStack(
DISTORTION_CALIBRATION_DATA, // put null here to use FITTING_STRATEGY.distortionCalibrationData
EYESIS_CAMERA_PARAMETERS, // use null for old version - in fitting strategy instance
pathname,
overwriteExtrinsic,
overwriteDistortion); // requires fitting strategy to be set?
else LENS_DISTORTIONS.setDistortionFromImageStack(
DISTORTION_CALIBRATION_DATA, // put null here to use FITTING_STRATEGY.distortionCalibrationData
pathname,
numSensor,
true,
overwriteExtrinsic,
overwriteDistortion); // report missing files
return;
}
/* ======================================================================== */
......@@ -2980,14 +2975,16 @@ if (MORE_BUTTONS) {
boolean saveNonCalibrated=gd.getNextBoolean();
if (numSensor<0){
LENS_DISTORTIONS.saveDistortionAsImageStack(
DISTORTION_CALIBRATION_DATA, // put null here to use FITTING_STRATEGY.distortionCalibrationData
CAMERAS, // to save channel map
"sensor_calibratrion" , //String title,
"sensor_calibration" , //String title,
pathname,
saveNonCalibrated); // boolean emptyOK) if false will throw for non-calibrated sensors
} else {
LENS_DISTORTIONS.saveDistortionAsImageStack(
DISTORTION_CALIBRATION_DATA, // put null here to use FITTING_STRATEGY.distortionCalibrationData
CAMERAS, // to save channel map
"sensor_calibratrion" , //String title,
"sensor_calibration" , //String title,
pathname,
numSensor,
saveNonCalibrated); // boolean emptyOK) if false will throw for non-calibrated sensors
......@@ -3504,7 +3501,7 @@ if (MORE_BUTTONS) {
matchSimulatedPatternSet[imgCounter].invalidateFocusMask();
if (matchSimulatedPatternSet[imgCounter].getPointersXY(imp_set[imgCounter],LASER_POINTERS.laserUVMap.length)==null) { // no pointers in this image
if (MatchSimulatedPattern.getPointersXYUV(imp_set[imgCounter],LASER_POINTERS)==null) { // no pointers in this image
IJ.showMessage("Error","No laser pointers detected for image #" + imgCounter + " - they are needed for absolute grid positioning\nProcess canceled");
return;
}
......@@ -3546,6 +3543,7 @@ if (MORE_BUTTONS) {
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS, // is it null or 1?
ABERRATIONS_PARAMETERS,
LASER_POINTERS,
imp_calibrated); // gridImages null - use specified files - single image
if (DISTORTION_CALIBRATION_DATA.pathName== null){ // failed to select/open the file
DISTORTION_CALIBRATION_DATA=null;
......@@ -5019,7 +5017,11 @@ if (MORE_BUTTONS) {
FOCUS_MEASUREMENT_PARAMETERS.resetResults();
PROPERTIES=new Properties(); // reset properties
FOCUS_MEASUREMENT_PARAMETERS.manufacturingState=0; // new SFE - reset for old format
loadProperties(path, null, true, PROPERTIES);
// loadProperties(path, null, true, PROPERTIES);
PROPERTIES = readProperties( path, true, PROPERTIES);
getAllProperties(PROPERTIES);
if (DEBUG_LEVEL>0) System.out.println("Configuration parameters are restored from "+path);
if (DEBUG_LEVEL>2) System.out.println("numSFE="+numSFE+" iLens="+iLens+" iState="+iState+" sfeParameters.length="+sfeParameters.length);
if (DEBUG_LEVEL>2) System.out.println("sfeParameters["+numSFE+"].length="+sfeParameters[numSFE].length);
if (DEBUG_LEVEL>2) System.out.println("sfeParameters["+numSFE+"]["+iLens+"].length="+sfeParameters[numSFE][iLens].length);
......@@ -6260,14 +6262,10 @@ if (MORE_BUTTONS) {
// Find curernt orientation
double [] currentOrientation=GONIOMETER.estimateOrientation (
CAMERAS.getImages(1), // last acquired images with number of pointers detected>0
// DISTORTION, //MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
// GONIOMETER_PARAMETERS, //LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
// PATTERN_DETECT, //MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
// LASER_POINTERS, //MatchSimulatedPattern.LaserPointer laserPointer, // null OK
// SIMUL, //SimulationPattern.SimulParameters simulParametersDefault,
DISTORTION_CALIBRATION_DATA, // DistortionCalibrationData distortionCalibrationData,
PATTERN_PARAMETERS, //PatternParameters patternParameters, // should not be null
LENS_DISTORTIONS, //Distortions lensDistortions, // should not be null
LASER_POINTERS, // as a backup measure if data is not provided in grid files (old versions)
COMPONENTS.equalizeGreens, //boolean equalizeGreens,
THREADS_MAX, // int threadsMax,
UPDATE_STATUS, //boolean updateStatus,
......@@ -9416,14 +9414,42 @@ if (MORE_BUTTONS) {
/// POWER_CONTROL.lightsOff();
return;
}
/* ======================================================================== */
/* ======================================================================== */
if (label.equals("LWIR grids")) {
calculateLwirGrids();
return;
}
if (label.equals("Import Subsystem")) {
importSystem(null, "EYESIS_CAMERA_PARAMETERS.");
return;
}
if (label.equals("Select LWIR grids")) {
selectLwirGrids(LWIR_PARAMETERS);
return;
}
if (label.equals("Manual hint")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (LENS_DISTORTIONS==null) {
IJ.showMessage("LENS_DISTORTION is not set");
return;
}
if (LENS_DISTORTIONS.fittingStrategy==null) {
IJ.showMessage("LENS_DISTORTION.fittingStrategy is not set");
return;
}
LENS_DISTORTIONS.debugLevel=DEBUG_LEVEL;
GenericDialog gd=new GenericDialog("Select grid image to add manual hint");
gd.addNumericField("Grid Image index", 0,0);
gd.showDialog();
if (gd.wasCanceled()) return;
int numGridImage= (int) gd.getNextNumber();
LENS_DISTORTIONS.manualGridHint(numGridImage);
return;
}
/* ======================================================================== */
......@@ -9434,8 +9460,196 @@ if (MORE_BUTTONS) {
}
/* ===== Other methods ==================================================== */
public boolean selectLwirGrids(LwirReaderParameters lwirReaderParameters) {
//DistortionProcessConfiguration
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
LENS_DISTORTIONS=new Distortions(LENS_DISTORTION_PARAMETERS,PATTERN_PARAMETERS,REFINE_PARAMETERS,this.SYNC_COMMAND.stopRequested);
int min_files = 8; // use folders that have all 8 files
int lwir_chn0 = lwirReaderParameters.getLwirChn0();
int vnir_chn0 = lwirReaderParameters.getVnirChn0();
int numStations = 3;
GenericDialog gd = new GenericDialog("Setup Goniometer/Camera Stations");
gd.addMessage("Setting up calibration that includes multiple camera tripod or goniometer positions.");
gd.addMessage("File selection dialog will open for each station separateley.");
gd.addNumericField("Number of goniometer/camera stations", numStations,0);
gd.addMessage("lwir_chn0 = "+lwir_chn0);
gd.addMessage("vnir_chn0 = "+vnir_chn0);
gd.addMessage("min_files = "+min_files);
gd.showDialog();
if (gd.wasCanceled()) return false;
numStations= (int) gd.getNextNumber();
String [] grid_extensions={".tif",".tiff"};
String [] src_extensions={".tif",".tiff"};
CalibrationFileManagement.MultipleExtensionsFileFilter gridFilter =
new CalibrationFileManagement.MultipleExtensionsFileFilter("grid",grid_extensions,"Calibrated grid files");
CalibrationFileManagement.MultipleExtensionsFileFilter sourceFilter =
new CalibrationFileManagement.MultipleExtensionsFileFilter("",src_extensions,"Source calibration images");
// CalibrationFileManagement.DirectoryContentsFilter gridDirFilter =
// new CalibrationFileManagement.DirectoryContentsFilter (gridFilter, min_files, 0, null);
String [][] gridFileDirs= new String [numStations][];
String [] sourceStationDirs = new String [numStations]; // directories of the source files per station
for (int numStation=0;numStation<numStations;numStation++){
CalibrationFileManagement.DirectoryChoser dc = new CalibrationFileManagement.DirectoryChoser(
gridFilter,
min_files,
0,
null);
dc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
dc.setMultiSelectionEnabled(true);
dc.setDialogTitle("Select Calibrated Grid File Directories for Station "+numStation+ "("+(numStation+1)+" of "+numStations+")");
dc.setApproveButtonText("Select");
File cur_dir = new File(DISTORTION_PROCESS_CONFIGURATION.gridDirectory);
if (cur_dir != null) {
cur_dir = cur_dir.getParentFile();
}
dc.setCurrentDirectory(cur_dir);
int returnVal = dc.showOpenDialog(IJ.getInstance());
if (returnVal!=JFileChooser.APPROVE_OPTION) return false;
File [] files = dc.getSelectedFiles();
if (files.length<1) return false;
// Can not make it work correctly with multiple selection, giving up for now
ArrayList<File> filelist = new ArrayList<File>();
for (int nFile=0;nFile<files.length;nFile++) {
int num_match = files[nFile].list(gridFilter).length;
if (num_match >= min_files) {
filelist.add(files[nFile]);
}
}
gridFileDirs[numStation]=new String[filelist.size()];
for (int nFile=0;nFile<gridFileDirs[numStation].length;nFile++) {
gridFileDirs[numStation][nFile]= filelist.get(nFile).getPath();
}
if ((gridFileDirs[numStation]==null) || (gridFileDirs[numStation].length==0)) {
if (!IJ.showMessageWithCancel("No files selected","Retry? (Cancel will abort the command)")) return false;
numStation--;
}
}
//sourceDirectory
for (int numStation=0;numStation<numStations;numStation++){
File cur_dir = new File(DISTORTION_PROCESS_CONFIGURATION.sourceDirectory);
if (cur_dir != null) {
cur_dir = cur_dir.getParentFile();
}
sourceStationDirs[numStation] = CalibrationFileManagement.selectDirectory(
false, // boolean save,
("Station "+numStation+ "("+(numStation+1)+" of "+numStations+"): "+"Select source directory (if available, OK to cancel)"), // String title,
("Select source directory "+ (numStation+1)), // String button,
null, // FileFilter filter,
cur_dir.getPath()); // String defaultPath);
}
PATTERN_PARAMETERS.debugLevel=MASTER_DEBUG_LEVEL;
EYESIS_CAMERA_PARAMETERS.updateNumstations (numStations);
DISTORTION_CALIBRATION_DATA=new DistortionCalibrationData( // new way for LWIR - initialize form dirs
gridFileDirs,
sourceStationDirs,
gridFilter,
sourceFilter,
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS,
LASER_POINTERS, //LaserPointer laserPointers
true, // boolean read_grids
MASTER_DEBUG_LEVEL);
if (MASTER_DEBUG_LEVEL <100) return true;
// patterns are not yet read here!
/*
PATTERN_PARAMETERS.debugLevel=MASTER_DEBUG_LEVEL;
EYESIS_CAMERA_PARAMETERS.updateNumstations (numStations);
//if (MASTER_DEBUG_LEVEL==0) return; //TODO: Remove - just debugging
DISTORTION_CALIBRATION_DATA=new DistortionCalibrationData(
gridFileDirs,
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS,
MASTER_DEBUG_LEVEL);
*/
LENS_DISTORTIONS.initImageSet(
DISTORTION_CALIBRATION_DATA,
EYESIS_CAMERA_PARAMETERS
);
// set initial orientation of the cameras from the sensors that see mpst of the matching pointers
// just for the LMA to start
DISTORTION_CALIBRATION_DATA.setInitialOrientation(true);
return true;
}
/* ======================================================================== */
/*
if (label.equals("Select Grid Files")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
LENS_DISTORTIONS=new Distortions(LENS_DISTORTION_PARAMETERS,PATTERN_PARAMETERS,REFINE_PARAMETERS,this.SYNC_COMMAND.stopRequested);
String [] extensions={".tif",".tiff"};
CalibrationFileManagement.MultipleExtensionsFileFilter gridFilter =
new CalibrationFileManagement.MultipleExtensionsFileFilter("grid",extensions,"Calibrated grid files");
GenericDialog gd = new GenericDialog("Setup Goniometer/Camera Stations");
gd.addMessage("Setting up calibration that includes multiple camera tripod or goniometer positions.");
gd.addMessage("File selection dialog will open for each station separateley.");
gd.addNumericField("Number of goniometer/camera stations", 1,0);
gd.showDialog();
if (gd.wasCanceled()) return;
int numStations= (int) gd.getNextNumber();
String [][] gridFiles= new String [numStations][];
for (int numStation=0;numStation<numStations;numStation++){
gridFiles[numStation]=CalibrationFileManagement.selectFiles(false,
"Select Calibrated Grid Files for Station "+numStation+ "("+(numStation+1)+" of "+numStations+")",
"Select",
gridFilter,
null); // String [] defaultPaths);
if ((gridFiles[numStation]==null) || (gridFiles[numStation].length==0)) {
if (!IJ.showMessageWithCancel("No files selected","Retry? (Cancel will abort the command)")) return;
numStation--;
}
}
PATTERN_PARAMETERS.debugLevel=MASTER_DEBUG_LEVEL;
EYESIS_CAMERA_PARAMETERS.updateNumstations (numStations);
//if (MASTER_DEBUG_LEVEL==0) return; //TODO: Remove - just debugging
DISTORTION_CALIBRATION_DATA=new DistortionCalibrationData(
gridFiles,
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS,
MASTER_DEBUG_LEVEL);
LENS_DISTORTIONS.initImageSet(
DISTORTION_CALIBRATION_DATA,
EYESIS_CAMERA_PARAMETERS
);
// set initial orientation of the cameras from the sensors that see mpst of the matching pointers
// just for the LMA to start
DISTORTION_CALIBRATION_DATA.setInitialOrientation(true);
return;
}
*/
/* ======================================================================== */
// Add subcamera to the current system as a subsystem
public boolean importSystem(String path, String prefix) { // use null to ask
path = readPropertiesPath(
path,
PROCESS_PARAMETERS.kernelsDirectory,
PROCESS_PARAMETERS.useXML); // PROPERTIES,
if (path == null) return false;
Properties properties = readProperties(
path,
PROCESS_PARAMETERS.useXML,
null); // Properties properties
return EYESIS_CAMERA_PARAMETERS.importSystem(
properties,
prefix,
null,
LENS_DISTORTIONS,
DISTORTION_CALIBRATION_DATA, // may be null, then it will not be updated, obviously (sensor masks)
ABERRATIONS_PARAMETERS.calibrationDirectory);//String calibration_directory
//getProperties(String prefix,Properties properties)
//EyesisCameraParameters
}
/* ======================================================================== */
public void calculateLwirGrids() {
long startTime=System.nanoTime();
......@@ -9611,15 +9825,13 @@ if (MORE_BUTTONS) {
imp_sel=new ImagePlus(sourceFilesList[numFile]); // read source file
JP4_INSTANCE.decodeProperiesFromInfo(imp_sel);
matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize); // TODO: is it needed each time?
if (!DISTORTION_PROCESS_CONFIGURATION.useNoPonters && (matchSimulatedPattern.getPointersXY(imp_sel,LASER_POINTERS.laserUVMap.length)==null)) {
if (!DISTORTION_PROCESS_CONFIGURATION.useNoPonters && (MatchSimulatedPattern.getPointersXYUV(imp_sel,LASER_POINTERS)==null)) {
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
continue; // no pointers in this image
}
// /getPointersXY(ImagePlus imp, int numPointers){ if
// calculate distortion grid for it
matchSimulatedPattern.invalidateFlatFieldForGrid(); //Reset Flat Field calibration - different image.
matchSimulatedPattern.invalidateFocusMask();
......@@ -9943,8 +10155,13 @@ if (MORE_BUTTONS) {
{
// boolean noAuto=label.equals("Restore no autoload");
ABERRATIONS_PARAMETERS.autoRestore=false;
String confPath=loadProperties(null,PROCESS_PARAMETERS.kernelsDirectory,PROCESS_PARAMETERS.useXML, PROPERTIES);
// String confPath=loadProperties(null,PROCESS_PARAMETERS.kernelsDirectory, PROCESS_PARAMETERS.useXML, PROPERTIES);
String confPath = readPropertiesPath(null, PROCESS_PARAMETERS.kernelsDirectory,PROCESS_PARAMETERS.useXML);
PROPERTIES = readProperties( confPath, true, PROPERTIES);
getAllProperties(PROPERTIES);
if (DEBUG_LEVEL>0) System.out.println("Configuration parameters are restored from " + confPath);
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
EyesisAberrations.AberrationParameters dbg_eap = ABERRATIONS_PARAMETERS;
if (ABERRATIONS_PARAMETERS.autoRestore && !noAuto){
if (DEBUG_LEVEL>0)System.out.println("Auto-loading configuration files");
if (LENS_DISTORTIONS==null) {
......@@ -9956,6 +10173,7 @@ if (MORE_BUTTONS) {
LENS_DISTORTIONS, // should be initialized, after update DISTORTION_CALIBRATION_DATA from this
PATTERN_PARAMETERS,
EYESIS_CAMERA_PARAMETERS, //EyesisCameraParameters eyesisCameraParameters,
LASER_POINTERS,
UPDATE_STATUS,
DEBUG_LEVEL
);
......@@ -10754,7 +10972,11 @@ if (MORE_BUTTONS) {
index=i;
}
String configPath=fileList[index].getAbsolutePath();
loadProperties(configPath, null, true, PROPERTIES);
// loadProperties(configPath, null, true, PROPERTIES);
PROPERTIES = readProperties( configPath, true, PROPERTIES);
getAllProperties(PROPERTIES);
if (DEBUG_LEVEL>0) System.out.println("Configuration parameters are restored from " + configPath);
restoreFocusingHistory(false);
return true;
}
......@@ -10765,6 +10987,7 @@ if (MORE_BUTTONS) {
Distortions distortions, // should be initialized, after update DISTORTION_CALIBRATION_DATA from this
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers,
boolean updateStstus,
int debugLevel
){
......@@ -10776,20 +10999,24 @@ if (MORE_BUTTONS) {
if (configPaths[0]==null) return false;
System.out.println("+++++++++++ autoLoadFiles() eyesisCameraParameters.numStations="+eyesisCameraParameters.numStations+
" +eyesisCameraParameters.goniometerHorizontal.length="+eyesisCameraParameters.goniometerHorizontal.length);
DistortionCalibrationData dcd=new DistortionCalibrationData(
DistortionCalibrationData dcd=new DistortionCalibrationData( // reads all grids
true,
configPaths[0],
patternParameters,
eyesisCameraParameters,
aberrationParameters,
laserPointers,
null); // gridImages null - use specified files
if (distortions.fittingStrategy!=null) {
distortions.fittingStrategy.distortionCalibrationData=dcd;
} else if (configPaths[1]==null) return false; // fitting strategy was null ind is not specified
} else if (configPaths[1]==null) return false; // fitting strategy was null and is not specified
if ((dcd.eyesisCameraParameters == null) || (dcd.eyesisCameraParameters.goniometerHorizontal == null)) {
System.out.println("+++++++++++ autoLoadFiles(): got null");
} else {
System.out.println("+++++++++++ autoLoadFiles() dcd.eyesisCameraParameters.numStations="+dcd.eyesisCameraParameters.numStations+
" +dcd.eyesisCameraParameters.goniometerHorizontal.length="+dcd.eyesisCameraParameters.goniometerHorizontal.length);
}
if (configPaths[1]!=null) {
FittingStrategy fs=distortions.fittingStrategy; // save old value
......@@ -10812,9 +11039,11 @@ if (MORE_BUTTONS) {
patternParameters.selectAndRestore(true,configPaths[2],dcd.eyesisCameraParameters.numStations); // returns path or null on failure
}
if ((configPaths[3] !=null) && (configPaths[3] != "")){ // load sensor
if (distortions.fittingStrategy==null) return false;
if (distortions.fittingStrategy==null) return false; // Why?
if (DEBUG_LEVEL>0) System.out.println("Autoloading sensor calibration files "+configPaths[3]);
distortions.setDistortionFromImageStack(
dcd,
EYESIS_CAMERA_PARAMETERS, // use null for old version - in fitting strategy instance
configPaths[3],
aberrationParameters.autoRestoreSensorOverwriteOrientation,
aberrationParameters.autoRestoreSensorOverwriteDistortion
......@@ -10834,7 +11063,7 @@ if (MORE_BUTTONS) {
public void getAndSaveImage(
boolean alwaysShow, // true overwrites focusMeasurementParameters.showResults
boolean alwaysSave, // true overwrites focusMeasurementParameters.saveResults
CalibrationHardwareInterface.CamerasInterface camerasInterface,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
boolean updateStatus,
......@@ -10979,8 +11208,8 @@ if (MORE_BUTTONS) {
public int [] focusingCenterStepsAuto(
int numIterations, // maximal number of iterations (0 - suggest only, do not move). When calling from the button - first time single iteration, second time - as specified
double focusTolerance, // will exit after whatever comes first tolearance or number of iterations
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -11081,8 +11310,8 @@ if (MORE_BUTTONS) {
}
public int [] focusingStepsAuto(
int numIterations, // maximal number of iterations (0 - suggest only, do not move). When calling from the button - first time single iteration, second time - as specified
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -11271,8 +11500,8 @@ if (MORE_BUTTONS) {
public int [] focusingStepsAutoOld(
int numIterations, // maximal number of iterations (0 - suggest only, do not move). When calling from the button - first time single iteration, second time - as specified
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -11479,8 +11708,8 @@ if (MORE_BUTTONS) {
public int [] fineFocusingStepsAuto(
int numIterations, // maximal number of iterations (0 - suggest only, do not move). When calling from the button - first time single iteration, second time - as specified
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -11589,8 +11818,8 @@ if (MORE_BUTTONS) {
public int [] preFocusingStepsAuto(
int numIterations, // maximal number of iterations (0 - suggest only, do not move). When calling from the button - first time single iteration, second time - as specified
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -11662,8 +11891,8 @@ if (MORE_BUTTONS) {
public double[] ScanFocusTilt(
// boolean scanHysteresis, // after scanning forward, go in reverse (different number of steps to measure hysteresis
int [] centerMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -11994,8 +12223,8 @@ if (MORE_BUTTONS) {
public double[] ScanFocus(
// boolean scanHysteresis, // after scanning forward, go in reverse (different number of steps to measure hysteresis
int [] centerMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -12124,8 +12353,8 @@ if (MORE_BUTTONS) {
public boolean moveAndMaybeProbe(
boolean justMove, // just move, no probing around
int [] newMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -12165,8 +12394,8 @@ if (MORE_BUTTONS) {
boolean noHysteresis,
boolean justMove, // just move, no probing around
int [] newMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -12331,8 +12560,8 @@ if (MORE_BUTTONS) {
boolean noHysteresis,
boolean justMove, // just move, no probing around
int [] newMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -12429,8 +12658,8 @@ if (MORE_BUTTONS) {
public void moveMeasureAndSave(
boolean noHysteresis,
int [] newMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -12601,8 +12830,8 @@ if (MORE_BUTTONS) {
public boolean moveAndMeasureSharpness(
int [] newMotorPos, // null OK
CalibrationHardwareInterface.FocusingMotors focusingMotors,
CalibrationHardwareInterface.CamerasInterface camerasInterface,
FocusingMotors focusingMotors,
CamerasInterface camerasInterface,
LensDistortionParameters lensDistortionParameters,
MatchSimulatedPattern matchSimulatedPattern, // should not bee null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
......@@ -13161,156 +13390,6 @@ Reff=sqrt(1/sqrt(Ar*Br-(Cr/2)^2))
}
//returns number of matched laser pointers
/*
public int updateFocusGrid(
double x0, // lens center on the sensor
double y0, // lens center on the sensor
ImagePlus imp,
MatchSimulatedPattern matchSimulatedPattern,
MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
MatchSimulatedPattern.LaserPointer laserPointer, // null OK
SimulationPattern.SimulParameters simulParametersDefault,
boolean maskNonPSF, // mask out areas not needed for focusing PSF measurements
boolean equalizeGreens,
int threadsMax,
boolean updateStatus,
int debug_level){// debug level used inside loops
long startTime=System.nanoTime();
SimulationPattern.SimulParameters simulParameters=simulParametersDefault.clone();
simulParameters.smallestSubPix= focusMeasurementParameters.smallestSubPix;
simulParameters.bitmapNonuniforityThreshold=focusMeasurementParameters.bitmapNonuniforityThreshold;
simulParameters.subdiv= focusMeasurementParameters.subdiv;
MatchSimulatedPattern.DistortionParameters distortionParameters= distortionParametersDefault.clone();
distortionParameters.refineInPlace=false;
distortionParameters.correlationMaxOffset=focusMeasurementParameters.maxCorr;
distortionParameters.correlationSize=focusMeasurementParameters.correlationSize;
distortionParameters.correlationGaussWidth=focusMeasurementParameters.correlationGaussWidth;
distortionParameters.refineCorrelations=false;
distortionParameters.fastCorrelationOnFirstPass=true;
distortionParameters.fastCorrelationOnFinalPass=true;
distortionParameters.correlationAverageOnRefine=false;
distortionParameters.minUVSpan=focusMeasurementParameters.minUVSpan;
distortionParameters.flatFieldCorrection=focusMeasurementParameters.flatFieldCorrection;
distortionParameters.flatFieldExpand=focusMeasurementParameters.flatFieldExpand;
if (maskNonPSF) {
distortionParameters.numberExtrapolated=0; //1; //3; // measuring PSF - extrapolate
} else {
distortionParameters.numberExtrapolated=1; // measuring distortions - do not extrapolate
}
//System.out.println("distortionParameters.correlationSize="+distortionParameters.correlationSize);
// add more overwrites
boolean updating=(matchSimulatedPattern.PATTERN_GRID!=null) &&
(!distortionParameters.flatFieldCorrection || (matchSimulatedPattern.flatFieldForGrid!=null));
ImagePlus imp_eq=matchSimulatedPattern.applyFlatField (imp); // will throw if image size mismatch
if (updating) {
double maxActualCorr= matchSimulatedPattern.refineDistortionCorrelation (
distortionParameters, //
patternDetectParameters,
simulParameters,
equalizeGreens,
imp_eq, // if grid is flat-field calibrated, apply it
focusMeasurementParameters.maxCorr, // maximal allowed correction, in pixels (0.0) - any
threadsMax,
updateStatus,
debug_level);// debug level used inside loops
matchSimulatedPattern.recalculateWaveVectors (
updateStatus,
debug_level);// debug level used inside loops
if (debug_level>1) System.out.println("refineDistortionCorrelation() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
//Bad: NaN (no cells), maxActualCorr<0 -number of new empty nodes, >focusMeasurementParameters.maxCorr - also bad (no correction)
if (!((maxActualCorr>=0) && (maxActualCorr<=focusMeasurementParameters.maxCorr))) {
if (debug_level>0) System.out.println("updateFocusGrid() failed, refineDistortionCorrelation() ->"+maxActualCorr+ " (maxCorr="+focusMeasurementParameters.maxCorr+")");
// Do full
updating=false;
} else {
if (debug_level>1) System.out.println("updateFocusGrid() ->"+maxActualCorr+ " (maxCorr="+focusMeasurementParameters.maxCorr+")");
}
}
int numAbsolutePoints=0;
if (updating) {
// add new nodes if the appeared after shift of the pattern
if (debug_level>1) { // calulate/print number of defined nodes in the grid
System.out.println("updateFocusGrid(), number of defined grid cells (before distortions()) = "+matchSimulatedPattern.numDefinedCells());
}
matchSimulatedPattern.distortions(
distortionParameters, //
patternDetectParameters,
simulParameters,
equalizeGreens,
imp_eq, // image to process
threadsMax,
updateStatus,
debug_level);// debug level used inside loops
if (debug_level>1) System.out.println("distortions() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
matchSimulatedPattern.recalculateWaveVectors (
updateStatus,
debug_level);// debug level used inside loops
if (debug_level>1) System.out.println("recalculateWaveVectors() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
if (debug_level>1) { // calulate/print number of defined nodes ina grid
System.out.println("updateFocusGrid(), number of defined grid cells (after distortions()) = "+matchSimulatedPattern.numDefinedCells());
}
} else {
// matchSimulatedPattern.invalidateFlatFieldForGrid(); //Keep these!
// matchSimulatedPattern.invalidateFocusMask();
numAbsolutePoints=matchSimulatedPattern.calculateDistortions( // allow more of grid around pointers?
distortionParameters, //
patternDetectParameters,
simulParameters,
equalizeGreens,
imp_eq,
laserPointer, //null, //LASER_POINTERS, // LaserPointer laserPointer, // LaserPointer object or null
true, // don't care -removeOutOfGridPointers
threadsMax,
updateStatus,
DEBUG_LEVEL,
distortionParameters.loop_debug_level); // debug level
}
if (maskNonPSF) {
matchSimulatedPattern.maskFocus(
x0, // lens center on the sensor
y0, // lens center on the sensor
focusMeasurementParameters);
if (debug_level>1) System.out.println("maskFocus() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
if (debug_level>1) { // calulate/print number of defined nodes ina grid
System.out.println("number of defined grid cells (after maskFocus()) = "+matchSimulatedPattern.numDefinedCells());
}
if(debug_level>2) {
double [] test_masked=new double [matchSimulatedPattern.focusMask.length];
float [] pixels_eq=(float []) imp_eq.getProcessor().getPixels();
for (int i=0;i<test_masked.length;i++) test_masked[i]=matchSimulatedPattern.focusMask[i]?pixels_eq[i]:0.0;
SDFA_INSTANCE.showArrays(test_masked,matchSimulatedPattern.getImageWidth(), matchSimulatedPattern.getImageHeight(), "MASKED");
}
}
if (debug_level>1) System.out.println("updateFocusGrid() finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
if (debug_level>2) {
double [] test_uv=new double [matchSimulatedPattern.UV_INDEX.length];
for (int i=0;i<matchSimulatedPattern.UV_INDEX.length;i++) test_uv[i]=matchSimulatedPattern.UV_INDEX[i];
SDFA_INSTANCE.showArrays(test_uv,matchSimulatedPattern.getImageWidth(), matchSimulatedPattern.getImageHeight(), "UV_INDEX");
}
return numAbsolutePoints;
}
*/
//====================================================
public double [][][] pixToAngles(
double [][][] pXYArray,
......@@ -15039,7 +15118,77 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
if (DEBUG_LEVEL>0) System.out.println("Configuration parameters are saved to "+path);
}
/* ======================================================================== */
public String readPropertiesPath(
String path,
String directory,
boolean useXML){
String [] XMLPatterns= {".conf-xml",".xml"};
String [] confPatterns={".conf"};
String [] patterns=useXML?XMLPatterns:confPatterns;
if (path==null) {
path= CalibrationFileManagement.selectFile(false, // save
"Configuration file selection", // title
"Read configuration file", // button
new CalibrationFileManagement.MultipleExtensionsFileFilter(patterns,(useXML?"XML ":"")+"Configuration files ("+(useXML?"*.conf-xml":"*.conf")+")"), // filter
directory); // may be ""
} else {
// do not add extension if it already exists
if ((path.length()<patterns[0].length()) || (!path.substring(path.length()-patterns[0].length()).equals(patterns[0]))){
path+=patterns[0];
}
}
return path;
}
/* ======================================================================== */
public Properties readProperties(
String path,
boolean useXML,
Properties properties){
if (properties != null) {
setAllProperties(properties); // Setting properties from current parameters so missing (in the file) parameters will not cause an error
} else {
properties = new Properties();
}
InputStream is;
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
IJ.showMessage("Error","Failed to open configuration file: "+path);
return null;
}
if (useXML) {
try {
properties.loadFromXML(is);
} catch (IOException e) {
IJ.showMessage("Error","Failed to read XML configuration file: "+path);
return null;
}
} else {
try {
properties.load(is);
} catch (IOException e) {
IJ.showMessage("Error","Failed to read configuration file: "+path);
return null;
}
}
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return properties;
}
/* ======================================================================== */
/*
public String loadProperties(
String path,
String directory,
......@@ -15061,7 +15210,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
path+=patterns[0];
}
}
if (path==null) return path;
if ((path==null) || (properties == null))return path;
InputStream is;
try {
is = new FileInputStream(path);
......@@ -15097,6 +15246,7 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
return path;
}
*/
/* ======================================================================== */
public void setAllProperties(Properties properties){
boolean select= (properties.getProperty("selected")!=null);
......@@ -248,5 +248,104 @@ public class CalibrationFileManagement {
return description;
}
}
// select directory that contains matching MultipleExtensionsFileFilter in specified min/max quantities
//https://stackoverflow.com/questions/22302199/java-filefilter-to-select-certain-directories
// public static class DirectoryContentsFilter extends FileFilter implements FilenameFilter {
public static class DirectoryChoser extends javax.swing.JFileChooser {
private static final long serialVersionUID = 390855361964415146L;
protected MultipleExtensionsFileFilter multipleExtensionsFileFilter;
protected int min_files;
protected int max_files;
protected String description;
public DirectoryChoser (
MultipleExtensionsFileFilter multipleExtensionsFileFilter,
int min_files,
int max_files,
String description) // may be null;
{
this.multipleExtensionsFileFilter= multipleExtensionsFileFilter;
this.min_files = min_files;
this.max_files = max_files;
this.description = description;
}
@Override
public boolean isDirectorySelectionEnabled() {
// setOpenButtonState(this, false);
File file = getSelectedFile();
// File [] files = getSelectedFiles();
if(file == null){
// setOpenButtonState(this, true);
return true; // false;
}
// setOpenButtonState(this, false);
if (!file.isDirectory()) return false;
/*
// Can not make it work correctly with multiple selection, giving up for now
// get a list of all matching files
int num_match = file.list(multipleExtensionsFileFilter).length;
if (num_match < min_files) return false;
if ((max_files > 0) && (num_match > max_files)) {
return false;
}
*/
setOpenButtonState(this, true);
return true;
}
private void setOpenButtonState(java.awt.Container c, boolean flag) {
int len = c.getComponentCount();
for (int i = 0; i < len; i++) {
java.awt.Component comp = c.getComponent(i);
if (comp instanceof javax.swing.JButton) {
javax.swing.JButton b = (javax.swing.JButton)comp;
if ( b != null && b.getText() != null && b.getText().equals("Select") ) {
b.setEnabled(flag);
}
} else if (comp instanceof java.awt.Container) {
setOpenButtonState((java.awt.Container) comp, flag);
}
}
}
/*
@Override
public boolean accept (File file) {
if (!file.isDirectory()) return false;
// get a list of all matching files
int num_match = file.list(multipleExtensionsFileFilter).length;
if (num_match < min_files) return false;
if ((max_files > 0) && (num_match > max_files)) return false;
return true;
}
@Override
public boolean accept (File dir, String name) {
// No name filter, need to resolve
// Path dir_path = dir.toPath();
File target = Paths.get(dir.toString(),name).toFile();
return accept(target);
}
@Override
public String getDescription() { // if description is null - generate it
if (description == null) {
description = "Directories containing";
if (min_files > 0) description +=" not less than "+min_files;
if (max_files > 0) description +=" not more than "+max_files;
description += " "+multipleExtensionsFileFilter.description;
}
return description;
}
*/
}
}
......@@ -29,6 +29,8 @@ import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.configuration.ConfigurationException;
......@@ -54,31 +56,26 @@ import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import ij.text.TextWindow;
//import EyesisCameraParameters;
//import Distortions.EyesisSubCameraParameters;
//import LensDistortionParameters;
//import PatternParameters;
//import DistortionCalibrationData.GridImageParameters;
//import DistortionCalibrationData.GridImageSet;
// stores per pattern image camera/subcamera parameters, filenames, ...
// saves / restores them from a disk file
public class DistortionCalibrationData{
public static final int INDEX_PX = 0;
public static final int INDEX_PY = 1;
public static final int INDEX_U = 2;
public static final int INDEX_V = 3;
public static final int INDEX_CONTRAST = 4;
public static final int INDEX_R = 5;
public static final int INDEX_G = 6;
public static final int INDEX_B = 7;
public String pathName=null;
public EyesisCameraParameters eyesisCameraParameters; // has "cartesian"
// public int numStations=1; // number of differnt camera tripod/goniometer stations (locations)
public int numSubCameras=1;
public int numPointers=4; // maximal number of pointers to look for
public int numMotors =3; // maximal number of motors to look for
public GridImageParameters [] gIP= null; // per-grid image parameters
public GridImageSet [] gIS= null; // sets of images with the same timestamp
// public String [] paths=null;
// private ImagePlus [] gridImages=null; // array of grid images (to be used instead of files)
// public double [] timestamps=null;
// public int [] channels=null;
// keep for now?
public double [][] pars=null; // for each defined image: set of (22) parameters
// public double [][][] pixelsXY=null; // for each image, each grid node - a pair of {px,py}
// public int [][][] pixelsUV=null; // for each image, each grid node - a pair of {gridU, gridV}
public double [][] sensorMasks= null; // per-channel (not image) mask
//pixelsXY, pixelsUV should match, second dimension is variable
......@@ -95,7 +92,10 @@ import ij.text.TextWindow;
GridImageSet gridImageSet=null;
public int stationNumber=0; // changes when camera/goniometer is moved to new position
public String path=null;
public String source_path = null; // Full path of the source image this grid was calculated from
public double [][] laserPixelCoordinates=null; // first index - absolute number of pointer. Each element may be either null or {x,y} pair
// moving for new files to have laser UV contained in the file
public double [][] laserUVCoordinates=null; // first index - absolute number of pointer. Each element may be either null or {u,v} pair
public int matchedPointers=0;
public int hintedMatch=-1; // -1 - not tried, 0 - no real grid (i.e. double reflection), applied orientation, applied orientation and shift
public boolean enabled=true; //false; // to mask out some images from all strategy steps (i.e w/o reliable absolute calibration)
......@@ -590,19 +590,22 @@ import ij.text.TextWindow;
public DistortionCalibrationData (
String [] filenames,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers
) {
String [][] stationFilenames={filenames};
setupDistortionCalibrationData(
stationFilenames,
patternParameters,
eyesisCameraParameters // debugLevel
eyesisCameraParameters, // debugLevel
laserPointers
);
}
public DistortionCalibrationData (
String [] filenames,
PatternParameters patternParameters,
String [] filenames,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers,
int debugLevel
) {
this.debugLevel=debugLevel;
......@@ -610,7 +613,8 @@ import ij.text.TextWindow;
setupDistortionCalibrationData(
stationFilenames,
patternParameters,
eyesisCameraParameters // debugLevel
eyesisCameraParameters, // debugLevel
laserPointers
);
}
......@@ -618,20 +622,48 @@ import ij.text.TextWindow;
String [][] stationFilenames,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers,
int debugLevel
) {
this.debugLevel=debugLevel;
setupDistortionCalibrationData(
stationFilenames,
patternParameters,
eyesisCameraParameters // debugLevel
eyesisCameraParameters, // debugLevel
laserPointers
);
}
public void setupDistortionCalibrationData (
public DistortionCalibrationData (
String [][] stationFilenames,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters
String [] source_dirs, // directories of the source files per station
CalibrationFileManagement.MultipleExtensionsFileFilter gridFilter,
CalibrationFileManagement.MultipleExtensionsFileFilter sourceFilter,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers, // as a backup if data is not available in the file
boolean read_grids,
int debugLevel
) {
this.debugLevel=debugLevel;
setupDirDistortionCalibrationData(
stationFilenames,
source_dirs, // directories of the source files per station
gridFilter,
sourceFilter,
patternParameters,
eyesisCameraParameters, // debugLevel
laserPointers, // as a backup if data is not available in the file
read_grids
);
}
public void setupDistortionCalibrationData (
String [][] stationFilenames,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers // as a backup if data is not available in the file
) {
setupIndices();
this.eyesisCameraParameters=eyesisCameraParameters;
......@@ -683,11 +715,324 @@ import ij.text.TextWindow;
initPars (this.gIP.length,parameterDescriptions.length);
if (this.debugLevel>1) System.out.println("setupDistortionCalibrationData(): Resetting this.gIS");
this.gIS=null; // so it will be initialized in readAllGrids()
readAllGrids(patternParameters); // prepare grid parameters for LMA
readAllGrids(
patternParameters,
laserPointers); // prepare grid parameters for LMA
// no orientation
}
// from data organized as image sets
public void setupDirDistortionCalibrationData (
String [][] stationFilenames, // per-station List of image set directories
String [] source_dirs, // directories of the source files per station
CalibrationFileManagement.MultipleExtensionsFileFilter gridFilter,
CalibrationFileManagement.MultipleExtensionsFileFilter sourceFilter,
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers, // as a backup if data is not available in the file
boolean read_grids
) {
class DirTs{
int station;
String [] paths;
String [] spaths; // can be null
// String dir;
double ts;
int getStation() {return station;}
// String getDir() {return dir;}
double getTs() {return ts;}
String [] getPaths() {return paths;}
String [] getSourcePaths() {return spaths;} // may not be null
DirTs(int station,
String dir, // grid image set directory that contains channel files (may be different timestamps)
String sdir, // source super directory that contains image set directories with files
int num_chn,
CalibrationFileManagement.MultipleExtensionsFileFilter gridFilter,
CalibrationFileManagement.MultipleExtensionsFileFilter sourceFilter)
{
this.station = station;
// this.dir = dir;
int dot_index = dir.lastIndexOf("_");
String digits = "0123456789";
int ts_start = dot_index -1;
while ((ts_start >=0) && (digits.indexOf(dir.charAt(ts_start)) >= 0)) ts_start--;
this.ts = Double.parseDouble(dir.substring(ts_start + 1).replace('_','.'));
String [] files = (new File(dir)).list(gridFilter); // are these full files?
paths = new String[num_chn];
for (String path:files) {
int last_dash = path.lastIndexOf('-');
int last = path.lastIndexOf('_');
if (last_dash >last) last = last_dash;
int last_dot = path.lastIndexOf('.');
if (last_dot < 0) {
last_dot = path.length();
}
int chn = Integer.parseInt(path.substring(last+1, last_dot));
paths[chn] = (new File(dir,path)).getPath();
//grid-elphelimg_1559195695_507621_4.tiff
}
spaths = new String[num_chn];
if (sdir != null) {
// consruct source image set directory name
String set_name = (new File(dir)).getName();
File set_dir = new File(sdir, set_name );
String [] sfiles = set_dir.list(sourceFilter);
for (String spath:sfiles) {
int last_dash = spath.lastIndexOf('-');
int last = spath.lastIndexOf('_');
if (last_dash >last) last = last_dash;
int last_dot = spath.lastIndexOf('.');
if (last_dot < 0) {
last_dot = spath.length();
}
int chn = Integer.parseInt(spath.substring(last+1, last_dot));
spaths[chn] = (new File(set_dir,spath)).getPath();
}
}
}
}
setupIndices();
this.eyesisCameraParameters=eyesisCameraParameters;
int numSubCameras=(eyesisCameraParameters==null)?1:eyesisCameraParameters.eyesisSubCameras[0].length;
this.numSubCameras=numSubCameras;
this.eyesisCameraParameters.numStations=stationFilenames.length;
// int numFiles=0;
// DirTs [][] dirTs = new DirTs [stationFilenames.length][];
ArrayList<DirTs> dirTsList = new ArrayList<DirTs>();
for (int numStation=0;numStation<stationFilenames.length;numStation++){
for (int is = 0; is < stationFilenames[numStation].length; is++) {
dirTsList.add(new DirTs(
numStation,
stationFilenames[numStation][is], // String dir,
source_dirs[numStation],
numSubCameras, // int num_chn,
gridFilter,
sourceFilter));
}
}
// sort list
Collections.sort(dirTsList, new Comparator<DirTs>() {
@Override
public int compare(DirTs lhs, DirTs rhs) {
return rhs.ts > lhs.ts ? -1 : (rhs.ts < lhs.ts) ? 1 : 0;
}
});
int numFiles = 0;
for (DirTs dt:dirTsList) {
String [] paths = dt.getPaths();
for (String p:paths) if (p!=null) numFiles++;
}
this.gIS=new GridImageSet[dirTsList.size()];
this.gIP=new GridImageParameters[numFiles];
int numFile=0;
Opener opener=new Opener();
JP46_Reader_camera jp4_reader= new JP46_Reader_camera(false);
ImagePlus imp_grid=null;
ImageStack stack;
boolean disableNoFlatfield=false; // true only for processing transitional images - mixture of ff/ no-ff
int numOfGridNodes= 0;
int numOfGridNodes_extra= 0;
for (int nis = 0; nis<this.gIS.length; nis++) {
DirTs dt = dirTsList.get(nis);
this.gIS[nis]=new GridImageSet();
this.gIS[nis].timeStamp= dt.getTs();
this.gIS[nis].imageSet=new GridImageParameters [numSubCameras];
this.gIS[nis].setStationNumber(dt.getStation());
float [][][] set_pixels = new float [numSubCameras][][];
int [] set_widths = new int [numSubCameras];
String [] paths = dt.getPaths();
String [] spaths = dt.getSourcePaths();
int with_pointers = -1;
for (int nc = 0; nc < paths.length; nc++) {
String p = paths[nc];
boolean first_in_set = true;
if (p != null) {
this.gIP[numFile] = new GridImageParameters(numFile);
this.gIP[numFile].path = p;
this.gIP[numFile].source_path = spaths[nc];
this.gIP[numFile].setStationNumber(dt.getStation());
this.gIP[numFile].timestamp = dt.getTs();
this.gIP[numFile].channel = nc;
this.gIP[numFile].setNumber = nis;
this.gIP[numFile].gridImageSet = this.gIS[nis];
this.gIS[nis].imageSet[nc]=this.gIP[numFile];
//numFile
if (first_in_set || read_grids) {
if (read_grids) {
if (this.updateStatus) IJ.showStatus("Reading grid file "+(numFile+1)+" (of "+(numFiles)+"): "+this.gIP[numFile].path);
if (this.debugLevel>-1) System.out.print(numFile+" ("+this.gIP[numFile].getStationNumber()+
":"+this.gIP[numFile].setNumber+":"+this.gIP[numFile].channel+"): "+this.gIP[numFile].path);
}
imp_grid=opener.openImage("", this.gIP[numFile].path); // or (path+filenames[nFile])
if (imp_grid==null) {
String msg="Failed to read grid file "+this.gIP[numFile].path;
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
this.gIP[numFile].gridImage = imp_grid; // Save all images?
// TODO: here - need to decode properties
jp4_reader.decodeProperiesFromInfo(imp_grid);
this.gIP[numFile].laserPixelCoordinates = MatchSimulatedPattern.getPointersXYUV(imp_grid, laserPointers);
this.gIP[numFile].motors = getMotorPositions(imp_grid, this.numMotors);
this.gIS[nis].motors= this.gIP[numFile].motors.clone();
this.gIP[numFile].matchedPointers = getUsedPonters(imp_grid);
if (this.gIP[numFile].matchedPointers > 0) {
with_pointers = numFile;
}
double [] saturations=new double [4];
for (int i=0;i<saturations.length;i++) {
saturations[i]=Double.NaN;
if (imp_grid.getProperty("saturation_" + i) !=null) saturations[i]=Double.parseDouble((String) imp_grid.getProperty("saturation_" + i));
}
if (!Double.isNaN(saturations[1])) this.gIP[numFile].saturation[0]=saturations[1];
if (!Double.isNaN(saturations[2])) this.gIP[numFile].saturation[2]=saturations[2];
if (!Double.isNaN(saturations[0]) && !Double.isNaN(saturations[3])) {
this.gIP[numFile].saturation[1]=0.5*(saturations[0]+saturations[3]);
} else {
if (!Double.isNaN(saturations[0])) this.gIP[numFile].saturation[1]=saturations[0];
if (!Double.isNaN(saturations[3])) this.gIP[numFile].saturation[1]=saturations[3];
}
if (read_grids) {
stack=imp_grid.getStack();
if ((stack==null) || (stack.getSize()<4)) {
String msg="Expected a 8-slice stack in "+this.gIP[numFile].path;
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
float [][] pixels=new float[stack.getSize()][]; // now - 8 (x,y,u,v,contrast, vignR,vignG,vignB
set_pixels[nc] = pixels;
set_widths[nc] = imp_grid.getWidth();
for (int i=0;i<pixels.length;i++) pixels[i]= (float[]) stack.getPixels(i+1); // pixel X : negative - no grid here
int numBadNodes = 0;
if (this.eyesisCameraParameters.badNodeThreshold>0.0){
boolean thisDebug =false;
// thisDebug|= (fileNumber== 720); // chn 25
numBadNodes=fixBadGridNodes(
pixels,
stack.getWidth(),
this.eyesisCameraParameters.badNodeThreshold,
this.eyesisCameraParameters.maxBadNeighb,
this.debugLevel+(thisDebug?3:0),
thisDebug?("fixBad-"+numFile):null
);
}
this.gIP[numFile].flatFieldAvailable=pixels.length>=8;
if (disableNoFlatfield && !this.gIP[numFile].flatFieldAvailable) this.gIP[numFile].enabled=false; // just to use old mixed data
int [][] shiftRotMatrix= MatchSimulatedPattern.getRemapMatrix(this.gIP[numFile].getUVShiftRot());
int [] sizeSizeExtra=setGridsWithRemap(
numFile,
shiftRotMatrix, // int [][] reMap,
pixels,
patternParameters);
numOfGridNodes+=sizeSizeExtra[0];
numOfGridNodes_extra+=sizeSizeExtra[1];
if (this.debugLevel>-1) {
if (this.gIP[numFile].pixelsUV != null) {
System.out.print(" ["+ this.gIP[numFile].pixelsUV.length+"]");
} else {
System.out.print(" [null]");
}
if (numBadNodes>0)
System.out.print(" -- replaced "+numBadNodes+" bad grid nodes");
int [] uvrot=this.gIP[numFile].getUVShiftRot();
System.out.println(" shift:rot="+uvrot[0]+"/"+uvrot[1]+":"+uvrot[2]+
" enabled="+this.gIP[numFile].enabled+" hintedMatch="+this.gIP[numFile].hintedMatch);
}
calcGridPeriod(numFile); // will be used to filter out reflections
//System.out.println ("pixelsXY["+fileNumber+"]length="+pixelsXY[fileNumber].length);
} //if (read_grids)
// not reading the grid itself
first_in_set = false;
}
numFile++;
}
}
if (with_pointers >= 0) { // set initial grids offset from the grid files in the same image set that do not have absolute calibration
boolean [] sensor_mask = null; // later may be used to limit scope to VNIR-only
int extra_search = 1;
int base_channel = this.gIP[with_pointers].channel;
for (int nc = 0; nc < this.gIS[nis].imageSet.length; nc++) if ((sensor_mask == null) || sensor_mask[nc]) {
boolean invert_color = ((base_channel ^ nc) & 4) != 0;
if (this.gIS[nis].imageSet[nc].matchedPointers <= 0) {
int [] uv_shift_rot = correlateGrids(
set_widths[base_channel], // int base_width,
set_pixels[base_channel], // float [][] base_pixels,
set_widths[nc], // int test_width,
set_pixels[nc], // float [][] test_pixels,
invert_color,
extra_search);
this.gIS[nis].imageSet[nc].setUVShiftRot(uv_shift_rot);
int [][] shiftRotMatrix= MatchSimulatedPattern.getRemapMatrix(this.gIS[nis].imageSet[nc].getUVShiftRot());
// int [] sizeSizeExtra=
int imgNum = with_pointers - base_channel + nc;
setGridsWithRemap( // null immediately
imgNum,
shiftRotMatrix, // int [][] reMap,
set_pixels[nc],
patternParameters);
}
}
// for (this.gIS[nis]
}
//
} // for (int nis = 0; nis<this.gIS.length; nis++)
initPars (this.gIP.length,parameterDescriptions.length);
// readAllGrids(patternParameters); // prepare grid parameters for LMA
// Create parameters array
/// initPars (this.gIP.length,parameterDescriptions.length);
/// if (this.debugLevel>1) System.out.println("setupDistortionCalibrationData(): Resetting this.gIS");
/// this.gIS=null; // so it will be initialized in readAllGrids()
/// readAllGrids(patternParameters); // prepare grid parameters for LMA
// no orientation
if (read_grids) {
if (this.debugLevel>3) {
System.out.println("setupDirDistortionCalibrationData(), numFiles="+numFiles);
for (int n=0;n<this.gIP.length;n++) {
System.out.println(n+": length="+this.gIP[n].pixelsXY.length);
System.out.println("pixelsUV[][][0]/pixelsUV[][][1] pixelsXY[][][0]/pixelsXY[][][1]");
for (int i=0;i<this.gIP[n].pixelsXY.length;i++){
System.out.println(n+":"+i+" "+
this.gIP[n].pixelsUV[i][0]+"/"+
this.gIP[n].pixelsUV[1][1]+" "+
IJ.d2s(this.gIP[n].pixelsXY[i][0], 2)+"/"+
IJ.d2s(this.gIP[n].pixelsXY[i][1], 2)
);
}
}
}
if (this.debugLevel>0) {
System.out.println("setupDirDistortionCalibrationData(), numFiles="+numFiles+", total number of grid nodes="+numOfGridNodes+", unused nodes "+numOfGridNodes_extra);
}
/// buildImageSets(this.gIS!=null); // already done
// probably - do not need to verify that this.gIS is null - should do that anyway. UPDATE: no, now reading config file creates gIS
}
}
public DistortionCalibrationData (
EyesisCameraParameters eyesisCameraParameters
) {
......@@ -700,15 +1045,19 @@ import ij.text.TextWindow;
public DistortionCalibrationData (
ImagePlus [] images, // images in the memory
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters
ImagePlus [] images, // images in the memory
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
LaserPointer laserPointers
) {
setupIndices();
int numSubCameras=(eyesisCameraParameters==null)?1:eyesisCameraParameters.eyesisSubCameras[0].length;
this.numSubCameras=numSubCameras;
this.eyesisCameraParameters=eyesisCameraParameters;
setImages(images,patternParameters);
setImages(
images,
patternParameters,
laserPointers);
}
public int get_gIS_index(int numImg){
......@@ -986,7 +1335,8 @@ import ij.text.TextWindow;
public void setImages(
ImagePlus [] images, // images in the memory
PatternParameters patternParameters){
PatternParameters patternParameters,
LaserPointer laserPointers){
this.gIP=new GridImageParameters[images.length];
for (int i=0;i<images.length;i++){
this.gIP[i]=new GridImageParameters(i);
......@@ -1000,7 +1350,9 @@ import ij.text.TextWindow;
// Create parameters array
initPars (this.gIP.length,parameterDescriptions.length);
this.gIS=null; // so it will be created in readAllGrids()
readAllGrids(patternParameters); // prepare grid parameters for LMA
readAllGrids(
patternParameters, // prepare grid parameters for LMA
laserPointers); //
// no orientation
}
......@@ -1061,17 +1413,7 @@ import ij.text.TextWindow;
if (num_avg>0) dTilt = this.gIS[i].goniometerTilt - (sum_avg/num_avg);
}
// double firstHorAxisErrPhi=Double.NaN;
// double firstHorAxisErrPsi=Double.NaN;
// double firstGXYZ0= Double.NaN;
// double firstGXYZ1= Double.NaN;
// double firstGXYZ2= Double.NaN;
double firstInterAxisAngle=Double.NaN;
// firstHorAxisErrPhi=this.gIS[i].horAxisErrPhi;
// firstHorAxisErrPsi=this.gIS[i].horAxisErrPsi;
// firstGXYZ0=this.gIS[i].GXYZ[0];
// firstGXYZ1=this.gIS[i].GXYZ[1];
// firstGXYZ2=this.gIS[i].GXYZ[2];
firstInterAxisAngle = this.gIS[i].interAxisAngle;
sb.append(i+"\t"+IJ.d2s(this.gIS[i].timeStamp,6));
......@@ -1079,12 +1421,6 @@ import ij.text.TextWindow;
sb.append("\t"+(Double.isNaN(this.gIS[i].goniometerAxial)?"---":((this.gIS[i].orientationEstimated?"(":"")+IJ.d2s(axial_corr_sign,3)+(this.gIS[i].orientationEstimated?")":""))));
sb.append("\t"+(Double.isNaN(this.gIS[i].goniometerTilt)?"---":((this.gIS[i].orientationEstimated?"(":"")+IJ.d2s(this.gIS[i].goniometerTilt,3)+(this.gIS[i].orientationEstimated?")":""))));
// sb.append("\t"+(Double.isNaN(firstHorAxisErrPhi)?"---":IJ.d2s(firstHorAxisErrPhi,3)));
// sb.append("\t"+(Double.isNaN(firstHorAxisErrPsi)?"---":IJ.d2s(firstHorAxisErrPsi,3)));
// sb.append("\t"+(Double.isNaN(firstGXYZ0)?"---":IJ.d2s(firstGXYZ0,3)));
// sb.append("\t"+(Double.isNaN(firstGXYZ1)?"---":IJ.d2s(firstGXYZ1,3)));
// sb.append("\t"+(Double.isNaN(firstGXYZ2)?"---":IJ.d2s(firstGXYZ2,3)));
sb.append("\t"+(Double.isNaN(dTilt)?"---":IJ.d2s(dTilt,3)));
sb.append("\t"+(Double.isNaN(firstInterAxisAngle)?"---":IJ.d2s(firstInterAxisAngle,3)));
......@@ -1115,7 +1451,9 @@ import ij.text.TextWindow;
if (this.gIS[i].imageSet[n]!=null){
int numPointers=0; // count number of laser pointers
if (this.gIS[i].imageSet[n].laserPixelCoordinates!=null){
for (int j=0;j<this.gIS[i].imageSet[n].laserPixelCoordinates.length;j++) if (this.gIS[i].imageSet[n].laserPixelCoordinates[j]!=null) numPointers++;
for (int j=0;j<this.gIS[i].imageSet[n].laserPixelCoordinates.length;j++) {
if (this.gIS[i].imageSet[n].laserPixelCoordinates[j]!=null) numPointers++;
}
}
if (!this.gIS[i].imageSet[n].enabled) sb.append("(");
sb.append(numPointers+"("+this.gIS[i].imageSet[n].matchedPointers+"):"+this.gIS[i].imageSet[n].hintedMatch +
......@@ -1129,7 +1467,7 @@ import ij.text.TextWindow;
new TextWindow("Image calibration state (pointers/hinted state)", header, sb.toString(), 900,1400);
}
/**
* crete list of image indices per image set
* create list of image indices per image set
* @return array of image indices for each image set
*/
public int [][] listImages(boolean enabledOnly){
......@@ -1925,6 +2263,7 @@ import ij.text.TextWindow;
PatternParameters patternParameters,
EyesisCameraParameters eyesisCameraParameters,
EyesisAberrations.AberrationParameters aberrationParameters,
LaserPointer laserPointers,
ImagePlus[] gridImages ){ // null - use specified files
setupIndices();
String [] extensions={".dcal-xml","-distcal.xml"};
......@@ -1969,7 +2308,9 @@ import ij.text.TextWindow;
}
// setGridImages(gridImages);
}
readAllGrids(patternParameters); // prepare grid parameters for LMA
readAllGrids(
patternParameters, // prepare grid parameters for LMA
laserPointers);
updateSetOrientation(null); // update orientation of image sets (built in readAllGrids() UPDATE - not anymore)
}
......@@ -2049,6 +2390,7 @@ import ij.text.TextWindow;
HierarchicalConfiguration sub = hConfig.configurationAt("file("+i+")");
this.gIP[i].imgNumber=i;
this.gIP[i].path=sub.getString("name");
this.gIP[i].source_path=sub.getString("source_path");
this.gIP[i].timestamp=Double.parseDouble(sub.getString("timestamp"));
this.gIP[i].channel=Integer.parseInt(sub.getString("channel"));
if (sub.getString("stationNumber")!=null) this.gIP[i].setStationNumber(Integer.parseInt(sub.getString("stationNumber")));
......@@ -2168,6 +2510,7 @@ import ij.text.TextWindow;
hConfig.addProperty("file","");
hConfig.addProperty("file.setNumber",this.gIP[i].setNumber);
hConfig.addProperty("file.name",this.gIP[i].path);
hConfig.addProperty("file.source_path",this.gIP[i].source_path);
hConfig.addProperty("file.enabled",this.gIP[i].enabled);
hConfig.addProperty("file.hintedMatch",this.gIP[i].hintedMatch); // new
hConfig.addProperty("file.timestamp",IJ.d2s(this.gIP[i].timestamp,6));
......@@ -2251,20 +2594,16 @@ import ij.text.TextWindow;
int [][] reMap,
float [][] pixels,
PatternParameters patternParameters){
// boolean disableNoFlatfield=false; // true only for processing transitional images - mixture of ff/ no-ff
int sensorWidth=this.eyesisCameraParameters.getSensorWidth(this.gIP[fileNumber].channel);
int sensorHeight=this.eyesisCameraParameters.getSensorHeight(this.gIP[fileNumber].channel);
int station=this.gIP[fileNumber].getStationNumber();
int size=0;
int size_extra=0;
// int numOfGridNodes=0;
// int numOfGridNodes_extra=0;
for (int i=0;i<pixels[0].length;i++) if ((pixels[0][i]>=0) && (pixels[1][i]>=0) && (pixels[0][i]<sensorWidth) && (pixels[1][i]<sensorHeight)){
int u=Math.round(pixels[2][i]);
int v=Math.round(pixels[3][i]);
int u1= reMap[0][0]*u + reMap[0][1]*v + reMap[0][2]; // u
int v1= reMap[1][0]*u + reMap[1][1]*v + reMap[1][2]; // v;
// if (patternParameters.getXYZM(u,v,this.debugLevel>1)!=null) size++;
if (patternParameters.getXYZM(u1,v1,false,station)!=null) size++; // already assumes correct uv?
else size_extra++;
}
......@@ -2276,22 +2615,14 @@ import ij.text.TextWindow;
this.gIP[fileNumber].pixelsXY_extra=new double [size_extra][6];
this.gIP[fileNumber].pixelsUV_extra=new int [size_extra][2];
// numOfGridNodes+=size;
// numOfGridNodes_extra+=size_extra;
int index=0;
int index_extra=0;
// boolean vignettingAvailable=pixels.length>=8;
// this.gIP[fileNumber].flatFieldAvailable=pixels.length>=8;
// if (disableNoFlatfield && !this.gIP[fileNumber].flatFieldAvailable) this.gIP[fileNumber].enabled=false; // just to use old mixed data
for (int i=0;i<pixels[0].length;i++) if ((pixels[0][i]>=0) && (pixels[1][i]>=0) && (pixels[0][i]<sensorWidth) && (pixels[1][i]<sensorHeight)) {
int u=Math.round(pixels[2][i]);
int v=Math.round(pixels[3][i]);
int u1= reMap[0][0]*u + reMap[0][1]*v + reMap[0][2]; // u
int v1= reMap[1][0]*u + reMap[1][1]*v + reMap[1][2]; // v;
// if (patternParameters.getXYZM(u,v,this.debugLevel>1)!=null) {
if (patternParameters.getXYZM(u1,v1,false,station)!=null) {
this.gIP[fileNumber].pixelsXY[index][0]=pixels[0][i];
this.gIP[fileNumber].pixelsXY[index][1]=pixels[1][i];
......@@ -2325,12 +2656,13 @@ import ij.text.TextWindow;
}
public boolean readAllGrids(PatternParameters patternParameters){
public boolean readAllGrids(
PatternParameters patternParameters,
LaserPointer laserPointers // as a backup if data is not available in the file
){
boolean disableNoFlatfield=false; // true only for processing transitional images - mixture of ff/ no-ff
System.out.println("readAllGrids(), this.debugLevel="+this.debugLevel+" this.gIS is "+((this.gIS==null)?"null":"not null"));
int numImages=getNumImages();
// this.pixelsXY=new double[numImages][][];
// this.pixelsUV=new int[numImages][][];
Opener opener=new Opener();
JP46_Reader_camera jp4_reader= new JP46_Reader_camera(false);
ImagePlus imp_grid=null;
......@@ -2357,12 +2689,9 @@ import ij.text.TextWindow;
// TODO: here - need to decode properties
jp4_reader.decodeProperiesFromInfo(imp_grid);
}
this.gIP[fileNumber].laserPixelCoordinates=getPointersXY(imp_grid, this.numPointers);
this.gIP[fileNumber].laserPixelCoordinates=MatchSimulatedPattern.getPointersXYUV(imp_grid, laserPointers);
this.gIP[fileNumber].motors=getMotorPositions(imp_grid, this.numMotors);
this.gIP[fileNumber].matchedPointers=getUsedPonters(imp_grid);
// this.gIP[fileNumber].enabled=true; // will filter separately
// this.gIP[fileNumber].hintedMatch=-1; // unknown yet - now read from the calibration file
double [] saturations=new double [4];
for (int i=0;i<saturations.length;i++) {
saturations[i]=Double.NaN;
......@@ -2389,15 +2718,6 @@ import ij.text.TextWindow;
if (this.eyesisCameraParameters.badNodeThreshold>0.0){
boolean thisDebug =false;
// thisDebug|= (fileNumber== 720); // chn 25
// thisDebug|= (fileNumber== 793); // chn 10
// thisDebug|= (fileNumber== 895); // chn 15
// thisDebug|= (fileNumber==1359); // chn 0
// thisDebug|= (fileNumber==1029); // chn 2
// thisDebug|= (fileNumber==1081); // chn 14
// int maxBadNeighb=1; // 7 of 8 shold be good
int numBadNodes=fixBadGridNodes(
pixels,
stack.getWidth(),
......@@ -2417,13 +2737,8 @@ import ij.text.TextWindow;
this.gIP[fileNumber].flatFieldAvailable=pixels.length>=8;
if (disableNoFlatfield && !this.gIP[fileNumber].flatFieldAvailable) this.gIP[fileNumber].enabled=false; // just to use old mixed data
// start new code:
/*
this.gIP[i].UVShiftRot[0]=sub.getInt("gridShiftX", 0);
this.gIP[i].UVShiftRot[1]=sub.getInt("gridShiftY", 0);
this.gIP[i].UVShiftRot[2]=sub.getInt("gridRotate", 0);
*/
int [][] shiftRotMatrix= (new MatchSimulatedPattern()).getRemapMatrix(this.gIP[fileNumber].getUVShiftRot());
int [][] shiftRotMatrix= MatchSimulatedPattern.getRemapMatrix(this.gIP[fileNumber].getUVShiftRot());
int [] sizeSizeExtra=setGridsWithRemap(
fileNumber,
shiftRotMatrix, // int [][] reMap,
......@@ -2431,71 +2746,6 @@ import ij.text.TextWindow;
patternParameters);
numOfGridNodes+=sizeSizeExtra[0];
numOfGridNodes_extra+=sizeSizeExtra[1];
/*
int sensorWidth=this.eyesisCameraParameters.getSensorWidth(this.gIP[fileNumber].channel);
int sensorHeight=this.eyesisCameraParameters.getSensorHeight(this.gIP[fileNumber].channel);
int station=this.gIP[fileNumber].getStationNumber();
int size=0;
int size_extra=0;
for (int i=0;i<pixels[0].length;i++) if ((pixels[0][i]>=0) && (pixels[1][i]>=0) && (pixels[0][i]<sensorWidth) && (pixels[1][i]<sensorHeight)){
int u=(int) Math.round(pixels[2][i]);
int v=(int) Math.round(pixels[3][i]);
// if (patternParameters.getXYZM(u,v,this.debugLevel>1)!=null) size++;
if (patternParameters.getXYZM(u,v,false,station)!=null) size++; // already assumes correct uv?
else size_extra++;
}
this.gIP[fileNumber].resetMask();
this.gIP[fileNumber].pixelsXY=new double [size][6];
this.gIP[fileNumber].pixelsUV=new int [size][2];
this.gIP[fileNumber].pixelsXY_extra=new double [size_extra][6];
this.gIP[fileNumber].pixelsUV_extra=new int [size_extra][2];
numOfGridNodes+=size;
numOfGridNodes_extra+=size_extra;
int index=0;
int index_extra=0;
// boolean vignettingAvailable=pixels.length>=8;
// this.gIP[fileNumber].flatFieldAvailable=pixels.length>=8;
// if (disableNoFlatfield && !this.gIP[fileNumber].flatFieldAvailable) this.gIP[fileNumber].enabled=false; // just to use old mixed data
for (int i=0;i<pixels[0].length;i++) if ((pixels[0][i]>=0) && (pixels[1][i]>=0) && (pixels[0][i]<sensorWidth) && (pixels[1][i]<sensorHeight)) {
int u=(int) Math.round(pixels[2][i]);
int v=(int) Math.round(pixels[3][i]);
// if (patternParameters.getXYZM(u,v,this.debugLevel>1)!=null) {
if (patternParameters.getXYZM(u,v,false,station)!=null) {
this.gIP[fileNumber].pixelsXY[index][0]=pixels[0][i];
this.gIP[fileNumber].pixelsXY[index][1]=pixels[1][i];
this.gIP[fileNumber].pixelsUV[index][0]= u;
this.gIP[fileNumber].pixelsUV[index][1]= v;
if (this.gIP[fileNumber].flatFieldAvailable){
this.gIP[fileNumber].pixelsXY[index][2]=pixels[4][i];
for (int n=0;n<3;n++) this.gIP[fileNumber].pixelsXY[index][n+3]=pixels[n+5][i]/this.gIP[fileNumber].intensityRange[n];
} else {
for (int n=0;n<4;n++)this.gIP[fileNumber].pixelsXY[index][n+2]=1.0;
}
index++;
} else {
this.gIP[fileNumber].pixelsXY_extra[index_extra][0]=pixels[0][i];
this.gIP[fileNumber].pixelsXY_extra[index_extra][1]=pixels[1][i];
this.gIP[fileNumber].pixelsUV_extra[index_extra][0]= u;
this.gIP[fileNumber].pixelsUV_extra[index_extra][1]= v;
if (this.gIP[fileNumber].flatFieldAvailable){
this.gIP[fileNumber].pixelsXY_extra[index_extra][2]=pixels[4][i];
for (int n=0;n<3;n++){
this.gIP[fileNumber].pixelsXY_extra[index_extra][n+3]=pixels[n+5][i]/this.gIP[fileNumber].intensityRange[n];
}
} else {
for (int n=0;n<4;n++)this.gIP[fileNumber].pixelsXY_extra[index_extra][n+2]=1.0;
}
index_extra++;
}
}
*/
calcGridPeriod(fileNumber); // will be used to filter out reflections
//System.out.println ("pixelsXY["+fileNumber+"]length="+pixelsXY[fileNumber].length);
......@@ -2519,23 +2769,8 @@ import ij.text.TextWindow;
System.out.println("readAllGrids(), numImages="+numImages+", total number of grid nodes="+numOfGridNodes+", unused nodes "+numOfGridNodes_extra);
}
// probably - do not need to verify that this.gIS is null - should do that anyway. UPDATE: no, now reading config file creates gIS
/*
if (this.gIS!=null){
System.out.println("readAllGrids() 1: ");
for (int is=0;is<this.gIS.length;is++){
System.out.println("readAllGrids() 1: "+is+": tilt="+this.gIS[is].goniometerTilt+" axial="+this.gIS[is].goniometerAxial+" estimated="+this.gIS[is].orientationEstimated);
}
}
*/
buildImageSets(this.gIS!=null);
/*
if (this.gIS!=null){
System.out.println("readAllGrids() 2: ");
for (int is=0;is<this.gIS.length;is++){
System.out.println("readAllGrids() 2: "+is+": tilt="+this.gIS[is].goniometerTilt+" axial="+this.gIS[is].goniometerAxial+" estimated="+this.gIS[is].orientationEstimated);
}
}
*/
return true;
}
/**
......@@ -2806,7 +3041,7 @@ import ij.text.TextWindow;
// TODO: Move all custom image properties (including encode/decode from JP4_reader_camera) to a separate class.
// below is a duplicatie from MatchSimulatedPattern
@Deprecated
public double[][] getPointersXY(ImagePlus imp, int numPointers){
// read image info to properties (if it was not done yet - should it?
if ((imp.getProperty("timestamp")==null) || (((String) imp.getProperty("timestamp")).length()==0)) {
......@@ -3117,9 +3352,11 @@ import ij.text.TextWindow;
return this.gIP[num].timestamp;
}
public int getNumImages() {
if (this.gIP == null) return 0;
return this.gIP.length;
}
public int getNumParameters() {
if (this.parameterDescriptions == null) return 0;
return this.parameterDescriptions.length;
}
public int getNumSubCameras() {
......@@ -3634,5 +3871,84 @@ import ij.text.TextWindow;
return result;
}
// Methods related to Talon (instructor/student) systems
// calculates UV offset (no rotations) for test grid by best contrast match to known grid
// int [] correlateGrids(int base_grid_num, int test_grid_num, boolean invert_color) {
// returns
int [] correlateGrids(
int base_width,
float [][] base_pixels,
int test_width,
float [][] test_pixels,
boolean invert_color,
int extra_search) {
int base_height = base_pixels[0].length/base_width;
int test_height = test_pixels[0].length/test_width;
int search_rad = Math.max(
(Math.max(base_width, test_width)- Math.min(base_width, test_width) + 1) /2,
(Math.max(base_height, test_height)-Math.min(base_height, test_height) + 1) /2) + extra_search;
int offs_x = base_width/2 - test_width/2; // subtract from test.x
int offs_y = base_height/2 - test_height/2; // subtract from test.y
double [] corr = new double [(2*search_rad + 1)*(2*search_rad + 1)];
for (int dy = -search_rad; dy <= search_rad; dy++) {
for (int dx = -search_rad; dx <= search_rad; dx++) {
double sum = 0;
for (int y0 = 0; y0 < base_height; y0++) {
int y1 = y0 - offs_y - dy;
if ((y1 >= 0) && (y1 < test_height)) {
for (int x0 = 0; x0 < base_width; x0++) {
int x1 = x0 - offs_x - dx;
if ((x1 >= 0) && (x1 < test_width)) {
sum+= base_pixels[INDEX_CONTRAST][y0*base_width + x0] * test_pixels[INDEX_CONTRAST][y1*test_width + x1];
}
}
}
}
corr[(2*search_rad + 1)*(search_rad + dy) +(search_rad + dx)] = sum;
}
}
int [] indx_max_even_odd = {0,0};
for (int i = 1; i < corr.length; i++) {
int parity = ((i /(2*search_rad + 1)) + (i %(2*search_rad + 1))) & 1;
if (corr[indx_max_even_odd[parity]] <corr[i]) {
indx_max_even_odd[parity] = i;
}
}
// find first non-zero matching cell
int indx0=-1,indx1=-1;
int [] rslt = new int[3];
for (int parity = 0; parity < 2; parity++) {
int dy = indx_max_even_odd[parity] / (2*search_rad + 1) - search_rad;
int dx = indx_max_even_odd[parity] % (2*search_rad + 1) - search_rad;
first_nonzero:
for (int y0 = 0; y0 < base_height; y0++) {
int y1 = y0 - offs_y - dy;
if ((y1 >= 0) && (y1 < test_height)) {
for (int x0 = 0; x0 < base_width; x0++) {
int x1 = x0 - offs_x - dx;
if ((x1 >= 0) && (x1 < test_width)) {
indx0 = y0*base_width + x0;
indx1 = y1*test_width + x1;
if ((base_pixels[INDEX_CONTRAST][indx0] > 0 )&&
(test_pixels[INDEX_CONTRAST][indx1] > 0)) {
break first_nonzero;
}
}
}
}
}
// test grid with index indx1 matches base grid with indx0
rslt[0] = Math.round(base_pixels[INDEX_U][indx0] - test_pixels[INDEX_U][indx1]);
rslt[1] = Math.round(base_pixels[INDEX_V][indx0] - test_pixels[INDEX_V][indx1]);
rslt[2] = 0; // rotation
if (((rslt[0] + rslt[1] + (invert_color?1:0)) & 1) == 0) break;
}
return rslt;
}
// Set initial shifts for the grids that do not have absolute match from the one in the same set that does
// end of class DistortionCalibrationData
}
......@@ -23,6 +23,7 @@ package com.elphel.imagej.calibration;
**
*/
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.ArrayList;
......@@ -35,6 +36,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.SwingUtilities;
import com.elphel.imagej.calibration.hardware.CamerasInterface;
import com.elphel.imagej.cameras.EyesisCameraParameters;
import com.elphel.imagej.cameras.EyesisSubCameraParameters;
import com.elphel.imagej.common.DoubleGaussianBlur;
......@@ -51,6 +53,7 @@ import ij.ImageStack;
import ij.Prefs;
//import ij.process.*;
import ij.gui.GenericDialog;
import ij.gui.PointRoi;
import ij.io.FileSaver;
import ij.io.Opener;
import ij.process.FloatProcessor;
......@@ -2568,7 +2571,7 @@ For each point in the image
//TODO: add additional parameter - process all, but with matched pointers less than 2
public int applyHintedGrids(
MatchSimulatedPattern.LaserPointer laserPointer, // LaserPointer object that specifies actual laser pointers on the target
LaserPointer laserPointer, // LaserPointer object that specifies actual laser pointers on the target
boolean removeOutOfGridPointers,
double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only
boolean processAll, // if true - process all images, false - only disabled
......@@ -2671,8 +2674,6 @@ For each point in the image
continue;
}
// int numPointers=(laserPointer!=null)?laserPointer.laserUVMap.length:0;
// double [][] pointersXY=(numPointers>0)?getPointersXY(imp, numPointers):null;
double [] goniometerTiltAxial=dcd.getImagesetTiltAxial(numGridImage);
if ((goniometerTiltAxial==null) || Double.isNaN(goniometerTiltAxial[0]) || Double.isNaN(goniometerTiltAxial[1])){
if (this.debugLevel>0) {
......@@ -2807,7 +2808,7 @@ For each point in the image
int [] fileUVShiftRot=dcd.gIP[numGridImage].getUVShiftRot();
int [] extraUVShiftRot=matchSimulatedPattern.getUVShiftRot(true); // last shift/rotation during matching pattern, correct for zero shift
// int [] extraDbg=matchSimulatedPattern.getUVShiftRot(false);
int [] combinedUVShiftRot=matchSimulatedPattern.combineUVShiftRot(fileUVShiftRot,extraUVShiftRot);
int [] combinedUVShiftRot=MatchSimulatedPattern.combineUVShiftRot(fileUVShiftRot,extraUVShiftRot);
dcd.gIP[numGridImage].setUVShiftRot(combinedUVShiftRot);
System.out.println("applyHintedGrids(): dcd.gIP["+numGridImage+"].hintedMatch="+dcd.gIP[numGridImage].hintedMatch+
" dcd.gIP["+numGridImage+"].matchedPointers="+dcd.gIP[numGridImage].matchedPointers+ " points:"+index+" extra points:"+index_extra);
......@@ -2822,16 +2823,60 @@ For each point in the image
}
return numSuccess;
}
public void showSourceImage(int numGridImage){
String source_path=fittingStrategy.distortionCalibrationData.gIP[numGridImage].source_path;
if (source_path != null) {
ImagePlus imp = new ImagePlus(source_path);
imp.show();
}
}
public int [][] getImageMarkers(int numGridImage){
String source_path=fittingStrategy.distortionCalibrationData.gIP[numGridImage].source_path;
if (source_path != null) {
final ImagePlus imp = new ImagePlus(source_path);
imp.show();
/*
Thread msg_box_thread = new Thread() {
@Override
public void run() {
IJ.showMessage("Please place point markers on the "+imp.getTitle());
}
};
msg_box_thread.setPriority(Thread.MIN_PRIORITY);
msg_box_thread.start();
try {
msg_box_thread.join();
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
*/
// IJ.showMessage("Please place point markers on the "+imp.getTitle());
System.out.println("got it");
PointRoi pointRoi = null;
if (imp.getRoi() instanceof PointRoi) {
pointRoi = (PointRoi) imp.getRoi();
} else {
IJ.showMessage("This image does not have point marks - please mark it in "+source_path);
return null;
}
Point [] points = pointRoi.getContainedPoints();
int [][] ipoints = new int [points.length][2];
for (int n = 0; n < ipoints.length; n++) {
ipoints[n][0] = points[n].x;
ipoints[n][1] = points[n].y;
}
return ipoints;
}
return null;
}
public void showGridImage(int numGridImage){
DistortionCalibrationData.GridImageParameters grid=fittingStrategy.distortionCalibrationData.gIP[numGridImage];
/*
public double [][] pixelsXY= null; // for each image, each grid node - a pair of {px,py}
public int [][] pixelsUV= null; // for each image, each grid node - a pair of {gridU, gridV}
public double [][] pixelsXY_extra= null; // extra data, for nodes that are out of the physical grid (may be needed after re-calibration)
public int [][] pixelsUV_extra= null;
*/
boolean valid=false;
int minU=0,maxU=0,minV=0,maxV=0;
for (int i=0;i<grid.pixelsUV.length;i++){
......@@ -2898,9 +2943,145 @@ For each point in the image
}
(new ShowDoubleFloatArrays()).showArrays(pixels, width, height, true, "grid-"+numGridImage, titles);
}
public void manualGridHint(int imgNumber) {
int [][] markers = getImageMarkers(imgNumber);
if ((markers != null) && (markers.length > 0)) {
double [][] xyuv = new double [markers.length][4];
for (int i =0; i < markers.length; i++) {
xyuv[i][0]=markers[i][0];
xyuv[i][1]=markers[i][1];
xyuv[i][2]=0.5;
xyuv[i][3]=0.5;
}
GenericDialog gd=new GenericDialog("Specify U,V coordinates of the marker(s)");
gd.addMessage("Center white cell U=0.5, V=0.5");
for (int n = 0; n < markers.length; n++) {
String label = "Marker "+(n+1)+" (x="+markers[n][0]+", y="+markers[n][1];
gd.addNumericField(label+" U", xyuv[n][2], 1, 5, "");
gd.addNumericField(label+" V", xyuv[n][3], 1, 5, "");
}
gd.showDialog();
if (gd.wasCanceled()) return;
for (int i =0; i < markers.length; i++) {
xyuv[i][2] = gd.getNextNumber();
xyuv[i][3] = gd.getNextNumber();
}
// read grid image
String grid_path=fittingStrategy.distortionCalibrationData.gIP[imgNumber].path;
if (grid_path != null) {
ImagePlus imp = new ImagePlus(grid_path);
JP46_Reader_camera jp4_instance= new JP46_Reader_camera(false);
jp4_instance.decodeProperiesFromInfo(imp);
MatchSimulatedPattern.setPointersXYUV(imp, xyuv);
updateGridToPointer(imp, xyuv);
jp4_instance.encodeProperiesToInfo(imp);
System.out.println("Updated "+grid_path);
(new FileSaver(imp)).saveAsTiff(grid_path);
// imp.show();
}
return;
}
}
public void updateGridToPointer(ImagePlus imp_grid, double[][] xyuv) {
ImageStack stack=imp_grid.getStack();
if ((stack==null) || (stack.getSize()<4)) {
String msg="Expected a 8-slice stack in "+imp_grid.getTitle();
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
float [][] pixels=new float[stack.getSize()][]; // now - 8 (x,y,u,v,contrast, vignR,vignG,vignB
for (int i=0;i<pixels.length;i++) pixels[i]= (float[]) stack.getPixels(i+1); // pixel X : negative - no grid here
int width = imp_grid.getWidth();
int height = imp_grid.getHeight();
// start with translation only using xyuv[0][], may use full matching - same as laser pointers later
int indx_best = -1;
double d2_best = Double.NaN;
for (int indx = 0; indx < pixels[0].length; indx++) {
double dx = pixels[0][indx] - xyuv[0][0];
double dy = pixels[1][indx] - xyuv[0][1] ;
double d2 = dx*dx + dy*dy;
if (Double.isNaN(d2_best) || (d2 < d2_best)) {
indx_best = indx;
d2_best = d2;
}
}
int ix0 = indx_best % width;
int iy0 = indx_best / width;
PolynomialApproximation polynomialApproximation =new PolynomialApproximation(0);// no debug
double [][][] data = new double[9][3][];
int indx = 0;
for (int idy = -1; idy <=1; idy++) {
int iy = iy0+idy;
for (int idx = -1; idx <=1; idx++) {
int ix = ix0 + idx;
data[indx][0] = new double[2];
data[indx][1] = new double[2];
data[indx][2] = new double[1];
data[indx][0][0] = idx;
data[indx][0][1] = idy;
if ((ix >= 0) && (ix < width) && (iy >= 0) && (iy < height)) {
int offs = iy * width + ix;
data[indx][1][0] = pixels[0][offs] - xyuv[0][0];
data[indx][1][1] = pixels[1][offs] - xyuv[0][1];
data[indx][2][0] = 1.0;
} else {
data[indx][2][0] = 0.0;
}
indx++;
}
}
double [][] coeff = polynomialApproximation.quadraticApproximation(
data,
true); // force linear
double [][] aA = {{coeff[0][0],coeff[0][1]},{coeff[1][0],coeff[1][1]}};
double [][] aB = {{-coeff[0][2]},{-coeff[1][2]}};
Matrix A = new Matrix(aA);
Matrix B = new Matrix(aB);
Matrix V = A.solve(B);
double [] av = V.getColumnPackedCopy();
double u, v; // = xyuv[0][2]-()
if (av[0] < 0) {
av[0] += 1.0;
ix0 -= 1;
}
if (av[1] < 0) {
av[1] += 1.0;
iy0 -= 1;
}
u = xyuv[0][2] - (
(1-av[0])*(1-av[1]) * pixels[2][(iy0 + 0) * width + ix0 + 0]+
( av[0])*(1-av[1]) * pixels[2][(iy0 + 0) * width + ix0 + 1]+
(1-av[0])*( av[1]) * pixels[2][(iy0 + 1) * width + ix0 + 0]+
( av[0])*( av[1]) * pixels[2][(iy0 + 1) * width + ix0 + 1]);
v = xyuv[0][3] - (
(1-av[0])*(1-av[1]) * pixels[3][(iy0 + 0) * width + ix0 + 0]+
( av[0])*(1-av[1]) * pixels[3][(iy0 + 0) * width + ix0 + 1]+
(1-av[0])*( av[1]) * pixels[3][(iy0 + 1) * width + ix0 + 0]+
( av[0])*( av[1]) * pixels[3][(iy0 + 1) * width + ix0 + 1]);
int idu = (int)Math.round(u);
int idv = (int)Math.round(v);
// Verify that idy+idv - even number
if (((idu + idv) & 1) != 0) {
String msg = "Incorrect shift - u="+u+", v="+v+", idu="+idu+", idv="+idv+", idu+idv="+(idu+idv)+" SHOULD BE EVEN!";
System.out.println(msg);
IJ.showMessage(msg);
}
for (int i = 0; i < pixels[2].length; i++) {
pixels[2][i] += idu;
pixels[3][i] += idv;
}
}
public void showGridAndHint(){
GenericDialog gd=new GenericDialog("Show selected grid and/or hint grid");
gd.addNumericField("Grid Image index", 0,0);
gd.addCheckbox("Show source image (if available)", true);
gd.addCheckbox("Show grid image", true);
gd.addCheckbox("Show hint grid", true);
gd.addCheckbox("Use imageSet data if available (unchecked - camera data)", true);
......@@ -2909,12 +3090,15 @@ For each point in the image
if (gd.wasCanceled()) return;
int numGridImage= (int) gd.getNextNumber();
boolean showGrid=gd.getNextBoolean();
boolean showSource=gd.getNextBoolean();
boolean showHint=gd.getNextBoolean();
boolean useSetData=gd.getNextBoolean();
IJ.showStatus("grid: "+((fittingStrategy.distortionCalibrationData.gIP[numGridImage].path==null)?"":fittingStrategy.distortionCalibrationData.gIP[numGridImage].path));
// showStatus("grid: "+((fittingStrategy.distortionCalibrationData.gIP[numGridImage].path==null)?"":fittingStrategy.distortionCalibrationData.gIP[numGridImage].path),0);
if (showGrid) showGridImage(numGridImage);
if (showSource) showSourceImage(numGridImage);
// if (showSource) getImageMarkers(numGridImage);
if (showHint) calcAndShowHintGrid(numGridImage,useSetData);
}
......@@ -2946,6 +3130,12 @@ For each point in the image
(useSetData?fittingStrategy.distortionCalibrationData.gIP[numGridImage].getSetNumber():-1),
true // filter border
);
if (hintGrid == null) {
String msg = "hintGrid is null";
IJ.showMessage("Error",msg);
System.out.println(msg);
return;
}
showHintGrid(hintGrid,"hint-"+numGridImage);
}
......@@ -3167,12 +3357,6 @@ For each point in the image
int sensorWidth=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.getSensorWidth(subCamera);
int sensorHeight=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.getSensorHeight(subCamera);
System.out.println("estimateGridOnSensor(): subCamera="+subCamera+", goniometerHorizontal="+goniometerHorizontal+", goniometerAxial="+goniometerAxial);
/* calcInterParamers(
this.lensDistortionParameters, // 22-long parameter vector for the image
null, // this.interParameterDerivatives, // [22][]
parVector,
null); // if no derivatives, null is OK
*/
this.lensDistortionParameters.lensCalcInterParamers(
this.lensDistortionParameters, // 22-long parameter vector for the image
this.fittingStrategy.distortionCalibrationData.eyesisCameraParameters.isTripod,
......@@ -5878,7 +6062,8 @@ List calibration
return null;
}
public void saveDistortionAsImageStack(
CalibrationHardwareInterface.CamerasInterface camerasInterface, // to save channel map
DistortionCalibrationData distortionCalibrationData, // null OK
CamerasInterface camerasInterface, // to save channel map
String title,
String path,
boolean emptyOK){
......@@ -5892,6 +6077,7 @@ List calibration
String channelPath= (hadSuffix?path.substring(0,indexSuffix):(path.substring(0,indexPeriod)+"-"))+
String.format("%02d",chNum)+path.substring(indexPeriod);
saveDistortionAsImageStack(
distortionCalibrationData,
camerasInterface, // to save channel map
title,
channelPath,
......@@ -5901,12 +6087,14 @@ List calibration
}
public ImagePlus saveDistortionAsImageStack(
CalibrationHardwareInterface.CamerasInterface camerasInterface, // to save channel map
DistortionCalibrationData distortionCalibrationData, // null OK
CamerasInterface camerasInterface, // to save channel map
String title,
String path,
int numSensor,
boolean emptyOK){
ImagePlus imp=getDistortionAsImageStack(
distortionCalibrationData,
camerasInterface, // to save channel map
title,
numSensor,
......@@ -5929,10 +6117,14 @@ List calibration
// / int numChannels=this.fittingStrategy.distortionCalibrationData.getNumChannels(); // number of used channels
// TODO: Currently saves data from Station 0
public ImagePlus getDistortionAsImageStack(
CalibrationHardwareInterface.CamerasInterface camerasInterface, // to save channel map
DistortionCalibrationData distortionCalibrationData, // null OK - will use old way from fittingStrategy
CamerasInterface camerasInterface, // to save channel map
String title,
int numSensor,
boolean emptyOK){
if (distortionCalibrationData == null) {
distortionCalibrationData = this.fittingStrategy.distortionCalibrationData;
}
int stationNumber=0;
String [] titles={"X-corr","Y-corr","mask","R-vign","G-vign","B-vign"};
double [][] pixelCorr=null;
......@@ -5955,10 +6147,10 @@ List calibration
float [][]pixels=new float [titles.length][length]; // dx, dy, sensor mask,v-r,v-g,v-b
// assuming all sensors have the same dimension
double [] mask=null;
if (fittingStrategy.distortionCalibrationData.sensorMasks.length<=numSensor) return null; // no data
if ((fittingStrategy.distortionCalibrationData.sensorMasks!=null) &&
(fittingStrategy.distortionCalibrationData.sensorMasks[numSensor]!=null)){
mask=fittingStrategy.distortionCalibrationData.sensorMasks[numSensor];
if (distortionCalibrationData.sensorMasks.length<=numSensor) return null; // no data
if ((distortionCalibrationData.sensorMasks!=null) &&
(distortionCalibrationData.sensorMasks[numSensor]!=null)){
mask=distortionCalibrationData.sensorMasks[numSensor];
}
for (int index=0;index<length;index++){
......@@ -5981,9 +6173,9 @@ List calibration
imp = new ImagePlus(title, stack);
// set properties sufficient to un-apply distortions to the image
// First - corrections
EyesisSubCameraParameters subCam=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor];
EyesisSubCameraParameters subCam=distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor];
subCam.updateCartesian(); // recalculate other parameters
double entrancePupilForward=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.entrancePupilForward[stationNumber];
double entrancePupilForward=distortionCalibrationData.eyesisCameraParameters.entrancePupilForward[stationNumber];
imp.setProperty("VERSION", "1.0");
imp.setProperty("comment_arrays", "Array corrections from acquired image to radially distorted, in pixels");
imp.setProperty("arraysSet", ""+(pixelCorr!=null)); // per-pixel arrays are not set, using 0.0
......@@ -6036,11 +6228,17 @@ List calibration
imp.setProperty("comment_channel", "number of the sensor (channel) in the camera");
imp.setProperty("channel", ""+numSensor);
imp.setProperty("comment_subcamera", "number of the subcamera with individual IP, starting with 0");
imp.setProperty("subcamera", ""+camerasInterface.getSubCamera(numSensor));
imp.setProperty("sensor_port",""+camerasInterface.getSensorPort(numSensor));
if (camerasInterface != null) {
subCam.subcamera = camerasInterface.getSubCamera(numSensor);
subCam.sensor_port = camerasInterface.getSensorPort(numSensor);
subCam.subchannel = camerasInterface.getSubChannel(numSensor);
}
imp.setProperty("subcamera", ""+subCam.subcamera);
imp.setProperty("sensor_port",""+subCam.sensor_port);
imp.setProperty("comment_subchannel", "number of the sensor port on a subcamera (0..2)");
imp.setProperty("subchannel", ""+camerasInterface.getSubChannel(numSensor));
imp.setProperty("subchannel", ""+subCam.subchannel);
imp.setProperty("comment_entrancePupilForward", "entrance pupil distance from the azimuth/radius/height, outwards in mm");
imp.setProperty("entrancePupilForward", ""+entrancePupilForward); // currently global, decoders will use per-sensor
imp.setProperty("comment_defects", "Sensor hot/cold pixels list as x:y:difference");
......@@ -6075,15 +6273,29 @@ List calibration
public void setDistortionFromImageStack(
DistortionCalibrationData distortionCalibrationData, // null OK
EyesisCameraParameters eyesisCameraParameters, // null OK
String path,
boolean overwriteExtrinsic,
boolean overwriteDistortion){
int indexPeriod=path.indexOf('.',path.lastIndexOf(Prefs.getFileSeparator()));
int numSubCameras=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[0].length;
if (eyesisCameraParameters == null) {
eyesisCameraParameters = fittingStrategy.distortionCalibrationData.eyesisCameraParameters;
}
if (distortionCalibrationData == null) {
distortionCalibrationData = fittingStrategy.distortionCalibrationData;
}
int numSubCameras=distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[0].length;
for (int chNum=0;chNum<numSubCameras;chNum++){
String channelPath=path.substring(0,indexPeriod-2)+String.format("%02d",chNum)+path.substring(indexPeriod);
try { // disable here for now
setDistortionFromImageStack(channelPath, chNum, false, overwriteExtrinsic, overwriteDistortion);
setDistortionFromImageStack(
distortionCalibrationData,
channelPath,
chNum,
false,
overwriteExtrinsic,
overwriteDistortion);
} catch (Exception e) {
System.out.println("setDistortionFromImageStack(): " + e.toString());
e.printStackTrace();
......@@ -6092,13 +6304,14 @@ List calibration
}
public void setDistortionFromImageStack(
DistortionCalibrationData distortionCalibrationData,
String path,
int numSensor,
boolean reportProblems,
boolean overwriteExtrinsic,
boolean overwriteDistortion){
Opener opener=new Opener();
ImagePlus imp=opener.openImage("", path);
Opener opener=new Opener();
ImagePlus imp=opener.openImage("", path);
if (imp==null) {
if (!reportProblems) return;
String msg="Failed to read sensor calibration data file "+path;
......@@ -6106,18 +6319,26 @@ List calibration
System.out.println(msg);
throw new IllegalArgumentException (msg);
}
if (this.debugLevel>0) System.out.println("Read "+path+" as a sensor calibration data");
if (this.debugLevel>0) System.out.println("Read "+path+" as a sensor calibration data");
(new JP46_Reader_camera(false)).decodeProperiesFromInfo(imp);
setDistortionFromImageStack(imp, numSensor, overwriteExtrinsic, overwriteDistortion);
setDistortionFromImageStack(distortionCalibrationData,
imp,
numSensor,
overwriteExtrinsic,
overwriteDistortion);
this.pathNames[numSensor]=path;
}
//TODO: look more after testing. Currently all station parameters are set from the sensor images, may be minor differences
public void setDistortionFromImageStack(
DistortionCalibrationData distortionCalibrationData,
ImagePlus imp,
int numSensor,
boolean overwriteExtrinsic,
boolean overwriteDistortion){
if (distortionCalibrationData == null) {
distortionCalibrationData = this.fittingStrategy.distortionCalibrationData;
}
// int corrX=0,corrY=1,
int corrMask=2;
if (numSensor<0) {
......@@ -6163,7 +6384,7 @@ List calibration
for (int i=0;i<pixels.length;i++) pixels[i]= (float[]) stack.getPixels(i+1);
int numSubCameras=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[0].length;
int numSubCameras=distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[0].length;
if (numSensor>=numSubCameras){
String msg="Loaded calibration channel number "+numSensor+"is higher than maximal in the system "+(numSubCameras-1);
IJ.showMessage("Error",msg);
......@@ -6172,18 +6393,18 @@ List calibration
// System.out.println("setDistortionFromImageStack(): processing channel channel "+numSensor);
EyesisSubCameraParameters subCam;
EyesisCameraParameters cam= fittingStrategy.distortionCalibrationData.eyesisCameraParameters;
EyesisCameraParameters cam= distortionCalibrationData.eyesisCameraParameters;
this.pixelCorrectionWidth= Integer.parseInt ((String) imp.getProperty("pixelCorrectionWidth"));
this.pixelCorrectionHeight= Integer.parseInt ((String) imp.getProperty("pixelCorrectionHeight"));
this.pixelCorrectionDecimation= Integer.parseInt ((String) imp.getProperty("pixelCorrectionDecimation"));
if ((this.fittingStrategy!=null) && (this.fittingStrategy.distortionCalibrationData!=null) && (this.fittingStrategy.distortionCalibrationData.eyesisCameraParameters!=null)){
this.fittingStrategy.distortionCalibrationData.eyesisCameraParameters.decimateMasks=this.pixelCorrectionDecimation;
this.fittingStrategy.distortionCalibrationData.eyesisCameraParameters.sensorWidth= this.pixelCorrectionWidth;
this.fittingStrategy.distortionCalibrationData.eyesisCameraParameters.sensorHeight=this.pixelCorrectionHeight;
if ((distortionCalibrationData!=null) && (distortionCalibrationData.eyesisCameraParameters!=null)){
distortionCalibrationData.eyesisCameraParameters.decimateMasks=this.pixelCorrectionDecimation;
distortionCalibrationData.eyesisCameraParameters.sensorWidth= this.pixelCorrectionWidth;
distortionCalibrationData.eyesisCameraParameters.sensorHeight=this.pixelCorrectionHeight;
}
for (int stationNumber=0;stationNumber<fittingStrategy.distortionCalibrationData.eyesisCameraParameters.numStations; stationNumber++){
subCam=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor];
for (int stationNumber=0; stationNumber < distortionCalibrationData.eyesisCameraParameters.numStations; stationNumber++){
subCam=distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor];
subCam.distortionRadius= Double.parseDouble((String) imp.getProperty("distortionRadius"));
subCam.focalLength= Double.parseDouble((String) imp.getProperty("focalLength"));
......@@ -6251,15 +6472,20 @@ List calibration
if (imp.getProperty("r_od_"+i+"_o") !=null) subCam.r_od[i][0]= Double.parseDouble((String) imp.getProperty("r_od_"+i+"_o"));
if (imp.getProperty("r_od_"+i+"_d") !=null) subCam.r_od[i][1]= Double.parseDouble((String) imp.getProperty("r_od_"+i+"_d"));
}
if (imp.getProperty("subcamera") !=null) subCam.subcamera= Integer.parseInt((String) imp.getProperty("subcamera"));
if (imp.getProperty("sensor_port") !=null) subCam.sensor_port= Integer.parseInt((String) imp.getProperty("sensor_port"));
if (imp.getProperty("subchannel") !=null) subCam.subchannel= Integer.parseInt((String) imp.getProperty("subchannel"));
}
for (int imgNum=0;imgNum<fittingStrategy.distortionCalibrationData.getNumImages();imgNum++){
int imageSubCam= fittingStrategy.distortionCalibrationData.getImageSubcamera(imgNum);
int stationNumber=fittingStrategy.distortionCalibrationData.getImageStation(imgNum);
for (int imgNum=0;imgNum < distortionCalibrationData.getNumImages();imgNum++){
int imageSubCam= distortionCalibrationData.getImageSubcamera(imgNum);
int stationNumber=distortionCalibrationData.getImageStation(imgNum);
if (imageSubCam==numSensor){
// vector from the data we just set
double [] parVector=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.getParametersVector(stationNumber,imageSubCam);
if (overwriteExtrinsic) fittingStrategy.distortionCalibrationData.setSubcameraParameters(parVector,imgNum);
else if (overwriteDistortion) fittingStrategy.distortionCalibrationData.setIntrinsicParameters(parVector,imgNum);
double [] parVector= distortionCalibrationData.eyesisCameraParameters.getParametersVector(stationNumber,imageSubCam);
if (overwriteExtrinsic) distortionCalibrationData.setSubcameraParameters(parVector,imgNum);
else if (overwriteDistortion) distortionCalibrationData.setIntrinsicParameters(parVector,imgNum);
}
}
......@@ -6306,25 +6532,25 @@ List calibration
}
// System.out.println("setDistortionFromImageStack(): defined="+defined );
if (defined) {
if (this.fittingStrategy.distortionCalibrationData.sensorMasks==null) {
this.fittingStrategy.distortionCalibrationData.sensorMasks=new double [numSubCameras][];
for (int i=0;i<this.fittingStrategy.distortionCalibrationData.sensorMasks.length;i++)
this.fittingStrategy.distortionCalibrationData.sensorMasks[i]=null;
// System.out.println("setDistortionFromImageStack(): created this.fittingStrategy.distortionCalibrationData.sensorMasks["+numSubCameras+"] of null-s" );
if (distortionCalibrationData.sensorMasks==null) {
distortionCalibrationData.sensorMasks=new double [numSubCameras][];
for (int i=0;i<distortionCalibrationData.sensorMasks.length;i++)
distortionCalibrationData.sensorMasks[i]=null;
// System.out.println("setDistortionFromImageStack(): created distortionCalibrationData.sensorMasks["+numSubCameras+"] of null-s" );
}
if (numSensor>=this.fittingStrategy.distortionCalibrationData.sensorMasks.length){ // increase number of elements
double [][] tmp=this.fittingStrategy.distortionCalibrationData.sensorMasks;
this.fittingStrategy.distortionCalibrationData.sensorMasks=new double[numSensor+1][];
for (int i=0;i<this.fittingStrategy.distortionCalibrationData.sensorMasks.length;i++)
if (i<tmp.length)this.fittingStrategy.distortionCalibrationData.sensorMasks[i]=tmp[i];
else this.fittingStrategy.distortionCalibrationData.sensorMasks[i]=null;
if (numSensor>=distortionCalibrationData.sensorMasks.length){ // increase number of elements
double [][] tmp=distortionCalibrationData.sensorMasks;
distortionCalibrationData.sensorMasks=new double[numSensor+1][];
for (int i=0;i<distortionCalibrationData.sensorMasks.length;i++)
if (i<tmp.length)distortionCalibrationData.sensorMasks[i]=tmp[i];
else distortionCalibrationData.sensorMasks[i]=null;
}
if (this.fittingStrategy.distortionCalibrationData.sensorMasks[numSensor]==null){
this.fittingStrategy.distortionCalibrationData.sensorMasks[numSensor]=new double[pixels[corrMask].length];
// System.out.println("setDistortionFromImageStack(): created this.fittingStrategy.distortionCalibrationData.sensorMasks["+numSensor+"] of ["+pixels[corrMask].length+"]" );
if (distortionCalibrationData.sensorMasks[numSensor]==null){
distortionCalibrationData.sensorMasks[numSensor]=new double[pixels[corrMask].length];
// System.out.println("setDistortionFromImageStack(): created distortionCalibrationData.sensorMasks["+numSensor+"] of ["+pixels[corrMask].length+"]" );
}
for (int i= 0;i<this.fittingStrategy.distortionCalibrationData.sensorMasks[numSensor].length;i++) // null pointer
this.fittingStrategy.distortionCalibrationData.sensorMasks[numSensor][i]=pixels[corrMask][i];
for (int i= 0;i<distortionCalibrationData.sensorMasks[numSensor].length;i++) // null pointer
distortionCalibrationData.sensorMasks[numSensor][i]=pixels[corrMask][i];
}
}
/**
......
......@@ -4562,6 +4562,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public String partialKernelDirectory="";
public String psfKernelDirectory="";
public String aberrationsKernelDirectory="";
public String calibrationDirectory="";
public boolean autoRestore;
public String calibrationPath="";
public String strategyPath="";
......@@ -4598,6 +4599,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
properties.setProperty(prefix+"partialKernelDirectory",this.partialKernelDirectory);
properties.setProperty(prefix+"psfKernelDirectory",this.psfKernelDirectory);
properties.setProperty(prefix+"aberrationsKernelDirectory",this.aberrationsKernelDirectory);
properties.setProperty(prefix+"calibrationDirectory",this.calibrationDirectory);
properties.setProperty(prefix+"autoRestore",this.autoRestore+"");
properties.setProperty(prefix+"calibrationPath",this.calibrationPath);
......@@ -4642,6 +4644,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (properties.getProperty(prefix+"partialKernelDirectory")!=null) this.partialKernelDirectory=properties.getProperty(prefix+"partialKernelDirectory");
if (properties.getProperty(prefix+"psfKernelDirectory")!=null) this.psfKernelDirectory=properties.getProperty(prefix+"psfKernelDirectory");
if (properties.getProperty(prefix+"aberrationsKernelDirectory")!=null) this.aberrationsKernelDirectory=properties.getProperty(prefix+"aberrationsKernelDirectory");
if (properties.getProperty(prefix+"calibrationDirectory")!=null) this.calibrationDirectory=properties.getProperty(prefix+"calibrationDirectory");
if (properties.getProperty(prefix+"autoRestore")!=null) this.autoRestore=Boolean.parseBoolean(properties.getProperty(prefix+"autoRestore"));
if (properties.getProperty(prefix+"calibrationPath")!=null) this.calibrationPath=properties.getProperty(prefix+"calibrationPath");
......@@ -4792,6 +4795,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
gd.addCheckbox("Select combined kernsls directory", false);
gd.addStringField("Aberrations kernels directory", this.aberrationsKernelDirectory, 60);
gd.addCheckbox("Select aberrations kernels directory", false);
gd.addStringField("Calibration directory (sensor, grid, strategy...)", this.calibrationDirectory, 60);
gd.addCheckbox("Select calibration directory", false);
gd.addCheckbox("Supress non-essential message boxes", this.noMessageBoxes);
gd.addCheckbox("Overwrite result files if they exist", this.overwriteResultFiles);
gd.addCheckbox("Use reprojected grids for partial kernel calculation (false - extracted grids)", this.partialToReprojected);
......@@ -4843,6 +4848,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (gd.getNextBoolean()) selectPSFKernelDirectory(false, this.psfKernelDirectory, false);
this.aberrationsKernelDirectory=gd.getNextString();
if (gd.getNextBoolean()) selectAberrationsKernelDirectory(false, this.aberrationsKernelDirectory, false);
this.calibrationDirectory=gd.getNextString();
if (gd.getNextBoolean()) selectCalibrationDirectory(false, this.calibrationDirectory, false);
this.noMessageBoxes= gd.getNextBoolean();
this.overwriteResultFiles= gd.getNextBoolean();
this.partialToReprojected= gd.getNextBoolean();
......@@ -4921,7 +4928,18 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (dir!=null) this.aberrationsKernelDirectory=dir;
return dir;
}
public String selectCalibrationDirectory(boolean smart, String defaultPath, boolean newAllowed) {
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
"Calibration directory", // title
"Select calibration directory", // button
null, // filter
defaultPath); //this.sourceDirectory);
if (dir!=null) this.calibrationDirectory=dir;
return dir;
}
//
}
......
......@@ -29,6 +29,8 @@ package com.elphel.imagej.calibration;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import com.elphel.imagej.calibration.hardware.CamerasInterface;
import com.elphel.imagej.calibration.hardware.GoniometerMotors;
import com.elphel.imagej.cameras.EyesisCameraParameters;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.common.WindowTools;
......@@ -50,7 +52,7 @@ horizontal axis:
private ShowDoubleFloatArrays sdfaInstance = new ShowDoubleFloatArrays(); // just
// for
// debugging
public CalibrationHardwareInterface.CamerasInterface cameras = null;
public CamerasInterface cameras = null;
public LwirReader lwirReader = null;
// public CalibrationHardwareInterface.LaserPointers lasers = null;
// public static CalibrationHardwareInterface.FocusingMotors motorsS=null;
......@@ -67,7 +69,7 @@ horizontal axis:
public MatchSimulatedPattern[] matchSimulatedPatterns = null; // =new
// MatchSimulatedPattern();
public MatchSimulatedPattern.LaserPointer laserPointers = null;
public LaserPointer laserPointers = null;
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters=null;
public SimulationPattern.SimulParameters simulParametersDefault=null;
public Goniometer.GoniometerParameters goniometerParameters = null;
......@@ -78,11 +80,11 @@ horizontal axis:
public double bottomRollersClearance=36.0; // angular clearance between the two bottom rollers
public Goniometer(CalibrationHardwareInterface.CamerasInterface cameras,
public Goniometer(CamerasInterface cameras,
MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
EyesisCameraParameters eyesisCameraParameters,
MatchSimulatedPattern.LaserPointer laserPointers,
LaserPointer laserPointers,
SimulationPattern.SimulParameters simulParametersDefault,
Goniometer.GoniometerParameters goniometerParameters,
DistortionProcessConfiguration distortionProcessConfiguration
......@@ -104,7 +106,7 @@ horizontal axis:
MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
EyesisCameraParameters eyesisCameraParameters,
MatchSimulatedPattern.LaserPointer laserPointers,
LaserPointer laserPointers,
SimulationPattern.SimulParameters simulParametersDefault,
Goniometer.GoniometerParameters goniometerParameters,
DistortionProcessConfiguration distortionProcessConfiguration
......@@ -754,15 +756,10 @@ horizontal axis:
public double[] estimateOrientation(
ImagePlus[] images, // last acquire images with number of pointers
// detected>0
// MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
// LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
// Goniometer.GoniometerParameters goniometerParameters,
// MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
// MatchSimulatedPattern.LaserPointer laserPointer, // null OK
// SimulationPattern.SimulParameters simulParametersDefault,
DistortionCalibrationData distortionCalibrationData,
PatternParameters patternParameters, // should not be null
Distortions lensDistortions, // should not be null
LaserPointer laserPointers, // as a back up measure
boolean equalizeGreens,
int threadsMax,
boolean updateStatus,
......@@ -815,8 +812,7 @@ horizontal axis:
// used alternatively if keeping it
this.matchSimulatedPatterns[numSensor].invalidateFlatFieldForGrid(); // Reset Flat Filed calibration - different image.
this.matchSimulatedPatterns[numSensor].invalidateFocusMask();
if (matchSimulatedPatterns[numSensor].getPointersXY(images[numSensor],
this.laserPointers.laserUVMap.length) == null) { // no pointers in this image
if (MatchSimulatedPattern.getPointersXYUV(images[numSensor],this.laserPointers) == null) { // no pointers in this image
String msg = "No laser pointers detected for "+ images[numSensor].getTitle()+ " - they are needed for absolute grid positioning";
if (debug_level > 0) System.out.println("Warning: " + msg);
IJ.showMessage("Warning", msg);
......@@ -933,8 +929,9 @@ horizontal axis:
* //PatternParameters patternParameters, eyesisCameraParameters
* //EyesisCameraParameters eyesisCameraParameters );
*/
distortionCalibrationData.setImages(imp_calibrated, // ImagePlus [] images, // imagesin the memory
patternParameters); // PatternParameters patternParameters);
distortionCalibrationData.setImages(imp_calibrated, // ImagePlus [] images, // images in the memory
patternParameters, // PatternParameters patternParameters);
laserPointers);
distortionCalibrationData.initImageSet(eyesisCameraParameters);
// Set initial azimuth and elevation
......@@ -1075,7 +1072,7 @@ horizontal axis:
5682.48889 per degree
*/
// motors rotate positive - look down, positive - CCW
CalibrationHardwareInterface.GoniometerMotors goniometerMotors=null;
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
// public double scanStepTilt=20.0; // degrees (equal steps not larger than
......@@ -1098,11 +1095,11 @@ horizontal axis:
public GoniometerParameters(CalibrationHardwareInterface.GoniometerMotors goniometerMotors){
public GoniometerParameters(GoniometerMotors goniometerMotors){
this.goniometerMotors=goniometerMotors;
}
public GoniometerParameters(
CalibrationHardwareInterface.GoniometerMotors goniometerMotors,
GoniometerMotors goniometerMotors,
String gridGeometryFile,
String initialCalibrationFile, // not needed
String strategyFile,
......
package com.elphel.imagej.calibration;
import java.util.Properties;
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 ij.IJ;
import ij.gui.GenericDialog;
public class LaserPointer{
public double headLasersTilt= 1.06; // degrees, right laser lower than left laser
public double minimalIntensity=0.05; // of scaled saturation when laser is on
public double maximalIntensity=1.5; // of scaled saturation when laser is off
public int overexposedRadius = 30; // no pointers closer than this to overexposed areas
public double lowpassSigma=1.0; // 0.8; // low pass sigma, in pixels
public double highpassSigma=20; // high pass sigma, in pixels
public double headLowpassSigma=0.8; // low pass sigma, in pixels for optical head lasers
public double quadraticScaleSigma=1.0; // find local maximum by quadratic intrepolating pixels around maximal value (relative to lkow pass sigma)
public int algorithmNumber=4;
public int closestOffender=3;
public int fartherstOffender=200;
public double fatZero =0.05;
public double greenFloor=0.6; // when dividing by green, add this fraction of maximal value (decrease green accordingly)
public boolean useOther=true; // when true - use red and other color, when false - only red
public boolean otherGreen=true; // other color is green (false - blue)
public double threshold=0.1;
// default grid orientation, used if not enough pointers visible (modified when more visible)
public boolean swapUV=false; // first
public boolean flipU=false;
public boolean flipV=false;
public boolean whiteOnly=true; // verify laser is on the white pattern cell
public double maxOffsetFromCenter=0.6; // maximal offset of the laser spot from the center, relative to cell radius
public double [][] laserUVMap; // first index - number of pointer points
// new variables TODO: add handling (all linear dimensions in sensor pixels)
public double laserSignalToNoise=1.5; // Minimal signal-to-noise ratio for laser pointers
public double localMaxRadius=10; // sensor pix. currently uses just square (2*localMaxRadius+1)**2
public boolean usePatternFilter=true; // Filter laser positions by likely pattern white cells
public int decimatePatternFilter=2; // reduce resolution for pattern filter
public double localContrastSigma=40; // use to calculate local level and contrast
public double localToGlobalContrast=0.8; // 0 - same contrast normalization for the whole image, 1.0 - pure local
public double patternLowPassSigma=4.0; // filter normalized patetrn before thresholding
public double patternThreshold=0.2; // fraction of dispersion (same positive for white cells, negative for black ones)
public double maximalCellSize=30.0; // White cells should have black pixels in all 4 quadrants not farther than this
public int numPasses=3; // number of black/white alternations of the surrounding cells to use in quadrant filtering
public boolean bordersOK=false; // frame border as good cell for quadrant filter
public double blurredMaskThreshold=0.1; // select only areas with multiple pattern white cells
public double maskGrow=2.0; // grow final mask (pixels)
public int debugLevel=1;
private long startTime=System.nanoTime();
private long lastTime=startTime;
private long thisTime=startTime;
private void printTiming(String title){
this.thisTime=System.nanoTime();
System.out.println(title+ " calculated at "+IJ.d2s(0.000000001*(this.thisTime-this.startTime),3)+
" (+"+IJ.d2s(0.000000001*(this.thisTime-this.lastTime),3)+") sec");
this.lastTime=this.thisTime;
}
private void printTimingInit(){
this.startTime=System.nanoTime();
this.lastTime=this.startTime;
this.thisTime=this.startTime;
}
public LaserPointer(
double headLasersTilt, // degrees, right laser lower than left laser
double minimalIntensity,
double maximalIntensity,
int overexposedRadius,
double lowpassSigma, // low pass sigma, in pixels
double highpassSigma,
double headLowpassSigma, // low pass sigma, in pixels for optical head lasers
double quadraticScaleSigma, // find local maximum by quadratic intrepolating pixels around maximal value (relative to lkow pass sigma)
int algorithmNumber,
int closestOffender,
int fartherstOffender,
double fatZero,
double greenFloor, // when dividing by green, add this fraction of maximal value (decrease green accordingly)
boolean useOther, // when true - use red and other color, when false - only red
boolean otherGreen, // other color is green (false - blue)
double threshold,
boolean swapUV, // first
boolean flipU,
boolean flipV,
boolean whiteOnly, // verify laser is on the white pattern cell
double maxOffsetFromCenter, // maximal offset of the laser spot from the center (<0.5)
double [][] laserUVMap, // first index - number of pointer points
double laserSignalToNoise, // Minimal signal-to-noise ratio for laser pointers
double localMaxRadius, // sensor pix. currently uses just square (2*localMaxRadius+1)**2
boolean usePatternFilter, // Filter laser positions by likely pattern white cells
int decimatePatternFilter,
double localContrastSigma,
double localToGlobalContrast,
double patternLowPassSigma,
double patternThreshold,
double maximalCellSize,
int numPasses, // number of black/white alternations of the surrounding cells to use in quadrant filtering
boolean bordersOK, // frame boreder as good cell for quadrant filter
double blurredMaskThreshold, // select only areas with multiple pattern white cells
double maskGrow, // grow final mask (pixels)
int debugLevel
) {
this.headLasersTilt=headLasersTilt; // degrees, right laser lower than left laser
this.minimalIntensity=minimalIntensity;
this.maximalIntensity=maximalIntensity;
this.overexposedRadius=overexposedRadius;
this.lowpassSigma=lowpassSigma;
this.highpassSigma=highpassSigma;
this.headLowpassSigma=headLowpassSigma; // low pass sigma, in pixels for optical head lasers
this.quadraticScaleSigma= quadraticScaleSigma; // find local maximum by quadratic intrepolating pixels around maximal value (relative to lkow pass sigma)
this.algorithmNumber=algorithmNumber;
this.closestOffender=closestOffender;
this.fartherstOffender=fartherstOffender;
this.fatZero=fatZero;
this.greenFloor= greenFloor;
this.useOther=useOther;
this.otherGreen=otherGreen;
this.threshold= threshold;
this.swapUV=swapUV; // first
this.flipU=flipU;
this.flipV=flipV;
this.whiteOnly=whiteOnly;
this.maxOffsetFromCenter=maxOffsetFromCenter;
this.laserUVMap=new double[laserUVMap.length][2];
for (int i=0;i<laserUVMap.length;i++) {
this.laserUVMap[i][0]=laserUVMap[i][0];
this.laserUVMap[i][1]=laserUVMap[i][1];
}
this.laserSignalToNoise=laserSignalToNoise; // Minimal signal-to-noise ratio for laser pointers
this.localMaxRadius=localMaxRadius; // sensor pix. currently uses just square (2*localMaxRadius+1)**2
this.usePatternFilter=usePatternFilter; // Filter laser positions by likely pattern white cells
this.decimatePatternFilter=decimatePatternFilter;
this.localContrastSigma=localContrastSigma;
this.localToGlobalContrast=localToGlobalContrast;
this.patternLowPassSigma=patternLowPassSigma;
this.patternThreshold=patternThreshold;
this.maximalCellSize=maximalCellSize;
this.numPasses=numPasses; // number of black/white alternations of the surrounding cells to use in quadrant filtering
this.bordersOK=bordersOK; // frame boreder as good cell for quadrant filter
this.blurredMaskThreshold=blurredMaskThreshold; // select only areas with multiple pattern white cells
this.maskGrow=maskGrow; // grow final mask (pixels)
this.debugLevel=debugLevel;
}
public int getNumberOfPointers(){
return this.laserUVMap.length;
}
@Override
public LaserPointer clone(){
return new LaserPointer(
this.headLasersTilt,// degrees, right laser lower than left laser
this.minimalIntensity,
this.maximalIntensity,
this.overexposedRadius,
this.lowpassSigma, // low pass sigma, in pixels
this.highpassSigma,
this.quadraticScaleSigma, // find local maximum by quadratic intrepolating pixels around maximal value (relative to lkow pass sigma)
this.headLowpassSigma,
this.algorithmNumber,
this.closestOffender,
this.fartherstOffender,
this.fatZero,
this.greenFloor, // when dividing by green, add this fraction of maximal value (decrease green accordingly)
this.useOther,
this.otherGreen,
this.threshold,
this.swapUV,
this.flipU,
this.flipV,
this.whiteOnly,
this.maxOffsetFromCenter,
this.laserUVMap, // first index - number of pointer points
this.laserSignalToNoise, // Minimal signal-to-noise ratio for laser pointers
this.localMaxRadius, // sensor pix. currently uses just square (2*localMaxRadius+1)**2
this.usePatternFilter, // Filter laser positions by likely pattern white cells
this.decimatePatternFilter,
this.localContrastSigma,
this.localToGlobalContrast,
this.patternLowPassSigma,
this.patternThreshold,
this.maximalCellSize,
this.numPasses, // number of black/white alternations of the surrounding cells to use in quadrant filtering
this.bordersOK,
this.blurredMaskThreshold,// select only areas with multiple pattern white cells
this.maskGrow, // grow final mask (pixels)
this.debugLevel
);
}
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"headLasersTilt",this.headLasersTilt+"");
properties.setProperty(prefix+"minimalIntensity",this.minimalIntensity+"");
properties.setProperty(prefix+"maximalIntensity",this.maximalIntensity+"");
properties.setProperty(prefix+"overexposedRadius",this.overexposedRadius+"");
properties.setProperty(prefix+"lowpassSigma",this.lowpassSigma+"");
properties.setProperty(prefix+"highpassSigma",this.highpassSigma+"");
properties.setProperty(prefix+"headLowpassSigma",this.headLowpassSigma+"");
properties.setProperty(prefix+"quadraticScaleSigma",this.quadraticScaleSigma+"");
properties.setProperty(prefix+"algorithmNumber",this.algorithmNumber+"");
properties.setProperty(prefix+"closestOffender",this.closestOffender+"");
properties.setProperty(prefix+"fartherstOffender",this.fartherstOffender+"");
properties.setProperty(prefix+"fatZero",this.fatZero+"");
properties.setProperty(prefix+"greenFloor",this.greenFloor+"");
properties.setProperty(prefix+"useOther",this.useOther+"");
properties.setProperty(prefix+"otherGreen",this.otherGreen+"");
properties.setProperty(prefix+"threshold",this.threshold+"");
properties.setProperty(prefix+"swapUV",this.swapUV+"");
properties.setProperty(prefix+"flipU",this.flipU+"");
properties.setProperty(prefix+"flipV",this.flipV+"");
properties.setProperty(prefix+"whiteOnly",this.whiteOnly+"");
properties.setProperty(prefix+"maxOffsetFromCenter",this.maxOffsetFromCenter+"");
properties.setProperty(prefix+"numberOfLaserPoints",this.laserUVMap.length+"");
for (int i=0;i<this.laserUVMap.length;i++) {
properties.setProperty(prefix+"laserUVMap_"+i+"u",this.laserUVMap[i][0]+"");
properties.setProperty(prefix+"laserUVMap_"+i+"v",this.laserUVMap[i][1]+"");
}
properties.setProperty(prefix+"laserSignalToNoise",this.laserSignalToNoise+"");
properties.setProperty(prefix+"localMaxRadius",this.localMaxRadius+"");
properties.setProperty(prefix+"usePatternFilter",this.usePatternFilter+"");
properties.setProperty(prefix+"decimatePatternFilter",this.decimatePatternFilter+"");
properties.setProperty(prefix+"localContrastSigma",this.localContrastSigma+"");
properties.setProperty(prefix+"localToGlobalContrast",this.localToGlobalContrast+"");
properties.setProperty(prefix+"patternLowPassSigma",this.patternLowPassSigma+"");
properties.setProperty(prefix+"patternThreshold",this.patternThreshold+"");
properties.setProperty(prefix+"maximalCellSize",this.maximalCellSize+"");
properties.setProperty(prefix+"numPasses",this.numPasses+"");
properties.setProperty(prefix+"bordersOK",this.bordersOK+"");
properties.setProperty(prefix+"blurredMaskThreshold",this.blurredMaskThreshold+"");
properties.setProperty(prefix+"maskGrow",this.maskGrow+"");
properties.setProperty(prefix+"debugLevel",this.debugLevel+"");
}
public void getProperties(String prefix,Properties properties){
int numberOfLaserPoints=0;
if (properties.getProperty(prefix+"headLasersTilt")!=null)
this.headLasersTilt=Double.parseDouble(properties.getProperty(prefix+"headLasersTilt"));
if (properties.getProperty(prefix+"minimalIntensity")!=null)
this.minimalIntensity=Double.parseDouble(properties.getProperty(prefix+"minimalIntensity"));
if (properties.getProperty(prefix+"maximalIntensity")!=null)
this.maximalIntensity=Double.parseDouble(properties.getProperty(prefix+"maximalIntensity"));
if (properties.getProperty(prefix+"overexposedRadius")!=null)
this.overexposedRadius=Integer.parseInt(properties.getProperty(prefix+"overexposedRadius"));
if (properties.getProperty(prefix+"lowpassSigma")!=null)
this.lowpassSigma=Double.parseDouble(properties.getProperty(prefix+"lowpassSigma"));
if (properties.getProperty(prefix+"highpassSigma")!=null)
this.highpassSigma=Double.parseDouble(properties.getProperty(prefix+"highpassSigma"));
if (properties.getProperty(prefix+"headLowpassSigma")!=null)
this.headLowpassSigma=Double.parseDouble(properties.getProperty(prefix+"headLowpassSigma"));
if (properties.getProperty(prefix+"quadraticScaleSigma")!=null)
this.quadraticScaleSigma=Double.parseDouble(properties.getProperty(prefix+"quadraticScaleSigma"));
if (properties.getProperty(prefix+"algorithmNumber")!=null)
this.algorithmNumber=Integer.parseInt(properties.getProperty(prefix+"algorithmNumber"));
if (properties.getProperty(prefix+"closestOffender")!=null)
this.closestOffender=Integer.parseInt(properties.getProperty(prefix+"closestOffender"));
if (properties.getProperty(prefix+"fartherstOffender")!=null)
this.fartherstOffender=Integer.parseInt(properties.getProperty(prefix+"fartherstOffender"));
if (properties.getProperty(prefix+"fatZero")!=null)
this.fatZero=Double.parseDouble(properties.getProperty(prefix+"fatZero"));
if (properties.getProperty(prefix+"greenFloor")!=null)
this.greenFloor=Double.parseDouble(properties.getProperty(prefix+"greenFloor"));
if (properties.getProperty(prefix+"useOther")!=null)
this.useOther=Boolean.parseBoolean(properties.getProperty(prefix+"useOther"));
if (properties.getProperty(prefix+"otherGreen")!=null)
this.otherGreen=Boolean.parseBoolean(properties.getProperty(prefix+"otherGreen"));
if (properties.getProperty(prefix+"threshold")!=null)
this.threshold=Double.parseDouble(properties.getProperty(prefix+"threshold"));
if (properties.getProperty(prefix+"swapUV")!=null)
this.swapUV=Boolean.parseBoolean(properties.getProperty(prefix+"swapUV"));
if (properties.getProperty(prefix+"flipU")!=null)
this.flipU=Boolean.parseBoolean(properties.getProperty(prefix+"flipU"));
if (properties.getProperty(prefix+"flipV")!=null)
this.flipV=Boolean.parseBoolean(properties.getProperty(prefix+"flipV"));
if (properties.getProperty(prefix+"whiteOnly")!=null)
this.whiteOnly=Boolean.parseBoolean(properties.getProperty(prefix+"whiteOnly"));
if (properties.getProperty(prefix+"maxOffsetFromCenter")!=null)
this.maxOffsetFromCenter=Double.parseDouble(properties.getProperty(prefix+"maxOffsetFromCenter"));
if (properties.getProperty(prefix+"numberOfLaserPoints")!=null) {
numberOfLaserPoints=Integer.parseInt(properties.getProperty(prefix+"numberOfLaserPoints"));
this.laserUVMap=new double[numberOfLaserPoints][2];
for (int i=0;i<this.laserUVMap.length;i++) {
this.laserUVMap[i][0]=Double.parseDouble(properties.getProperty(prefix+"laserUVMap_"+i+"u"));
this.laserUVMap[i][1]=Double.parseDouble(properties.getProperty(prefix+"laserUVMap_"+i+"v"));
}
}
if (properties.getProperty(prefix+"laserSignalToNoise")!=null)
this.laserSignalToNoise=Double.parseDouble(properties.getProperty(prefix+"laserSignalToNoise"));
if (properties.getProperty(prefix+"localMaxRadius")!=null)
this.localMaxRadius=Double.parseDouble(properties.getProperty(prefix+"localMaxRadius"));
if (properties.getProperty(prefix+"usePatternFilter")!=null)
this.usePatternFilter=Boolean.parseBoolean(properties.getProperty(prefix+"usePatternFilter"));
if (properties.getProperty(prefix+"decimatePatternFilter")!=null)
this.decimatePatternFilter=Integer.parseInt(properties.getProperty(prefix+"decimatePatternFilter"));
if (properties.getProperty(prefix+"localContrastSigma")!=null)
this.localContrastSigma=Double.parseDouble(properties.getProperty(prefix+"localContrastSigma"));
if (properties.getProperty(prefix+"localToGlobalContrast")!=null)
this.localToGlobalContrast=Double.parseDouble(properties.getProperty(prefix+"localToGlobalContrast"));
if (properties.getProperty(prefix+"patternLowPassSigma")!=null)
this.patternLowPassSigma=Double.parseDouble(properties.getProperty(prefix+"patternLowPassSigma"));
if (properties.getProperty(prefix+"patternThreshold")!=null)
this.patternThreshold=Double.parseDouble(properties.getProperty(prefix+"patternThreshold"));
if (properties.getProperty(prefix+"maximalCellSize")!=null)
this.maximalCellSize=Double.parseDouble(properties.getProperty(prefix+"maximalCellSize"));
if (properties.getProperty(prefix+"numPasses")!=null)
this.numPasses=Integer.parseInt(properties.getProperty(prefix+"numPasses"));
if (properties.getProperty(prefix+"bordersOK")!=null)
this.bordersOK=Boolean.parseBoolean(properties.getProperty(prefix+"bordersOK"));
if (properties.getProperty(prefix+"blurredMaskThreshold")!=null)
this.blurredMaskThreshold=Double.parseDouble(properties.getProperty(prefix+"blurredMaskThreshold"));
if (properties.getProperty(prefix+"maskGrow")!=null)
this.maskGrow=Double.parseDouble(properties.getProperty(prefix+"maskGrow"));
if (properties.getProperty(prefix+"debugLevel")!=null)
this.debugLevel=Integer.parseInt(properties.getProperty(prefix+"debugLevel"));
}
public boolean showFilterDialog(String title){
GenericDialog gd = new GenericDialog(title);
gd.addNumericField("Decimate image for Pattern filter", this.decimatePatternFilter, 0,1,"x");
gd.addNumericField("Sigma to calculate local level and contrast", this.localContrastSigma, 2,5,"sensor pixels");
gd.addNumericField("Local/global contrast normalization", 100*this.localToGlobalContrast, 1,5,"%");
gd.addNumericField("Filter sigma to apply to the pattern before thresholding", this.patternLowPassSigma, 1,5,"sensor pix");
gd.addNumericField("Pattern cell threshold as a fraction of dispersion", 100*this.patternThreshold, 1,5,"%");
gd.addNumericField("Maximal pattern cell size (for discrimination)", this.maximalCellSize, 1,5,"pix");
gd.addNumericField("Number of black/white alternations of the surrounding cells to use in quadrant filtering", this.numPasses, 0);
gd.addCheckbox ("Borders as good cells for quadrant filter of possible pattern", this.bordersOK);
gd.addNumericField("Blurred white pattern cells mask (to remove separate white cells)", 100*this.blurredMaskThreshold, 1,5,"%");
gd.addNumericField("Grow final detected pattern white cells mask", this.maskGrow, 2,5,"sensor pixels");
gd.addNumericField("Debug level", this.debugLevel, 0);
gd.showDialog();
if (gd.wasCanceled()) return false;
this.decimatePatternFilter= (int) gd.getNextNumber();
this.localContrastSigma= gd.getNextNumber();
this.localToGlobalContrast= 0.01*gd.getNextNumber();
this.patternLowPassSigma= gd.getNextNumber();
this.patternThreshold= 0.01*gd.getNextNumber();
this.maximalCellSize= gd.getNextNumber();
this.numPasses= (int) gd.getNextNumber();
this.bordersOK= gd.getNextBoolean();
this.blurredMaskThreshold= 0.01*gd.getNextNumber();
this.maskGrow= gd.getNextNumber();
this.debugLevel= (int) gd.getNextNumber();
return true;
}
public boolean showDialog(String title){
return showDialog(title, -1);
}
public boolean showDialog(String title,
int numberOfPoints) { // >0 - ask only UV, <=0 all, use same number of points
GenericDialog gd = new GenericDialog(title);
if (numberOfPoints<=0) {
gd.addNumericField("Angle between 2 laser spots and horizontal (right lower than left - positive)", this.headLasersTilt, 3,7,"degrees");
gd.addNumericField("Minimal intensity at the expected pointer as a fraction of saturation", 100*this.minimalIntensity, 1,5,"%");
gd.addNumericField("Maximal expected intensity at pointer (when it is off as a fraction of scaled saturation)", 100*this.maximalIntensity, 1,5,"%");
gd.addNumericField("Do not look for the pointer closer than this distance from overexposed areas", this.overexposedRadius, 0,5,"pix");
gd.addNumericField("Target laser spot detection low pass filter (4 spots)", this.lowpassSigma, 1,5,"pix");
gd.addNumericField("Target spot detection high pass filter (4 spots)", this.highpassSigma, 1,5,"pix");
gd.addNumericField("Optical head laser spot detection low pass filter (2 spots)", this.headLowpassSigma, 1,5,"pix");
gd.addNumericField("Scale low pass sigma when quadratic interpolate for maximum (0 - no interpolation)", this.quadraticScaleSigma, 1,5,"x");
gd.addNumericField("Algorithm number to detect pointers ", this.algorithmNumber, 0,1,"");
gd.addNumericField("Do not check for above-threshold closer to the current point", this.closestOffender, 0,5,"pix");
gd.addNumericField("Prohibit above-threshold points closer to each other than", this.fartherstOffender, 0,5,"pix");
gd.addNumericField("Fat zero for combining differences", this.fatZero, 3,5,"");
gd.addNumericField("Normalization to green, floor (100% - no normalization)", 100.0*this.greenFloor, 1,5,"%");
gd.addCheckbox("Compare red to other color (green or blue)", this.useOther);
gd.addCheckbox("If compare, compare to green (unchecked - blue)", this.otherGreen);
gd.addNumericField("Red/Green difference to R/G average to be a laser spot", 100.0*this.threshold, 1,7,"%");
gd.addMessage("Default grid orientation, used if not enough pointers are visible (auto-modified when more appear)");
gd.addCheckbox("Swap U avd V",this.swapUV); // first
gd.addCheckbox("Flip U direction",this.flipU);
gd.addCheckbox("Flip V direction",this.flipV);
gd.addCheckbox("Allow laser pointers on the white cells only",this.whiteOnly);
gd.addNumericField("Maximal relative distance of the laser spot from the pattern cell center ", 100.0*this.maxOffsetFromCenter, 1,7,"%");
gd.addNumericField("Minimal pointer S/N ratio", this.laserSignalToNoise, 2,5,"x");
gd.addNumericField("Radius for finding local maximums", this.localMaxRadius, 2,5,"sensor pixels");
gd.addMessage("==== Pattern Filter Parameters ====");
gd.addCheckbox ("Use pattern filter for laser pointer detection (and apply next settings)", this.usePatternFilter);
gd.addNumericField("Decimate image for Pattern filter", this.decimatePatternFilter, 0,1,"x");
gd.addNumericField("Sigma to calculate local level and contrast", this.localContrastSigma, 2,5,"sensor pixels");
gd.addNumericField("Local/global contrast normalization", 100*this.localToGlobalContrast, 1,5,"%");
gd.addNumericField("Filter sigma to apply to the pattern before thresholding", this.patternLowPassSigma, 1,5,"sensor pix");
gd.addNumericField("Pattern cell threshold as a fraction of dispersion", 100*this.patternThreshold, 1,5,"%");
gd.addNumericField("Maximal pattern cell size (for discrimination)", this.maximalCellSize, 1,5,"pix");
gd.addNumericField("Number of black/white alternations of the surrounding cells to use in quadrant filtering", this.numPasses, 0);
gd.addCheckbox ("Borders as good cells for quadrant filter of possible pattern", this.bordersOK);
gd.addNumericField("Blurred white pattern cells mask (to remove separate white cells)", 100*this.blurredMaskThreshold, 1,5,"%");
gd.addNumericField("Grow final detected pattern white cells mask", this.maskGrow, 2,5,"sensor pixels");
gd.addNumericField("Pattern filter debug level", this.debugLevel, 0);
} else {
double [][] newLaserUVMap = new double [numberOfPoints][2];
for (int i=0; i<numberOfPoints;i++) {
newLaserUVMap[i][0]=(i>(laserUVMap.length-1))?0.0:this.laserUVMap[i][0];
newLaserUVMap[i][1]=(i>(laserUVMap.length-1))?0.0:this.laserUVMap[i][1];
}
this.laserUVMap=newLaserUVMap;
}
for (int i=0;i<this.laserUVMap.length;i++) {
gd.addMessage("Laser point "+i+" grid coordinates:");
gd.addNumericField("Grid U "+i, this.laserUVMap[i][0], 2,7,"grid periods");
gd.addNumericField("Grid V "+i, this.laserUVMap[i][1], 2,7,"grid periods");
}
if (numberOfPoints<=0) {
gd.addNumericField("Number of laser points (will ask for U V if modified)", this.laserUVMap.length, 0,2,"");
}
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
if (numberOfPoints<=0) {
this.headLasersTilt=gd.getNextNumber();
this.minimalIntensity= 0.01*gd.getNextNumber();
this.maximalIntensity= 0.01*gd.getNextNumber();
this.overexposedRadius= (int) gd.getNextNumber();
this.lowpassSigma= gd.getNextNumber();
this.highpassSigma= gd.getNextNumber();
this.headLowpassSigma= gd.getNextNumber();
this.quadraticScaleSigma= gd.getNextNumber();
this.algorithmNumber= (int) gd.getNextNumber();
this.closestOffender= (int) gd.getNextNumber();
this.fartherstOffender= (int) gd.getNextNumber();
this.fatZero= gd.getNextNumber();
this.greenFloor= 0.01*gd.getNextNumber();
this.useOther= gd.getNextBoolean();
this.otherGreen= gd.getNextBoolean();
this.threshold= 0.01*gd.getNextNumber();
this.swapUV= gd.getNextBoolean();
this.flipU= gd.getNextBoolean();
this.flipV= gd.getNextBoolean();
this.whiteOnly= gd.getNextBoolean();
this.maxOffsetFromCenter=0.01*gd.getNextNumber();
this.laserSignalToNoise= gd.getNextNumber();
this.localMaxRadius= gd.getNextNumber();
this.usePatternFilter= gd.getNextBoolean();
this.decimatePatternFilter= (int) gd.getNextNumber();
this.localContrastSigma= gd.getNextNumber();
this.localToGlobalContrast= 0.01*gd.getNextNumber();
this.patternLowPassSigma= gd.getNextNumber();
this.patternThreshold= 0.01*gd.getNextNumber();
this.maximalCellSize= gd.getNextNumber();
this.numPasses= (int) gd.getNextNumber();
this.bordersOK= gd.getNextBoolean();
this.blurredMaskThreshold= 0.01*gd.getNextNumber();
this.maskGrow= gd.getNextNumber();
this.debugLevel= (int) gd.getNextNumber();
}
for (int i=0;i<this.laserUVMap.length;i++) {
this.laserUVMap[i][0]= gd.getNextNumber();
this.laserUVMap[i][1]= gd.getNextNumber();
}
if (numberOfPoints<=0) {
numberOfPoints= (int) gd.getNextNumber();
if ((numberOfPoints > 0) && (numberOfPoints!=this.laserUVMap.length)) showDialog(title,numberOfPoints);
}
return true;
}
/*
ponterXY=laserPointers.laserPointer.getPointerXY( // returns x,y pair or null if pointer not detected
greens, // combined Bayer greens for each image, starting with no-laser
this.laserPointers.laserWasOn(nPointer), // array specifying which image should have pointer on
imp_pointed.getWidth(),// image width in pixels
imp_pointed.getTitle()+"-"+nPointer, // String title,
this.debugLevel // debug level (normal == 1)
);
*/
public boolean [] localMaximum(
double [] pixels,
int width,
int radius,
int debugLevel){
int height=pixels.length/width;
ShowDoubleFloatArrays sdfra_instance= null;
if (debugLevel>1) {
sdfra_instance= new ShowDoubleFloatArrays(); // just for debugging?
}
boolean [] bmax=new boolean[pixels.length];
// horizontal pass
double []hmax = new double [pixels.length];
for (int i=0;i<height;i++){
int j0,j1;
double max=0.0;
for (int j=0;j<width;j++){
j0=j-radius;
if (j0<0) j0=0;
j1=j+radius;
if (j1>=width) j1=width-1;
if (j>0) {
max=Math.max(max,pixels[width*i+j1]);
if ((j0>0) && (pixels[width*i+j0-1]<max)) {
hmax[i*width+j]=max;
continue; // first (to be removed) pixel was not max
}
}
max=pixels[width*i+j0];
for (int k=width*i+j0+1;k<=width*i+j1;k++) if (pixels[k]>max) max= pixels[k];
hmax[i*width+j]=max;
}
}
if (debugLevel>2) sdfra_instance.showArrays(hmax, width, height, "hmax-"+radius);
//vertical pass
for (int j=0;j<width;j++){
int i0,i1;
double max=0.0;
for (int i=0;i<height;i++){
int index=i*width+j;
i0=i-radius;
if (i0<0) i0=0;
i1=i+radius;
if (i1>=height) i1=height-1;
if (i>0) {
max=Math.max(max,hmax[width*i1+j]);
if ((i0>0) && (hmax[width*(i0-1)+j]<max)) {
bmax[index]= (pixels[index]==max);
continue; // first (to be removed) pixel was not max
}
}
max=pixels[width*i0+j];
for (int k=width*i0+j+width;k<=width*i1+j;k+=width) if (hmax[k]>max) max= hmax[k];
bmax[index]= (pixels[index]==max);
}
}
return bmax;
}
public boolean [] getPatternMask(
double [] pixels,
int width
){
ShowDoubleFloatArrays sdfra_instance= null;
if (this.debugLevel>1) sdfra_instance= new ShowDoubleFloatArrays(); // just for debugging?
DoubleGaussianBlur gb=new DoubleGaussianBlur();
double initialScale=0.5;
int height=pixels.length/width;
double scale=initialScale/this.decimatePatternFilter;
double [] dpixels;
int dheight,dwidth;
int extraWidth=0,extraHeight=0;
double k=1.0/(this.decimatePatternFilter*this.decimatePatternFilter);
double k1=0.0,k2=0.0,k3=0.0;
dwidth=width/this.decimatePatternFilter;
if (dwidth*this.decimatePatternFilter<width){
extraWidth=width-(dwidth*this.decimatePatternFilter);
dwidth++;
k1=1.0/(this.decimatePatternFilter*extraWidth);
}
dheight=height/this.decimatePatternFilter;
if (dheight*this.decimatePatternFilter<height) {
extraHeight=height- (dheight*this.decimatePatternFilter);
dheight++;
k2=1.0/(this.decimatePatternFilter*extraHeight);
}
if ((dheight>0) && (dwidth>0)) k3=1.0/(extraWidth*extraHeight);
double d;
// decimate original image (to speedup calculations)
if (this.decimatePatternFilter>1){
int i,j;
dpixels=new double [dwidth*dheight];
for (i=0;i<height/this.decimatePatternFilter;i++){
for (j=0;j<width/this.decimatePatternFilter;j++){
d=0;
int index=this.decimatePatternFilter*(i*width+j);
for (int m=0;m<this.decimatePatternFilter;m++){
for (int n=0;n<this.decimatePatternFilter;n++){
d+=pixels[index+n];
}
index+=width;
}
/*
if (i*dwidth+j>=dpixels.length){
System.out.println(
"dpixels.length="+dpixels.length+"\n"+
"width="+width+"\n"+
"height="+height+"\n"+
"dwidth="+dwidth+"\n"+
"dheight="+dheight+"\n"+
"i="+i+"\n"+
"j="+j+"\n");
}
*/
dpixels[i*dwidth+j]=d*k;
}
if (extraWidth>0){ // j==dWidth-1
d=0;
int index=this.decimatePatternFilter*(i*width+j);
for (int m=0;m<extraWidth;m++){
for (int n=0;n<this.decimatePatternFilter;n++){
d+=pixels[index+n];
}
index+=width;
}
dpixels[i*dwidth+j]=d*k1;
}
}
if (extraHeight>0){ // i==dHeight-1
for (j=0;j<width/this.decimatePatternFilter;j++){
d=0;
int index=this.decimatePatternFilter*(i*width+j);
for (int m=0;m<extraHeight;m++){
for (int n=0;n<this.decimatePatternFilter;n++){
d+=pixels[index+n];
}
index+=width;
}
dpixels[i*dwidth+j]=d*k2;
}
if (extraWidth>0){ // j==dWidth-1
d=0;
int index=this.decimatePatternFilter*(i*width+j);
for (int m=0;m<extraWidth;m++){
for (int n=0;n<this.decimatePatternFilter;n++){
d+=pixels[index+n];
}
index+=width;
}
dpixels[i*dwidth+j]=d*k3;
}
}
} else dpixels=pixels.clone();
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels, dwidth, dheight, "decimated");
double [] dpixels_lp=dpixels.clone();
gb.blurDouble(dpixels_lp, dwidth, dheight, scale*this.localContrastSigma, scale*this.localContrastSigma, 0.01);
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels_lp, dwidth, dheight, "dpixels_lp");
double sum=0.0;
for (int i=0;i<dpixels.length;i++){
dpixels[i]-=dpixels_lp[i];
dpixels_lp[i]=dpixels[i]*dpixels[i];
sum+=dpixels_lp[i];
}
double corr=(1.0-this.localToGlobalContrast)*Math.sqrt(sum/(dwidth*dheight));
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels_lp, dwidth, dheight, "dpixels_var");
gb.blurDouble(dpixels_lp, dwidth, dheight, scale*this.localContrastSigma, scale*this.localContrastSigma, 0.01);
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels_lp, dwidth, dheight, "dpixels_var_blur");
for (int i=0;i<dpixels.length;i++){
dpixels_lp[i]=this.localToGlobalContrast*Math.sqrt(dpixels_lp[i])+corr;
dpixels[i]/=dpixels_lp[i];
}
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels_lp, dwidth, dheight, "dpixels_denom");
if (this.patternLowPassSigma>0) {
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels, dwidth, dheight, "dpixels_normalized");
gb.blurDouble(dpixels, dwidth, dheight, scale*this.patternLowPassSigma, scale*this.patternLowPassSigma, 0.01);
}
if (this.debugLevel>1) sdfra_instance.showArrays(dpixels, dwidth, dheight, "dpixels_norm_blur");
int [] ipixels=new int [dpixels.length];
for (int i=0;i<dpixels.length;i++){
if (dpixels[i]>this.patternThreshold) ipixels[i]=1;
else if (dpixels[i]<-this.patternThreshold) ipixels[i]=-1;
else ipixels[i]=0;
}
if (this.debugLevel>1) sdfra_instance.showArrays(ipixels, dwidth, dheight, "ipixels_threshold");
int maxDist = (int) Math.round(scale*this.maximalCellSize);
if (maxDist<1) maxDist=1;
// TODO: save intermediate ipixels and use it with blurred version from more passes?
for (int pass=this.numPasses-1;pass>=0;pass--) {
filterQuadrant(
ipixels,
dwidth,
(pass & 1)==0, // false, // each black cell should have white in all 4 quadrants
maxDist,
this.bordersOK
);
if (this.debugLevel>2) sdfra_instance.showArrays(ipixels, dwidth, dheight, "pass-"+pass);
}
//blur-threshold-grow
// convert to Double (white cells - 1.0, black and none - 0.0)
for (int i=0;i<dpixels.length;i++) dpixels[i]= (ipixels[i]>0)?1.0:0.0;
// blur result with sigma > cell period to find continuous pattern cell areas
gb.blurDouble(dpixels, dwidth, dheight, scale*this.localContrastSigma, scale*this.localContrastSigma, 0.01);
if (this.debugLevel>2) sdfra_instance.showArrays(dpixels, dwidth, dheight, "white_blurred");
// Threshold to boolean mask
boolean [] dmask=new boolean[dpixels.length];
for (int i=0;i<dpixels.length;i++) dmask[i]= (dpixels[i]>=this.blurredMaskThreshold);
if (this.debugLevel>1) sdfra_instance.showArrays(dmask, dwidth, dheight, "white_threshold");
int iBlurMaskGrow= (int) Math.round(scale*this.localContrastSigma); // does in need separate coefficient?
growMask( dmask, //boolean [] pixels,
dwidth, // int width,
iBlurMaskGrow); //int grow);
if (this.debugLevel>1) sdfra_instance.showArrays(dmask, dwidth, dheight, "white_threshold_grown"+iBlurMaskGrow);
// Mask out white cells outside of the compact areas just found
for (int i=0;i<dpixels.length;i++) if (!dmask[i]) ipixels[i]=0;
if (this.debugLevel>1) sdfra_instance.showArrays(ipixels, dwidth, dheight, "ipixels_masked");
boolean [] mask=new boolean[pixels.length];
if (this.decimatePatternFilter>1){
for (int i=0;i<pixels.length;i++){
int y= (i/width)/this.decimatePatternFilter;
int x= (i%width)/this.decimatePatternFilter;
mask[i]= (ipixels[x+dwidth*y]==1); // "good" white cells
}
} else {
for (int i=0;i<pixels.length;i++) mask[i]= (ipixels[i]==1); // "good" white cells
}
int finalMaskGrow=(int) Math.round(this.maskGrow*initialScale);
if (this.maskGrow>0.0) {
growMask(mask, //boolean [] pixels,
width, // int width,
finalMaskGrow);// //int grow);
}
return mask;
}
void growMask(
boolean [] pixels,
int width,
int grow){
int height=pixels.length/width;
int [] distLeft= new int [pixels.length];
int [] distRight=new int [pixels.length]; // also used for down
int [] distUp= new int [pixels.length];
int v1,v2;
int index1,index2;
int initialValue=width+height;
for (int i=0;i<height;i++){
v1=initialValue;
v2=initialValue;
index1=i*width;
index2=index1+width-1;
for (int j=0;j<width;j++){
if (pixels[index1]) v1=0; else v1++;
if (pixels[index2]) v2=0; else v2++;
distLeft[index1++]=v1;
distRight[index2--]=v2;
}
}
// combine two (min distance)
for (int i=0;i<pixels.length;i++) if (distRight[i]<distLeft[i])distLeft[i]=distRight[i];
// Down
for (int j=0;j<width;j++)distRight[j]= distLeft[j]; // very top line (now used for down)
index1=0;
for (int i=width;i<pixels.length;i++){
v1=distRight[index1++]+1;
distRight[i]= (v1>distLeft[i])?distLeft[i]:v1;
}
// Up
for (int j=pixels.length-width;j<pixels.length;j++) distUp[j]= distLeft[j]; // very bottom line
index1=pixels.length-1;
for (int i=pixels.length-1-width;i>=0;i--){
v1=distUp[index1--]+1;
distUp[i]= (v1>distLeft[i])?distLeft[i]:v1;
}
// combine two (min distance)
for (int i=0;i<pixels.length;i++) if (distUp[i]<distRight[i])distRight[i]=distUp[i];
// Now distRight contains the shortest distance from the nearest enabled pixels
// update the original pixels to include tyhe new ones
for (int i=0;i<pixels.length;i++) pixels[i] |= (distRight[i]<=grow);
}
void filterQuadrant(
int [] pixels,
int width,
boolean fromBlack,
int maxDist,
boolean bordersOK
){
int height=pixels.length/width;
ShowDoubleFloatArrays sdfra_instance= null;
if (this.debugLevel>1) sdfra_instance= new ShowDoubleFloatArrays(); // just for debugging?
int [] distLeft= new int [pixels.length];
int [] distRight=new int [pixels.length]; // also used for down
int [] distUp= new int [pixels.length];
int sign=fromBlack?-1:1;
int initialValue=bordersOK?0:(width+height);
int v1,v2;
int index1,index2;
for (int i=0;i<height;i++){
v1=initialValue;
v2=initialValue;
index1=i*width;
index2=index1+width-1;
for (int j=0;j<width;j++){
if (pixels[index1]==sign) v1=0; else v1++;
if (pixels[index2]==sign) v2=0; else v2++;
distLeft[index1++]=v1;
distRight[index2--]=v2;
}
}
if (this.debugLevel>3){
sdfra_instance.showArrays(distLeft, width, height, "distLeft-"+fromBlack);
sdfra_instance.showArrays(distRight, width, height, "distRight-"+fromBlack);
}
// combine two (max distance)
for (int i=0;i<pixels.length;i++) if (distRight[i]>distLeft[i])distLeft[i]=distRight[i];
if (this.debugLevel>3) sdfra_instance.showArrays(distLeft, width, height, "comboLeftRight-"+fromBlack);
// Down
for (int j=0;j<width;j++)distRight[j]= bordersOK?0:distLeft[j]; // now used for down
index1=0;
for (int i=width;i<pixels.length;i++){
// v1=distLeft[index1++]+1;
v1=distRight[index1++]+1;
distRight[i]= (v1>distLeft[i])?distLeft[i]:v1;
}
if (this.debugLevel>3) sdfra_instance.showArrays(distRight, width, height, "distDown-"+fromBlack);
// Up
for (int j=pixels.length-width;j<pixels.length;j++) distUp[j]= bordersOK?0:distLeft[j];
index1=pixels.length-1;
for (int i=pixels.length-1-width;i>=0;i--){
// v1=distLeft[index1--]+1;
v1=distUp[index1--]+1;
distUp[i]= (v1>distLeft[i])?distLeft[i]:v1;
}
if (this.debugLevel>3) sdfra_instance.showArrays(distUp, width, height, "distUp-"+fromBlack);
// combine two (max distance)
for (int i=0;i<pixels.length;i++) if (distUp[i]>distRight[i])distRight[i]=distUp[i];
if (this.debugLevel>3) sdfra_instance.showArrays(distRight, width, height, "combo-"+fromBlack);
// Now distRight contains the longest of 4 quadrants distance from "good" pixels - remove bad opposite side ones
for (int i=0;i<pixels.length;i++) if ((distRight[i]>maxDist) && (pixels[i]!=sign)) pixels[i]=0; // if opposite signe (or 0) make 0
}
public double [] getPointerXY( // returns x,y pair or null if pointer not detected
double [][] backgroundBayer, // Bayer array of the background (lasers off) image 0,3 -G, 1-R,2-B
double [][] pointedBayer, // Bayer array of the (laser on) image
int width, // image width in pixels
boolean modBackground, // modify background array (on the first pass)
String title,
int debugLevel // debug level (normal == 1)
){
ShowDoubleFloatArrays sdfra_instance= null;
if (debugLevel>1) sdfra_instance= new ShowDoubleFloatArrays(); // just for debugging?
// As high precision is not needed we can map Bayer pixels to the same grid of half resolution of the image
// 0,3 - green 1 - red (laser)
int bayerG1=0;
int bayerG2=3;
int bayerR=1;
double avrgGreenB=0.0;
// double avrgGreenP=0.0;
int len=backgroundBayer[bayerG1].length;
int halfWidth=width/2;
int halfHeight=len/halfWidth;
if (debugLevel>2){
String subtitles[] ={"green1","red","blue","green2","combo","5"};
sdfra_instance.showArrays(pointedBayer.clone(), halfWidth, halfHeight, true, title+"-bayer", subtitles);
}
for (int i=0; i<len;i++){
if (modBackground) backgroundBayer[bayerG1][i]=0.5*(backgroundBayer[bayerG1][i]+backgroundBayer[bayerG2][i]);
avrgGreenB+=backgroundBayer[bayerG1][i];
pointedBayer[bayerG1][i]=0.5*(pointedBayer[bayerG1][i]+pointedBayer[bayerG2][i]);
// avrgGreenP+=pointedBayer[bayerG1][i];
}
avrgGreenB/=len;
// avrgGreenP/=len;
for (int i=0; i<len;i++){
if (modBackground) {
backgroundBayer[bayerR][i]/=(backgroundBayer[bayerG1][i]*(1.0-this.greenFloor)+avrgGreenB*this.greenFloor);
}
pointedBayer[bayerR][i] = pointedBayer[bayerR][i]/
(backgroundBayer[bayerG1][i]*(1.0-this.greenFloor)+avrgGreenB*this.greenFloor)-backgroundBayer[bayerR][i];
}
if (debugLevel>3) sdfra_instance.showArrays(pointedBayer[bayerR].clone(), halfWidth, halfHeight, title);
// low pass filter, 2-d
DoubleGaussianBlur gb=new DoubleGaussianBlur();
gb.blurDouble(pointedBayer[bayerR], halfWidth, halfHeight, this.lowpassSigma, this.lowpassSigma, 0.01);
if (debugLevel>2) sdfra_instance.showArrays(pointedBayer[bayerR].clone(), halfWidth, halfHeight, title+"-smooth");
// Finding just maximum, to centroid here
int indx=0;
double max=pointedBayer[bayerR][indx];
for (int i=0; i<len;i++){
if (pointedBayer[bayerR][i]>max) {
max=pointedBayer[bayerR][i];
indx=i;
}
}
double [] result={2*(indx%halfWidth)+1.0, 2*(indx/halfWidth)-1.0};
if (debugLevel>1) System.out.println("Max="+max+"(>"+this.threshold+"?), x="+result[0]+", y="+result[1]);
if (max>=this.threshold) return result;
return null;
}
public double [][] getPointerXY( // returns x,y pair or null if pointer not detected
boolean headLaserMode,
double saturationRed, // maximal red intensity scaled to reduced exposure
double scaleExposureForLasers,
// boolean skipFirst, // do not use no-pointer image (may have different exposure time)
double [][] pre_greens, // combined Bayer greens for each image, starting with no-laser (maybe Blue or none)
double [][] reds, // red Bayer component for each image, starting with no-laser
boolean [][] whichOn, // array specifying which image should have pointer on
int width, // image width in pixels
String title,
int debugLevel // debug level (normal == 1)
){
int debugTiming=1;
if (debugLevel>debugTiming) printTimingInit();
boolean skipFirst=scaleExposureForLasers>0.0; // do not use no-pointer image (may have different exposure time)
/// if (scaleExposureForLasers>0) saturationRed*=scaleExposureForLasers; // scaled to reduced exposure time
double noLaserMaxRed=(scaleExposureForLasers>0)?(saturationRed/scaleExposureForLasers):saturationRed;
if (this.maximalIntensity<1.0) noLaserMaxRed*=this.maximalIntensity;
double [][] greens=headLaserMode?null:pre_greens;
int startIndex=skipFirst?1:0;
ShowDoubleFloatArrays sdfra_instance= null;
String [] subtitles_all= null;
String [] subtitles= null;
if (debugLevel>1) {
sdfra_instance= new ShowDoubleFloatArrays(); // just for debugging?
subtitles_all= new String [reds.length];
for (int i=0;i<reds.length;i++){
subtitles_all[i]="";
for (int j=0;j<whichOn.length;j++) subtitles_all[i]+=whichOn[j][i]?"+":"-";
}
subtitles= new String [whichOn.length];
for (int i=0;i<whichOn.length;i++){
subtitles[i]="p-"+i;
}
}
// As high precision is not needed we can map Bayer pixels to the same grid of half resolution of the image
// 0,3 - green 1 - red (laser)
double avrgGreen;
double avrgRed;
int len=reds[0].length;
int halfWidth=width/2;
int halfHeight=len/halfWidth;
double minimalIntensity=saturationRed*this.minimalIntensity;
double maximalIntensity=saturationRed*this.maximalIntensity;
int [] thresholds = new int [reds[0].length];
boolean [] overexposed = new boolean [len]; /* somewhat duplicates thersholds */
for (int i=0;i<len;i++) overexposed[i]=reds[0][i] > noLaserMaxRed;
for (int i=0;i<thresholds.length;i++) thresholds[i]=0;
if (debugLevel>2){
if (greens!=null) sdfra_instance.showArrays(greens, halfWidth, halfHeight, true, "green-"+title, subtitles_all);
sdfra_instance.showArrays(reds, halfWidth, halfHeight, true, "red-"+title, subtitles_all);
}
if (debugLevel>debugTiming) printTiming("red-"+title);
boolean[] patternMask=null;
if (this.usePatternFilter){
double [] ppixels=(greens!=null)?greens[0]:reds[0];
patternMask=getPatternMask( ppixels, halfWidth );
if (debugLevel>2) sdfra_instance.showArrays(patternMask, halfWidth, halfHeight, "patternMask-"+title);
if (debugLevel>debugTiming) printTiming("patternMask-"+title);
}
for (int i=startIndex;i<reds.length;i++) {
avrgGreen=0.0;
avrgRed=0.0;
for (int j=0; j<len;j++) avrgRed+= reds[i][j];
if (greens!=null) for (int j=0; j<len;j++) avrgGreen+=greens[i][j];
avrgGreen/=len;
avrgRed/=len;
if (greens!=null){
for (int j=0; j<len;j++){
if ((reds[i][j]<minimalIntensity)) thresholds[j] |= 1; // under
if ((reds[i][j]>maximalIntensity)) thresholds[j] |= 2; // over
reds[i][j]=reds[i][j]/avrgRed- greens[i][j]/avrgGreen*(1-this.greenFloor); // always
}
} else {
for (int j=0; j<len;j++){
if ((reds[i][j]<minimalIntensity)) thresholds[j] |= 1; // under
if ((reds[i][j]>maximalIntensity)) thresholds[j] |= 2; // over
reds[i][j]/=avrgRed;
}
}
}
DoubleGaussianBlur gb=new DoubleGaussianBlur();
greens=null; // don't need it anymore
if (debugLevel>2){
System.out.println("saturationRed="+saturationRed+" minimalIntensity="+minimalIntensity+" maximalIntensity="+maximalIntensity);
sdfra_instance.showArrays(reds, halfWidth, halfHeight, true, "normalized-"+title, subtitles_all);
}
if (debugLevel>debugTiming) printTiming("normalized-"+title);
double [] dThresholds=new double [len];
for (int i=0;i<len;i++){
dThresholds[i]=((thresholds[i] & 1)!=0)?(-1): ( ((thresholds[i] & 2)!=0)?1.0:0.0 );
}
if (debugLevel>2) sdfra_instance.showArrays(dThresholds, halfWidth, halfHeight, "intensity_limits-"+title);
if (debugLevel>debugTiming) printTiming("intensity_limits-"+title);
// high-pass images
if (!headLaserMode && (this.highpassSigma>0)){
for (int numImg=startIndex;numImg<reds.length;numImg++){
double [] redBlured=reds[numImg].clone();
gb.blurDouble(redBlured, halfWidth, halfHeight, this.highpassSigma, this.highpassSigma, 0.01);
for (int i=0;i<redBlured.length;i++)reds[numImg][i]-=redBlured[i];
}
}
if (debugLevel>2)sdfra_instance.showArrays(reds, halfWidth, halfHeight, true, "highpass-"+title, subtitles_all);
if (debugLevel>debugTiming) printTiming("highpass-"+title);
// low pass filter, 2-d
double threshold=headLaserMode?this.threshold:this.threshold; // so far - the same?
double lpSigma=headLaserMode?this.headLowpassSigma:this.lowpassSigma;
double [][] diffOnOff=new double[whichOn.length][len];
double [][] noise=null; // used in algorithm 4
// int debugX=952,debugY=665,debugAround=3,debugPointer=1;
// if (headLaserMode || (this.algorithmNumber==0) || (this.algorithmNumber==2)){
if (headLaserMode || (this.algorithmNumber==0)){
for (int numPointer=0; numPointer <whichOn.length;numPointer++) for (int i=0;i<len;i++){
double on=-1.0,off=-1.0;
for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++){
if (whichOn[numPointer][nImg]){
if ((on<0) || (on>reds[nImg][i])) on=reds[nImg][i]; // smallest among "on"
} else {
if ((off<0) || (off<reds[nImg][i])) off=reds[nImg][i]; // largest among "off"
}
}
diffOnOff[numPointer][i]=on-off; // difference between lowest "on" and largest "off"
}
} else if (this.algorithmNumber==1){
for (int numPointer=0; numPointer <whichOn.length;numPointer++) {
// int numSamples=0;
int numPositiveSamples=0;
for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++){
// numSamples++;
if (whichOn[numPointer][nImg]) numPositiveSamples++;
}
for (int i=0;i<len;i++) {
diffOnOff[numPointer][i]=1.0;
for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++) {
if (whichOn[numPointer][nImg]) diffOnOff[numPointer][i] +=reds[nImg][i];
else diffOnOff[numPointer][i] -=reds[nImg][i];
}
diffOnOff[numPointer][i]/=numPositiveSamples;
}
}
} else if (this.algorithmNumber==2){
for (int numPointer=0; numPointer <whichOn.length;numPointer++) {
int numSamples=0;
// int numPositiveSamples=0;
for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++){
numSamples++;
// if (whichOn[numPointer][nImg]) numPositiveSamples++;
}
double pwr=1.0/numSamples;
for (int i=0;i<len;i++) {
double on=-1.0,off=-1.0;
for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++){
if (whichOn[numPointer][nImg]){
if ((on<0) || (on>reds[nImg][i])) on=reds[nImg][i]; // smallest among "on"
} else {
if ((off<0) || (off<reds[nImg][i])) off=reds[nImg][i]; // largest among "off"
}
}
if (on<off){
diffOnOff[numPointer][i]=0.0;
continue;
}
double average=0.5*(on+off); // middle between highest "off" and lowest "on"
diffOnOff[numPointer][i]=1.0;
for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++) {
double diff=reds[nImg][i]-average+this.fatZero;
if (!whichOn[numPointer][nImg]) diff=-diff;
if (diff>0.0) diffOnOff[numPointer][i]*=diff;
else {
diffOnOff[numPointer][i]=0;
break;
}
}
if (diffOnOff[numPointer][i]>0.0) {
diffOnOff[numPointer][i]=Math.pow(diffOnOff[numPointer][i],pwr);
}
diffOnOff[numPointer][i]-=this.fatZero;
}
}
} else if (this.algorithmNumber==3){
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
for (int i=0;i<len;i++){
double d=0.0;
for (int nImg=1;nImg<whichOn[numPointer].length; nImg++){ // skip first image with all 0ff
if (whichOn[numPointer][nImg]) d+=reds[nImg][i];
else d-=reds[nImg][i];
}
diffOnOff[numPointer][i]=d/(whichOn[numPointer].length-1);
}
}
} else if (this.algorithmNumber==4){ // sometimes long - 11.391 sec, other - 0.558 s
double avOn,avOff;
noise=new double [whichOn.length][];
if (debugLevel>debugTiming) printTiming("alg_"+this.algorithmNumber+"-start-"+title);
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
if (debugLevel>debugTiming) printTiming("numPointer-"+numPointer+"-"+whichOn[numPointer].length+"-"+len+"-"+title);
noise[numPointer]=new double[len];
for (int i=0;i<len;i++){
// double d=0.0;
avOn= 0.0;
avOff=0.0;
for (int nImg=1;nImg<whichOn[numPointer].length; nImg++){
if (whichOn[numPointer][nImg]) {
// d+=reds[nImg][i];
avOn+=reds[nImg][i];
} else {
// d-=reds[nImg][i];
avOff+=reds[nImg][i];
}
}
double d=avOn-avOff;
diffOnOff[numPointer][i]=d/(whichOn[numPointer].length-1);
avOn/=((whichOn[numPointer].length-1)/2);
avOff/=((whichOn[numPointer].length-1)/2);
double s2=0.0;
for (int nImg=1;nImg<whichOn[numPointer].length; nImg++){
d=reds[nImg][i]-((whichOn[numPointer][nImg])?avOn:avOff);
s2+=d*d;
}
// s2n[numPointer][i]=diffOnOff[numPointer][i]/(Math.sqrt(s2/(whichOn[numPointer].length-1)));
noise[numPointer][i]=(Math.sqrt(s2/(whichOn[numPointer].length-1)));
}
}
}
// mask out too dim/too bright - TODO: still need to grow overexposed mask
/* Mask out pixels closer than overexposedRadius from overesposed areas*/
//overexposedRadius
if (debugLevel>debugTiming) printTiming("alg_"+this.algorithmNumber+"-done-"+title);
if (!headLaserMode) {
int discardBorder=5;
if (this.overexposedRadius>0){
boolean [] overexposedTmp;
for (int n=0;n<this.overexposedRadius;n++){
overexposedTmp=overexposed;
overexposed=new boolean[len];
int i=0;
// System.out.println("halfWidth="+halfWidth+" halfHeight="+halfHeight+" len="+len);
for (int iy=0;iy<halfHeight;iy++) for (int ix=0;ix<halfWidth;ix++){
/*
if (i>=len){
System.out.println(" iy="+iy+" ix="+ix+" i="+i);
break;
}
overexposed[iy*halfWidth+ix] = ((iy>0) && overexposedTmp[i-halfWidth]);
overexposed[iy*halfWidth+ix] |= ((ix>0) && overexposedTmp[i-1]);
overexposed[iy*halfWidth+ix] |= ((iy<(halfHeight-1)) && overexposedTmp[i+halfWidth]);
overexposed[iy*halfWidth+ix] |= ((ix<(halfWidth-1)) && overexposedTmp[i+1]);
overexposed[i++]=
((iy>0) && overexposedTmp[i-halfWidth]) ||
((ix>0) && overexposedTmp[i-1]) ||
((iy<(halfHeight-1)) && overexposedTmp[i+halfWidth]) ||
((ix<(halfWidth-1)) && overexposedTmp[i+1]);
*/
overexposed[i] = overexposedTmp[i];
overexposed[i] |= ((iy>0) && overexposedTmp[i-halfWidth]);
overexposed[i] |= ((ix>0) && overexposedTmp[i-1]);
overexposed[i] |= ((iy<(halfHeight-1)) && overexposedTmp[i+halfWidth]);
overexposed[i] |= ((ix<(halfWidth-1)) && overexposedTmp[i+1]);
i++;
}
}
}
if (debugLevel>debugTiming) printTiming("grown_by_"+this.overexposedRadius+"-"+title);
int debugNumBorder=0;
for (int iy=0;iy<halfHeight;iy++) for (int ix=0;ix<halfWidth;ix++){
if ((iy<discardBorder) || (ix<discardBorder) || (ix>=(halfWidth-discardBorder)) || (iy>=(halfHeight-discardBorder))){
overexposed[iy*halfWidth+ix]=true;
debugNumBorder++;
}
}
int debugNumOver=0;
for (int i=0;i<len;i++){
if (overexposed[i]) debugNumOver++;
}
if (debugLevel>debugTiming) printTiming("Number of overexposed/border pixels="+debugNumOver+" border pixels="+debugNumBorder+" for "+title);
for (int numPointer=0; numPointer <whichOn.length;numPointer++) {
for (int i=0;i<len;i++) if (overexposed[i]) diffOnOff[numPointer][i]=0.0; // too close to overexposed in no-lasers image
}
for (int numPointer=0; numPointer <whichOn.length;numPointer++) for (int nImg=startIndex;nImg<whichOn[numPointer].length; nImg++){
if (whichOn[numPointer][nImg]){
// for (int i=0;i<len;i++) if ((thresholds[i]& (1<<nImg))!=0) diffOnOff[numPointer][i]=0.0; // too dim for on
for (int i=0;i<len;i++) if ((thresholds[i]& 1)!=0) diffOnOff[numPointer][i]=0.0; // too dim for on
}
// else {
// for (int i=0;i<len;i++) if ((thresholds[i]& (1<<(nImg+numImages)))!=0) diffOnOff[numPointer][i]=0.0; // too bright for off
// for (int i=0;i<len;i++) if ((thresholds[i]& 2)!=0) diffOnOff[numPointer][i]=0.0; // too bright for off
// }
}
}
if (debugLevel>2){
sdfra_instance.showArrays(diffOnOff, halfWidth, halfHeight, true, "diffOnOff-"+title, subtitles);
if (noise!=null) sdfra_instance.showArrays(noise, halfWidth, halfHeight, true, "noise-"+title, subtitles);
}
if (debugLevel>debugTiming) printTiming("diffOnOff-"+title);
if (lpSigma>0.0) {
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
gb.blurDouble(diffOnOff[numPointer], halfWidth, halfHeight, lpSigma, lpSigma, 0.01);
// TODO: use different (2x?) sigma for noise? Otherwise
if (noise!=null) gb.blurDouble(noise[numPointer], halfWidth, halfHeight, lpSigma, lpSigma, 0.01);
}
}
if (debugLevel>2){
sdfra_instance.showArrays(diffOnOff, halfWidth, halfHeight, true, "diffSmooth-"+(threshold)+"-"+title, subtitles);
if (noise!=null) sdfra_instance.showArrays(noise, halfWidth, halfHeight, true, "noise_Smooth-"+(threshold)+"-"+title, subtitles);
}
if (debugLevel>debugTiming) printTiming("diffSmooth-"+title);
if (noise!=null){
for (int numPointer=0; numPointer <whichOn.length;numPointer++) for (int i=0;i<len;i++){
noise[numPointer][i]=diffOnOff[numPointer][i]/noise[numPointer][i]; // now - s/n
}
if (debugLevel>2) sdfra_instance.showArrays(noise, halfWidth, halfHeight, true, "s2n_Smooth-"+(threshold)+"-"+title, subtitles);
if (debugLevel>debugTiming) printTiming("s2n_Smooth-"+title);
}
// zero out non-local max pixels
double [][] localMaxPixels=new double [diffOnOff.length][diffOnOff[0].length];
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
localMaxPixels[numPointer]=diffOnOff[numPointer].clone();
boolean [] isLocalMax=localMaximum(
localMaxPixels[numPointer], //double [] pixels,
halfWidth, // int width,
(int) this.localMaxRadius/2, //); //int radius)
debugLevel-1);
if (debugLevel>3) sdfra_instance.showArrays(isLocalMax, halfWidth, halfHeight, "isLocalMax-"+(numPointer)+"-"+title);
for (int i=0;i<localMaxPixels[numPointer].length;i++) if (!isLocalMax[i]) localMaxPixels[numPointer][i]=0.0;
}
// remove close to overexposed and border pixels
if (!headLaserMode) {
for (int numPointer=0; numPointer <whichOn.length;numPointer++) {
for (int i=0;i<len;i++) if (overexposed[i]) localMaxPixels[numPointer][i]=0.0; // too close to overexposed in no-lasers image
}
}
if (debugLevel>2) sdfra_instance.showArrays(localMaxPixels, halfWidth, halfHeight, true, "localmax-"+(threshold)+"-"+title, subtitles);
if (debugLevel>debugTiming) printTiming("localmax-"+title);
// filter by S/N ratio
if (noise!=null){
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
for (int i=0;i<localMaxPixels[numPointer].length;i++) if (noise[numPointer][i]<this.laserSignalToNoise) localMaxPixels[numPointer][i]=0.0;
}
if (debugLevel>2)sdfra_instance.showArrays(localMaxPixels, halfWidth, halfHeight, true, "localmax_s2n-"+(this.laserSignalToNoise)+"-"+title, subtitles);
if (debugLevel>debugTiming) printTiming("localmax_s2n-"+title);
}
double [] firstMax= new double [whichOn.length];
int [] firstMaxIndex=new int [whichOn.length];
int [] numberOfMax=new int [whichOn.length];
// final filter by a global threshold
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
firstMax[numPointer]=0.0;
numberOfMax[numPointer]=0;
firstMaxIndex[numPointer]=0;
for (int i=0;i<localMaxPixels[numPointer].length;i++) {
if ((localMaxPixels[numPointer][i]> 0.0) && (localMaxPixels[numPointer][i]>=threshold)){ // is threshold>0.0 always
if (localMaxPixels[numPointer][i]>firstMax[numPointer]) {
firstMax[numPointer]=localMaxPixels[numPointer][i];
firstMaxIndex[numPointer]=i;
}
numberOfMax[numPointer]++;
} else{
localMaxPixels[numPointer][i]=0.0;
}
}
}
// zero out all out of pattern maximums
if (patternMask!=null){
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
for (int i=0;i<localMaxPixels[numPointer].length;i++) if (!patternMask[i]) localMaxPixels[numPointer][i]=0.0;
}
if (debugLevel>2) sdfra_instance.showArrays(localMaxPixels, halfWidth, halfHeight, true, "in-patt-max-"+(threshold)+"-"+title, subtitles);
if (debugLevel>debugTiming) printTiming("in-patt-max-"+title);
}
if (debugLevel>2)sdfra_instance.showArrays(localMaxPixels, halfWidth, halfHeight, true, "localmax_threshold-"+(this.laserSignalToNoise)+"-"+title, subtitles);
if (debugLevel>debugTiming) printTiming("localmax_threshold-"+(this.laserSignalToNoise)+"-"+title);
if (debugLevel>1) {
String dbgStr="";
for (int numPointer=0; numPointer <numberOfMax.length;numPointer++) if (numberOfMax[numPointer]>0){
dbgStr+=" "+numPointer+":"+IJ.d2s(firstMax[numPointer],4)+" ["+(firstMaxIndex[numPointer]%halfWidth)+":"+
(firstMaxIndex[numPointer]/halfWidth)+"]("+numberOfMax[numPointer]+")";
}
if (dbgStr.length()>0) System.out.println("Maximums found: "+dbgStr);
}
// remove smaller maximum if it is too close to larger one, and if there are some left - find the next replacement
while (this.fartherstOffender>0){
int n1=-1,n2=-1;
boolean tooClose=false;
double co2=0.25*this.fartherstOffender*this.fartherstOffender;
for (n1=0;n1<numberOfMax.length;n1++) if (numberOfMax[n1]>0){
for (n2=n1+1;n2<numberOfMax.length;n2++) if (numberOfMax[n2]>0){
double dx=(firstMaxIndex[n1]%halfWidth)-(firstMaxIndex[n2]%halfWidth);
double dy=(firstMaxIndex[n1]/halfWidth)-(firstMaxIndex[n2]/halfWidth);
if (dx*dx+dy*dy < co2) {
tooClose=true;
if (debugLevel>0) { // rare events, output details to verify program
System.out.println ("Two detected pointers in image "+title+": "+n1+"("+numberOfMax[n1]+") and "+n2+"("+numberOfMax[n2]+") are too close,");
System.out.println ("Distance="+IJ.d2s(2*Math.sqrt(dx*dx+dy*dy),3)+" sensor pixels is smaller than configured limit of "+this.fartherstOffender);
}
break;
}
}
if (tooClose) break;
}
if (!tooClose) break;
int numPointer= (firstMax[n1]>firstMax[n2])?n2:n1;
if (debugLevel>0) { // rare events, output details to verify program
int numFirstPointer=(firstMax[n1]>firstMax[n2])?n1:n2;
System.out.println ("More intense pointer is #"+numFirstPointer+" ("+firstMax[numFirstPointer]+"), x="
+(2*(firstMaxIndex[numFirstPointer]%halfWidth))+" y="+(2*(firstMaxIndex[numFirstPointer]/halfWidth)));
System.out.println ("Will remove other pointer #"+numPointer+" ("+firstMax[numPointer]+"), x="
+(2*(firstMaxIndex[numPointer]%halfWidth))+" y="+(2*(firstMaxIndex[numPointer]/halfWidth)));
}
localMaxPixels[numPointer][firstMaxIndex[numPointer]]=0.0;
numberOfMax[numPointer]--;
if (numberOfMax[numPointer]>0){ // look for the next maximum
firstMax[numPointer]=localMaxPixels[numPointer][0];
firstMaxIndex[numPointer]=0;
for (int i=0;i<localMaxPixels[numPointer].length;i++) if ((localMaxPixels[numPointer][i]>0) && (localMaxPixels[numPointer][i]>firstMax[numPointer])){
firstMax[numPointer]=localMaxPixels[numPointer][i];
firstMaxIndex[numPointer]=i;
}
if (debugLevel>0) { // rare events, output details to verify program
System.out.println ("Found replacement pointer for #"+numPointer+" ("+firstMax[numPointer]+"), x??="
+(2*(firstMaxIndex[numPointer]%halfWidth))+" y??="+(2*(firstMaxIndex[numPointer]/halfWidth)));
System.out.println (numberOfMax[numPointer]+ " pointer candidate"+((numberOfMax[numPointer]>1)?"s":"")+" remain"+((numberOfMax[numPointer]>1)?"s":"")+".");
}
}
}
/*
// remove points close (but not too close) to bright/overexposed OBSOLETE?
if (!headLaserMode && (this.fartherstOffender>0)) {
for (int numPointer=0; numPointer <whichOn.length;numPointer++){ //
// for (int i=0;i<diffOnOff[numPointer].length;i++) if (diffOnOff[numPointer][i]>=threshold){
for (int i=0;i<diffOnOff[numPointer].length;i++) if (localMaxPixels[numPointer][i]>=threshold){
int xc=i%halfWidth;
int yc=i/halfWidth;
int xMin=xc-this.fartherstOffender;
int xMax=xc+this.fartherstOffender;
int yMin=yc-this.fartherstOffender;
int yMax=yc+this.fartherstOffender;
int xMinC=xc-this.closestOffender;
int xMaxC=xc+this.closestOffender;
int yMinC=yc-this.closestOffender;
int yMaxC=yc+this.closestOffender;
if (xMin<0) xMin=0;
if (xMax>=halfWidth) xMax=halfWidth-1;
if (yMin<0) yMin=0;
if (yMax>=halfHeight) yMax=halfHeight-1;
for (int y=yMin;y<=yMax;y++)
for (int x=xMin;x<=xMax;x++)
if (!((x>xMinC) && (x<xMaxC) && (y>yMinC) && (y<yMaxC)) && ((thresholds[y*halfWidth+x]& 2)!=0)) {
diffOnOff[numPointer][i]=0.0;
break;
}
}
}
if (debugLevel>2) sdfra_instance.showArrays(diffOnOff, halfWidth, halfHeight, true, "filteredSmooth-"+title, subtitles);
}
*/
// Finding just maximums, no centroid here
double [][] pointers = new double[whichOn.length][];
for (int numPointer=0; numPointer <whichOn.length;numPointer++){
if (numberOfMax[numPointer]>0) {
pointers[numPointer]=new double[2];
int [] localMaxXY={firstMaxIndex[numPointer]%halfWidth,firstMaxIndex[numPointer]/halfWidth};
double [] dMaxXY= {localMaxXY[0], localMaxXY[1]};
if (debugLevel>2) System.out.println("Pointer "+numPointer+" max X="+dMaxXY[0]+" max Y="+dMaxXY[1]);
if (this.quadraticScaleSigma>0.0){
double quadSigma=this.quadraticScaleSigma*((lpSigma>0.0)?lpSigma:1.0);
double k=0.5/(quadSigma*quadSigma);
int range=(int) Math.round(quadSigma*3.0);
if (range<1) range=1;
int minX=localMaxXY[0]-range;
int maxX=localMaxXY[0]+range;
int minY=localMaxXY[1]-range;
int maxY=localMaxXY[1]+range;
if (minX<0)minX=0;
if (minY<0)minY=0;
if (maxX>= halfWidth) maxX= halfWidth-1;
if (maxY>=halfHeight) maxY=halfHeight-1;
double [][][] data =new double [(maxX-minX+1)*(maxY-minY+1)][3][];
int index=0;
for (int y=minY;y<=maxY;y++) for (int x=minX;x<=maxX;x++){
data[index][0] = new double [2];
data[index][0][0] = x-localMaxXY[0];
data[index][0][1] = y-localMaxXY[1];
data[index][1]= new double[1];
data[index][1][0]= diffOnOff[numPointer][x+halfWidth*y];
data[index][2]= new double[1];
data[index][2][0]= Math.exp(-k*(data[index][0][0]*data[index][0][0] + data[index][0][1]*data[index][0][1]));
index++;
}
double [] corrXY=(new PolynomialApproximation()).quadraticMax2d (data);
if (corrXY!=null) {
dMaxXY[0]+=corrXY[0];
dMaxXY[1]+=corrXY[1];
}
if (debugLevel>2) { // something wrong, (E-17)
if (corrXY!=null) System.out.println("Pointer "+numPointer+" corr X="+corrXY[0]+" corr Y="+corrXY[1]);
else System.out.println("Pointer "+numPointer+": failed to find correction by quadratic approximation of the vicinity");
}
}
// bayer shift
pointers[numPointer][0]=2*dMaxXY[0]+1.0;
pointers[numPointer][1]=2*dMaxXY[1]+0.0; //-1.0;
} else pointers[numPointer]=null;
if (debugLevel>1) {
if (pointers[numPointer]!=null) System.out.println("Pointer "+numPointer+": Max="+firstMax[numPointer]+"(>"+this.threshold+"?), x="+
pointers[numPointer][0]+", y="+pointers[numPointer][1]);
else if (debugLevel>2) System.out.println("Pointer "+numPointer+" is not detected");
}
}
if (debugLevel>debugTiming) printTiming("getPointerXY()-done for "+title);
return pointers;
}
}
......@@ -45,7 +45,7 @@ public class LensAdjustment {
MatchSimulatedPattern.DistortionParameters distortionParametersDefault,
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters,
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
MatchSimulatedPattern.LaserPointer laserPointer, // null OK
LaserPointer laserPointer, // null OK
SimulationPattern.SimulParameters simulParametersDefault,
boolean maskNonPSF, // mask out areas not needed for focusing PSF measurements
boolean equalizeGreens,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
package com.elphel.imagej.calibration;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import ij.IJ;
import ij.gui.GenericDialog;
public class UVLEDandLasers{
public int debugLevel=1;
private int state=-1; // bit-wise on/off, <0 - undefined
private String uvLasersIP="192.168.0.236";
public int uvLasersBus=0;
public double [] uvLasersCurrents={0,0,0,0}; // will be overwritten
public boolean [] laserState=null;
public boolean [] uvState=null;
public double maxCurrent=100; //mA
public long [] lastExposureStart={-1,-1,-1,-1}; // timestamp the LED was last turned to this current
public double [] runningCurrent={0.0,0.0,0.0,0.0}; // currently running current, mA
public double [] ampsSeconds={0.0,0.0,0.0,0.0}; // cumulative Amps*seconds
public UVLEDandLasers(
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
}
public void setParameters(
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
this.uvLasersIP=focusMeasurementParameters.uvLasersIP;
this.uvLasersBus=focusMeasurementParameters.uvLasersBus;
this.uvLasersCurrents=focusMeasurementParameters.uvLasersCurrents;
this.ampsSeconds=focusMeasurementParameters.ampsSeconds;
for (int i=0;i<this.uvLasersCurrents.length;i++) {
if (this.uvLasersCurrents[i]>this.maxCurrent) this.uvLasersCurrents[i]=this.maxCurrent;
if (this.uvLasersCurrents[i]<0.0) this.uvLasersCurrents[i]=0.0;
}
}
public void getParameters(
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
focusMeasurementParameters.uvLasersIP=this.uvLasersIP;
focusMeasurementParameters.uvLasersBus=this.uvLasersBus;
focusMeasurementParameters.uvLasersCurrents=this.uvLasersCurrents;
}
public boolean uvLaserSettings(
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
boolean result=uvLaserSettings();
getParameters(focusMeasurementParameters);
return result;
}
public boolean uvControl(
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
boolean result=uvControl();
getParameters(focusMeasurementParameters);
return result;
}
public void updateCurrents(){
long thisTime=System.nanoTime();
for (int i=0;i<uvState.length;i++){
if (this.debugLevel>3) System.out.println("LED"+i+" runningCurrent="+runningCurrent[i]+" time passed="+
(thisTime-lastExposureStart[i])+" amps-sec="+ampsSeconds[i]);
if (runningCurrent[i]>0) ampsSeconds[i]+=(0.001*runningCurrent[i])*(0.000000001*(thisTime-lastExposureStart[i]));
lastExposureStart[i]=thisTime;
runningCurrent[i]=(uvState[i])?uvLasersCurrents[i]:0.0;
if (this.debugLevel>3) System.out.println("LED"+i+" new runningCurrent="+runningCurrent[i]);
}
}
public void resetCumulativeCurrents(){
long thisTime=System.nanoTime();
for (int i=0;i<uvState.length;i++){
ampsSeconds[i]=0.0;
lastExposureStart[i]=thisTime;
runningCurrent[i]=(uvState[i])?uvLasersCurrents[i]:0.0;
}
}
///55 504 690 774
//3 220 482 180 430 159
/**
* returns true if any of the UV LEDs is (or was if dialog canceled) on
*/
public boolean uvControl(){
updateStatus();
GenericDialog gd = new GenericDialog("UV LED Control");
gd.addMessage("IP address="+this.uvLasersIP+" i2c bus="+this.uvLasersBus);
gd.addMessage("UV LEDs are referenced when viewd from the target to the camera");
gd.addCheckbox("UV LED 0 (left/near), "+this.uvLasersCurrents[0]+" mA (total "+IJ.d2s(ampsSeconds[0],3)+" Amp-sec)",this.uvState[0]);
gd.addCheckbox("UV LED 1 (right/near),"+this.uvLasersCurrents[1]+" mA (total "+IJ.d2s(ampsSeconds[1],3)+" Amp-sec)",this.uvState[1]);
gd.addCheckbox("UV LED 2 (right/far), "+this.uvLasersCurrents[2]+" mA (total "+IJ.d2s(ampsSeconds[2],3)+" Amp-sec)",this.uvState[2]);
gd.addCheckbox("UV LED 3 (left/far), "+this.uvLasersCurrents[3]+" mA (total "+IJ.d2s(ampsSeconds[3],3)+" Amp-sec)",this.uvState[3]);
gd.addCheckbox("Turn them all",false);
gd.addCheckbox("Reset cumulative Amps-seconds",false);
gd.enableYesNoCancel("Apply", "Change Currents, then apply");
boolean anyOn=false;
for (int i=0;i<uvState.length;i++ ) anyOn|=uvState[i];
gd.showDialog();
if (gd.wasCanceled()) return anyOn;
if (!gd.wasOKed()) {
if (!uvLaserSettings()) return anyOn;
}
this.uvState[0]=gd.getNextBoolean();
this.uvState[1]=gd.getNextBoolean();
this.uvState[2]=gd.getNextBoolean();
this.uvState[3]=gd.getNextBoolean();
if (gd.getNextBoolean()){
this.uvState[0]=true;
this.uvState[1]=true;
this.uvState[2]=true;
this.uvState[3]=true;
}
if (gd.getNextBoolean())resetCumulativeCurrents();
setLasersAndUV(
null, // lasers - do not touch
this.uvState, // may be null
this.uvLasersCurrents// may be null
);
anyOn=false;
for (int i=0;i<uvState.length;i++ ) anyOn|=uvState[i];
return anyOn;
}
/*
* public double [] uvLasersCurrents={0,0,0,0}; // will be overwritten
public boolean [] laserState=null;
public boolean [] uvState=null;
*/
public boolean uvLaserSettings(){
GenericDialog gd = new GenericDialog("UV LED and laser configuration (103641 board)");
gd.addStringField ("IP address of the camera with 103641 board (UV LEDs and lasers) are attached", this.uvLasersIP,40);
gd.addNumericField("I2C bus where LED/laser board is attached (0 - through 10359, 1 - through 10369)", this.uvLasersBus, 0);
// gd.addMessage("New value for LED current will not be applied to the turned on device in this dialog");
gd.addNumericField("UV LED1 \"on\" current (left/near when looking from the target)", this.uvLasersCurrents[0], 3,5,"mA");
gd.addNumericField("UV LED2 \"on\" current (right/near when looking from the target)", this.uvLasersCurrents[0], 3,5,"mA");
gd.addNumericField("UV LED3 \"on\" current (right/far when looking from the target)", this.uvLasersCurrents[0], 3,5,"mA");
gd.addNumericField("UV LED4 \"on\" current (left/far when looking from the target)", this.uvLasersCurrents[0], 3,5,"mA");
gd.showDialog();
if (gd.wasCanceled()) return false;
this.uvLasersIP= gd.getNextString();
this.uvLasersBus= (int) gd.getNextNumber();
this.uvLasersCurrents[0]= gd.getNextNumber();
this.uvLasersCurrents[1]= gd.getNextNumber();
this.uvLasersCurrents[2]= gd.getNextNumber();
this.uvLasersCurrents[3]= gd.getNextNumber();
for (int i=0;i<this.uvLasersCurrents.length;i++) {
if (this.uvLasersCurrents[i]>this.maxCurrent) this.uvLasersCurrents[i]=this.maxCurrent;
if (this.uvLasersCurrents[i]<0.0) this.uvLasersCurrents[i]=0.0;
}
return true;
}
public boolean allOff(LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
return allOff();
}
public boolean uvOff(LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
return uvOff();
}
public boolean lasersToggle (LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
return lasersToggle();
}
public boolean lasersOff(LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
return lasersOff();
}
public boolean lasersOn(LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
return lasersOn();
}
public boolean setLasersAndUV(
boolean [] lasersOn, // may be null
boolean [] uvOn, // may be null
double [] uvCurrents,// may be null
LensAdjustment.FocusMeasurementParameters focusMeasurementParameters){
setParameters(focusMeasurementParameters);
return setLasersAndUV(lasersOn,uvOn,uvCurrents);
}
public boolean allOff(){
boolean [] lasersOn={false,false};
boolean [] uvOn={false,false,false,false};
return setLasersAndUV(lasersOn,uvOn,null);
}
public boolean uvOff(){
boolean [] uvOn={false,false,false,false};
return setLasersAndUV(null,uvOn,null);
}
public boolean lasersToggle(){
updateStatus();
for (int i=0;i<this.laserState.length;i++) this.laserState[i]=!this.laserState[i];
return setLasersAndUV(this.laserState,null,null);
}
public boolean lasersOff(){
boolean [] lasersOn={false,false};
return setLasersAndUV(lasersOn,null,null);
}
public boolean lasersOn(){
boolean [] lasersOn={true,true};
return setLasersAndUV(lasersOn,null,null);
}
public boolean setLasersAndUV(
boolean [] lasersOn, // may be null
boolean [] uvOn, // may be null
double [] uvCurrents// may be null
){
if (this.debugLevel>2) System.out.println("lasersOn="+((lasersOn==null)?"null":("{"+lasersOn[0]+","+lasersOn[1]+"}"))+
" uvOn="+((uvOn==null)?"null":("{"+uvOn[0]+","+uvOn[1]+","+uvOn[2]+","+uvOn[3]+"} "))+
" uvCurrents="+((uvCurrents==null)?"null":("{"+uvCurrents[0]+","+uvCurrents[1]+","+uvCurrents[2]+","+uvCurrents[3]+"} ")));
String command="";
if (lasersOn!=null) for (int i=0;i<lasersOn.length;i++) {
command+="&laser"+i+"="+(lasersOn[i]?1:0);
}
if (uvOn!=null) for (int i=0;i<uvOn.length;i++) {
int data=(uvOn[i] && (uvCurrents!=null) && (uvCurrents.length>i))?((int) Math.round(uvCurrents[i])):0;
command+="&uv"+i+"="+data;
}
boolean result=commandToDevice(command);
if (result) updateCurrents();
return result;
}
public boolean [] getLasers(){
updateStatus();
return this.laserState;
}
/**
* Will send an empty command (just i2c bus number) and update current state of LEDs and lasers (if they were modified by other master)
* @return true if OK, false - failure (not yet used, now all errors throw)
*/
public boolean updateStatus(){
return commandToDevice("");
}
public boolean commandToDevice(String command){
String url="http://"+this.uvLasersIP+"/103641.php?bus="+this.uvLasersBus+command; // should start with "&"
if (this.debugLevel>1) System.out.println("setDevice: "+url);
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("board_103641")) {
String msg="Root element: expected \"board_103641\", got\"" + dom.getDocumentElement().getNodeName()+"\"";
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
String quoted=((dom.getDocumentElement().getElementsByTagName("data9500").item(0).getChildNodes().item(0)).getNodeValue());
// remove opening and closing "
if (quoted.startsWith("\"")){
quoted=quoted.substring(1, quoted.length()-1);
}
this.state=Integer.decode(quoted);
if (this.state==0){ // should normally not happen
String msg="Data read from the board is 0, that is not currently possible if everything works.";
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
} catch(MalformedURLException e){
String msg="Please check the URL:" + e.toString();
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
} catch(IOException e1){
String msg = e1.getMessage();
if (msg==null || msg.equals("")) msg = ""+e1;
IJ.showMessage("Error",msg);
return false;
// throw new IllegalArgumentException (msg);
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
return false;
}catch(SAXException se) {
se.printStackTrace();
return false;
}
boolean [] laserState={
(this.state & 0x10)==0,
(this.state & 0x20)==0};
boolean [] uvState={
(this.state & 0x01)==0,
(this.state & 0x02)==0,
(this.state & 0x04)==0,
(this.state & 0x08)==0};
//http://192.168.0.13/i2c.php?bus=1&raw=0x2700&data=0xdf
this.laserState=laserState;
this.uvState=uvState;
return true;
}
}
\ No newline at end of file
package com.elphel.imagej.calibration.hardware;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.elphel.imagej.calibration.MatchSimulatedPattern;
import com.elphel.imagej.calibration.UVLEDandLasers;
import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.jp4.JP46_Reader_camera;
import ij.IJ;
import ij.ImagePlus;
import ij.Prefs;
import ij.gui.GenericDialog;
import ij.io.FileSaver;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
public class CamerasInterface{
// JP46_Reader_camera JP4_INSTANCE= new JP46_Reader_camera(false);
public LaserPointersHardware laserPointers=null;
private int masterSubCamera=0; // "master" camera index of IP in the list
private int masterPort= 0; // "master" camera port (0..3) to apply trigger to
private JP46_Reader_camera [] jp4_Instances=null;
private String [] resetURLs=null;
private String [] imageURLs=null;
private String [] metaURLs=null;
private String triggerURL="";
private boolean [] flipImages=null;
private ImagePlus [] images= null; // to reuse same instances
private ImagePlus [] imagesIP= null;
// TODO: when saving/restoring save cameraSubnet, iBaseIP, cameraIPs, so any IPs are OK through config, generate - sequential
private String cameraSubnet="192.168.0.";
private int iBaseIP=236;
private String [] cameraIPs = null; // since nc393 port is a part of cameraIPs[]
private int [] channelIPPort = null; // index in camareIPs (each IP/port combination) for each individual sensor
private int imgsrvPort=8081;
private String resetURLcmd="towp/save/pointers"; // advance buffer, next time will wait for the next frame acquired
// will return XML, just "trig" - 1x1 GIF
private String triggerURLcmd="trig/pointers"; // TRIG=4 should be set in advance, this command will set in single-shot trigger mode
private String imageURLcmd="torp/wait/bimg"; // will wait if needed. If repeated (as when reading Exif)- won't wait
private String metaURLcmd="torp/wait/meta"; // will get XML, including timestamp
private String lastTimestamp="";
public int debugLevel=2;
private double lastTemperature=Double.NaN;
private int colorMode=5; // JP4
private boolean noWait= true; // when false, IRQ_SMART=3 and the frame is available only 1 frame later, when true IRQ_SMART=6, frame is available after compression end
private boolean nc393 = false;
private int debugSensorNumber=-1; // increase debug level for this particular sensor
private int JPEGquality=99; // JPEG quality
private boolean cameraAutoExposure = false;
private boolean cameraAutoWhiteBalance =false;
private String cameraExtraURLCommon = ""; // (should start with "&")
private boolean setupTriggerMode= false;
private boolean externalTriggerCabling=false;
private boolean noCabling= false; // for single camera
private double cameraExposure= 5.0;
private double scaleExposureForLasers= 0.4;
private double scaleExposureForHeadLasers= 0.05;
private double cameraAutoExposureMax= 30.0; //Maximal autoexposure value
private double cameraGain = 2.0;
private double cameraRScale =1.25;
private double cameraBScale =1.5;
private double cameraGScale =1.0;
private double [] cameraExposureCorr=null; // per-camera exposure correction1
private double [] cameraGainCorr = null; // per-camera gain correction;
private double [] cameraRScaleCorr = null; // per-camera R/G scale correction;
private double [] cameraBScaleCorr = null; // per-camera B/G scale correction;
private double [] cameraGScaleCorr = null; // per-camera GB/G scale correction;
private String [] cameraExtraURL = null; // per-camera extra URL (should start with "&")
// these are initialized after being null, when the cameras are probed
private int [] cameraFrameNumber=null;
private boolean [] triggeredMode= null; // true - triggered, false - free running
private boolean [][] sensorPresent= null; // probe which sensors (of 3) are detected per system board (NC393 - per board/port)
// TODO - try if skipping setting TRIG_PERIOD=0, IRQ_SMART=6 (when they are already set) will fix hanging
private int [] triggerPeriod= null;
private int [] cameraMasterPort= null;
private int [] irqSmart= null;
private int [] motorsPosition= null; // motors steps when the images were acquired (for null)
private long startTime=System.nanoTime();
private long lastTime=startTime;
private long thisTime=startTime;
public boolean reportTiming=false;
public int cameraBootTimeSeconds=100;
public int connectionTimeoutMilliseconds=3000;
private void printTiming(String title){
if (this.reportTiming) {
this.thisTime=System.nanoTime();
System.out.println(title+ " done at "+IJ.d2s(0.000000001*(this.thisTime-this.startTime),3)+
" (+"+IJ.d2s(0.000000001*(this.thisTime-this.lastTime),3)+") sec");
this.lastTime=this.thisTime;
}
}
private void printTimingInit(){
this.startTime=System.nanoTime();
this.lastTime=this.startTime;
this.thisTime=this.startTime;
}
private int [][] channelMap_23_393={ // ip index, channel number, port
{0,0,3},{0,0,2},{0,0,0},{0,0,1},{1,0,3},{1,0,2},{1,0,0},{1,0,1},
{0,1,3},{0,1,2},{0,1,0},{0,1,1},{1,1,3},{1,1,2},{1,1,0},{1,1,1},
{0,2,3},{0,2,2},{0,2,0},{0,2,1},{1,2,3},{1,2,2},{1,2,0},{1,2,1},
{2,0,2},{2,0,3}};
private int [][] channelMap21={ // ip index, channel number
{0,1,0},{0,0,0},{0,2,0},
{1,1,0},{1,0,0},{1,2,0},
{2,1,0},{2,0,0},{2,2,0},
{3,1,0},{3,0,0},{3,2,0},
{4,1,0},{4,0,0},{4,2,0},
{5,1,0},{5,0,0},{5,2,0},
{6,1,0},{6,0,0},{6,2,0}};
private int [][] channelMap1={ // ip index, channel number
// {0,-1}}; // negative channel - single camera
{0,0,0}}; // Try with 0
private int [][] channelMap2={ // ip index, channel number
{0,0,0},{0,1,0}};
private int [][] channelMap3={ // ip index, channel number
// {0,-1}}; // negative channel - single camera
{0,0,0},{1,0,0},{2,0,0}};
private int [][] channelMap=null;
public int maxNumberOfThreads=100;
/**
* Initialize JP46_Reader_camera instances, one per sub-camera
*/
public CamerasInterface(int size, LaserPointersHardware laserPointers){
this.laserPointers=laserPointers;
initDefaultMap(size);
initIPs();
initJP4();
initCamParsDefaultArrays(this.cameraIPs.length);
}
public CamerasInterface(int size){
initDefaultMap(size);
initIPs();
initJP4();
initCamParsDefaultArrays(this.cameraIPs.length);
}
public void setNumberOfThreads(int n){
this.maxNumberOfThreads=n;
}
public int getSubCamera (int channelNumber){
return ((channelNumber>=0)&& (channelNumber<this.channelMap.length))?this.channelMap[channelNumber][0]:-1;
}
public int getSubChannel (int channelNumber){
return ((channelNumber>=0)&& (channelNumber<this.channelMap.length))?this.channelMap[channelNumber][1]:-1;
}
public int getSensorPort (int channelNumber){
return ((channelNumber>=0)&& (channelNumber<this.channelMap.length))?this.channelMap[channelNumber][2]:-1;
}
// not used anywhere
public int getChannel (int subCam, int subChn){
return getChannel (subCam, subChn, 0); // for compatibility with 353
}
public int getChannel (int subCam, int subChn, int port){
for (int channelNumber=0;channelNumber<this.channelMap.length;channelNumber++)
if ((this.channelMap[channelNumber][0]==subCam) &&
(this.channelMap[channelNumber][1]==subChn) &&
(this.channelMap[channelNumber][2]==port)) return channelNumber;
return -1;
}
private void initJP4(){
this.jp4_Instances=new JP46_Reader_camera[this.cameraIPs.length];
this.resetURLs=new String [this.cameraIPs.length];
this.imageURLs=new String [this.cameraIPs.length];
this.metaURLs= new String [this.cameraIPs.length];
// this.triggerURL is already defined
// this.triggerURL="http://"+this.cameraIPs[this.masterSubCamera]+":"+(this.imgsrvPort+this.masterPort)+"/"+triggerURLcmd;
this.images= new ImagePlus[this.channelMap.length];
this.imagesIP= new ImagePlus[this.cameraIPs.length];
for (int i=0; i<this.cameraIPs.length;i++){
this.jp4_Instances[i]=new JP46_Reader_camera(false);// invisible
// this.jp4_Instances[i].camera_url="http://"+this.cameraIPs[i]+":"+this.imgsrvPort+"/";
this.jp4_Instances[i].camera_url="http://"+this.cameraIPs[i]+"/";
this.jp4_Instances[i].camera_img= this.imageURLcmd; // not currently used
this.jp4_Instances[i].camera_img_new=this.imageURLcmd; //"torp/wait/" will survive, only "towp/wait/" is removed for Exif re-read
this.jp4_Instances[i].ABSOLUTELY_SILENT=true;
// this.resetURLs[i]="http://"+this.cameraIPs[i]+":"+this.imgsrvPort+"/"+resetURLcmd;
// this.imageURLs[i]="http://"+this.cameraIPs[i]+":"+this.imgsrvPort+"/"+this.imageURLcmd;
// this.metaURLs[i]= "http://"+this.cameraIPs[i]+":"+this.imgsrvPort+"/"+metaURLcmd;
this.resetURLs[i]="http://"+this.cameraIPs[i]+"/"+resetURLcmd;
this.imageURLs[i]="http://"+this.cameraIPs[i]+"/"+this.imageURLcmd;
this.metaURLs[i]= "http://"+this.cameraIPs[i]+"/"+metaURLcmd;
this.imagesIP[i]= null;
}
for (int i=0; i<this.images.length;i++) this.images[i]= null;
}
private void initCamParsDefaultArrays(int num){
this.cameraExposureCorr=new double[num];
this.cameraGainCorr= new double[num];
this.cameraRScaleCorr= new double[num];
this.cameraBScaleCorr= new double[num];
this.cameraGScaleCorr= new double[num];
this.cameraExtraURL= new String[num];
for (int i=0; i<num;i++){
this.cameraExposureCorr[i]=1.0;
this.cameraGainCorr[i]= 1.0;
this.cameraRScaleCorr[i]= 1.0;
this.cameraBScaleCorr[i]= 1.0;
this.cameraGScaleCorr[i]= 1.0;
this.cameraExtraURL[i]= "";
}
}
/**
* Initialize cameraIPs from subNet and baseIP (sequentially)
*/
private void initIPs(){
ArrayList<Integer> ip_ports_list= new ArrayList<Integer>();
for (int i=0;i<this.channelMap.length;i++) {
Integer ip_port=(this.channelMap[i][0]<<2) + this.channelMap[i][2];
if (!ip_ports_list.contains(ip_port)) ip_ports_list.add(ip_port);
}
Collections.sort(ip_ports_list);
this.cameraIPs = new String [ip_ports_list.size()];
this.channelIPPort = new int [this.channelMap.length];
for (int i = 0; i<this.cameraIPs.length; i++){
int ip_index= ip_ports_list.get(i)>>2;
int sensor_port = ip_ports_list.get(i) & 3;
this.cameraIPs[i] = this.cameraSubnet+(this.iBaseIP + ip_index) + ":"+ (this.imgsrvPort+sensor_port);
for (int j = 0; j<this.channelMap.length; j++){
if ((this.channelMap[j][0] == ip_index) && (this.channelMap[j][2] == sensor_port)) {
this.channelIPPort[j] = i;
}
}
}
this.triggerURL="http://"+this.cameraSubnet+(this.iBaseIP+this.masterSubCamera)+":"+
(this.imgsrvPort+ (this.masterPort & 3))+"/"+triggerURLcmd;
if (this.debugLevel>2) System.out.println("DEBUG393: initIPs(): this.triggerURL ="+this.triggerURL);
}
/*
//pre nc393
private void initIPs(){
if (this.debugLevel>2) System.out.println("initIPs(): this.iBaseIP=" + this.iBaseIP );
int size=0;
for (int i=0;i<this.channelMap.length;i++) if (this.channelMap[i][0]>size) size=this.channelMap[i][0];
size++;
this.cameraIPs=new String [size];
for (int i=0;i<size;i++) this.cameraIPs[i]=this.cameraSubnet+(this.iBaseIP+i);
// this.masterSubCamera=0;
}
*/
/**
* Initialize default subcamera map
* @param size number of subcameras
*/
private void initDefaultMap(int size){
this.channelMap=new int [size][];
this.flipImages=new boolean[size];
int []port_seq={1,0,2,3};
this.masterSubCamera=0;
this.masterPort=0;
if (this.nc393){
this.imgsrvPort=2323;
this.resetURLcmd="towp/save/pointers"; // advance buffer, next time will wait for the next frame acquired
this.imageURLcmd="torp/wait/timestamp_name/bimg"; // will wait if needed. If repeated (as when reading Exif)- won't wait
this.metaURLcmd="torp/wait/meta"; // will get XML, including timestamp
if (size == 26) {
for (int i=0;i<size;i++){
this.channelMap[i]=channelMap_23_393[i].clone();
this.flipImages[i]=false;
}
this.masterSubCamera = 2;
this.masterPort=2;
} else for (int i=0;i<size;i++){
this.flipImages[i]=false;
this.channelMap[i]=new int[3];
this.channelMap[i][0]= i >> 2;
this.channelMap[i][1]= 0;
if (size <4) {
this.channelMap[i][2]= i;
} else {
this.channelMap[i][2]= port_seq[i & 3];
}
}
} else {
if (size==1) { // single camera - old lens focusing
this.channelMap[0]=channelMap1[0].clone();
this.flipImages[0]=true;
} else if (size==2){ // New lens focusing machine
this.channelMap[0]=channelMap2[0].clone();
this.flipImages[0]=true; // main sensor under test
this.channelMap[1]=channelMap2[1].clone();
this.flipImages[1]=false; // extra sensor for location
} else if (size==3){
for (int i=0;i<size;i++){
this.flipImages[i]=false;
int i0=((i>=this.channelMap3.length)?(this.channelMap3.length-1):i);
// this.channelMap[i]=this.channelMap21[i0].clone();
this.channelMap[i]=this.channelMap3[i0].clone();
}
} else for (int i=0;i<size;i++){
this.flipImages[i]=false;
int i0=((i>=this.channelMap21.length)?(this.channelMap21.length-1):i);
this.channelMap[i]=this.channelMap21[i0].clone();
}
}
}
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"cameraSubnet",this.cameraSubnet);
properties.setProperty(prefix+"iBaseIP",this.iBaseIP+"");
properties.setProperty(prefix+"masterSubCamera",this.masterSubCamera+"");
properties.setProperty(prefix+"masterPort",this.masterPort+"");
properties.setProperty(prefix+"cameraBootTimeSeconds",this.cameraBootTimeSeconds+"");
properties.setProperty(prefix+"connectionTimeoutMilliseconds",this.connectionTimeoutMilliseconds+"");
properties.setProperty(prefix+"imgsrvPort",this.imgsrvPort+"");
properties.setProperty(prefix+"resetURLcmd",this.resetURLcmd);
properties.setProperty(prefix+"triggerURLcmd",this.triggerURLcmd);
properties.setProperty(prefix+"imageURLcmd",this.imageURLcmd);
properties.setProperty(prefix+"metaURLcmd",this.metaURLcmd);
properties.setProperty(prefix+"channelMap.length",this.channelMap.length+"");
for (int i=0;i<this.channelMap.length;i++) {
properties.setProperty(prefix+"channelMap_"+i+"_IPindex", this.channelMap[i][0]+"");
properties.setProperty(prefix+"channelMap_"+i+"_subchannel",this.channelMap[i][1]+"");
properties.setProperty(prefix+"channelMap_"+i+"_port", this.channelMap[i][2]+"");
properties.setProperty(prefix+"flipImages_"+i ,this.flipImages[i]?"1":"0");
}
properties.setProperty(prefix+"cameraIPs.length",this.cameraIPs.length+"");
properties.setProperty(prefix+"colorMode",this.colorMode+"");
properties.setProperty(prefix+"noWait",this.noWait+"");
properties.setProperty(prefix+"nc393",this.nc393+"");
properties.setProperty(prefix+"debugSensorNumber",this.debugSensorNumber+"");
properties.setProperty(prefix+"JPEGquality",this.JPEGquality+"");
properties.setProperty(prefix+"cameraAutoExposure",this.cameraAutoExposure+"");
properties.setProperty(prefix+"cameraAutoWhiteBalance",this.cameraAutoWhiteBalance+"");
properties.setProperty(prefix+"cameraExtraURLCommon","<![CDATA["+this.cameraExtraURLCommon+"]]>");
properties.setProperty(prefix+"setupTriggerMode",this.setupTriggerMode+"");
properties.setProperty(prefix+"externalTriggerCabling",this.externalTriggerCabling+"");
properties.setProperty(prefix+"noCabling",this.noCabling+"");
properties.setProperty(prefix+"cameraExposure",this.cameraExposure+"");
properties.setProperty(prefix+"scaleExposureForLasers",this.scaleExposureForLasers+"");
properties.setProperty(prefix+"scaleExposureForHeadLasers",this.scaleExposureForHeadLasers+"");
properties.setProperty(prefix+"cameraAutoExposureMax",cameraAutoExposureMax+"");
properties.setProperty(prefix+"cameraGain",this.cameraGain+"");
properties.setProperty(prefix+"cameraRScale",this.cameraRScale+"");
properties.setProperty(prefix+"cameraBScale",this.cameraBScale+"");
properties.setProperty(prefix+"cameraGScale",this.cameraGScale+"");
for (int i=0;i<this.cameraIPs.length;i++){
properties.setProperty(prefix+"cameraIPs_"+i,this.cameraIPs[i]+"");
properties.setProperty(prefix+"cameraExposureCorr_"+i,this.cameraExposureCorr[i]+"");
properties.setProperty(prefix+"cameraGainCorr_"+i, this.cameraGainCorr[i]+"");
properties.setProperty(prefix+"cameraRScaleCorr_"+i, this.cameraRScaleCorr[i]+"");
properties.setProperty(prefix+"cameraBScaleCorr_"+i, this.cameraBScaleCorr[i]+"");
properties.setProperty(prefix+"cameraGScaleCorr_"+i, this.cameraGScaleCorr[i]+"");
properties.setProperty(prefix+"cameraExtraURL_"+i, "<![CDATA["+this.cameraExtraURL[i]+"]]>");
}
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"channelMap.length")!=null) {
// next initializes default values, so it should be before reading them from saved properties
initDefaultMap (Integer.parseInt(properties.getProperty(prefix+"channelMap.length")));
this.flipImages=new boolean[this.channelMap.length];
for (int i=0;i<this.channelMap.length;i++) {
if (properties.getProperty(prefix+"channelMap_"+i+"_IPindex")!=null)
this.channelMap[i][0]=Integer.parseInt(properties.getProperty(prefix+"channelMap_"+i+"_IPindex"));
if (properties.getProperty(prefix+"channelMap_"+i+"_subchannel")!=null)
this.channelMap[i][1]=Integer.parseInt(properties.getProperty(prefix+"channelMap_"+i+"_subchannel"));
if (properties.getProperty(prefix+"channelMap_"+i+"_port")!=null)
this.channelMap[i][2]=Integer.parseInt(properties.getProperty(prefix+"channelMap_"+i+"_port"));
if (properties.getProperty(prefix+"flipImages_"+i)!=null)
this.flipImages[i]=(Integer.parseInt(properties.getProperty(prefix+"flipImages_"+i))>0);
}
}
int numCams=0;
if (properties.getProperty(prefix+"cameraIPs.length")!=null) {
numCams=Integer.parseInt(properties.getProperty(prefix+"cameraIPs.length"));
this.cameraIPs=new String[numCams];
for (int i=0;i<numCams;i++) {
if (properties.getProperty(prefix+"cameraIPs_"+i)!=null)
this.cameraIPs[i]=properties.getProperty(prefix+"cameraIPs_"+i);
}
}
initCamParsDefaultArrays(numCams);
if (properties.getProperty(prefix+"cameraSubnet")!=null)
this.cameraSubnet=properties.getProperty(prefix+"cameraSubnet");
if (properties.getProperty(prefix+"iBaseIP")!=null)
this.iBaseIP=Integer.parseInt(properties.getProperty(prefix+"iBaseIP"));
if (properties.getProperty(prefix+"masterSubCamera")!=null)
this.masterSubCamera=Integer.parseInt(properties.getProperty(prefix+"masterSubCamera"));
if (properties.getProperty(prefix+"masterPort")!=null)
this.masterPort=Integer.parseInt(properties.getProperty(prefix+"masterPort"));
if (properties.getProperty(prefix+"cameraBootTimeSeconds")!=null)
this.cameraBootTimeSeconds=Integer.parseInt(properties.getProperty(prefix+"cameraBootTimeSeconds"));
if (properties.getProperty(prefix+"connectionTimeoutMilliseconds")!=null)
this.connectionTimeoutMilliseconds=Integer.parseInt(properties.getProperty(prefix+"connectionTimeoutMilliseconds"));
if (properties.getProperty(prefix+"imgsrvPort")!=null)
this.imgsrvPort=Integer.parseInt(properties.getProperty(prefix+"imgsrvPort"));
if (properties.getProperty(prefix+"resetURLcmd")!=null)
this.resetURLcmd=properties.getProperty(prefix+"resetURLcmd");
if (properties.getProperty(prefix+"triggerURLcmd")!=null)
this.triggerURLcmd=properties.getProperty(prefix+"triggerURLcmd");
if (properties.getProperty(prefix+"imageURLcmd")!=null)
this.imageURLcmd=properties.getProperty(prefix+"imageURLcmd");
if (properties.getProperty(prefix+"metaURLcmd")!=null)
this.metaURLcmd=properties.getProperty(prefix+"metaURLcmd");
// both defaults were here
if (properties.getProperty(prefix+"colorMode")!=null)
this.colorMode=Integer.parseInt(properties.getProperty(prefix+"colorMode"));
if (properties.getProperty(prefix+"debugSensorNumber")!=null)
this.debugSensorNumber=Integer.parseInt(properties.getProperty(prefix+"debugSensorNumber"));
if (properties.getProperty(prefix+"JPEGquality")!=null)
this.JPEGquality=Integer.parseInt(properties.getProperty(prefix+"JPEGquality"));
if (properties.getProperty(prefix+"noWait")!=null)
this.noWait=Boolean.parseBoolean(properties.getProperty(prefix+"noWait"));
if (properties.getProperty(prefix+"nc393")!=null)
this.nc393=Boolean.parseBoolean(properties.getProperty(prefix+"nc393"));
if (properties.getProperty(prefix+"cameraAutoExposure")!=null)
this.cameraAutoExposure=Boolean.parseBoolean(properties.getProperty(prefix+"cameraAutoExposure"));
if (properties.getProperty(prefix+"cameraAutoWhiteBalance")!=null)
this.cameraAutoWhiteBalance=Boolean.parseBoolean(properties.getProperty(prefix+"cameraAutoWhiteBalance"));
if (properties.getProperty(prefix+"cameraExtraURLCommon")!=null) {
this.cameraExtraURLCommon=properties.getProperty(prefix+"cameraExtraURLCommon");
if ((this.cameraExtraURLCommon.length()>10) && this.cameraExtraURLCommon.substring(0,9).equals("<![CDATA["))
this.cameraExtraURLCommon=this.cameraExtraURLCommon.substring(9,this.cameraExtraURLCommon.length()-3);
}
if (properties.getProperty(prefix+"setupTriggerMode")!=null)
this.setupTriggerMode=Boolean.parseBoolean(properties.getProperty(prefix+"setupTriggerMode"));
if (properties.getProperty(prefix+"externalTriggerCabling")!=null)
this.externalTriggerCabling=Boolean.parseBoolean(properties.getProperty(prefix+"externalTriggerCabling"));
if (properties.getProperty(prefix+"noCabling")!=null)
this.noCabling=Boolean.parseBoolean(properties.getProperty(prefix+"noCabling"));
if (properties.getProperty(prefix+"cameraExposure")!=null)
this.cameraExposure=Double.parseDouble(properties.getProperty(prefix+"cameraExposure"));
if (properties.getProperty(prefix+"scaleExposureForLasers")!=null)
this.scaleExposureForLasers=Double.parseDouble(properties.getProperty(prefix+"scaleExposureForLasers"));
if (properties.getProperty(prefix+"scaleExposureForHeadLasers")!=null)
this.scaleExposureForHeadLasers=Double.parseDouble(properties.getProperty(prefix+"scaleExposureForHeadLasers"));
if (properties.getProperty(prefix+"cameraAutoExposureMax")!=null)
this.cameraAutoExposureMax=Double.parseDouble(properties.getProperty(prefix+"cameraAutoExposureMax"));
if (properties.getProperty(prefix+"cameraGain")!=null)
this.cameraGain=Double.parseDouble(properties.getProperty(prefix+"cameraGain"));
if (properties.getProperty(prefix+"cameraRScale")!=null)
this.cameraRScale=Double.parseDouble(properties.getProperty(prefix+"cameraRScale"));
if (properties.getProperty(prefix+"cameraBScale")!=null)
this.cameraBScale=Double.parseDouble(properties.getProperty(prefix+"cameraBScale"));
if (properties.getProperty(prefix+"cameraGScale")!=null)
this.cameraGScale=Double.parseDouble(properties.getProperty(prefix+"cameraGScale"));
for (int i=0;i<numCams;i++) {
if (properties.getProperty(prefix+"cameraExposureCorr_"+i)!=null)
this.cameraExposureCorr[i]=Double.parseDouble(properties.getProperty(prefix+"cameraExposureCorr_"+i));
if (properties.getProperty(prefix+"cameraGainCorr_"+i)!=null)
this.cameraGainCorr[i]=Double.parseDouble(properties.getProperty(prefix+"cameraGainCorr_"+i));
if (properties.getProperty(prefix+"cameraRScaleCorr_"+i)!=null)
this.cameraRScaleCorr[i]=Double.parseDouble(properties.getProperty(prefix+"cameraRScaleCorr_"+i));
if (properties.getProperty(prefix+"cameraBScaleCorr_"+i)!=null)
this.cameraBScaleCorr[i]=Double.parseDouble(properties.getProperty(prefix+"cameraBScaleCorr_"+i));
if (properties.getProperty(prefix+"cameraGScaleCorr_"+i)!=null)
this.cameraGScaleCorr[i]=Double.parseDouble(properties.getProperty(prefix+"cameraGScaleCorr_"+i));
if (properties.getProperty(prefix+"cameraExtraURL_"+i)!=null) {
this.cameraExtraURL[i]=properties.getProperty(prefix+"cameraExtraURL_"+i);
if ((this.cameraExtraURL[i].length()>10) && this.cameraExtraURL[i].substring(0,9).equals("<![CDATA["))
this.cameraExtraURL[i]=this.cameraExtraURL[i].substring(9,this.cameraExtraURL[i].length()-3);
}
}
initIPs(); // was missing here?
initJP4();
}
public boolean showDialog(String title, int numCams, boolean askRegenerate) { // numCams<=0 -> do not initialize number
if (numCams>0){
// initDefaultMap(1);
initDefaultMap(numCams);
initIPs();
initCamParsDefaultArrays(this.cameraIPs.length);
initJP4();
}
//http://192.168.0.223/parsedit.php?title=PHASES&SENSOR_PHASE&MULTI_PHASE1&MULTI_PHASE2&MULTI_PHASE3&DEBUG&CABLE_TIM&FPGA_TIM0&FPGA_TIM1&DLY359_P1&DLY359_P2&DLY359_P3&DLY359_C1&DLY359_C2&DLY359_C3&SENSOR&FRAME_SIZE=@&refresh
//http://192.168.0.228/parsedit.php?immediate&EXPOS=25000*0&AUTOEXP_ON=0*0&WB_EN=0*0
//http://192.168.0.221/parsedit.php?immediate&EXPOS=25000*0&AUTOEXP_ON=0*0&WB_EN=0*0&COLOR=1*0&GAINR=0x20000*0&GAING=0x20000*0&GAINB=0x36666*0&GAINGB=0x20000*0
//http://192.168.0.221/parsedit.php?title=PHASES&SENSOR_PHASE&MULTI_PHASE1&MULTI_PHASE2&MULTI_PHASE3&FRAME_SIZE=@
//http://192.168.0.222/parsedit.php?title=day&immediate&EXPOS=20000*0&AUTOEXP_ON=0*0&WB_EN=0*0&COLOR=1*0&GAINR=0x270a4*0&GAING=0x20000*0&GAINB=0x2999a*0&GAINGB=0x20000*0
//http://192.168.0.236/parsedit.php?title=night&immediate&EXPOS=13000*0&AUTOEXP_ON=0*0&WB_EN=0*0&COLOR=1*0&GAINR=0x1fb35*0&GAING=0x20000*0&GAINB=0x3961c*0&GAINGB=0x20000*0
//http://192.168.0.221/parsedit.php?title=bright-day&immediate&EXPOS=10000*0&AUTOEXP_ON=0*0&WB_EN=0*0&COLOR=1*0&GAINR=0x270a4*0&GAING=0x20000*0&GAINB=0x2999a*0&GAINGB=0x20000*0
//http://192.168.0.221/parsedit.php?immediate&TRIG&TRIG_PERIOD
GenericDialog gd = new GenericDialog(title);
gd.addCheckbox ("NC393 (unchecked - nc353)", this.nc393);
gd.addStringField ("Subnet of the cameras (3 first of the four IPv4 address ending with '.')",this.cameraSubnet,12);
gd.addNumericField("Last byte of the first sub-camera IP address)",this.iBaseIP,0);
gd.addNumericField("Camera boot time",this.cameraBootTimeSeconds,0,3,"sec");
gd.addNumericField("Network connection timeout",this.connectionTimeoutMilliseconds,0,3,"ms");
gd.addNumericField("Index (in IP table) of the master camera (used for triggering)",this.masterSubCamera,0);
gd.addNumericField("Master (used for triggering), normally lowest connected port (0..3)",this.masterPort,0);
gd.addNumericField("Image server port number)",this.imgsrvPort,0);
gd.addStringField ("Image server command to reset image buffer",this.resetURLcmd,25);
gd.addStringField ("Image server command to trigger acquisition",this.triggerURLcmd,25);
gd.addStringField ("Image server command to acquire image (waits for the new one after reset)",this.imageURLcmd,25);
gd.addStringField ("Image server command to receive XML metadata (with timestamp)",this.metaURLcmd,25);
gd.addMessage("Configure each sub-camera - which IP index and channel does it use.");
if (askRegenerate) gd.addMessage("You may change number of subcameras and press REGENERATE below");
for (int i=0; i< this.channelMap.length;i++){
gd.addMessage("---------------------------------------------------------");
gd.addNumericField("Subcamera "+(i+1)+" IP index (starting from 0)", this.channelMap[i][0],0);
gd.addNumericField("Subcamera "+(i+1)+" port (0..3)", this.channelMap[i][2],0);
gd.addNumericField("Subcamera "+(i+1)+" channel (0,1 or 2)", this.channelMap[i][1],0);
gd.addCheckbox("Subcamera "+(i+1)+" - used mirror", this.flipImages[i]);
}
gd.addMessage("---------------------------------------------------------");
if (askRegenerate) {
gd.addCheckbox ("Individually overwrite IP addresses",false);
gd.addNumericField("Number of subcameras (need to press REGENERATE button to change)", this.channelMap.length, 0);
gd.enableYesNoCancel("OK", "REGENERATE");
}
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
this.nc393= gd.getNextBoolean();
this.cameraSubnet= gd.getNextString();
if (!this.cameraSubnet.endsWith(".")) this.cameraSubnet += ".";
int bip= (int) gd.getNextNumber();
if ((bip>0) && (bip<255) && (bip!=this.iBaseIP)){
this.iBaseIP=bip;
initIPs();
}
this.cameraBootTimeSeconds=(int) gd.getNextNumber();
this.connectionTimeoutMilliseconds=(int) gd.getNextNumber();
this.masterSubCamera= (int) gd.getNextNumber(); // should be after initIPs()!
this.masterPort= (int) gd.getNextNumber(); // should be after initIPs()!
this.imgsrvPort= (int) gd.getNextNumber();
this.resetURLcmd= gd.getNextString();
this.triggerURLcmd= gd.getNextString();
this.imageURLcmd= gd.getNextString();
this.metaURLcmd= gd.getNextString();
for (int i=0; i< this.channelMap.length;i++){
this.channelMap[i][0]=(int) gd.getNextNumber();
this.channelMap[i][2]=(int) gd.getNextNumber();
this.channelMap[i][1]=(int) gd.getNextNumber();
this.flipImages[i]= gd.getNextBoolean();
}
if (askRegenerate) {
boolean overwriteIPs=gd.getNextBoolean();
int newSubCams=(int) gd.getNextNumber();
// if (!gd.wasOKed() &&(newSubCams!=this.channelMap.length)) {
if (!gd.wasOKed()) { // regenerate always if pressed, even if number is the same
// initDefaultMap(newSubCams);
// initIPs();
int [][] backupMap=this.channelMap;
if (!showDialog(title, newSubCams, false)) {
this.channelMap=backupMap;
return false; // channelMap is restored, but some other fields may be broken
}
}
if (overwriteIPs && !editSubCamerasIPs()) return false;
}
return true;
}
/**
* Wait for camera to boot
* @param chn - camera channel number (0)
* @return -1 if camera is not yet set to trigger mode, else - last frame number acquired
* throws on timeout
*/
public int getCurrentFrameNumberWithTimeout(int chn, boolean showStatus, AtomicInteger stopRequested){
long startTime=System.nanoTime();
double dTimeOut=1E9* this.cameraBootTimeSeconds;
long endTime=startTime+(long) dTimeOut;
while (true){
if (probeCameraState(chn, showStatus, true,this.connectionTimeoutMilliseconds)){
if (showStatus) IJ.showProgress(0.0);
if (!this.triggeredMode[chn]) return -1;
if (this.triggerPeriod[chn]>1) return -1; // trigger period is not set to 1 - not yet programmed
return this.cameraFrameNumber[chn];
}
long time=System.nanoTime();
if (time>endTime){
if (showStatus) IJ.showProgress(0.0);
throw new IllegalArgumentException ("Timeout while waiting for the camera #"+chn+" to respond");
}
if (stopRequested.get()>0) {
System.out.println("User requested stop");
if (showStatus) IJ.showProgress(0.0);
throw new IllegalArgumentException ("Waiting for camera #"+chn+" aborted by user request");
}
if (showStatus) IJ.showProgress((time-startTime)/dTimeOut);
}
}
public String getSerialNumber(int chn, int EEPROM_chn){
int colon_index = this.cameraIPs[chn].indexOf(":");
int sensor_port = Integer.parseInt(this.cameraIPs[chn].substring(colon_index+1)) - this.imgsrvPort;
String ip=this.cameraIPs[chn].substring(0, colon_index);
// String url="http://"+this.cameraIPs[chn]+"/i2c.php?cmd=fromEEPROM0&EEPROM_chn="+EEPROM_chn;
String url="http://"+ip+"/i2c.php?cmd=fromEEPROM" + sensor_port+ "&EEPROM_chn="+EEPROM_chn;
Document dom=null;
String serial=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("board")) {
String msg="Root element: expected 'board', got \"" + dom.getDocumentElement().getNodeName()+"\"";
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
serial=(dom.getDocumentElement().getElementsByTagName("serial").item(0).getChildNodes().item(0)).getNodeValue();
// remove opening and closing "
if (serial==null){
String msg="Could not read tag <serial>";
IJ.showMessage("Error",msg);
System.out.println(msg);
return null;
}
if (serial.startsWith("\"")){
serial=serial.substring(1, serial.length()-1);
}
} catch(MalformedURLException e){
String msg="Please check the URL:" + e.toString();
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
} catch(IOException e1){
String msg = e1.getMessage();
if (msg==null || msg.equals("")) msg = ""+e1;
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
throw new IllegalArgumentException ("PCE error");
}catch(SAXException se) {
se.printStackTrace();
throw new IllegalArgumentException ("SAX error");
}
return serial;
}
public double getSensorTemperature(int chn, int EEPROM_chn){
// Need to configure camera to be able to read temperature
if (sensorPresent==null) { // cameras were not probed/configured
probeCameraState(); // testing detection
printTiming("=== probeCameraState()");
setupCameraAcquisition();
printTiming("=== setupCameraAcquisition()");
}
if (!this.sensorPresent[chn][0] && !this.sensorPresent[chn][1] && !this.sensorPresent[chn][2]) EEPROM_chn=0; // no 10359 - null pointer while "lens center" if first
int colon_index = this.cameraIPs[chn].indexOf(":");
int sensor_port = Integer.parseInt(this.cameraIPs[chn].substring(colon_index+1)) - this.imgsrvPort;
String ip=this.cameraIPs[chn].substring(0, colon_index);
// String url="http://"+this.cameraIPs[chn]+"/i2c.php?cmd=fromEEPROM0&EEPROM_chn="+EEPROM_chn;
String url="http://"+ip+"/i2c.php?cmd=fromEEPROM"+ sensor_port +"&EEPROM_chn="+EEPROM_chn;
this.lastTemperature=Double.NaN;
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("board")) {
String msg="Root element: expected 'board', got \"" + dom.getDocumentElement().getNodeName()+"\"";
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
String sTemperature=null;
if ((dom.getDocumentElement().getElementsByTagName("sensorTemperature").item(0))!=null){
sTemperature=(dom.getDocumentElement().getElementsByTagName("sensorTemperature").item(0).getChildNodes().item(0)).getNodeValue();
}else{
sTemperature= "0.0";
}
// remove opening and closing "
if (sTemperature==null){
String msg="Could not read sensor temperature";
// IJ.showMessage("Error",msg);
System.out.println("Warning: "+msg);
return Double.parseDouble(sTemperature);
}
this.lastTemperature= Double.parseDouble(sTemperature);
} catch(MalformedURLException e){
String msg="Please check the URL:" + e.toString();
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
} catch(IOException e1){
String msg = e1.getMessage();
if (msg==null || msg.equals("")) msg = ""+e1;
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
throw new IllegalArgumentException ("PCE error");
}catch(SAXException se) {
se.printStackTrace();
throw new IllegalArgumentException ("SAX error");
}
return this.lastTemperature;
}
// private int [] motors= null; // motors steps when the images were acquired (for null)
public int [] getMotorsPosition() {return this.motorsPosition;} // may be null
public void setMotorsPosition (int [] position) {this.motorsPosition=position;}
public void resetInitialization(){
System.out.println("resetInitialization()");
this.sensorPresent=null;
}
public int probeCameraState(){
int numOnline=0;
int numSensors=0;
int numChn=this.cameraIPs.length;
initCameraArrays(numChn);
/*
this.cameraFrameNumber=new int[numChn];
this.triggeredMode=new boolean[numChn];
this.sensorPresent=new boolean[numChn][];
// TODO - try if skipping setting TRIG_PERIOD=0, IRQ_SMART=6 (when they are already set) will fix hanging
this.triggerPeriod=new int[numChn];
this.irqSmart= new int[numChn];
*/
for (int chn=0;chn<numChn;chn++){
this.cameraFrameNumber[chn]=-1;
this.triggeredMode[chn]=false;
this.sensorPresent[chn]=null; // camera did not respond, {false,false,false} - single camera (no 10359)
if (this.debugLevel>1) System.out.println("Probing camera "+chn+" ("+this.cameraIPs[chn]+")...");
IJ.showStatus("Probing camera "+chn+" ("+this.cameraIPs[chn]+")...");
if (probeCameraState(chn)) {
numOnline++;
printTiming("===== probing channel "+chn);
boolean single_no_mux= (!this.sensorPresent[chn][0] && !this.sensorPresent[chn][1] && !this.sensorPresent[chn][2]);
if (this.debugLevel>1) System.out.println("Frame number: "+this.cameraFrameNumber[chn]+
", Trigger mode:"+(this.triggeredMode[chn]?"ex":"in")+"ternal, "+
" sensors attached:"+(this.sensorPresent[chn][0]?"1 ":"")+(this.sensorPresent[chn][1]?"2 ":"")+(this.sensorPresent[chn][2]?"3 ":"")+
(single_no_mux?"single-sensor, no multiplexer":"") +
(" Master port "+this.cameraMasterPort[chn])
);
for (int i=0;i<this.sensorPresent[chn].length;i++) if (this.sensorPresent[chn][i]) numSensors++;
if (single_no_mux) numSensors++;
} else {
if (this.debugLevel>1) System.out.println("Camera did not respond");
}
}
IJ.showStatus("Found "+numOnline+" camera IP, "+numSensors+" sensors");
if (this.debugLevel>1) System.out.println("Found "+numOnline+" camera IP, "+numSensors+" sensors");
return numOnline;
}
public void initCameraArrays(int numChn){
if (this.debugLevel>1) System.out.println("initCameraArrays("+numChn+")");
this.cameraFrameNumber=new int[numChn];
this.triggeredMode= new boolean[numChn];
this.sensorPresent= new boolean[numChn][];
// TODO - try if skipping setting TRIG_PERIOD=0, IRQ_SMART=6 (when they are already set) will fix hanging
this.triggerPeriod= new int[numChn];
this.irqSmart= new int[numChn];
this.cameraMasterPort= new int[numChn]; // not sure if will use it - master port for each camera:port
}
public boolean probeCameraState(
int chn){
return probeCameraState(chn, false, false,0);
}
public boolean probeCameraState(
int chn,
boolean showStatus,
boolean doNotThrow,
int timeout // ms
){
//http://192.168.0.221/parsedit.php?immediate&TRIG&TRIG_PERIOD&FRAME
String url;
int colon_index = this.cameraIPs[chn].indexOf(":");
int sensor_port = Integer.parseInt(this.cameraIPs[chn].substring(colon_index+1)) - this.imgsrvPort;
String ip=this.cameraIPs[chn].substring(0, colon_index);
if (this.nc393){
// url="http://"+this.cameraIPs[chn]+"/parsedit.php?immediate&TRIG&TRIG_PERIOD&SENS_AVAIL&FRAME";
url="http://"+ip+"/parsedit.php?sensor_port="+sensor_port+"&immediate&TRIG&TRIG_PERIOD&SENS_AVAIL&FRAME&TRIG_MASTER";
} else {
// url="http://"+this.cameraIPs[chn]+"/parsedit.php?immediate&TRIG&TRIG_PERIOD&IRQ_SMART&SENS_AVAIL&FRAME";
url="http://"+ip+"/parsedit.php?immediate&TRIG&TRIG_PERIOD&IRQ_SMART&SENS_AVAIL&FRAME";
}
if (this.debugLevel>1) System.out.println("url="+url);
Document dom=null;
if ((this.cameraFrameNumber==null) || ((this.cameraFrameNumber.length<(chn+1)))) initCameraArrays(chn+1);
// did not find yet - why cameraFrameNumber is not null, but sensorPresent is? Added next lines until find
if ((this.triggeredMode==null) || ((this.triggeredMode.length<(chn+1)))) initCameraArrays(chn+1);
if ((this.sensorPresent==null) || ((this.sensorPresent.length<(chn+1)))) initCameraArrays(chn+1);
if ((this.triggerPeriod==null) || ((this.triggerPeriod.length<(chn+1)))) initCameraArrays(chn+1);
if (!this.nc393) {
if ((this.irqSmart==null) || ((this.irqSmart.length<(chn+1)))) initCameraArrays(chn+1);
} else {
if ((this.cameraMasterPort==null) || ((this.cameraMasterPort.length<(chn+1)))) initCameraArrays(chn+1);
}
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
if (timeout<=0){
dom = db.parse(url);
} else {
URL uUrl = new URL(url);
URLConnection con = uUrl.openConnection();
con.setConnectTimeout(timeout);//The timeout in mills
dom = db.parse(con.getInputStream());
}
if (!dom.getDocumentElement().getNodeName().equals("parameters")) {
String msg="Root element: expected 'parameters', got \"" + dom.getDocumentElement().getNodeName()+"\"";
if (showStatus) IJ.showStatus(msg);
if (doNotThrow) return false;
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
// String sNode;
if (this.triggeredMode==null) System.out.println("this.triggeredMode==null");
if (this.triggeredMode.length<(chn+1)) System.out.println("this.triggeredMode.length="+this.triggeredMode.length+" chn="+chn);
this.triggeredMode[chn]= (Integer.parseInt((dom.getDocumentElement().getElementsByTagName("TRIG").item(0).getChildNodes().item(0)).getNodeValue())==4);
int sensAvail= Integer.parseInt((dom.getDocumentElement().getElementsByTagName("SENS_AVAIL").item(0).getChildNodes().item(0)).getNodeValue());
if (this.sensorPresent==null) System.out.println("sensorPresent==null");
if (this.sensorPresent.length<(chn+1)) System.out.println("sensorPresent="+this.sensorPresent.length+" chn="+chn);
this.sensorPresent[chn]=new boolean[3];
for (int i=0;i<this.sensorPresent[chn].length;i++) this.sensorPresent[chn][i]=(sensAvail & (1<<i))!=0;
this.triggerPeriod[chn]= Integer.parseInt((dom.getDocumentElement().getElementsByTagName("TRIG_PERIOD").item(0).getChildNodes().item(0)).getNodeValue());
if (!this.nc393) {
this.irqSmart[chn]= Integer.parseInt((dom.getDocumentElement().getElementsByTagName("IRQ_SMART").item(0).getChildNodes().item(0)).getNodeValue());
this.cameraMasterPort[chn]= sensor_port;
} else {
this.cameraMasterPort[chn]= Integer.parseInt((dom.getDocumentElement().getElementsByTagName("TRIG_MASTER").item(0).getChildNodes().item(0)).getNodeValue());
}
this.cameraFrameNumber[chn]= Integer.parseInt((dom.getDocumentElement().getElementsByTagName("FRAME").item(0).getChildNodes().item(0)).getNodeValue());
} catch(MalformedURLException e){
String msg="Please check the URL:" + e.toString();
IJ.showMessage("Error",msg);
if (showStatus) IJ.showStatus(msg);
if (doNotThrow) return false;
throw new IllegalArgumentException (msg);
} catch(IOException e1){
String msg = e1.getMessage();
if (msg==null || msg.equals("")) msg = ""+e1;
msg="Camera "+chn+" ("+this.cameraIPs[chn]+") did not respond: "+msg; // "Connection refused"
if (showStatus) IJ.showStatus(msg);
if (doNotThrow) return false;
IJ.showMessage("Error",msg);
System.out.println(msg);
return false;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
String msg="PCE error "+pce.getMessage();
if (showStatus) IJ.showStatus(msg);
if (doNotThrow) return false;
throw new IllegalArgumentException (msg);
}catch(SAXException se) {
se.printStackTrace();
String msg="SAX error "+se.getMessage();
if (showStatus) IJ.showStatus(msg);
if (doNotThrow) return false;
throw new IllegalArgumentException (msg);
}
return true;
}
public boolean setupCameraAcquisition(){
return setupCameraAcquisition(Double.NaN);
}
public boolean setupCameraAcquisition(final double exposureScale){
final int ipLength=this.resetURLs.length;
final boolean [] results=new boolean[ipLength];
for (int chn=0;chn<ipLength;chn++) results[chn]=(this.sensorPresent[chn]!=null);
final Thread[] threads = newThreadArray(this.maxNumberOfThreads);
final AtomicInteger chnAtomic = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int chn=chnAtomic.getAndIncrement(); chn<ipLength;chn=chnAtomic.getAndIncrement()) if (results[chn]){
results[chn]=setupCameraAcquisition(chn,exposureScale);
}
}
};
}
startAndJoin(threads);
if (Double.isNaN(exposureScale)){ // full init
int nRepeat=this.setupTriggerMode?4:1;
if (this.nc393) nRepeat++; // is it needed?
for (int i=0;i<nRepeat;i++){
if (this.debugLevel>0) System.out.println((i+1)+" of "+nRepeat+": Triggering cameras to give parameters a chance to propagate");
trigger();
try
{
Thread.sleep( 1000 ); // ms
}
catch ( InterruptedException e )
{
System.out.println( "awakened prematurely" );
}
}
}
boolean result=true;
for (int chn=0;chn<ipLength;chn++) if (this.sensorPresent[chn]!=null) result &=results[chn];
return result;
}
public boolean setupCameraAcquisitionNoTHreads(double exposureScale){
boolean result=true;
for (int chn=0;chn<this.cameraIPs.length;chn++) if (this.sensorPresent[chn]!=null){
result&=setupCameraAcquisition(chn,exposureScale);
}
// trigger ?
if (Double.isNaN(exposureScale)){ // just a hack - if exposureScale is non-NaN only update exposure
trigger();
//sleep (1000);
for ( long endTime=System.nanoTime()+(1000000000);endTime<System.nanoTime(););
}
return result;
}
// TODO: issue several TRIG pulses after setting parameters?
public boolean setupCameraAcquisition(int chn, double exposureScale){
int colon_index = this.cameraIPs[chn].indexOf(":");
int sensor_port = Integer.parseInt(this.cameraIPs[chn].substring(colon_index+1)) - this.imgsrvPort;
String ip=this.cameraIPs[chn].substring(0, colon_index);
boolean isMasterSubcamera = ip.equals(this.cameraSubnet+(this.iBaseIP+this.masterSubCamera));
boolean isMasterPort = (this.cameraMasterPort[chn] == sensor_port); // for 353 should always be master port
if (isMasterSubcamera && (this.cameraMasterPort[chn] != this.masterPort)){
System.out.println("Master port mismatch for camera "+ip+" (master) - parameters master port = "+
this.masterPort+", camera responded with "+this.cameraMasterPort[chn] );
}
if (this.debugLevel>1) System.out.println("DEBUG393: chn="+chn+" sensor_port="+sensor_port+" ip= "+ip+" isMasterSubcamera="+isMasterSubcamera+ " isMasterPort="+isMasterPort);
boolean exposureOnly=!Double.isNaN(exposureScale);
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*this.cameraExposure*this.cameraExposureCorr[chn])*(exposureOnly?exposureScale:1.0));
int autoExposureMax= (int) (Math.round(1000*this.cameraAutoExposureMax*this.cameraExposureCorr[chn]));
int gain= (int) (Math.round(0x10000*this.cameraGain*this.cameraGainCorr[chn]));
int rScale= (int) (Math.round(0x10000*this.cameraRScale*this.cameraRScaleCorr[chn]));
int bScale= (int) (Math.round(0x10000*this.cameraBScale*this.cameraBScaleCorr[chn]));
int gScale= (int) (Math.round(0x10000*this.cameraGScale*this.cameraGScaleCorr[chn]));
int autoExp= this.cameraAutoExposure?1:0;
int autoWB= this.cameraAutoWhiteBalance?1:0;
String extraURL="";
if (this.cameraExtraURLCommon.length()>0){
extraURL+=(this.cameraExtraURLCommon.substring(0,1).equals("&"))?"":"&"+this.cameraExtraURLCommon;
}
if (this.cameraExtraURL[chn].length()>0){
extraURL+=(this.cameraExtraURL[chn].substring(0,1).equals("&"))?"":"&"+this.cameraExtraURL[chn];
}
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;
String triggerMode="";
if (this.nc393) {
if (isMasterPort) {
/*
* P_TRIG_OUT (outputs):
* off: 0x00000
* external: 0x02000
* internal: 0x20000
* both: 0x22000
* P_TRIG_IN (inputs):
* off: 0x00000
* external: 0x80000
* internal: 0x08000
* both: 0x88000
*/
if (this.setupTriggerMode){
triggerMode+="&TRIG_CONDITION="+(this.noCabling?(0):(this.externalTriggerCabling?"0x80000":"0x08000"))+"*0"+
"&TRIG_OUT="+(this.noCabling?(0):(this.externalTriggerCabling?"0x02000":"0x20000"))+"*0"+
"&TRIG=4*3";
}
if ((this.triggerPeriod[chn]>1) || this.setupTriggerMode) {
triggerMode+="&TRIG_PERIOD=0*1"; // just stop it if it wasn't already, imgsrv /trig does not set it, only FPGA register
}
}
}else {
if (this.setupTriggerMode){
triggerMode+="&TRIG_CONDITION="+(this.noCabling?(0):(this.externalTriggerCabling?"0x200000":"0x20000"))+"*0"+
"&TRIG_OUT="+(this.noCabling?(0):(this.externalTriggerCabling?"0x800000":"0x80000"))+"*0"+
"&TRIG=4*3";
}
if ((this.triggerPeriod[chn]>1) || this.setupTriggerMode){
triggerMode+="&TRIG_PERIOD=1*0"; // just imgsrv /trig does not set it, only FPGA register
}
}
String url="http://"+ip+"/parsedit.php?immediate";
if (this.nc393) {
url += "&sensor_port="+sensor_port;
}
url+="&EXPOS="+exposure+"*0"; // always
if (!exposureOnly){
if (!this.nc393) {
if (this.irqSmart[chn]!=(this.noWait?6:3)){
url+="&IRQ_SMART="+(this.noWait?6:3)+"*0";
}
}
url+="&COLOR="+this.colorMode+"*"+(this.nc393?"1":"0")+
"&QUALITY="+this.JPEGquality+"*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"+
triggerMode+ // needed here?
"&FRAME"+
extraURL;
}
// if (this.debugLevel>2) {
if (this.debugLevel>1) { // temporary - debugging
System.out.println("Setting camera "+chn+", URL="+url);
}
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("parameters")) {
String msg="Root element: expected 'parameters', got \"" + dom.getDocumentElement().getNodeName()+"\"";
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
}
// String sNode;
if (!exposureOnly) this.cameraFrameNumber[chn]= Integer.parseInt((dom.getDocumentElement().getElementsByTagName("FRAME").item(0).getChildNodes().item(0)).getNodeValue());
} catch(MalformedURLException e){
String msg="Please check the URL:" + e.toString();
IJ.showMessage("Error",msg);
throw new IllegalArgumentException (msg);
} catch(IOException e1){
String msg = e1.getMessage();
if (msg==null || msg.equals("")) msg = ""+e1;
msg="Camera "+chn+" ("+this.cameraIPs[chn]+") did not respond\n"+msg;
IJ.showMessage("Error",msg);
System.out.println(msg);
return false;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
throw new IllegalArgumentException ("PCE error");
}catch(SAXException se) {
se.printStackTrace();
throw new IllegalArgumentException ("SAX error");
}
return true;
}
private boolean editSubCamerasIPs() {
GenericDialog gd = new GenericDialog("Edit IPs/hosts and ports of the sub cameras");
for (int i=0;i<this.cameraIPs.length;i++){
gd.addStringField(i+": IP address/host:sensor port of the subcamera",this.cameraIPs[i],25);
}
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
for (int i=0;i<this.cameraIPs.length;i++){
this.cameraIPs[i]=gd.getNextString();
}
initJP4(); // initialize JP46_Reader_camera class instances
/// initCamParsDefaultArrays(this.cameraIPs.length); - probably not needed as number of cameras is not changed
return true;
}
public boolean editCameraSettings(String title){
GenericDialog gd = new GenericDialog("title");
gd.addCheckbox ("NC393 (unchecked - nc353)", this.nc393);
gd.addNumericField("Camera exposure",this.cameraExposure,2,8,"ms");
gd.addNumericField("Scale camera exposure for target laser detection (4 lasers)",100*this.scaleExposureForLasers,1,5,"%");
gd.addNumericField("Scale camera exposure for optical head laser detection (2 lasers)",100*this.scaleExposureForHeadLasers,1,5,"%");
gd.addCheckbox ("Enable autoexposure", this.cameraAutoExposure);
gd.addNumericField("Maximal automatic exposure",this.cameraAutoExposureMax,2,8,"ms");
gd.addNumericField("Analog gain (2.0 recommended)",this.cameraGain,3,6,"x");
gd.addNumericField("Red-to-green color balance",this.cameraRScale,3,6,"x");
gd.addNumericField("Blue-to-green color balance",this.cameraBScale,3,6,"x");
gd.addNumericField("Green(blue row) to green (red row) color balance",this.cameraGScale,3,6,"x");
// TODO: Make one-time WB by averaging scales from all channels
gd.addCheckbox ("Enable auto white balance", this.cameraAutoWhiteBalance);
gd.addNumericField("Color mode (JP4=5)",this.colorMode,0,6,"");
gd.addNumericField("Compression quality",this.JPEGquality,0,6,"%");
gd.addCheckbox ("No wait for the next frame sync (IRQ_SMART=6, unchecked - IRQ_SMART=3)", this.noWait);
gd.addCheckbox ("Setup trigger mode", this.setupTriggerMode);
gd.addCheckbox ("Use external trigger wiring", this.externalTriggerCabling);
gd.addCheckbox ("Use internal FPGA trigger (no cables, for single camera)", this.noCabling);
// this.setupTriggerMode
// this.externalTriggerCabling
gd.addStringField ("Extra URL for all sub-cameras",this.cameraExtraURLCommon,40);
for (int i=0;i<this.cameraIPs.length;i++){
gd.addMessage("\n"+i+": camera "+this.cameraIPs[i]+" :");
gd.addNumericField(" Exposure correction ",this.cameraExposureCorr[i],2,8,"x");
gd.addNumericField(" Gain correction ",this.cameraGainCorr[i],2,8,"x");
gd.addNumericField(" R/G correction ",this.cameraRScaleCorr[i],2,8,"x");
gd.addNumericField(" B/G correction ",this.cameraBScaleCorr[i],2,8,"x");
gd.addNumericField(" G(B)/G(R) correction",this.cameraGScaleCorr[i],2,8,"x");
gd.addStringField (" Extra URL string ",this.cameraExtraURL[i],40);
}
gd.addNumericField("Debug sensor number (<0 - none)",this.debugSensorNumber,0,6,"");
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
this.nc393= gd.getNextBoolean();
this.cameraExposure= gd.getNextNumber();
this.scaleExposureForLasers= 0.01*gd.getNextNumber();
this.scaleExposureForHeadLasers=0.01*gd.getNextNumber();
this.cameraAutoExposure= gd.getNextBoolean();
this.cameraAutoExposureMax= gd.getNextNumber();
this.cameraGain= gd.getNextNumber();
this.cameraRScale= gd.getNextNumber();
this.cameraBScale= gd.getNextNumber();
this.cameraGScale= gd.getNextNumber();
this.cameraAutoWhiteBalance= gd.getNextBoolean();
this.colorMode= (int) gd.getNextNumber();
this.JPEGquality= (int) gd.getNextNumber();
this.noWait= gd.getNextBoolean();
this.setupTriggerMode= gd.getNextBoolean();
this.externalTriggerCabling= gd.getNextBoolean();
this.noCabling= gd.getNextBoolean();
this.cameraExtraURLCommon= gd.getNextString();
for (int i=0;i<this.cameraIPs.length;i++){
this.cameraExposureCorr[i]= gd.getNextNumber();
this.cameraGainCorr[i]= gd.getNextNumber();
this.cameraRScaleCorr[i]= gd.getNextNumber();
this.cameraBScaleCorr[i]= gd.getNextNumber();
this.cameraGScaleCorr[i]= gd.getNextNumber();
this.cameraExtraURL[i]= gd.getNextString();
}
this.debugSensorNumber= (int) gd.getNextNumber();
return true;
}
public void resetCameras(){
resetCameras(selectAllSubcameras());
}
public double[] timestampCameras(){
return timestampCameras(selectAllSubcameras());
}
public void resetIPs(){
resetIPs(selectAllIPs());
}
public double[] timestampIPs(){
return timestampIPs(selectAllIPs());
}
public boolean [] selectAllSubcameras(){
boolean [] all= new boolean[this.channelMap.length];
for (int i=0;i<all.length;i++) all[i]=true;
return all;
}
public boolean [] selectNoneSubcameras(){
boolean [] all= new boolean[this.channelMap.length];
for (int i=0;i<all.length;i++) all[i]=false;
return all;
}
public boolean [] selectAllIPs(){
boolean [] all= new boolean[this.cameraIPs.length];
for (int i=0;i<all.length;i++) all[i]=true;
return all;
}
public boolean [] selectIPs(boolean [] selectCameras){
boolean [] IPs= new boolean[this.cameraIPs.length];
for (int i=0;i<IPs.length;i++) IPs[i]=false;
for (int i=0;i<selectCameras.length;i++) if (i<this.channelMap.length) {
// IPs[this.channelMap[i][0]]=true;
IPs[this.channelIPPort[i]] = true; // since NC393
}
return IPs;
}
public void trigger(){
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
String url=this.triggerURL;
if (this.debugLevel>2) System.out.println(">>> trigger:" + url );
db.parse(url); // should be some XML (currently discarded)
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
return;
} catch(IOException e1){
IJ.showStatus("");
String error = e1.getMessage();
if (error==null || error.equals("")) error = ""+e1;
IJ.showMessage("trigger() ERROR", ""+error);
return;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
return;
}catch(SAXException se) {
se.printStackTrace();
return;
}
}
public double[] timestampCameras(boolean [] selection){
double [] ts_ip=timestampIPs(selectIPs(selection));
double [] ts=new double [selection.length];
for (int i=0;i<ts.length;i++){
ts[i]=0.0;
if (i<this.channelMap.length) ts[i]=ts_ip[this.channelMap[i][0]];
}
return ts;
}
public double[] timestampIPs(boolean [] ipSelection){
final Thread[] threads = newThreadArray(this.maxNumberOfThreads);
final AtomicInteger ipIndexAtomic = new AtomicInteger(0);
final int ipLength=this.resetURLs.length;
final int debugLevel=this.debugLevel;
final String [] metaURLs=this.metaURLs;
final double [] ts= new double[this.cameraIPs.length];
for (int i=0;i<ts.length;i++) ts[i]=0.0;
//TODO: Multithread the next cycle (per-sensor)
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int ipIndex=ipIndexAtomic.getAndIncrement(); ipIndex<ipLength;ipIndex=ipIndexAtomic.getAndIncrement()){
// for (int ipIndex=0;ipIndex<this.resetURLs.length;ipIndex++) if ((ipIndex<ipSelection.length) && ipSelection[ipIndex]){
try {
Document dom=null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
String url=metaURLs[ipIndex];
if (debugLevel>2) System.out.println("timestampIPs:" + url );
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("meta")) {
System.out.println("Root element: expected 'meta', got'" + dom.getDocumentElement().getNodeName()+"'");
IJ.showMessage("Error","Root element: expected 'meta', got'" + dom.getDocumentElement().getNodeName()+"'");
continue;
}
if (dom.getDocumentElement().getElementsByTagName("frame").getLength()==0) {
String sError="reading timestamp failed. Do you have camera firmware version >=8.1.1.1?";
System.out.println("ERROR: "+sError );
IJ.showMessage("Error",sError);
continue;
}
ts[ipIndex]=Double.parseDouble(
(dom.getDocumentElement().getElementsByTagName("timestamp").item(0).getChildNodes().item(0)).getNodeValue());
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
continue;
} catch(IOException e1){
IJ.showStatus("");
String error = e1.getMessage();
if (error==null || error.equals("")) error = ""+e1;
IJ.showMessage("timestampIPs() ERROR", ""+error);
continue;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
continue;
}catch(SAXException se) {
se.printStackTrace();
continue;
}
}
}
};
}
startAndJoin(threads);
return ts;
}
public void resetCameras(boolean [] selection){
if (this.debugLevel>2) {
System.out.println("resetCameras(...)");
for (int ii=0;ii<this.cameraIPs.length;ii++)System.out.println(ii+": "+this.cameraIPs[ii]);
}
resetIPs(selectIPs(selection));
}
public void resetIPs(boolean [] ipSelection){
final Thread[] threads = newThreadArray(this.maxNumberOfThreads);
final AtomicInteger ipIndexAtomic = new AtomicInteger(0);
final int ipLength=this.resetURLs.length;
final int debugLevel=this.debugLevel;
final String [] resetURLs=this.resetURLs;
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int ipIndex=ipIndexAtomic.getAndIncrement(); ipIndex<ipLength;ipIndex=ipIndexAtomic.getAndIncrement()){
String url="";
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
url=resetURLs[ipIndex];
if (debugLevel>2) System.out.println("--- resetURLs:" + url );
// if (debugLevel>1) System.out.println("--- resetURLs:" + url );
db.parse(url); // should be some XML (currently discarded)
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
continue;
} catch(IOException e1){
IJ.showStatus("");
String error = e1.getMessage();
if (error==null || error.equals("")) error = ""+e1;
IJ.showMessage("resetIPs() ERROR", url+"\n"+error);
continue;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
continue;
}catch(SAXException se) {
se.printStackTrace();
continue;
}
}
}
};
}
startAndJoin(threads);
}
public ImagePlus [] getImages(final boolean [] acquire, boolean resetAndTrigger, final boolean show){
final boolean [] acquireIPs=selectIPs(acquire);
if (this.debugLevel>2) {
System.out.println("getImages(...) 2");
for (int ii=0;ii<this.cameraIPs.length;ii++)System.out.println(ii+": "+this.cameraIPs[ii]);
}
if (resetAndTrigger) {
resetCameras();
trigger();
}
final double [] timestamps= timestampIPs(acquireIPs);
if (this.debugLevel>2) System.out.println("getImages(): this.imagesIP.length=" + this.imagesIP.length);
final Thread[] threads = newThreadArray(this.maxNumberOfThreads);
final AtomicInteger ipIndexAtomic = new AtomicInteger(0);
final int ipLength=this.resetURLs.length;
final int debugLevel=this.debugLevel;
final String [] imageURLs=this.imageURLs;
final ImagePlus [] imagesIP=this.imagesIP;
final JP46_Reader_camera [] jp4_Instances=this.jp4_Instances;
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int ipIndex=ipIndexAtomic.getAndIncrement(); ipIndex<ipLength;ipIndex=ipIndexAtomic.getAndIncrement()){
// for (int i=0;i<this.imagesIP.length;i++){
if (debugLevel>1/*2*/) System.out.println("getImages()3: ipIndex="+ipIndex+" acquireIPs.length=" +acquireIPs.length+
((ipIndex<acquireIPs.length)? (" acquireIPs[ipIndex]="+acquireIPs[ipIndex]):""));
if ((ipIndex<acquireIPs.length) && acquireIPs[ipIndex]) {
if (debugLevel>2) System.out.println("getImages:" + imageURLs[ipIndex] );
if ((debugLevel>3) &&(imagesIP[ipIndex]!=null) && show){
System.out.println("=============== old image ==========");
jp4_Instances[ipIndex].listImageProperties(imagesIP[ipIndex]);
}
imagesIP[ipIndex]=jp4_Instances[ipIndex].openURL( // gains inside were OK
imageURLs[ipIndex],
"",
true, //scale
imagesIP[ipIndex],
false); //show); // show image
imagesIP[ipIndex].setProperty("timestamp", IJ.d2s(timestamps[ipIndex],6));
imagesIP[ipIndex].setProperty("MIRRORED","NO");
if (debugLevel>2) {
jp4_Instances[ipIndex].listImageProperties(imagesIP[ipIndex],true); // to console - properties old - fixed
}
if (show){
imagesIP[ipIndex].updateAndDraw(); /// Redisplays final image
if (debugLevel>2){
System.out.println("=============== new image ==========");
jp4_Instances[ipIndex].listImageProperties(imagesIP[ipIndex]);
}
}
}
}
}
};
}
startAndJoin(threads);
//TODO: Multithread the next cycle (per-sensor)
final ImagePlus [] images=this.images;
final int [][] channelMap = this.channelMap;
final int [] channelIPPort = this.channelIPPort;
final AtomicInteger imageIndexAtomic = new AtomicInteger(0);
final int [] motorsPosition=this.motorsPosition;
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
// Next calls do not require image acquisition, so default settings for the new instance are OK
JP46_Reader_camera jp4_Instance= new JP46_Reader_camera(false);
for (int imageIndex=imageIndexAtomic.getAndIncrement(); imageIndex<images.length;imageIndex=imageIndexAtomic.getAndIncrement())
if ((imageIndex<acquire.length) && acquire[imageIndex]){
// for (int i=0;i<this.images.length;i++) if ((i<acquire.length) && acquire[i]) {
// int iIP=channelMap[imageIndex][0];
int iIP=channelIPPort[imageIndex]; // index in composite images (per ip/port)
if (sensorPresent[iIP]==null) { // system board for this channel did not respond null pointer - check cameras were detected
images[imageIndex]=null;
continue;
}
boolean singleSensor=true;
for (int s=0;s<sensorPresent[iIP].length;s++) singleSensor&= !sensorPresent[iIP][s];
if (singleSensor){ // no 10359 multiplexor
if (debugLevel>1) System.out.println("DEBUG393: demuxing single sensor imageIndex="+imageIndex+" iIP="+iIP);
images[imageIndex]=jp4_Instance.demuxClone(imagesIP[iIP]);
} else {
int subCam=channelMap[imageIndex][1];
if (!sensorPresent[iIP][subCam]){ // requested sensor does not exist
images[imageIndex]=null;
continue;
}
// skip missing channels, then demux
for (int s=0;s<channelMap[imageIndex][1];s++) if (!sensorPresent[iIP][s]) subCam--;
if (debugLevel>1) System.out.println("DEBUG393: demuxing imageIndex="+imageIndex+" iIP="+iIP+" subCam="+subCam);
images[imageIndex]=jp4_Instance.demuxImage(imagesIP[iIP],subCam);
}
// this.images[i]=this.jp4_Instances[j].demuxImageOrClone(this.imagesIP[j],this.channelMap[i][1]);
if (images[imageIndex]==null) continue;
if (debugLevel>2) jp4_Instance.listImageProperties(images[imageIndex]);
if (debugLevel>2) jp4_Instance.encodeProperiesToInfo(images[imageIndex]);
if (debugLevel>2) {
jp4_Instance.listImageProperties(images[imageIndex]);
jp4_Instance.decodeProperiesFromInfo(images[imageIndex]);
jp4_Instance.listImageProperties(images[imageIndex]);
}
String title=IJ.d2s(timestamps[iIP],6).replace('.','_')+String.format("-%02d.tiff", imageIndex); // sensor number
images[imageIndex].setTitle(title);
if (flipImages[imageIndex]) { // this is only for physical mirror
flipKeepBayer(images[imageIndex]);
if (debugLevel>2){
System.out.println("=============== flipKeepBayer ==========");
jp4_Instance.listImageProperties(images[imageIndex]);
}
if (show) images[imageIndex].updateAndDraw();
}
images[imageIndex].setProperty("channel", String.format("%02d", imageIndex));
images[imageIndex].setProperty("subcamera",""+getSubCamera(imageIndex));
images[imageIndex].setProperty("sensor_port",""+getSensorPort(imageIndex));
images[imageIndex].setProperty("subchannel", ""+getSubChannel(imageIndex));
// private int [] motorsPosition= null; // motors steps when the images were acquired (for null)
if (motorsPosition!=null) for (int m=0;m<motorsPosition.length;m++ ) {
images[imageIndex].setProperty("MOTOR"+(m+1), ""+motorsPosition[m]);
}
jp4_Instance.encodeProperiesToInfo(images[imageIndex]);
}
}
};
}
startAndJoin(threads);
return this.imagesIP;
}
// should be already triggered!
public ImagePlus [] getImages(
UVLEDandLasers uvLEDandLasers, // or null - not null only for adjustment machine lasers
boolean [] pre_acquire,
boolean [] pre_lasers,
boolean resetAndTrigger,
final boolean show){
// this.reportTiming=this.debugLevel>1; // Need to be set by caller
printTimingInit();
// long startTime = System.nanoTime();
final int debugLevel=this.debugLevel;
final boolean opticalHeadLasersMode=(uvLEDandLasers!=null);
// boolean [] lasers2={true,true};
final boolean [] lasers=opticalHeadLasersMode?pre_acquire:pre_lasers;
if (this.sensorPresent==null) { // cameras were not probed/configured
probeCameraState(); // testing detection
printTiming("=== probeCameraState()");
setupCameraAcquisition();
printTiming("=== setupCameraAcquisition()");
}
boolean [] acquire= new boolean[this.channelMap.length];
for (int i=0;i<acquire.length;i++) {
acquire[i]= ((i<pre_acquire.length) && pre_acquire[i]) || ((lasers!=null) && (i<lasers.length) && lasers[i]);
}
boolean [] opticalHeadLasersInitial=null;
int[] opticalHeadSequence={0,1,2};
final boolean [][] headLaserWasOn={{false,true,false},{false,false,true}};
if (opticalHeadLasersMode){
opticalHeadLasersInitial=uvLEDandLasers.getLasers();
} else if ((lasers!=null) && (this.laserPointers!=null)) {
if (this.debugLevel>2) System.out.println("************ turning lasers off *************");
this.laserPointers.setLasers(0);// turn off all lasers
//lasersSequence
if (this.debugLevel>2) {
System.out.println("getImages(...) 1");
for (int ii=0;ii<this.cameraIPs.length;ii++)System.out.println(ii+": "+this.cameraIPs[ii]);
}
}
if ((lasers==null) && !opticalHeadLasersMode) {
getImages(acquire, resetAndTrigger, show); // get images w/o lasers, flip if needed
printTiming("=== Image acquisition");
return this.imagesIP;
}
//scaleExposureForLasers
// reduce exposure for lasers (both 4 and 2)
final double scaleExposureForLasers=opticalHeadLasersMode?
(((this.scaleExposureForHeadLasers>0.0) && (this.scaleExposureForHeadLasers<1.0))?this.scaleExposureForHeadLasers:0.0):
(((this.scaleExposureForLasers>0.0) && (this.scaleExposureForLasers<1.0))?this.scaleExposureForLasers:0.0);
if (scaleExposureForLasers>0) setupCameraAcquisition(scaleExposureForLasers);
final boolean [] lasersIPs= selectIPs(opticalHeadLasersMode?acquire:lasers);
final int [] sequence=opticalHeadLasersMode?opticalHeadSequence:this.laserPointers.getSequence();
if (debugLevel>2) for (int i=0;i<sequence.length;i++) System.out.println(String.format("Laser sequence[%d]=0x%x", i,sequence[i]));
final ImagePlus [][] laserImagesIP=new ImagePlus[sequence.length-1][this.imagesIP.length];
if (this.debugLevel>2) System.out.println("this.imagesIP.length="+this.imagesIP.length+" sequence.length="+sequence.length);
final String [] imageURLs=this.imageURLs;
final JP46_Reader_camera [] jp4_Instances=this.jp4_Instances;
final Thread[] threads = newThreadArray(this.maxNumberOfThreads);
final AtomicInteger ipIndexAtomic = new AtomicInteger(0);
for (int nSeqNum=1; nSeqNum<sequence.length;nSeqNum++){
if (opticalHeadLasersMode) {
boolean [] bLasers={(sequence[nSeqNum]&1)!=0,(sequence[nSeqNum]&2)!=0};
uvLEDandLasers.setLasersAndUV(bLasers,null,null);
if (debugLevel>2) System.out.println("uvLEDandLasers.setLasersAndUV("+bLasers[0]+","+bLasers[1]+")");
} else {
this.laserPointers.setLasers (sequence[nSeqNum]);// turn on selected laser
if (debugLevel>2) System.out.println(String.format("this.laserPointers.setLasers (0x%x)", sequence[nSeqNum]));
}
resetIPs(selectIPs(lasersIPs)); // flush buffer
trigger(); // trigger cameras
ipIndexAtomic.set(0);
final int fnSeqNum=nSeqNum;
final boolean reportTiming=this.reportTiming;
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
for (int ipIndex=ipIndexAtomic.getAndIncrement(); ipIndex<lasersIPs.length;ipIndex=ipIndexAtomic.getAndIncrement()){
long st=System.nanoTime();
if (debugLevel>1) {
System.out.println("image url["+ipIndex+"]="+imageURLs[ipIndex]);
}
laserImagesIP[fnSeqNum-1][ipIndex]=jp4_Instances[ipIndex].openURL(
imageURLs[ipIndex],
"",
true, //scale
null, // new image, nothing to reuse
false); // show image no timestamps here
if (reportTiming){
System.out.println("==== "+imageURLs[ipIndex]+ " opened in "+IJ.d2s(0.000000001*(System.nanoTime()-st),3)+" sec");
}
laserImagesIP[fnSeqNum-1][ipIndex].setProperty("MIRRORED","NO");
}
}
};
}
startAndJoin(threads);
printTiming("=== Image # "+nSeqNum+" acquisition");
}
// acquire no-laser image after all others are acquired, so the camera is completely still at that time
if (opticalHeadLasersMode) {
boolean [] bLasers={(sequence[0]&1)!=0,(sequence[0]&2)!=0};
uvLEDandLasers.setLasersAndUV(bLasers,null,null);
if (debugLevel>2) System.out.println("uvLEDandLasers.setLasersAndUV("+bLasers[0]+","+bLasers[1]+")");
} else {
this.laserPointers.setLasers (sequence[0]);// turn on selected laser
if (debugLevel>2) System.out.println(String.format("this.laserPointers.setLasers (0x%x)", sequence[0]));
}
// this.laserPointers.setLasers (0);// turn off all lasers
if (scaleExposureForLasers>0.0) setupCameraAcquisition(1.0);
getImages(acquire, resetAndTrigger, show); // get images w/o lasers, flip if needed
printTiming("=== Final (no-laser) image # 0 acquired");
if (opticalHeadLasersMode) {
uvLEDandLasers.setLasersAndUV(opticalHeadLasersInitial,null,null);
if (debugLevel>2) System.out.println("Restoring lasers: uvLEDandLasers.setLasersAndUV("+opticalHeadLasersInitial[0]+","+opticalHeadLasersInitial[1]+")");
}
// now demux images (if composite) and process laser spots
// for (int sensorNum=0;sensorNum<this.images.length;sensorNum++) if (this.images[sensorNum]!=null){
// final MatchSimulatedPattern matchSimulatedPattern = new MatchSimulatedPattern();
// final ImagePlus imp_pointed=null;
final int bayerG1=0;
final int bayerG2=3;
final int bayerR=1;
final int bayerB=2;
final boolean useOther=laserPointers.laserPointer.useOther;
final boolean otherGreen=laserPointers.laserPointer.otherGreen;
final int [][] channelMap=this.channelMap;
final int [] channelIPPort = this.channelIPPort;
final ImagePlus [] images=this.images;
final boolean [] flipImages=this.flipImages;
final LaserPointersHardware laserPointers=this.laserPointers;
final boolean [][] sensorPresent=this.sensorPresent;
final int debugSensorNumber=this.debugSensorNumber;
printTiming("=== Acquisition done, starting multi-threaded laser pointer location processing");
//TODO: Multithread the next cycle (per-sensor)
final AtomicInteger sensorNumAtomic = new AtomicInteger(0);
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
// Next calls do not require image acquisition, so default settings for the new instance are OK
JP46_Reader_camera jp4_Instance= new JP46_Reader_camera(false);
MatchSimulatedPattern matchSimulatedPattern = new MatchSimulatedPattern();
for (int sensorNum=sensorNumAtomic.getAndIncrement(); sensorNum<lasers.length;sensorNum=sensorNumAtomic.getAndIncrement()) // null pointer
if (lasers[sensorNum] && (images[sensorNum]!=null)){
// for (int sensorNum=0;sensorNum<lasers.length;sensorNum++) if (lasers[sensorNum] && (this.images[sensorNum]!=null)){ // lasers - here sensors to use lasers for
// int iIP=channelMap[sensorNum][0];
int iIP=channelIPPort[sensorNum]; // index in composite images (per ip/port)
double saturationRed=255.0;
if (images[sensorNum].getProperty("saturation_0")!=null) saturationRed=Double.parseDouble((String)images[sensorNum].getProperty("saturation_0"));
if (scaleExposureForLasers>0) saturationRed*=scaleExposureForLasers; // scaled to reduced exposure time
double[][] backgroundBayer =matchSimulatedPattern.splitBayer (images[sensorNum], null, true); // full window
double[][] pointedBayer;
double [][] pontersXY=null;
// int iIP=this.channelMap[sensorNum][0];
int len=backgroundBayer[bayerG1].length;
double [][] greens=useOther?(new double [sequence.length][]):null;
double [][] reds= new double [sequence.length][];
if (useOther){
greens[0]=otherGreen?(new double[len]):backgroundBayer[bayerB];
if (otherGreen) for (int j=0; j<len;j++) greens[0][j]=0.5*(backgroundBayer[bayerG1][j]+backgroundBayer[bayerG2][j]);
}
reds[0]=backgroundBayer[bayerR]; // no need to clone?
if (debugLevel>2) System.out.println("getImages (): sensorNum="+sensorNum+", iIP="+iIP+" sequence.length="+sequence.length);
// if ((debugLevel>1) && (sensorNum==13)) System.out.println("getImages (): sensorNum="+sensorNum+", iIP="+iIP+" sequence.length="+sequence.length);
boolean singleSensor=true;
for (int s=0;s<sensorPresent[iIP].length;s++) singleSensor&= !sensorPresent[iIP][s];
ImagePlus imp_pointed=null;
for (int nSeqNum=1; nSeqNum<sequence.length; nSeqNum++){
if (debugLevel>2) System.out.println("getImages(): sensorNum="+sensorNum+", iIP="+iIP+" nSeqNum="+nSeqNum+" this.channelMap["+sensorNum+"][1]="+channelMap[sensorNum][1]);
// here we are processing only same sensors that produced no-laser images, no need to check if they exist again
if (singleSensor){ // no 10359 multiplexor
//imp_pointed=jp4_Instances[iIP].demuxClone(laserImagesIP[nSeqNum-1][iIP]);
imp_pointed=jp4_Instance.demuxClone(laserImagesIP[nSeqNum-1][iIP]);
} else {
int subCam=channelMap[sensorNum][1];
// skip missing channels, then demux
for (int s=0;s<channelMap[sensorNum][1];s++) if (!sensorPresent[iIP][s]) subCam--;
//imp_pointed=jp4_Instances[iIP].demuxImage(laserImagesIP[nSeqNum-1][iIP],subCam);
if (laserImagesIP[nSeqNum-1][iIP]==null){
System.out.println("getImages(): laserImagesIP["+(nSeqNum-1)+"]["+iIP+"]==null");
}
imp_pointed=jp4_Instance.demuxImage(laserImagesIP[nSeqNum-1][iIP],subCam);
}
imp_pointed.setTitle(imp_pointed.getTitle()+"_"+sensorNum);
if (flipImages[sensorNum]) {
flipKeepBayer(imp_pointed);
if (show) imp_pointed.updateAndDraw();
}
pointedBayer=matchSimulatedPattern.splitBayer (imp_pointed, null, true);
if (useOther){
greens[nSeqNum]=otherGreen?(new double[len]):pointedBayer[bayerB];
if (otherGreen) for (int j=0; j<len;j++) greens[nSeqNum][j]=0.5*(pointedBayer[bayerG1][j]+pointedBayer[bayerG2][j]);
}
reds[nSeqNum]=pointedBayer[bayerR].clone();
}
//minimalIntensity scaleExposureForLasers>0 saturationRed
pontersXY=laserPointers.laserPointer.getPointerXY( // returns x,y pair or null if pointer not detected
opticalHeadLasersMode,
saturationRed,
scaleExposureForLasers, //>0.0,
greens, // combined Bayer greens for each image, starting with no-laser
reds, // red Bayer component for each image, starting with no-laser
opticalHeadLasersMode?headLaserWasOn:laserPointers.laserWasOn(), // array specifying which image should have pointer on, for each laser
imp_pointed.getWidth(),// image width in pixels
imp_pointed.getTitle(), // String title,
debugLevel+ ((sensorNum==debugSensorNumber)?1:0) // debug level (normal == 1)
// debugLevel
);
int pointersDetected=0;
if (!opticalHeadLasersMode){
for (int nPointer=0; nPointer<laserPointers.getNumberOfLasers();nPointer++){
if (pontersXY[nPointer]!=null){
if (debugLevel>1) System.out.println("image:"+sensorNum+" pointer #"+(nPointer+1)+
", X="+pontersXY[nPointer][0]+", Y="+pontersXY[nPointer][1]);
images[sensorNum].setProperty("POINTER_X_"+nPointer, IJ.d2s(pontersXY[nPointer][0],1));
images[sensorNum].setProperty("POINTER_Y_"+nPointer, IJ.d2s(pontersXY[nPointer][1],1));
pointersDetected++;
}
}
if ((pointersDetected>0) && (debugLevel>0)) {
System.out.println("image:"+sensorNum+" - "+pointersDetected+" pointer"+((pointersDetected>1)?"s":"")+" detected");
}
} else {
for (int nPointer=0; nPointer<2;nPointer++){
if (pontersXY[nPointer]!=null){
if (debugLevel>1) System.out.println("image:"+sensorNum+" pointer #"+(nPointer+1)+
", X="+pontersXY[nPointer][0]+", Y="+pontersXY[nPointer][1]);
images[sensorNum].setProperty("HEAD_POINTER_X_"+nPointer, IJ.d2s(pontersXY[nPointer][0],1));
images[sensorNum].setProperty("HEAD_POINTER_Y_"+nPointer, IJ.d2s(pontersXY[nPointer][1],1));
pointersDetected++;
}
}
}
images[sensorNum].setProperty("HEAD_POINTERS", pointersDetected+"");
//jp4_Instances[iIP].encodeProperiesToInfo(images[sensorNum]);
jp4_Instance.encodeProperiesToInfo(images[sensorNum]);
}
}
};
}
startAndJoin(threads);
// this.laserPointers.setLasers (0);// turn off all lasers
printTiming("=== Image acquisition/laser pointers location");
return this.imagesIP;
}
public double [][] getHeadPointers(ImagePlus imp){
if (imp.getProperty("HEAD_POINTERS")==null) return null;
int numHeadPointers=Integer.parseInt((String) imp.getProperty("HEAD_POINTERS"));
double [][] headPointers=new double[numHeadPointers][];
for (int n=0;n<headPointers.length;n++){
if ((imp.getProperty("HEAD_POINTER_X_"+n)!=null) && (imp.getProperty("HEAD_POINTER_Y_"+n)!=null)){
headPointers[n]=new double[2];
headPointers[n][0]=Double.parseDouble((String)imp.getProperty("HEAD_POINTER_X_"+n));
headPointers[n][1]=Double.parseDouble((String)imp.getProperty("HEAD_POINTER_Y_"+n));
} else headPointers[n]=null;
}
return headPointers;
}
// return array of last acquired images
public ImagePlus [] getImages(){
return this.images;
}
public ImagePlus [] getImages(int numberOfPointers){ // return images with at least this number of pointers detected
ImagePlus [] filteredImages=this.images.clone();
for (int i=0;i<filteredImages.length;i++) if (getNumberOfPointers(i)<numberOfPointers) filteredImages[i]=null;
return filteredImages;
}
public int getNumberOfPointers (int sensorNum){
return getNumberOfPointers (this.images[sensorNum]);
}
public int getNumberOfPointers (ImagePlus imp){
if (imp==null) return 0;
if (imp.getProperty("POINTERS")!=null) return Integer.parseInt((String) imp.getProperty("POINTERS"));
else return 0;
}
public int saveImages(boolean [] selection, String directory, boolean updateStatus){
int numImg=0;
boolean notYetPrinted=true;
for (int i=0;(i<this.channelMap.length) && ((selection==null) || (i<selection.length));i++)
if ((this.images[i]!=null) && ((selection==null) || selection[i])){
FileSaver fs=new FileSaver(this.images[i]);
String path=directory+Prefs.getFileSeparator()+this.images[i].getTitle();
if (updateStatus) IJ.showStatus("Saving "+path);
if (this.debugLevel>0){
if (this.debugLevel>1) System.out.println("Saving "+path); // was >0
else if (notYetPrinted) {
System.out.println("Saving "+path+ " (and other with the same timestamp)" ); // was >0
notYetPrinted=false;
}
}
fs.saveAsTiff(path);
numImg++;
}
return numImg;
}
/*
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]);
*/
/**
* FLips image vertically and crops by one pixel at the top and bottom (to preserve Bayer pattern)
* @param imp
* @return
*/
public ImagePlus flipAndCrop(ImagePlus imp){
String title=imp.getTitle();
imp.setTitle(title+"-original");
ImageProcessor ip=imp.getProcessor();
ip.setRoi(0,1,ip.getWidth(),ip.getHeight()-2);
ImageProcessor ip2=ip.crop();
ip2.flipVertical();
ImagePlus imp_new=new ImagePlus(title,ip2);
// copy all properties and add "MIRRORED=Y"
Set<Object> imp_set;
Properties imp_prop;
Iterator<Object> itr;
String str;
imp_prop=imp.getProperties();
if (imp_prop!=null) {
imp_set=imp_prop.keySet();
itr=imp_set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
imp_new.setProperty(str,imp_prop.getProperty(str));
}
}
imp_new.setProperty("MIRRORED","YES");
return imp_new;
}
public ImagePlus flipKeepBayer(ImagePlus imp){
ImageProcessor ip=imp.getProcessor();
float [] pixels=(float[]) ip.getPixels();
float [] new_pixels=new float[pixels.length];
int width=ip.getWidth();
int height=ip.getHeight();
for (int i=1;i<height-1;i++) for (int j=0;j<width;j++){
new_pixels[i*width+j]=pixels[(height-i)*width+j];
}
for (int j=0;j<width;j++) new_pixels[j]=new_pixels[2*width+j]; // copy second line to 0
ip.setPixels(new_pixels);
imp.setProperty("MIRRORED","YES");
return imp;
}
public ImagePlus flipKeepBayerNew(ImagePlus imp){
float [] pixels=(float []) imp.getProcessor().getPixels();
float [] new_pixels=new float[pixels.length];
int width=imp.getWidth();
int height=imp.getHeight();
for (int i=1;i<height-1;i++) for (int j=0;j<width;j++){
new_pixels[i*width+j]=pixels[(height-i)*width+j];
}
for (int j=0;j<width;j++) new_pixels[j]=new_pixels[2*width+j]; // copy second line to 0
ImageProcessor ip=new FloatProcessor(imp.getWidth(), imp.getHeight());
ip.setPixels(new_pixels);
ip.resetMinAndMax();
ImagePlus imp_flipped= new ImagePlus(imp.getTitle()+"-flipped", ip);
imp_flipped.setProperty("MIRRORED","YES");
return imp_flipped;
}
// in detection mode - reduce exp
public void test1(boolean useLasers) {
getImages(
null, // UVLEDLasers
selectAllSubcameras(),
(useLasers?selectAllSubcameras():null),
true,
this.debugLevel>1); // reset and trigger
if (this.debugLevel>1) {
if (this.debugLevel>2) System.out.println("++++++++++++++++++ Image Properies ++++++++++++++++++++++++++++");
for (int i=0;i<this.images.length;i++) if (this.images[i]!=null) {
// int j=this.channelMap[i][0];
int j=channelIPPort[i]; // sincer NC393 adder port
if (this.debugLevel>2) {
System.out.println("Image #"+i);
this.jp4_Instances[j].listImageProperties(this.images[i]);
}
if ((this.debugLevel>2) || (getNumberOfPointers (i)>0)) {
this.images[i].show();
this.images[i].updateAndDraw();
}
}
}
}
public void acquire(String directory, boolean useLasers, boolean updateStatus) {
getImages(
null, // UVLEDLasers
selectAllSubcameras(),
(useLasers?selectAllSubcameras():null),
true,
this.debugLevel>1); // reset and trigger
int numImg=saveImages(selectAllSubcameras(), directory, updateStatus);
if (this.debugLevel>1) System.out.println("Saved "+numImg+" images.");
}
public ImagePlus acquireSingleImage (boolean useLasers, boolean updateStatus){
getImages(
null, // UVLEDLasers
selectAllSubcameras(),
(useLasers?selectAllSubcameras():null),
true,
this.debugLevel>1); // reset and trigger
this.lastTimestamp=(String) this.images[0].getProperty("timestamp");
return this.images[0];
}
public ImagePlus [] acquireSeveralImages (boolean useLasers, boolean updateStatus){
getImages(
null, // UVLEDLasers
selectAllSubcameras(),
(useLasers?selectAllSubcameras():null),
true,
this.debugLevel>1); // reset and trigger
this.lastTimestamp=(String) this.images[0].getProperty("timestamp");
return this.images;
}
public ImagePlus acquireSingleImage (UVLEDandLasers uvLEDLasers, boolean updateStatus){
getImages(
uvLEDLasers, // UVLEDLasers
selectAllSubcameras(),
null,
true,
this.debugLevel>1); // reset and trigger
this.lastTimestamp=(String) this.images[0].getProperty("timestamp");
return this.images[0];
}
public String getLastTimestampUnderscored(){
return this.lastTimestamp.replace('.','_');
}
/* 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);
}
}
}
\ No newline at end of file
package com.elphel.imagej.calibration.hardware;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.concurrent.atomic.AtomicInteger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import ij.IJ;
public class GoniometerMotors{
public double [][] motorsRange={null,{-100000,100000},{-500000,500000}};
public double stepsPerSecond= 732.7; // motor speed limit in steps per second
public double stepsPerDegreeTilt=-5682.48889; // minus that positive steps make negative elevation
// gearmotor -64steps 1:19 - 1216 steps/turn. Worm 1:80 -> 97280/turn. roller/tube ~1.44 ->388.3/degree
// public double stepsPerDegreeAxial=-388.3; // -36.0; // minus that positive steps make rotate CCW when looking from Eyesis top
public double stepsPerDegreeAxial=-369.64; // measured 133070 steps per360
public String ipAddress="192.168.0.109";
public int [] curpos=new int[3];
public int [] targetPosition={0,0,0};
public int debugLevel=2;
public int motorTolerance=5; // steps - disregard error less than that
public int motorStuckTolerance=5; // steps - disregard error less than that
public double coefficientETA=1.5; // allow moving 1.5 longer than at maximal speed
private long nanoETA;
private long nanoReferenceTime; // last time the position was checked
private int []referencePosition=null;
private double motorsStuckTestTime=5.0; // seconds
private boolean motorsInitialized=false;
public int tiltMotor=2; // 0-1-2
public int axialMotor=1; // 0-1-2
/**
* Tries to initialize motors if needed. Assumes that non-initialized motors were not tried to be moved
* @param force unconditionally try to initialize
* @return
*/
public boolean tryInit(
boolean force,
boolean updateStatus){
int delta=2*this.motorTolerance;
if (!force) {
if (motorsInitialized) return true;
updateMotorsPosition();
if ((Math.abs(curpos[tiltMotor])>2) || (Math.abs(curpos[axialMotor])>2)){
motorsInitialized=true;
return true;
}
System.out.println("Trying to move axial motor to see if it is initialized ...");
motorsInitialized=true; // to avoid loop
int newpos=curpos[axialMotor]+delta;
if (moveMotorSetETA(axialMotor, newpos)) {
if (waitMotor(axialMotor, null, true, updateStatus)) {// no interaction
moveMotorSetETA(axialMotor, newpos-delta); // restore original
if (waitMotor(axialMotor, null, true, updateStatus)) {// no interaction
return true; // should be always true here
}
}
}
motorsInitialized=false;
}
initMotors();
motorsInitialized=true;
return true;
}
// TODO: Enable simultaneous motors
public boolean moveMotorSetETA(int motorNumber, int position){
if ((motorNumber<0) ||(motorNumber>=this.motorsRange.length) || (this.motorsRange[motorNumber]==null)){
String msg="Motor "+motorNumber+" is undefined";
IJ.showMessage("Error",msg);
throw new RuntimeException(msg);
}
if ((position<this.motorsRange[motorNumber][0]) || (position>this.motorsRange[motorNumber][1])){
String msg="Motor "+motorNumber+" requested position "+position+" is out of range ("+
this.motorsRange[motorNumber][0]+"..."+this.motorsRange[motorNumber][1]+")";
System.out.println("Error: "+msg);
IJ.showMessage("Error",msg);
//throw new RuntimeException(msg);
return false;
}
if (!motorsInitialized) { // may be called from tryInit(), but with motorsInitialized set to true;
if (!tryInit(false, true)){ // do not force, update status
String msg="Motors failed to initialize";
System.out.println("Error: "+msg);
IJ.showMessage("Error",msg);
//throw new RuntimeException(msg);
return false;
}
}
// TODO: check init is needed
updateMotorsPosition();
this.targetPosition[motorNumber]=position;
this.nanoReferenceTime=System.nanoTime();
this.referencePosition=this.curpos.clone();
// commandElphel10364Motors("http://"+this.ipAddress+"/10364.php?m"+(motorNumber+1)+"="+this.targetPosition[motorNumber]+"&enable");
// set, wait, enable (to avoid continuing "old" movement that was aborted by disable
commandElphel10364Motors("http://"+this.ipAddress+"/10364.php?m"+(motorNumber+1)+"="+this.targetPosition[motorNumber]+"sleep=1");
enableMotors(true);
nanoETA=System.nanoTime()+((long)(1E9*(Math.abs(this.targetPosition[motorNumber]-this.curpos[motorNumber])*(this.coefficientETA/this.stepsPerSecond))));
return true;
}
/*
public boolean [] checkGotTarget(){
updateMotorsPosition(0); // no wait here
boolean [] result=new boolean [this.curpos.length];
for (int motorNumber=0;motorNumber<result.length;motorNumber++){
result[motorNumber]=Math.abs(this.targetPosition[motorNumber]-this.curpos[motorNumber])<this.motorTolerance;
}
return result;
}
*/
public boolean checkGotTarget(int motorNumber, int position){
updateMotorsPosition(0); // no wait here
return Math.abs(position-this.curpos[motorNumber])<this.motorTolerance;
}
public boolean waitMotor(
int motorNumber,
AtomicInteger stopRequested, // or null
boolean quiet,
boolean updateStatus
){
if ((motorNumber<0) ||(motorNumber>=this.motorsRange.length) || (this.motorsRange[motorNumber]==null)){
String msg="Motor "+motorNumber+" is undefined";
IJ.showMessage("Error",msg);
throw new RuntimeException(msg);
}
while (true) {
// enableMotors(true); // just in case? - not here, test first
updateMotorsPosition(1); // wait one second before testing to decrease re-test frequency
if (updateStatus) {
double axialAngle=curpos[axialMotor]/this.stepsPerDegreeAxial;
double tiltAngle=curpos[tiltMotor]/this.stepsPerDegreeTilt;
double axialTargetAngle=targetPosition[axialMotor]/this.stepsPerDegreeAxial;
double tiltTargetAngle=targetPosition[tiltMotor]/this.stepsPerDegreeTilt;
IJ.showStatus("Goniometer: tilt="+IJ.d2s(tiltAngle,1)+"\u00b0 ("+IJ.d2s(tiltTargetAngle,1)+"\u00b0) "+
", axial="+IJ.d2s(axialAngle,1)+"\u00b0 ("+IJ.d2s(axialTargetAngle,1)+"\u00b0) "+
" Tilt steps="+curpos[tiltMotor]+" ("+this.targetPosition[tiltMotor]+") "+
", axial steps="+curpos[axialMotor]+" ("+this.targetPosition[axialMotor]+")");
}
int positionError= Math.abs(this.targetPosition[motorNumber]-this.curpos[motorNumber]);
if (positionError<this.motorTolerance){
updateMotorsPosition(1); // re-test
positionError= Math.abs(this.targetPosition[motorNumber]-this.curpos[motorNumber]);
enableMotors(false);
return true;
}
enableMotors(true); // does not need to be enabled before
long nanoNow=System.nanoTime();
if ((stopRequested!=null) && (stopRequested.get()>1)){
enableMotors(false);
if (this.debugLevel>0) System.out.println("User interrupt");
stopRequested.set(0);
updateMotorsPosition(1);
double axialAngle=curpos[axialMotor]/this.stepsPerDegreeAxial;
double tiltAngle=curpos[tiltMotor]/this.stepsPerDegreeTilt;
double axialTargetAngle=targetPosition[axialMotor]/this.stepsPerDegreeAxial;
double tiltTargetAngle=targetPosition[tiltMotor]/this.stepsPerDegreeTilt;
String msg="Goniometer: tilt="+IJ.d2s(tiltAngle,1)+"\u00b0 ("+IJ.d2s(tiltTargetAngle,1)+"\u00b0) "+
", axial="+IJ.d2s(axialAngle,1)+"\u00b0 ("+IJ.d2s(axialTargetAngle,1)+"\u00b0) "+
" Tilt steps="+curpos[tiltMotor]+" ("+this.targetPosition[tiltMotor]+") "+
", axial steps="+curpos[axialMotor]+" ("+this.targetPosition[axialMotor]+")\n"+
"OK to continue, Cancel to abort movement";
if (!IJ.showMessageWithCancel("Goniometer interrupted", msg)) {
return false;
}
enableMotors(true);
this.nanoETA += System.nanoTime()-nanoNow;
}
if (nanoNow>this.nanoETA) {
enableMotors(false);
if (quiet) return false;
String msg="Motor "+motorNumber+" failed to reach destination "+this.targetPosition[motorNumber]+
", current position is "+this.curpos[motorNumber]+
"\nYou may try to manually fix the problem before hitting OK";
System.out.println ("Error:"+msg);
IJ.showMessage("Error",msg);
// if (IJ.showMessageWithCancel("Goniometer did not move", msg+"\n OK will try to initialize ");
// Give chance to manually fix the problem
updateMotorsPosition();
positionError= Math.abs(this.targetPosition[motorNumber]-this.curpos[motorNumber]);
if (positionError<this.motorTolerance){
enableMotors(false);
return true;
}
return false;
}
if ((nanoNow-this.nanoReferenceTime)> ((long) (this.motorsStuckTestTime*1E9))){
if(Math.abs(this.referencePosition[motorNumber]-this.curpos[motorNumber]) < motorStuckTolerance){
enableMotors(false);
if (quiet) return false;
String msg="Motor "+motorNumber+" is stuck at "+this.curpos[motorNumber]+". "+
this.motorsStuckTestTime+" seconds ago it was at "+this.referencePosition[motorNumber]+
", target position is "+this.targetPosition[motorNumber]+
"\nYou may try to manually fix the problem before hitting OK";
System.out.println ("Error:"+msg);
IJ.showMessage("Error",msg);
// Give chance to manually fix the problem
updateMotorsPosition();
positionError= Math.abs(this.targetPosition[motorNumber]-this.curpos[motorNumber]);
if (positionError<this.motorTolerance){
enableMotors(false);
return true;
}
return false;
} else {
this.nanoReferenceTime=System.nanoTime();
this.referencePosition=this.curpos.clone();
}
}
}
}
// first check tolerance, then - if motor is stuck
public int [] getCurrentPositions(){
updateMotorsPosition();
return this.curpos;
}
public int [] getTargetPositions(){
return this.targetPosition;
}
public int[] enableMotors(boolean enable) {
return commandElphel10364Motors("http://"+this.ipAddress+"/10364.php?"+(enable?"enable":"disable"));
}
public int[] initMotors() {
return commandElphel10364Motors("http://"+this.ipAddress+"/10364.php?init");
}
public int[] setHome() {
return commandElphel10364Motors("http://"+this.ipAddress+"/10364.php?m1=0&m2=0&m3=0&reset");
}
public int[] updateMotorsPosition() {
return commandElphel10364Motors("http://"+this.ipAddress+"/10364.php");
}
public int[] updateMotorsPosition(int sleep) {
return commandElphel10364Motors("http://"+this.ipAddress+"/10364.php?sleep="+sleep);
}
private int[] commandElphel10364Motors(String url) {
Document dom=null;
if (this.debugLevel>2) System.out.println("commandElphel10364Motors("+url+")");
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("motors")) {
IJ.showMessage("Root element: expected 'motors', got'" + dom.getDocumentElement().getNodeName()+"'");
return null;
}
this.curpos[0]=Integer.parseInt((dom.getDocumentElement().getElementsByTagName("motor1").item(0).getChildNodes().item(0)).getNodeValue());
this.curpos[1]=Integer.parseInt((dom.getDocumentElement().getElementsByTagName("motor2").item(0).getChildNodes().item(0)).getNodeValue());
this.curpos[2]=Integer.parseInt((dom.getDocumentElement().getElementsByTagName("motor3").item(0).getChildNodes().item(0)).getNodeValue());
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
return null;
} catch(IOException e1){
IJ.showStatus("");
String error = e1.getMessage();
if (error==null || error.equals("")) error = ""+e1;
IJ.showMessage("commandElphel10364Motors ERRROR", ""+error);
return null;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
return null;
}catch(SAXException se) {
se.printStackTrace();
return null;
}
// prevent accumulating position errors
/*
if ((this.lastMovedTo!=null) && (Math.abs(this.lastMovedTo[0]-this.curpos[0])<=this.positionTolerance) &&
(Math.abs(this.lastMovedTo[1]-this.curpos[1])<=this.positionTolerance) &&
(Math.abs(this.lastMovedTo[2]-this.curpos[2])<=this.positionTolerance)) this.curpos=this.lastMovedTo.clone();
*/
return this.curpos;
}
}
\ No newline at end of file
package com.elphel.imagej.calibration.hardware;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.elphel.imagej.calibration.LaserPointer;
import com.elphel.imagej.common.WindowTools;
import ij.IJ;
import ij.gui.GenericDialog;
public class LaserPointersHardware{
public int debugLevel=1;
public LaserPointer laserPointer=null; // class that defines geometry and extracts laser coordinates
private int state=-1; // bit-wise on/off, <0 - undefined
private String lasersIP="192.168.0.13";
private String lasersSequence="3c5a96"; // laser combinations to try, (non including 0)
private int [][][] registerData=
{
{{0x2600,0xff},{0x2700,0xff}}, // - - - - 0
{{0x2600,0xdf},{0x2700,0xff}}, // - - - + 1
{{0x2600,0xff},{0x2700,0xef}}, // - - + - 2
{{0x2600,0xdf},{0x2700,0xef}}, // - - + + 3
{{0x2600,0xef},{0x2700,0xff}}, // - + - - 4
{{0x2600,0xcf},{0x2700,0xff}}, // - + - + 5
{{0x2600,0xef},{0x2700,0xef}}, // - + + - 6
{{0x2600,0xcf},{0x2700,0xef}}, // - + + + 7
{{0x2600,0xff},{0x2700,0xdf}}, // + - - - 8
{{0x2600,0xdf},{0x2700,0xdf}}, // + - - + 9
{{0x2600,0xff},{0x2700,0xcf}}, // + - + - 10
{{0x2600,0xdf},{0x2700,0xcf}}, // + - + + 11
{{0x2600,0xef},{0x2700,0xdf}}, // + + - - 12
{{0x2600,0xcf},{0x2700,0xdf}}, // + + - + 13
{{0x2600,0xef},{0x2700,0xcf}}, // + + + - 14
{{0x2600,0xcf},{0x2700,0xcf}} // + + + + 15
};
public LaserPointersHardware(LaserPointer laserPointer){
this.laserPointer=laserPointer;
}
public int getNumberOfLasers(){
int numPointers=0;
for (numPointers=0; (1<<numPointers)<this.registerData.length;numPointers++);
if (this.debugLevel>3) System.out.println("getNumberOfLasers() first -> "+numPointers);
if (this.laserPointer==null) return numPointers;
if (numPointers>this.laserPointer.getNumberOfPointers()) numPointers=this.laserPointer.getNumberOfPointers();
if (this.debugLevel>3) System.out.println("getNumberOfLasers() second -> "+numPointers);
return numPointers;
}
//lasersSequence
public int [] getSequence(){
int [] sequence = new int [this.lasersSequence.length()+1];
sequence[0]=0;
for (int i=0;i<this.lasersSequence.length();i++){
sequence[i+1]=Integer.parseInt(this.lasersSequence.substring(i, i+1),16);
}
return sequence;
}
/**
*
* @param numLaser number of laser (0..1)
* @return // array, starting with lasers-off image, showing if this laser was on on the corresponding image
*/
public boolean [] laserWasOn(int numLaser){
int [] sequence=getSequence();
boolean [] wasOn=new boolean [sequence.length];
for (int i=0;i<sequence.length;i++) wasOn[i]= ((sequence[i]>>numLaser) & 1)!=0;
return wasOn;
}
//getNumberOfLasers()
public boolean [][] laserWasOn(){
boolean [][] wasOn=new boolean [getNumberOfLasers()][];
for (int i=0;i<wasOn.length;i++) wasOn[i]= laserWasOn(i);
return wasOn;
}
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"lasersIP",this.lasersIP+"");
properties.setProperty(prefix+"lasersSequence",this.lasersSequence+"");
properties.setProperty(prefix+"registerData.length",this.registerData.length+"");
for (int i=0;i<registerData.length;i++) {
properties.setProperty(prefix+"registerData_"+i+".length",this.registerData[i].length+"");
for (int j=0;j<registerData[i].length;j++) {
properties.setProperty(prefix+"registerData_"+i+"_"+j+".address","0x"+Integer.toHexString(this.registerData[i][j][0]));
properties.setProperty(prefix+"registerData_"+i+"_"+j+".data", "0x"+Integer.toHexString(this.registerData[i][j][1]));
}
}
}
//Integer.decode(string)
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"lasersIP")!=null)
this.lasersIP=properties.getProperty(prefix+"lasersIP");
if (properties.getProperty(prefix+"lasersSequence")!=null)
this.lasersSequence=properties.getProperty(prefix+"lasersSequence");
if (properties.getProperty(prefix+"registerData.length")!=null) {
this.registerData=new int [Integer.parseInt(properties.getProperty(prefix+"registerData.length"))][][];
for (int i=0;i<registerData.length;i++) {
this.registerData[i]=new int [Integer.parseInt(properties.getProperty(prefix+"registerData_"+i+".length"))][2];
if (properties.getProperty(prefix+"registerData_"+i+".length")!=null) {
this.registerData[i]=new int [Integer.parseInt(properties.getProperty(prefix+"registerData_"+i+".length"))][2];
for (int j=0;j<registerData[i].length;j++) {
// or make it throw exceptions if some data is missing?
if (properties.getProperty(prefix+"registerData_"+i+"_"+j+".address")!=null)
this.registerData[i][j][0]=Integer.decode(properties.getProperty(prefix+"registerData_"+i+"_"+j+".address"));
if (properties.getProperty(prefix+"registerData_"+i+"_"+j+".data")!=null)
this.registerData[i][j][1]=Integer.decode(properties.getProperty(prefix+"registerData_"+i+"_"+j+".data"));
}
}
}
}
}
/**
*
* @param title - Dialog title
* @param askRegenerate (will not change number of laser pointers and registers to change if false)
* @return true - OK, false - canceled
*/
public boolean showDialog(String title, boolean askRegenerate) {
GenericDialog gd = new GenericDialog(title);
gd.addStringField("IP address of the laser pointers",this.lasersIP,15);
gd.addStringField("Combinations of laser to try (excluding 0)",this.lasersSequence,15); // "3c5a96"
int numPointers;
int numRegisters=this.registerData[0].length;
for (numPointers=0; (1<<numPointers)<this.registerData.length;numPointers++);
for (int i=0;i<this.registerData.length;i++) {
String onOff="";
for (int j=0; j<numPointers;j++) onOff+=(((i>>j) & 1) ==1)?" * ":" - ";
gd.addMessage(i+" Lasers:"+onOff);
for (int j=0;j<this.registerData[i].length;j++) {
gd.addStringField(j+": register address= 0x",Integer.toHexString(this.registerData[i][j][0]),4);
gd.addStringField(j+": register data= 0x",Integer.toHexString(this.registerData[i][j][1]),2);
}
}
if (askRegenerate) {
gd.addNumericField("Number of pointers (need to press REGENERATE button to change)", numPointers, 0);
gd.addNumericField("Number of registers (need to press REGENERATE button to change)", numRegisters, 0);
gd.enableYesNoCancel("OK", "REGENERATE");
}
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
this.lasersIP=gd.getNextString();
this.lasersSequence=gd.getNextString();
for (int i=0;i<this.registerData.length;i++) {
for (int j=0;j<this.registerData[i].length;j++) {
this.registerData[i][j][0]=Integer.parseInt(gd.getNextString(),16);
this.registerData[i][j][1]=Integer.parseInt(gd.getNextString(),16);
}
}
if (askRegenerate) {
int newNumPointers = (int) gd.getNextNumber();
int newNumRegisters = (int) gd.getNextNumber();
if (!gd.wasOKed() && ((newNumPointers!=numPointers) || (newNumRegisters!=numRegisters))) {
//modify
int [][][] oldRegisterData=this.registerData;
int numLines=oldRegisterData.length;
int newNumLines= 1 << newNumPointers;
this.registerData = new int [newNumLines][newNumRegisters][2];
for (int i=0;i<newNumLines;i++) {
int i0=(i<numLines)?i:(numLines-1);
for (int j=0;j<newNumRegisters;j++) {
int j0=(j<oldRegisterData[i0].length)?j:(oldRegisterData[i0].length-1);
this.registerData[i][j][0]=oldRegisterData[i0][j0][0];
this.registerData[i][j][1]=oldRegisterData[i0][j0][1];
}
}
return showDialog(title, false);
}
}
return true;
}
public boolean setLasers (boolean [] lasers){
int intLasers=0;
for (int i=0;(i<lasers.length) && ((1<<i)<this.registerData.length);i++) intLasers |= lasers[i]?(1<<i):0;
return setLasers (intLasers);
}
public boolean setLasers (int intLasers){
if ((intLasers<0) || (intLasers>=this.registerData.length)) return false;
for (int i=0;i<this.registerData[intLasers].length; i++) {
String url="http://"+this.lasersIP+"/i2c.php?bus=1&raw=0x"+
Integer.toHexString(this.registerData[intLasers][i][0])+
"&data=0x"+Integer.toHexString(this.registerData[intLasers][i][1]);
if (this.debugLevel>2) System.out.println("setLasers: "+url);
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals("i2c")) {
System.out.println("Root element: expected 'i2c', got'" + dom.getDocumentElement().getNodeName()+"'");
IJ.showMessage("Error","Root element: expected 'i2c', got'" + dom.getDocumentElement().getNodeName()+"'");
return false;
}
//Integer.parseInt(((Node) (((Node) dom.getDocumentElement().getElementsByTagName("motor1").item(0)).getChildNodes().item(0))).getNodeValue());
boolean responceError= (dom.getDocumentElement().getElementsByTagName("error").getLength()!=0);
if (responceError) {
System.out.println("ERROR: register write ("+url+") FAILED" );
IJ.showMessage("Error","register write ("+url+") FAILED");
return false;
}
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
return false;
} catch(IOException e1){
IJ.showStatus("");
String error = e1.getMessage();
if (error==null || error.equals("")) error = ""+e1;
IJ.showMessage("setLasers ERROR", ""+error);
return false;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
return false;
}catch(SAXException se) {
se.printStackTrace();
return false;
}
}
//http://192.168.0.13/i2c.php?bus=1&raw=0x2700&data=0xdf
this.state=intLasers;
return true;
}
public boolean manualSetLasers(){
int numPointers;
for (numPointers=0; (1<<numPointers)<this.registerData.length;numPointers++);
int oldState=(this.state>=0)?this.state:0; // now showing -1 (undefined) as 0 - off
boolean [] lasers = new boolean[numPointers];
for (int i=0;i<lasers.length;i++) lasers[i]= ((oldState>>i) & 1)!=0;
GenericDialog gd = new GenericDialog("Turn laser pointers on/off");
for (int i=0; i<lasers.length;i++) {
gd.addCheckbox("Laser pointer "+(i+1),lasers[i]);
}
gd.showDialog();
if (gd.wasCanceled()) return false;
for (int i=0; i<lasers.length;i++) lasers[i]=gd.getNextBoolean();
return setLasers (lasers);
}
}
\ No newline at end of file
package com.elphel.imagej.calibration.hardware;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.elphel.imagej.common.WindowTools;
import ij.IJ;
import ij.gui.GenericDialog;
public class PowerControl{
public boolean [] states={false,false,false,false,false};
public boolean [] useControl={true,true,false,true,true};
// public int [] lightsChannels={2,3,4}; // which lights to control on on/off
public int [] lightsChannels={3,4}; // which lights to control on on/off
public String [] groups={"heater","fan","light","light1","light2"};
public int debugLevel=1;
private String powerIP="192.168.0.80";
private double lightsDelay=1.0;
private final String urlFormat="http://%s/insteon/index.php?cmd=%s&group=%s&timestamp=%d";
private final String rootElement="Document";
public boolean powerConrtolEnabled=false;
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"powerIP",this.powerIP+"");
properties.setProperty(prefix+"powerConrtolEnabled",this.powerConrtolEnabled+"");
properties.setProperty(prefix+"lightsDelay",this.lightsDelay+"");
}
//Integer.decode(string)
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"powerIP")!=null)
this.powerIP=properties.getProperty(prefix+"powerIP");
if (properties.getProperty(prefix+"powerConrtolEnabled")!=null)
this.powerConrtolEnabled=Boolean.parseBoolean(properties.getProperty(prefix+"powerConrtolEnabled"));
if (properties.getProperty(prefix+"lightsDelay")!=null)
this.lightsDelay=Double.parseDouble(properties.getProperty(prefix+"lightsDelay"));
}
public boolean setPower (String group, String state){
if (!powerConrtolEnabled) {
System.out.println("=== Power control is disabled ===");
return false;
}
long thisTime=System.nanoTime();
if (debugLevel>0) System.out.println("=== Power control: "+group+":"+state+" ===");
String url=String.format(urlFormat,this.powerIP,state,group,thisTime);
if (this.debugLevel>1) System.out.println("setPower: "+url);
Document dom=null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
dom = db.parse(url);
if (!dom.getDocumentElement().getNodeName().equals(rootElement)) {
System.out.println("Root element: expected \""+rootElement+"\", got \"" + dom.getDocumentElement().getNodeName()+"\"");
IJ.showMessage("Error","Root element: expected \""+rootElement+"\", got \"" + dom.getDocumentElement().getNodeName()+"\"");
return false;
}
// boolean responceError= (dom.getDocumentElement().getElementsByTagName("error").getLength()!=0);
// if (responceError) {
// System.out.println("ERROR: register write ("+url+") FAILED" );
// IJ.showMessage("Error","register write ("+url+") FAILED");
// return false;
// }
// System.out.println(dom);
// System.out.println(dom.getDocumentElement().toString());
// System.out.println(dom.getDocumentElement().getNodeName());
// System.out.println(dom.getDocumentElement().getElementsByTagName("message"));
// System.out.println(dom.getDocumentElement().getElementsByTagName("state"));
if (dom.getDocumentElement().getElementsByTagName("state").getLength()>0){
if (debugLevel>0) System.out.println("state="+(dom.getDocumentElement().getElementsByTagName("state").item(0).getChildNodes().item(0)).getNodeValue());
} else {
System.out.println("*** Empty Document from Insteon");
return false;
}
} catch(MalformedURLException e){
System.out.println("Please check the URL:" + e.toString() );
return false;
} catch(IOException e1){
IJ.showStatus("");
String error = e1.getMessage();
if (error==null || error.equals("")) error = ""+e1;
IJ.showMessage("setPower ERROR", ""+error);
return false;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
return false;
}catch(SAXException se) {
se.printStackTrace();
return false;
}
if (debugLevel>1) {
// debugging
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer=null;
try {
transformer = tf.newTransformer();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
try {
transformer.transform(new DOMSource(dom), new StreamResult(writer));
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String output = writer.getBuffer().toString().replaceAll("\n|\r", "");
System.out.println(output);
}
if (this.debugLevel>1) System.out.println("=== Power control: OK ===");
for (int i=0;i<this.groups.length;i++) if (this.groups[i].equals(group)){
this.states[i]=state.equals("on");
}
return true;
}
public boolean showDialog(String title, boolean control) {
GenericDialog gd = new GenericDialog(title);
boolean heaterOn=false, fanOn=false, lightOn=false, light1On=false, light2On=false;
gd.addCheckbox("Enable power control (heater, fan, lights) ", this.powerConrtolEnabled);
gd.addStringField("IP address of the power control",this.powerIP,15);
gd.addNumericField("Delay after lights on", this.lightsDelay, 1,4,"sec");
if (control){
if(useControl[0]) gd.addCheckbox("Heater On", heaterOn);
if(useControl[1]) gd.addCheckbox("Fan On", fanOn);
if(useControl[2]) gd.addCheckbox("Lights On", lightOn);
if(useControl[3]) gd.addCheckbox("Lights Top On", light1On);
if(useControl[4]) gd.addCheckbox("Lights Bottom On", light2On);
}
WindowTools.addScrollBars(gd);
if (control) gd.enableYesNoCancel("OK", "Control Power");
gd.showDialog();
if (gd.wasCanceled()) return false;
this.powerConrtolEnabled=gd.getNextBoolean();
this.powerIP=gd.getNextString();
this.lightsDelay=gd.getNextNumber();
if (control){
if(useControl[0]) heaterOn=gd.getNextBoolean();
if(useControl[1]) fanOn=gd.getNextBoolean();
if(useControl[2]) lightOn=gd.getNextBoolean();
if(useControl[3]) light1On=gd.getNextBoolean();
if(useControl[4]) light2On=gd.getNextBoolean();
if (!gd.wasOKed()) {
if(useControl[0])setPower("heater",heaterOn?"on":"off"); // setPower("heater","state");
if(useControl[1])setPower("fan",fanOn?"on":"off"); // setPower("fan","state");
if(useControl[2])setPower("light",lightOn?"on":"off"); // setPower("light","state");
if(useControl[3])setPower("light1",light1On?"on":"off"); // setPower("light1","state");
if(useControl[4])setPower("light2",light2On?"on":"off"); // setPower("light2","state");
}
}
return true;
}
public void lightsOnWithDelay(){
// turn on only new
boolean allOn=true;
for (int chn:this.lightsChannels) allOn&=this.states[chn];
if (allOn || !this.powerConrtolEnabled) return; // already on
for (int chn:this.lightsChannels) if (!this.states[chn]) setPower(this.groups[chn],"on");
System.out.print("Sleeping "+this.lightsDelay+" seconds to let lights stabilize on...");
try {
TimeUnit.MILLISECONDS.sleep((long) (1000*this.lightsDelay));
} catch (InterruptedException e) {
System.out.println("Sleep was interrupted");
// TODO Auto-generated catch block
}
System.out.println(" Done");
}
public void lightsOff(){
if (!this.powerConrtolEnabled) return; // already on
for (int chn:this.lightsChannels) if (this.states[chn]) setPower(this.groups[chn],"off");
}
public boolean isPowerControlEnabled(){
return this.powerConrtolEnabled;
}
public void setDebugLevel(int debugLevel){
this.debugLevel=debugLevel;
}
}
\ No newline at end of file
/**
*
*/
/**
* @author eyesis
*
*/
package com.elphel.imagej.calibration.hardware;
\ No newline at end of file
......@@ -3,8 +3,16 @@ import java.util.Properties;
import org.apache.commons.configuration.XMLConfiguration;
import com.elphel.imagej.calibration.CalibrationFileManagement;
import com.elphel.imagej.calibration.DistortionCalibrationData;
import com.elphel.imagej.calibration.Distortions;
import com.elphel.imagej.calibration.EyesisAberrations;
import com.elphel.imagej.calibration.LensDistortionParameters;
import com.elphel.imagej.common.GenericJTabbedDialog;
import com.elphel.imagej.common.WindowTools;
import Jama.Matrix;
import ij.Prefs;
/*
**
** EyesisCameraParameters.java
......@@ -566,7 +574,8 @@ import ij.gui.GenericDialog;
else destination.eyesisSubCameras=null;
destination.stationWeight=new double[destination.numStations];
for (int numStation=0;numStation<destination.numStations;numStation++) {
int srcNumStation=(numStation<source.numStations)?numStation:(source.numStations-1);
int srcNumStation=(numStation<source.numStations)?numStation:(source.numStations-1); // 0-1 !
if (srcNumStation < 0) break; // source does not have any stations?
destination.stationWeight[numStation]=source.stationWeight[srcNumStation];
destination.goniometerHorizontal[numStation]=source.goniometerHorizontal[srcNumStation];
destination.goniometerAxial[numStation]=source.goniometerAxial[srcNumStation];
......@@ -707,6 +716,9 @@ import ij.gui.GenericDialog;
this.entrancePupilForward[numStation]=Double.parseDouble(properties.getProperty(prefix+"entrancePupilForward_"+numStation));
if (properties.getProperty(prefix+"centerAboveHorizontal_"+numStation)!=null)
this.centerAboveHorizontal[numStation]=Double.parseDouble(properties.getProperty(prefix+"centerAboveHorizontal_"+numStation));
if (this.GXYZ[numStation] == null) {
this.GXYZ[numStation] = new double[3];
}
if (properties.getProperty(prefix+"GXYZ_0_"+numStation)!=null)
this.GXYZ[numStation][0]=Double.parseDouble(properties.getProperty(prefix+"GXYZ_0_"+numStation));
if (properties.getProperty(prefix+"GXYZ_1_"+numStation)!=null)
......@@ -1371,6 +1383,9 @@ import ij.gui.GenericDialog;
int numStation,
int numSubCameras){
System.out.println("initSubCameras("+numStation+","+numSubCameras+")");
if ((this.eyesisSubCameras == null) || (this.eyesisSubCameras.length != this.numStations)) {
this.eyesisSubCameras = new EyesisSubCameraParameters[this.numStations][];
}
this.eyesisSubCameras[numStation]=new EyesisSubCameraParameters[numSubCameras];
for (int i=0;i<numSubCameras;i++) this.eyesisSubCameras[numStation][i]=null;
if (numSubCameras==3) {
......@@ -1400,7 +1415,12 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][1]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
cartesian,
defaultLensDistortionModel,
......@@ -1426,7 +1446,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][2]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
cartesian,
defaultLensDistortionModel,
......@@ -1452,7 +1476,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
} else if (numSubCameras==1) {
this.cartesian = false;
this.eyesisSubCameras[numStation][0]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
......@@ -1480,7 +1508,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
} else if (numSubCameras == 21) {
// ================
// PHG21 parameters
......@@ -1511,7 +1543,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][1]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1537,7 +1573,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][2]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1563,7 +1603,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][3]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1589,7 +1633,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][4]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1615,7 +1663,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][5]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1641,7 +1693,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][6]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1667,7 +1723,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][7]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1693,7 +1753,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][8]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1719,7 +1783,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][9]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1745,7 +1813,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][10]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1771,7 +1843,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][11]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1797,7 +1873,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][12]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1823,7 +1903,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][13]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1849,7 +1933,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][14]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1875,7 +1963,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][15]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1901,7 +1993,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][16]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1927,7 +2023,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][17]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1953,7 +2053,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][18]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -1979,7 +2083,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][19]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -2005,7 +2113,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
this.eyesisSubCameras[numStation][20]=new EyesisSubCameraParameters( //TODO: modify for lens adjustment defaults?
this.cartesian,
defaultLensDistortionModel,
......@@ -2031,7 +2143,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
//
// end of PHG21 parameters
// =======================
......@@ -2062,7 +2178,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
for (int i=8;i<16;i++) if (i<numSubCameras) this.eyesisSubCameras[numStation][i]=new EyesisSubCameraParameters( // middle 8 cameras
this.cartesian,
defaultLensDistortionModel,
......@@ -2088,7 +2208,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
for (int i=16;i<24;i++) if (i<numSubCameras) this.eyesisSubCameras[numStation][i]=new EyesisSubCameraParameters( // bottom eight cameras
this.cartesian,
defaultLensDistortionModel,
......@@ -2114,7 +2238,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
1.0); //channelWeightDefault
1.0, //channelWeightDefault
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
if (24<numSubCameras) this.eyesisSubCameras[numStation][24]=new EyesisSubCameraParameters(
this.cartesian,
defaultLensDistortionModel,
......@@ -2140,7 +2268,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
8.0); //channelWeightDefault (was 4)
8.0, //channelWeightDefault (was 4)
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
if (25<numSubCameras) this.eyesisSubCameras[numStation][25]=new EyesisSubCameraParameters(
this.cartesian,
defaultLensDistortionModel,
......@@ -2166,7 +2298,11 @@ import ij.gui.GenericDialog;
968.0, // double py0=968.0; // center of the lens on the sensor, pixels
null, // eccentricity for b,a,a5,a6,a7,a8
null, // elongation for c,b,a,a5,a6,a7,a8
8.0); //channelWeightDefault (was 4)
8.0, //channelWeightDefault (was 4)
0, // public int subcamera
0, // public int sensor_port
0); // public int subchannel
}
}
public void recenterVertically(boolean [] subcams, boolean [] stations){
......@@ -2232,5 +2368,335 @@ import ij.gui.GenericDialog;
}
}
public class SubsystemOffsets {
public boolean use_first_station = true; // import data from first station, duplicate to all
public int offset_channel = 4; // 0;
public int new_subcam = 1; // new subcamera number
public double offset_height = 50.8;
public double offset_right = -35.0; //vnir -35., lwir +35.0
public double offset_forward = 15.0; //vnir +??, lwir -??
public double offset_heading = 0.0;
public double offset_elevation = 0.0;
public double offset_roll = 0.0;
public boolean update_sensor_files = true; // Update an re-write sensor files
public void dialogQuestions(GenericJTabbedDialog gd) {
gd.addCheckbox ("Use first station", this.use_first_station, "Import data for the first station only, clone for all current ones");
gd.addNumericField("Channel offset", this.offset_channel, 0,3,"","Add this to the sensor number after impofrt");
gd.addNumericField("New subcamera", this.new_subcam, 0,3,"","New subcamera number ater import");
gd.addNumericField("Offset height", this.offset_height, 3,6,"mm", "Place imported sub camera above composite camera center");
gd.addNumericField("Offset right", this.offset_right, 3,6,"mm", "Visible range camera exposure time (all channels)");
gd.addNumericField("Offset forward", this.offset_forward, 3,6,"mm", "Visible range camera exposure time (all channels)");
gd.addNumericField("Offset heading", this.offset_heading, 3,6,"°", "Visible range camera exposure time (all channels)");
gd.addNumericField("Offset elevation", this.offset_elevation, 3,6,"°", "Visible range camera exposure time (all channels)");
gd.addNumericField("Offset roll", this.offset_roll, 3,6,"°", "Visible range camera exposure time (all channels)");
gd.addCheckbox ("Transform sensor files", this.update_sensor_files, "Import sesnor files (ifavailable), re-write them for new extrinsics/channels");
}
public void dialogAnswers(GenericJTabbedDialog gd) {
this.use_first_station = gd.getNextBoolean();
this.offset_channel = (int) gd.getNextNumber();
this.new_subcam = (int) gd.getNextNumber();
this.offset_height = gd.getNextNumber();
this.offset_right = gd.getNextNumber();
this.offset_forward = gd.getNextNumber();
this.offset_heading = gd.getNextNumber();
this.offset_elevation = gd.getNextNumber();
this.offset_roll = gd.getNextNumber();
this.update_sensor_files = gd.getNextBoolean();
}
public boolean dialogOffests() {
GenericJTabbedDialog gd = new GenericJTabbedDialog("Set camera subsystem offsets",250,500);
dialogQuestions(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
dialogAnswers(gd);
return true;
}
}
public EyesisSubCameraParameters offsetSubCamera(SubsystemOffsets offsets, EyesisSubCameraParameters sub_camera) {
sub_camera.updateCartesian();
EyesisSubCameraParameters new_sub = sub_camera.clone();
double psi= Math.PI/180*offsets.offset_roll; // radians
double theta=Math.PI/180*offsets.offset_elevation; // radians
double phi= Math.PI/180*offsets.offset_heading; // radians
double psi_s= Math.PI/180*sub_camera.heading; // radians
double theta_s=Math.PI/180*sub_camera.theta; // radians
double phi_s= Math.PI/180*sub_camera.psi; // radians
double [][] asub_c = {{sub_camera.right},{sub_camera.height},{sub_camera.forward}}; // subcamera center
// rotate by -psi around Z
double [][] aRz={
{ Math.cos(psi),Math.sin(psi), 0.0},
{-Math.sin(psi),Math.cos(psi), 0.0},
{ 0.0, 0.0, 1.0}};
// rotate by -psi around x
double [][] aRx={
{1.0, 0.0, 0.0},
{0.0, Math.cos(theta),Math.sin(theta)},
{0.0,-Math.sin(theta),Math.cos(theta)}};
// rotate by -phi around y
double [][] aRy={
{Math.cos(phi), 0.0, Math.sin(phi)},
{0.0,1.0,0.0},
{-Math.sin(phi), 0.0, Math.cos(phi)}};
double [][] aoffs = {{offsets.offset_right},{offsets.offset_height},{offsets.offset_forward}};
// rotate by -psi around Z
double [][] aRz_s={
{ Math.cos(psi_s),Math.sin(psi_s), 0.0},
{-Math.sin(psi_s),Math.cos(psi_s), 0.0},
{ 0.0, 0.0, 1.0}};
// rotate by -psi around x
double [][] aRx_s={
{1.0, 0.0, 0.0},
{0.0, Math.cos(theta_s),Math.sin(theta_s)},
{0.0,-Math.sin(theta_s),Math.cos(theta_s)}};
// rotate by -phi around y
double [][] aRy_s={
{Math.cos(phi_s), 0.0, Math.sin(phi_s)},
{0.0,1.0,0.0},
{-Math.sin(phi_s), 0.0, Math.cos(phi_s)}};
Matrix sub_c=new Matrix(asub_c);
Matrix Rz= new Matrix(aRz);
Matrix Rx= new Matrix(aRx);
Matrix Ry= new Matrix(aRy);
Matrix offs= new Matrix(aoffs);
Matrix R = Ry.times(Rx.times(Rz));
Matrix Rz_s= new Matrix(aRz_s);
Matrix Rx_s= new Matrix(aRx_s);
Matrix Ry_s= new Matrix(aRy_s);
Matrix R_s = Ry_s.times(Rx_s.times(Rz_s));
double [] rhf = offs.plus(R.times(sub_c)).getRowPackedCopy();
/*
System.out.println("R=");
R.print(8, 3);
System.out.println("\nR_s=");
R_s.print(8, 3);
*/
Matrix R_t = R.times(R_s);
/*
System.out.println("\nR_t=");
R_t.print(8, 3);
*/
new_sub.cartesian = true;
new_sub.right = rhf[0];
new_sub.height = rhf[1];
new_sub.forward = rhf[2];
// projection of camera axis (z) on XZ plane
double min_cos = 0.001;
double zXZ = Math.sqrt(R_t.get(0, 2)*R_t.get(0, 2) + R_t.get(2, 2)*R_t.get(2, 2));
if (zXZ < min_cos) {
System.out.append("zXZ = "+zXZ);
}
double new_phi = Math.atan2(R_t.get(0, 2), R_t.get(2, 2));
double new_theta = Math.atan2(R_t.get(1, 2), zXZ);
double new_psi = Math.atan2(R_t.get(0, 1), R_t.get(1, 1));
new_sub.heading = 180.0/Math.PI*new_phi;
new_sub.theta = 180.0/Math.PI*new_theta;
new_sub.psi = 180.0/Math.PI*new_psi;
new_sub.updateCartesian();
return new_sub;
}
public boolean importSystem(
Properties properties,
String prefix,
SubsystemOffsets subsystemOffsets,
Distortions systemDistortions,
DistortionCalibrationData system_distortionCalibrationData,
String calibration_directory) {
EyesisCameraParameters sub_system = new EyesisCameraParameters();
sub_system.getProperties(prefix, properties);
if (subsystemOffsets == null) {
subsystemOffsets = new SubsystemOffsets();
}
if (!subsystemOffsets.dialogOffests()) {
return false;
}
System.out.println(
"use_first_stationl=" + subsystemOffsets.use_first_station +
"offset_channel=" + subsystemOffsets.offset_channel +
"\noffset_height=" + subsystemOffsets.offset_height +
"\noffset_right=" + subsystemOffsets.offset_right +
"\noffset_forward=" + subsystemOffsets.offset_forward +
"\noffset_heading=" + subsystemOffsets.offset_heading +
"\noffset_elevation=" + subsystemOffsets.offset_elevation +
"\noffset_roll=" + subsystemOffsets.offset_roll);
// remove all but first imported station if instructed so
if (subsystemOffsets.use_first_station) {
sub_system.updateNumstations (1);
}
// Import sensor files
String sensors_path = null;
Distortions sub_distortions = null;
DistortionCalibrationData sub_distortionCalibrationData = null;
EyesisAberrations.AberrationParameters sub_aberrationParameters = null;
LensDistortionParameters sub_lensDistortionParameters = null;
// boolean update_sensor_files = subsystemOffsets.update_sensor_files;
// TODO: check sub_distortions != null
if (subsystemOffsets.update_sensor_files) {
sub_aberrationParameters=new EyesisAberrations.AberrationParameters();
sub_aberrationParameters.getProperties("ABERRATIONS_PARAMETERS.", properties);
sub_lensDistortionParameters = new LensDistortionParameters();
sub_lensDistortionParameters.getProperties("LENS_DISTORTION_PARAMETERS.", properties);
sensors_path = sub_aberrationParameters.sensorsPath;
System.out.println("sensors_path = "+sensors_path);
String [][] stationFilenames = new String[sub_system.numStations][0];
sub_distortionCalibrationData = new DistortionCalibrationData(
// stationFilenames, // String [][] stationFilenames,
// null, // PatternParameters patternParameters,
sub_system // EyesisCameraParameters eyesisCameraParameters
// ,0 // debugLevel
);
// now read all sensor files
if ((sensors_path !=null) && (sensors_path != "")){ // load sensor
// if (sub_distortions.fittingStrategy==null) return false; // Why?
// if (DEBUG_LEVEL>0) System.out.println("Autoloading sensor calibration files "+configPaths[3]);
sub_distortions = new Distortions(
sub_lensDistortionParameters, // LensDistortionParameters lensDistortionParameters,
null, // PatternParameters patternParameters,
null, // RefineParameters refineParameters,
null //AtomicInteger stopRequested
);
// sub_distortions.lensDistortionParameters is null!
sub_distortions.setDistortionFromImageStack(
sub_distortionCalibrationData,
sub_system, // EYESIS_CAMERA_PARAMETERS, // use null for old version - in fitting strategy instance
sensors_path,
sub_aberrationParameters.autoRestoreSensorOverwriteOrientation,
sub_aberrationParameters.autoRestoreSensorOverwriteDistortion
);
} else {
System.out.println("Sensor files are not specified");
// update_sensor_files = false;
}
}
// TODO:recalculate extrinsics before import
for (int ns = 0; ns < sub_system.eyesisSubCameras.length; ns++) {
for (int nc = 0; nc < sub_system.eyesisSubCameras[ns].length; nc++) {
sub_system.eyesisSubCameras[ns][nc] = offsetSubCamera(subsystemOffsets,sub_system.eyesisSubCameras[ns][nc]);
sub_system.eyesisSubCameras[ns][nc].subcamera = subsystemOffsets.new_subcam;
}
}
// increase number of stations if needed to match existing
if (this.getNumStations() > sub_system.getNumStations()){
sub_system.updateNumstations (this.getNumStations());
}
// increase number of this stations if needed
if (!subsystemOffsets.use_first_station && (this.getNumStations() < sub_system.getNumStations())){
updateNumstations (sub_system.getNumStations());
}
for (int numStation = 0; numStation < this.getNumStations(); numStation++) {
// increase number of cameras if needed to accommodate import
if (this.getNumChannels(numStation) < (sub_system.getNumChannels(numStation) + subsystemOffsets.offset_channel)) {
EyesisSubCameraParameters [] stationCameras = eyesisSubCameras[numStation];
int new_channels = sub_system.getNumChannels(numStation) + subsystemOffsets.offset_channel;
eyesisSubCameras[numStation] = new EyesisSubCameraParameters[new_channels];
for (int nc = 0; nc <stationCameras.length; nc++) {
eyesisSubCameras[numStation][nc] = stationCameras[nc];
}
}
for (int nc = 0; nc < sub_system.getNumChannels(); nc++) {
eyesisSubCameras[numStation][nc+subsystemOffsets.offset_channel] = sub_system.eyesisSubCameras[numStation][nc];
}
}
if (sub_distortions !=null) {
boolean saveNonCalibrated= true;
int new_channels = sub_system.getNumChannels() + subsystemOffsets.offset_channel;
// expand arrays if needed
if (systemDistortions.pathNames == null) {
systemDistortions.pathNames = new String[new_channels];
} else if (systemDistortions.pathNames.length < new_channels) {
String [] tmpNames = systemDistortions.pathNames;
systemDistortions.pathNames = new String[new_channels];
for (int i = 0; i < tmpNames.length; i++ ) systemDistortions.pathNames[i] = tmpNames[i];
}
if (systemDistortions.pixelCorrection == null) {
systemDistortions.pixelCorrection = new double[new_channels][][];
} else if (systemDistortions.pixelCorrection.length < new_channels) {
double [][][] tmpPixelCorrection = systemDistortions.pixelCorrection;
systemDistortions.pixelCorrection = new double[new_channels][][];
for (int i = 0; i < tmpPixelCorrection.length; i++ ) systemDistortions.pixelCorrection[i] = tmpPixelCorrection[i];
}
if (system_distortionCalibrationData == null) {
system_distortionCalibrationData = new DistortionCalibrationData (this);
}
if (system_distortionCalibrationData.sensorMasks == null) {
system_distortionCalibrationData.sensorMasks = new double [new_channels][];
} else if (system_distortionCalibrationData.sensorMasks.length < new_channels) {
double [][] tmp_masks = system_distortionCalibrationData.sensorMasks;
system_distortionCalibrationData.sensorMasks = new double [new_channels][];
for (int i = 0; i < tmp_masks.length; i++ ) system_distortionCalibrationData.sensorMasks[i] = tmp_masks[i];
}
// now copy data over, update the path names?
String imported_name=sub_distortions.pathNames[0];
int last_sep = imported_name.lastIndexOf(Prefs.getFileSeparator());
if (last_sep>=0) imported_name = imported_name.substring(last_sep + 1);
int indexPeriod=imported_name.lastIndexOf('.');
int indexSuffix=indexPeriod;
String digits="0123456789";
for (int i=1;i<=2;i++) if (digits.indexOf(imported_name.charAt(indexSuffix-1))>=0) indexSuffix--; // remove 1 or 2 digits before period
boolean hadSuffix= (imported_name.charAt(indexSuffix-1)=='-');
for (int nc = 0; nc < sub_system.getNumChannels(); nc++) {
int chn = nc+subsystemOffsets.offset_channel;
systemDistortions.pathNames[chn]=calibration_directory+Prefs.getFileSeparator()+((hadSuffix?imported_name.substring(0,indexSuffix):(imported_name.substring(0,indexPeriod)+"-"))+
String.format("%02d",chn)+imported_name.substring(indexPeriod));
systemDistortions.pixelCorrection[chn] = sub_distortions.pixelCorrection[nc];
system_distortionCalibrationData.sensorMasks[chn] = sub_distortionCalibrationData.sensorMasks[nc];
}
// systemDistortions.pathnames
// systemDistortions.pixelCorrection
// sub_distortionCalibrationData.sensorMasks
String [] extensions={".calib-tiff"};
CalibrationFileManagement.MultipleExtensionsFileFilter parFilter = new CalibrationFileManagement.MultipleExtensionsFileFilter("",extensions,"distortion calibration .calib-tiff files");
String pathname=CalibrationFileManagement.selectFile(true,
"Save distortion calibration for sensor (will add channel number when saving all)",
"Save",
parFilter,
systemDistortions.getSensorPath(-1)); //String defaultPath
if ((pathname==null) || (pathname=="")) return true;
for (int nc = 0; nc < sub_system.getNumChannels(); nc++) {
int chn = nc+subsystemOffsets.offset_channel;
systemDistortions.saveDistortionAsImageStack(
system_distortionCalibrationData,
null, // camerasInterface, // to save channel map
"sensor_calibration", // title,
systemDistortions.pathNames[chn], // channelPath,
chn,
saveNonCalibrated);
}
}
return true;
}
}
......@@ -6,7 +6,7 @@ package com.elphel.imagej.cameras;
** Copyright (C) 2011-2014 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
**
** EyesisSubCameraParameters.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
......@@ -55,12 +55,18 @@ import java.util.Properties;
public double channelWeightCurrent=1.0;
public int [][] defectsXY=null; // pixel defects coordinates list (starting with worst)
public double [] defectsDiff=null; // pixel defects value (diff from average of neighbors), matching defectsXY
final private double [][] r_xy_dflt={{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0}}; // only 6, as for the first term delta x, delta y ==0
final private double [][] r_xy_dflt={{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0}}; // only 6, as for the first term delta x, delta y ==0
final private double [][] r_od_dflt= {{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0},{0.0,0.0}}; // ortho
public double [][] r_xy=null; // only 6, as for the first term delta x, delta y ==0
public double [][] r_xy=null; // only 6, as for the first term delta x, delta y ==0
public double [][] r_od=null; // ortho
// was not used before LWIR and import subsystem
public int subcamera = 0;
public int sensor_port = 0;
public int subchannel = 0;
/*
Modifying to accommodate for eccentricity of different terms (2 parameters per term) and elliptical shape (another 2 terms). When all are
zeroes, the old parameters are in effect:
......@@ -69,10 +75,10 @@ import java.util.Properties;
R[i] depends on px,py and r_xy[i][], r_o[i] (positive - "landscape", negative - "portrait"), r_d (positive - along y=x, negative - along y=-x)
R[i] = r0[i]*(1+ (r_od[i][0]*(y[i]**2-x[i]**2)+ 2*r_od[i][1]*x[i]*y[i])/r0[i]**2;
r0[i]=sqrt(x[i]**2+y[2]**2)
x[i]=pixel_x-px0-((i>0)?r_xy[i-1][0]:0)
x[i]=pixel_x-px0-((i>0)?r_xy[i-1][0]:0)
y[i]=pixel_y-py0-((i>0)?r_xy[i-1][1]:0)
*/
*/
public EyesisSubCameraParameters(
boolean cartesian,
int lensDistortionModel,
......@@ -89,10 +95,10 @@ import java.util.Properties;
double focalLength,
double pixelSize,//um
double distortionRadius, //mm - half width of the sensor
double distortionA8, // r^8
double distortionA7, // r^7
double distortionA6, // r^5
double distortionA5, // r^5
double distortionA8, // r^8
double distortionA7, // r^7
double distortionA6, // r^5
double distortionA5, // r^5
double distortionA, // r^4 (normalized to focal length or to sensor half width?)
double distortionB, // r^3
double distortionC, // r^2
......@@ -100,7 +106,10 @@ import java.util.Properties;
double py0, // center of the lens on the sensor, pixels
double [][] r_xy, // eccentricity for b,a,a5,a6,a7,a8
double [][] r_od, // elongation for c,b,a,a5,a6,a7,a8
double channelWeightDefault
double channelWeightDefault,
int subcamera,
int sensor_port,
int subchannel
){
this.cartesian = cartesian;
this.lensDistortionModel=lensDistortionModel;
......@@ -108,7 +117,7 @@ import java.util.Properties;
this.right = right;
this.forward = forward;
this.heading = heading;
this.azimuth=azimuth;
this.radius=radius;
this.height=height;
......@@ -137,11 +146,15 @@ import java.util.Properties;
this.channelWeightCurrent=this.channelWeightDefault;
this.defectsXY=null; // pixel defects coordinates list (starting with worst)
this.defectsDiff=null; // pixel defects value (diff from average of neighbors), matching defectsXY
this.subcamera = subcamera;
this.sensor_port = sensor_port;
this.subchannel = subchannel;
updateCartesian(); // set alternative
}
// defects are not cloned!
public EyesisSubCameraParameters clone() {
@Override
public EyesisSubCameraParameters clone() {
return new EyesisSubCameraParameters(
this.cartesian,
this.lensDistortionModel,
......@@ -169,7 +182,10 @@ import java.util.Properties;
this.py0,
this.r_xy,
this.r_od,
this.channelWeightDefault
this.channelWeightDefault,
this.subcamera,
this.sensor_port,
this.subchannel
);
}
public void setDefaultNonRadial(){
......@@ -180,39 +196,44 @@ import java.util.Properties;
}
// TODO: add/restore new properties
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"cartesian",this.cartesian+"");
properties.setProperty(prefix+"lensDistortionModel",this.lensDistortionModel+"");
properties.setProperty(prefix+"enableNoLaser",this.enableNoLaser+"");
properties.setProperty(prefix+"right",this.right+"");
properties.setProperty(prefix+"heading",this.heading+"");
properties.setProperty(prefix+"forward",this.forward+"");
properties.setProperty(prefix+"azimuth",this.azimuth+"");
properties.setProperty(prefix+"radius",this.radius+"");
properties.setProperty(prefix+"height",this.height+"");
properties.setProperty(prefix+"phi",this.phi+"");
properties.setProperty(prefix+"theta",this.theta+"");
properties.setProperty(prefix+"psi",this.psi+"");
properties.setProperty(prefix+"focalLength",this.focalLength+"");
properties.setProperty(prefix+"pixelSize",this.pixelSize+"");
properties.setProperty(prefix+"distortionRadius",this.distortionRadius+"");
properties.setProperty(prefix+"distortionA8",this.distortionA8+"");
properties.setProperty(prefix+"distortionA7",this.distortionA7+"");
properties.setProperty(prefix+"distortionA6",this.distortionA6+"");
properties.setProperty(prefix+"distortionA5",this.distortionA5+"");
properties.setProperty(prefix+"distortionA",this.distortionA+"");
properties.setProperty(prefix+"distortionB",this.distortionB+"");
properties.setProperty(prefix+"distortionC",this.distortionC+"");
properties.setProperty(prefix+"px0",this.px0+"");
properties.setProperty(prefix+"py0",this.py0+"");
properties.setProperty(prefix+"cartesian", this.cartesian+"");
properties.setProperty(prefix+"lensDistortionModel", this.lensDistortionModel+"");
properties.setProperty(prefix+"enableNoLaser", this.enableNoLaser+"");
properties.setProperty(prefix+"right", this.right+"");
properties.setProperty(prefix+"heading", this.heading+"");
properties.setProperty(prefix+"forward", this.forward+"");
properties.setProperty(prefix+"azimuth", this.azimuth+"");
properties.setProperty(prefix+"radius", this.radius+"");
properties.setProperty(prefix+"height", this.height+"");
properties.setProperty(prefix+"phi", this.phi+"");
properties.setProperty(prefix+"theta", this.theta+"");
properties.setProperty(prefix+"psi", this.psi+"");
properties.setProperty(prefix+"focalLength", this.focalLength+"");
properties.setProperty(prefix+"pixelSize", this.pixelSize+"");
properties.setProperty(prefix+"distortionRadius", this.distortionRadius+"");
properties.setProperty(prefix+"distortionA8", this.distortionA8+"");
properties.setProperty(prefix+"distortionA7", this.distortionA7+"");
properties.setProperty(prefix+"distortionA6", this.distortionA6+"");
properties.setProperty(prefix+"distortionA5", this.distortionA5+"");
properties.setProperty(prefix+"distortionA", this.distortionA+"");
properties.setProperty(prefix+"distortionB", this.distortionB+"");
properties.setProperty(prefix+"distortionC", this.distortionC+"");
properties.setProperty(prefix+"px0", this.px0+"");
properties.setProperty(prefix+"py0", this.py0+"");
for (int i=0;i<this.r_xy.length;i++){
properties.setProperty(prefix+"r_xy_"+i+"_x",this.r_xy[i][0]+"");
properties.setProperty(prefix+"r_xy_"+i+"_y",this.r_xy[i][1]+"");
properties.setProperty(prefix+"r_xy_"+i+"_x", this.r_xy[i][0]+"");
properties.setProperty(prefix+"r_xy_"+i+"_y", this.r_xy[i][1]+"");
}
for (int i=0;i<this.r_od.length;i++){
properties.setProperty(prefix+"r_od_"+i+"_o",this.r_od[i][0]+"");
properties.setProperty(prefix+"r_od_"+i+"_d",this.r_od[i][1]+"");
properties.setProperty(prefix+"r_od_"+i+"_o", this.r_od[i][0]+"");
properties.setProperty(prefix+"r_od_"+i+"_d", this.r_od[i][1]+"");
}
properties.setProperty(prefix+"channelWeightDefault",this.channelWeightDefault+"");
properties.setProperty(prefix+"subcamera", this.subcamera+"");
properties.setProperty(prefix+"sensor_port", this.sensor_port+"");
properties.setProperty(prefix+"subchannel", this.subchannel+"");
}
public void getProperties(String prefix,Properties properties){
getProperties(prefix,properties, -1);
......@@ -285,7 +306,13 @@ import java.util.Properties;
} else {
this.enableNoLaser=(channel<24);
}
if (properties.getProperty(prefix+"subcamera")!=null)
this.subcamera=Integer.parseInt(properties.getProperty(prefix+"subcamera"));
if (properties.getProperty(prefix+"sensor_port")!=null)
this.sensor_port=Integer.parseInt(properties.getProperty(prefix+"sensor_port"));
if (properties.getProperty(prefix+"subchannel")!=null)
this.subchannel=Integer.parseInt(properties.getProperty(prefix+"subchannel"));
}
public void setChannelWeightCurrent(
double weight){
......@@ -297,15 +324,15 @@ import java.util.Properties;
public double getChannelWeightDefault(){
return this.channelWeightDefault;
}
public void updateCartesian(){ // set alternative parameters
if (cartesian) {
this.azimuth = Math.atan2(this.right, this.forward)*180.0/Math.PI;
this.radius = Math.sqrt(this.forward*this.forward + this.right*this.right);
this.phi = this.heading - this.azimuth;
this.phi = this.heading - this.azimuth;
} else {
this.forward = this.radius * Math.cos(Math.PI*this.azimuth/180.0);
this.right = this.radius * Math.sin(Math.PI*this.azimuth/180.0);
this.forward = this.radius * Math.cos(Math.PI*this.azimuth/180.0);
this.right = this.radius * Math.sin(Math.PI*this.azimuth/180.0);
this.heading = this.phi + this.azimuth;
}
}
......
......@@ -56,7 +56,6 @@ public class LwirReaderParameters {
protected double vnir_gain_bg = 2.401; // 1.476;
protected boolean [] selected_channels = {true, true, true, true, true, true, true, true};
protected int max_lwir_width = 1024; //
/*
protected double [] vnir_exp_corr = {1.0, 1.0, 1.0, 1.0};
protected double [] vnir_gcorr_rbgb = {
......@@ -64,7 +63,6 @@ public class LwirReaderParameters {
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};
......@@ -80,7 +78,19 @@ public class LwirReaderParameters {
protected int debug_level = 0;//-3: OFF, -2:Fatal, -1:ERROR, 0:WARN, 1:INFO,2:DEBUG
protected boolean show_images = false;
protected int lwir_chn0 = 0; // not configurable
protected int vnir_chn0 = 4; // not configurable
// --- interface methods
public int getLwirChn0 () {
return lwir_chn0;
}
public int getVnirChn0 () {
return vnir_chn0;
}
public boolean is_LWIR(int width) {
return width <= max_lwir_width;
}
......
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