Commit 4ffb8a32 authored by Andrey Filippov's avatar Andrey Filippov

working on calculating grids for low frequency pattern

parent 78aea970
......@@ -1413,9 +1413,13 @@ Exception in thread "Thread-3564" java.lang.ArrayIndexOutOfBoundsException: 8970
NodeList allNodes=doc.getDocumentElement().getElementsByTagName("*");
for (int i=0;i<allNodes.getLength();i++) {
String name= allNodes.item(i).getNodeName();
String value=allNodes.item(i).getFirstChild().getNodeValue();
imp.setProperty(name, value);
String value="";
try {
value=allNodes.item(i).getFirstChild().getNodeValue();
} catch(Exception e) {
}
imp.setProperty(name, value);
}
return true;
......
......@@ -70,6 +70,7 @@ import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.jp4.JP46_Reader_camera;
import com.elphel.imagej.lwir.LwirReader;
import com.elphel.imagej.lwir.LwirReaderParameters;
import com.elphel.imagej.readers.EyesisTiff;
import Jama.Matrix; // Download here: http://math.nist.gov/javanumerics/jama/
import ij.IJ;
......@@ -222,10 +223,20 @@ public class Aberration_Calibration extends PlugInFrame implements ActionListene
0.4, // corrRingWidth - ring (around r=0.5 dist to opposite corr) width , center circle r=0.5*PATTERN_DETECT.corrRingWidth
5.0, // minCorrContrast - discrimination threshold between good and bad pattern correlation
0.0, // minGridPeriod
0.0, // maxGridPeriod
0.0, // maxGridPeriod
0.0, // minGridPeriodLwir
0.0, // maxGridPeriodLwir
0.0, // debugX+"");
0.0, // debugY+"");
-1.0 // this.debugRadius+"");
-1.0, // this.debugRadius+"");
false, // public boolean use_large_cells = false; // new method based on phase correlation should work with large cells,
// so only first negative correlation (1/2 period) fits in window
0.5, // public double phaseCoeff = 0.5; // "phasiness" of correlation
0.3, // public double lowpass_sigma = 0.3; // for phase correlation - frequency fraction of maximal
0.03, // public double min_frac = 0.03; // do not use higher order autocorrelation if min/max
// is weaker than this fraction of the zero maximum
0.5, //public double min_sin = 0.5; // minimal sine for the angle between two pattern vectors
true //public boolean no_crazy = true; // fail if quadratic approximation fails or returns outside of +/- 1.5
);
......@@ -674,11 +685,11 @@ public static MatchSimulatedPattern.DistortionParameters DISTORTION =new MatchSi
panelConf1 = new Panel();
panelConf1.setLayout(new GridLayout(1, 0, 5, 5));
addButton("Configure Globals",panelConf1);
addButton("Conf. Components",panelConf1);
addButton("Conf. Multifile",panelConf1,color_configure);
addButton("Conf. Simulation",panelConf1);
addButton("Conf. Pattern Detection",panelConf1);
addButton("Configure Globals", panelConf1,color_configure);
addButton("Conf. Components", panelConf1,color_configure);
addButton("Conf. Multifile", panelConf1,color_configure);
addButton("Conf. Simulation", panelConf1,color_configure);
addButton("Conf. Pattern Detection",panelConf1,color_configure);
addButton("Waves",panelConf1);
//WavePatternGenerator
add(panelConf1);
......@@ -994,6 +1005,8 @@ if (MORE_BUTTONS) {
addButton("Configure Goniometer", panelLWIR,color_configure);
addButton("Goniometer Move", panelLWIR,color_debug);
addButton("LWIR Goniometer", panelLWIR,color_conf_process);
addButton("LWIR grids", panelLWIR,color_process);
add(panelLWIR);
pack();
......@@ -1141,7 +1154,7 @@ if (MORE_BUTTONS) {
return;
/* ======================================================================== */
} else if (label.equals("Conf. Pattern Detection")) {
showPatternDetectParametersDialog(PATTERN_DETECT);
showPatternDetectParametersDialog(PATTERN_DETECT, (LWIR_READER != null));
return;
/* ======================================================================== */
} else if (label.equals("Waves")) {
......@@ -1404,6 +1417,8 @@ if (MORE_BUTTONS) {
matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
PATTERN_DETECT.minGridPeriod/2,
PATTERN_DETECT.maxGridPeriod/2,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
......@@ -1800,6 +1815,8 @@ if (MORE_BUTTONS) {
int numAbsolutePoints=matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
PATTERN_DETECT.minGridPeriod/2,
PATTERN_DETECT.maxGridPeriod/2,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
......@@ -2567,113 +2584,7 @@ if (MORE_BUTTONS) {
IJ.showMessage("Laser pointer data needed for this function is not provided");
return;
}
long startTime=System.nanoTime();
boolean noMessageBoxes=true;
String prefix="grid-";
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
DISTORTION_PROCESS_CONFIGURATION.debugLevel=MASTER_DEBUG_LEVEL;
if (matchSimulatedPattern==null) matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize);
matchSimulatedPattern.debugLevel=MASTER_DEBUG_LEVEL;
String [] sourceFilesList=DISTORTION_PROCESS_CONFIGURATION.selectSourceFiles(); // select files - with/without dialog
boolean saveGrids=DISTORTION_PROCESS_CONFIGURATION.saveGridImages;
boolean overwriteGrids=DISTORTION_PROCESS_CONFIGURATION.overwriteResultFiles;
if (sourceFilesList==null) return;
showPatternMinMaxPeriodDialog(PATTERN_DETECT);
for (int numFile=0;numFile<sourceFilesList.length;numFile++){
long startFileTime=System.nanoTime();
if (DEBUG_LEVEL>0){
System.out.println(IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+"s: Processing file # "+(numFile+1)+ " (of "+ sourceFilesList.length+"): "+sourceFilesList[numFile]);
}
if (saveGrids && !overwriteGrids){ // check if result already exists
int i = sourceFilesList[numFile].lastIndexOf('/');
if (i>0){
String path=prefix+sourceFilesList[numFile].substring(i+1);
String srcDir=DISTORTION_PROCESS_CONFIGURATION.selectGridFileDirectory(true,DISTORTION_PROCESS_CONFIGURATION.gridDirectory,true);
if (srcDir==null){
saveGrids=false; // do not ask about the next ones too
} else {
path=DISTORTION_PROCESS_CONFIGURATION.gridDirectory+Prefs.getFileSeparator()+path;
// File rsltFile=new File(path);
if ((new File(path)).exists()){
if (DEBUG_LEVEL>0) System.out.println("-->>> Skipping existing "+path+" (as requested in \"Configure Process Distortions\")");
continue;
}
}
}
}
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 (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();
int numAbsolutePoints=matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
LASER_POINTERS, // LaserPointer laserPointer, // LaserPointer object or null
DISTORTION_PROCESS_CONFIGURATION.removeOutOfGridPointers, //
null, // double [][][] hintGrid, // predicted grid array (or null)
0, // double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level, // debug level
noMessageBoxes);
if (DEBUG_LEVEL>1) System.out.println("numAbsolutePoints="+numAbsolutePoints);
if ((numAbsolutePoints==DISTORTION.errPatternNotFound) || (numAbsolutePoints==DISTORTION.errTooFewCells)) {
if (DEBUG_LEVEL>0) System.out.println("Grid "+(numFile+1)+" not found or too small ("+numAbsolutePoints+"), wasted "+
IJ.d2s(0.000000001*(System.nanoTime()-startFileTime),3)+" seconds )\n");
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
continue; // too few cells detected
}
if (DISTORTION_PROCESS_CONFIGURATION.useNoPonters || (numAbsolutePoints>0)){
//Calculate grid contrast and brightness for each color component
matchSimulatedPattern.calcGridIntensities (
DISTORTION, //final DistortionParameters distortionParameters, //
COMPONENTS.equalizeGreens,
imp_sel, // image to process
THREADS_MAX);
ImagePlus imp_calibrated=matchSimulatedPattern.getCalibratedPatternAsImage(imp_sel,prefix, numAbsolutePoints);
if (DISTORTION_PROCESS_CONFIGURATION.showGridImages) imp_calibrated.show();
if (saveGrids){
FileSaver fs=new FileSaver(imp_calibrated);
String srcDir=DISTORTION_PROCESS_CONFIGURATION.selectGridFileDirectory(true,DISTORTION_PROCESS_CONFIGURATION.gridDirectory,true);
if (srcDir==null){
saveGrids=false; // do not ask about the next ones too
} else {
String path=DISTORTION_PROCESS_CONFIGURATION.gridDirectory+Prefs.getFileSeparator()+imp_calibrated.getTitle();
if (UPDATE_STATUS) IJ.showStatus("Saving "+path);
if (DEBUG_LEVEL>0) System.out.println("-->>> Saving "+path+" - using "+numAbsolutePoints+" laser pointer references");
fs.saveAsTiffStack(path);
}
}
}
if (DEBUG_LEVEL>0) System.out.println("Grid "+(numFile+1)+" calculation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+" (in "+
IJ.d2s(0.000000001*(System.nanoTime()-startFileTime),3)+"s )\n");
//
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
}
if (DEBUG_LEVEL>0) System.out.println(((this.SYNC_COMMAND.stopRequested.get()>0)?"Partial (interrupted by user) set of grids":"All")+ " grids calculation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
calculateGrids();
return;
}
/* ======================================================================== */
......@@ -9506,6 +9417,15 @@ if (MORE_BUTTONS) {
/// POWER_CONTROL.lightsOff();
return;
}
/* ======================================================================== */
if (label.equals("LWIR grids")) {
// if ((LASER_POINTERS==null) || (LASER_POINTERS.laserUVMap.length==0)){
// IJ.showMessage("Laser pointer data needed for this function is not provided");
// return;
// }
calculateLwirGrids();
return;
}
......@@ -9522,7 +9442,250 @@ if (MORE_BUTTONS) {
/* ======================================================================== */
/* ======================================================================== */
public void calculateLwirGrids() {
long startTime=System.nanoTime();
boolean noMessageBoxes=true;
String prefix="grid-";
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
DISTORTION_PROCESS_CONFIGURATION.debugLevel=MASTER_DEBUG_LEVEL;
if (matchSimulatedPattern==null) matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize);
matchSimulatedPattern.debugLevel=MASTER_DEBUG_LEVEL;
String [] sourceSetList = DISTORTION_PROCESS_CONFIGURATION.selectSourceSets();
LWIR_PARAMETERS.selectSourceChannels();
boolean [] sel_chn = LWIR_PARAMETERS.getSelectedVnir(); // start with regular cameras only
int numFiles = LWIR_PARAMETERS.getSourceFilesFlat(sourceSetList, sel_chn).length; // just the number
String [][] sourceFilesList=LWIR_PARAMETERS.getSourceFiles(sourceSetList, sel_chn);
// String [] sourceFilesList=DISTORTION_PROCESS_CONFIGURATION.selectSourceFiles(); // select files - with/without dialog
boolean saveGrids=DISTORTION_PROCESS_CONFIGURATION.saveGridImages;
boolean overwriteGrids=DISTORTION_PROCESS_CONFIGURATION.overwriteResultFiles;
if (sourceSetList==null) return;
showPatternMinMaxPeriodDialog(PATTERN_DETECT, true);
int this_file = 0;
// if (DEBUG_LEVEL <100) return;
String gridDir=DISTORTION_PROCESS_CONFIGURATION.selectGridFileDirectory(
true,DISTORTION_PROCESS_CONFIGURATION.gridDirectory,true);
if (gridDir == null) saveGrids=false; // do not ask about the next ones too
for (int nset = 0; nset < sourceFilesList.length; nset++){
String set_name = sourceSetList[nset];
int i = set_name.lastIndexOf(Prefs.getFileSeparator());
if (i >=0) set_name = set_name.substring (set_name.lastIndexOf(Prefs.getFileSeparator())+1);
// create directory if it does not exist yet
String gridSetPath = null;
if (saveGrids) {
gridSetPath = gridDir + Prefs.getFileSeparator() + set_name;
File set_dir = new File(gridSetPath);
if (!set_dir.exists()) {
set_dir.mkdirs(); // including parent
}
}
for (int nfile = 0; nfile < sourceFilesList[nset].length; nfile++) if (sourceFilesList[nset][nfile] != null){
long startFileTime=System.nanoTime();
if (DEBUG_LEVEL>0){
System.out.println(IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+"s: Processing file # "+(this_file+1)+
" (of "+ sourceFilesList.length+"): " + numFiles);
}
if (saveGrids && !overwriteGrids){ // check if result already exists
i = sourceFilesList[nset][nfile].lastIndexOf('/');
if (i>0){
String grid_name = prefix+sourceFilesList[nset][nfile].substring(i+1);
String grid_path = gridSetPath + Prefs.getFileSeparator() + grid_name;
if ((new File(grid_path)).exists()){
if (DEBUG_LEVEL>0) System.out.println("-->>> Skipping existing "+grid_path+" (as requested in \"Configure Process Distortions\")");
continue;
}
}
}
imp_sel=new ImagePlus(sourceFilesList[nset][nfile]); // read source file
EyesisTiff.decodeProperiesFromInfo(imp_sel);
matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize); // TODO: is it needed each time?
matchSimulatedPattern.invalidateFlatFieldForGrid(); //Reset Flat Field calibration - different image.
matchSimulatedPattern.invalidateFocusMask();
int numAbsolutePoints=matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
PATTERN_DETECT.minGridPeriod/2,
PATTERN_DETECT.maxGridPeriod/2,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
null, // LASER_POINTERS, // LaserPointer laserPointer, // LaserPointer object or null
DISTORTION_PROCESS_CONFIGURATION.removeOutOfGridPointers, //
null, // double [][][] hintGrid, // predicted grid array (or null)
0, // double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level, // debug level
noMessageBoxes);
if (DEBUG_LEVEL>1) System.out.println("numAbsolutePoints="+numAbsolutePoints);
if ((numAbsolutePoints==DISTORTION.errPatternNotFound) || (numAbsolutePoints==DISTORTION.errTooFewCells)) {
if (DEBUG_LEVEL>0) System.out.println("Grid "+(this_file+1)+" not found or too small ("+numAbsolutePoints+"), wasted "+
IJ.d2s(0.000000001*(System.nanoTime()-startFileTime),3)+" seconds )\n");
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
continue; // too few cells detected
}
if (DISTORTION_PROCESS_CONFIGURATION.useNoPonters || (numAbsolutePoints>0)){
//Calculate grid contrast and brightness for each color component
matchSimulatedPattern.calcGridIntensities (
DISTORTION, //final DistortionParameters distortionParameters, //
COMPONENTS.equalizeGreens,
imp_sel, // image to process
THREADS_MAX);
ImagePlus imp_calibrated=matchSimulatedPattern.getCalibratedPatternAsImage(imp_sel,prefix, numAbsolutePoints);
if (DISTORTION_PROCESS_CONFIGURATION.showGridImages) imp_calibrated.show();
if (saveGrids){
FileSaver fs=new FileSaver(imp_calibrated);
String srcDir=DISTORTION_PROCESS_CONFIGURATION.selectGridFileDirectory(true,DISTORTION_PROCESS_CONFIGURATION.gridDirectory,true);
if (srcDir==null){
saveGrids=false; // do not ask about the next ones too
} else {
String path=DISTORTION_PROCESS_CONFIGURATION.gridDirectory+Prefs.getFileSeparator()+imp_calibrated.getTitle();
if (UPDATE_STATUS) IJ.showStatus("Saving "+path);
if (DEBUG_LEVEL>0) System.out.println("-->>> Saving "+path+" - using "+numAbsolutePoints+" laser pointer references");
fs.saveAsTiffStack(path);
}
}
}
if (DEBUG_LEVEL>0) System.out.println("Grid "+(this_file+1)+" calculation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+" (in "+
IJ.d2s(0.000000001*(System.nanoTime()-startFileTime),3)+"s )\n");
//
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
this_file++;
}
}
if (DEBUG_LEVEL>0) System.out.println(((this.SYNC_COMMAND.stopRequested.get()>0)?"Partial (interrupted by user) set of grids":"All")+ " grids calculation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
return;
}
/* ======================================================================== */
public void calculateGrids() {
long startTime=System.nanoTime();
boolean noMessageBoxes=true;
String prefix="grid-";
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
DISTORTION_PROCESS_CONFIGURATION.debugLevel=MASTER_DEBUG_LEVEL;
if (matchSimulatedPattern==null) matchSimulatedPattern= new MatchSimulatedPattern(DISTORTION.FFTSize);
matchSimulatedPattern.debugLevel=MASTER_DEBUG_LEVEL;
String [] sourceFilesList=DISTORTION_PROCESS_CONFIGURATION.selectSourceFiles(); // select files - with/without dialog
boolean saveGrids=DISTORTION_PROCESS_CONFIGURATION.saveGridImages;
boolean overwriteGrids=DISTORTION_PROCESS_CONFIGURATION.overwriteResultFiles;
if (sourceFilesList==null) return;
showPatternMinMaxPeriodDialog(PATTERN_DETECT,false);
for (int numFile=0;numFile<sourceFilesList.length;numFile++){
long startFileTime=System.nanoTime();
if (DEBUG_LEVEL>0){
System.out.println(IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+"s: Processing file # "+(numFile+1)+ " (of "+ sourceFilesList.length+"): "+sourceFilesList[numFile]);
}
if (saveGrids && !overwriteGrids){ // check if result already exists
int i = sourceFilesList[numFile].lastIndexOf('/');
if (i>0){
String path=prefix+sourceFilesList[numFile].substring(i+1);
String srcDir=DISTORTION_PROCESS_CONFIGURATION.selectGridFileDirectory(true,DISTORTION_PROCESS_CONFIGURATION.gridDirectory,true);
if (srcDir==null){
saveGrids=false; // do not ask about the next ones too
} else {
path=DISTORTION_PROCESS_CONFIGURATION.gridDirectory+Prefs.getFileSeparator()+path;
// File rsltFile=new File(path);
if ((new File(path)).exists()){
if (DEBUG_LEVEL>0) System.out.println("-->>> Skipping existing "+path+" (as requested in \"Configure Process Distortions\")");
continue;
}
}
}
}
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 (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();
int numAbsolutePoints=matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
PATTERN_DETECT.minGridPeriod/2,
PATTERN_DETECT.maxGridPeriod/2,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
LASER_POINTERS, // LaserPointer laserPointer, // LaserPointer object or null
DISTORTION_PROCESS_CONFIGURATION.removeOutOfGridPointers, //
null, // double [][][] hintGrid, // predicted grid array (or null)
0, // double hintGridTolerance, // allowed mismatch (fraction of period) or 0 - orientation only
THREADS_MAX,
UPDATE_STATUS,
DEBUG_LEVEL,
DISTORTION.loop_debug_level, // debug level
noMessageBoxes);
if (DEBUG_LEVEL>1) System.out.println("numAbsolutePoints="+numAbsolutePoints);
if ((numAbsolutePoints==DISTORTION.errPatternNotFound) || (numAbsolutePoints==DISTORTION.errTooFewCells)) {
if (DEBUG_LEVEL>0) System.out.println("Grid "+(numFile+1)+" not found or too small ("+numAbsolutePoints+"), wasted "+
IJ.d2s(0.000000001*(System.nanoTime()-startFileTime),3)+" seconds )\n");
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
continue; // too few cells detected
}
if (DISTORTION_PROCESS_CONFIGURATION.useNoPonters || (numAbsolutePoints>0)){
//Calculate grid contrast and brightness for each color component
matchSimulatedPattern.calcGridIntensities (
DISTORTION, //final DistortionParameters distortionParameters, //
COMPONENTS.equalizeGreens,
imp_sel, // image to process
THREADS_MAX);
ImagePlus imp_calibrated=matchSimulatedPattern.getCalibratedPatternAsImage(imp_sel,prefix, numAbsolutePoints);
if (DISTORTION_PROCESS_CONFIGURATION.showGridImages) imp_calibrated.show();
if (saveGrids){
FileSaver fs=new FileSaver(imp_calibrated);
String srcDir=DISTORTION_PROCESS_CONFIGURATION.selectGridFileDirectory(true,DISTORTION_PROCESS_CONFIGURATION.gridDirectory,true);
if (srcDir==null){
saveGrids=false; // do not ask about the next ones too
} else {
String path=DISTORTION_PROCESS_CONFIGURATION.gridDirectory+Prefs.getFileSeparator()+imp_calibrated.getTitle();
if (UPDATE_STATUS) IJ.showStatus("Saving "+path);
if (DEBUG_LEVEL>0) System.out.println("-->>> Saving "+path+" - using "+numAbsolutePoints+" laser pointer references");
fs.saveAsTiffStack(path);
}
}
}
if (DEBUG_LEVEL>0) System.out.println("Grid "+(numFile+1)+" calculation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3)+" (in "+
IJ.d2s(0.000000001*(System.nanoTime()-startFileTime),3)+"s )\n");
//
if (this.SYNC_COMMAND.stopRequested.get()>0) {
System.out.println("User requested stop");
break;
}
}
if (DEBUG_LEVEL>0) System.out.println(((this.SYNC_COMMAND.stopRequested.get()>0)?"Partial (interrupted by user) set of grids":"All")+ " grids calculation done at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
return;
}
/* ======================================================================== */
public void processCalibrationFiles() {
if (!showProcessCalibrationFilesDialog(PROCESS_PARAMETERS)) return;
......@@ -9570,6 +9733,8 @@ if (MORE_BUTTONS) {
matchSimulatedPattern.calculateDistortions(
DISTORTION, //
PATTERN_DETECT,
PATTERN_DETECT.minGridPeriod/2,
PATTERN_DETECT.maxGridPeriod/2,
SIMUL,
COMPONENTS.equalizeGreens,
imp_sel,
......@@ -12475,7 +12640,7 @@ if (MORE_BUTTONS) {
throw new IllegalArgumentException (msg);
}
matchSimulatedPattern.debugLevel=debugLevel;
/*
double sharpnessOld=matchSimulatedPattern.focusQualityOld(
imp,
focusMeasurementParameters.sampleSize, // will be twice the regualr FFT size
......@@ -12492,6 +12657,7 @@ if (MORE_BUTTONS) {
lensDistortionParameters.py0,
debugLevel);
if (debugLevel>0) System.out.println("Focus qualityOld1="+sharpnessOld1);
*/
double sharpness=matchSimulatedPattern.focusQuality(
imp,
focusMeasurementParameters.sampleSize, // will be twice the regualr FFT size
......@@ -17017,9 +17183,13 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
mapCell.x=nTileX*size;
pixels=splitBayer(imp, mapCell,COMPONENTS.equalizeGreens);
pixels[4]= normalizeAndWindow (pixels[4], hamming);
patternMap[nTileY][nTileX]=matchSimulatedPattern.findPattern(pixels[4],
patternMap[nTileY][nTileX]=matchSimulatedPattern.findPattern(
null,
pixels[4],
size,
patternDetectParameters,
patternDetectParameters.minGridPeriod/2,
patternDetectParameters.maxGridPeriod/2,
true,
title); // title - will not be used
/* Now verify by correlating with the actual pattern */
......@@ -17581,6 +17751,8 @@ private double [][] jacobianByJacobian(double [][] jacobian, boolean [] mask) {
if (matchSimulatedPattern.PATTERN_GRID==null) {
double[][] distortedPattern= matchSimulatedPattern.findPatternDistorted(input_bayer, // pixel array to process (no windowing!)
patternDetectParameters,
patternDetectParameters.minGridPeriod/2,
patternDetectParameters.maxGridPeriod/2,
true, //(greensToProcess==4), // boolean greens, // this is a pattern for combined greens (diagonal), adjust results accordingly
title); // title prefix to use for debug images
......@@ -19833,7 +20005,7 @@ use the result to create a rejectiobn mask - if the energy was high, (multiplica
return true;
}
/* ======================================================================== */
public boolean showPatternDetectParametersDialog(MatchSimulatedPattern.PatternDetectParameters patternDetectParameters) {
public boolean showPatternDetectParametersDialog(MatchSimulatedPattern.PatternDetectParameters patternDetectParameters, boolean use_lwir) {
///gaussWidth
GenericDialog gd = new GenericDialog("Parameters");
gd.addNumericField("Gaussian width for the window function (<=0 - use Hamming):", patternDetectParameters.gaussWidth, 3);
......@@ -19849,16 +20021,30 @@ use the result to create a rejectiobn mask - if the energy was high, (multiplica
gd.addNumericField("Minimal pattern correlation contrast" , patternDetectParameters.minCorrContrast, 3); //5.0; // Discrimination threshold between good and bad pattern correleation
gd.addNumericField("Minimal pattern grid period (<=0.0 - do not check)" , patternDetectParameters.minGridPeriod, 2,5,"pix");
gd.addNumericField("Maximal pattern grid period (<=0.0 - do not check)" , patternDetectParameters.maxGridPeriod, 2,5,"pix");
if (use_lwir) {
gd.addNumericField("Minimal pattern grid period for LWIR sensors (<=0.0 - do not check)" , patternDetectParameters.minGridPeriodLwir, 2,5,"pix");
gd.addNumericField("Maximal pattern grid period for LWIR sensors (<=0.0 - do not check)" , patternDetectParameters.maxGridPeriodLwir, 2,5,"pix");
}
gd.addMessage("----- debug -----");
gd.addNumericField("Debug grid near pixel X" , patternDetectParameters.debugX, 1,6,"pix");
gd.addNumericField("Debug grid near pixel X" , patternDetectParameters.debugY, 1,6,"pix");
gd.addNumericField("Debug grid nodes at this distance of (x,Y) - <0 - no debug", patternDetectParameters.debugRadius, 1,5,"pix");
gd.addMessage("----- New method that should work with large cells (only half-period negative correlations fit in window) -----");
gd.addCheckbox ("Use large cell method (with phase correlation)", patternDetectParameters.use_large_cells); // true;
gd.addNumericField("\"phasiness\" of correlation" , patternDetectParameters.phaseCoeff, 2,5,"");
gd.addNumericField("Low-pass sigma for phase correlation - frequency fraction of maximal", patternDetectParameters.lowpass_sigma, 2,5,"");
gd.addNumericField("Minimal min/max amplitude fraction of the zero one" , patternDetectParameters.min_frac, 2,5,"");
gd.addNumericField("Minimal absolute value of sine of the patern vectors angle" , patternDetectParameters.min_sin, 2,5,"");
gd.addCheckbox ("Fail if quadratic approximation fails or returns outside of +/- 1.5", patternDetectParameters.no_crazy); // true;
gd.showDialog();
if (gd.wasCanceled()) return false;
patternDetectParameters.gaussWidth= gd.getNextNumber(); //0.4
patternDetectParameters.corrGamma= gd.getNextNumber(); //0.2; lower the value - higher harmonics will participate in pattern frequency measurements
patternDetectParameters.corrSigma= gd.getNextNumber(); // 1.5; // pattern detection: high-pass filter (0.0 - none) gamma(PS)
patternDetectParameters.corrGamma= gd.getNextNumber(); //0.2; lower the value - higher harmonics will participate in pattern frequency measurements
patternDetectParameters.corrSigma= gd.getNextNumber(); // 1.5; // pattern detection: high-pass filter (0.0 - none) gamma(PS)
patternDetectParameters.diffSpectrCorr= (int) gd.getNextNumber();
patternDetectParameters.shrinkClusters= gd.getNextNumber(); // 0.5; // Shrink clusters by this ratio (remove lowest) after initial separation
patternDetectParameters.multiplesToTry= (int) gd.getNextNumber();
......@@ -19869,23 +20055,44 @@ use the result to create a rejectiobn mask - if the energy was high, (multiplica
patternDetectParameters.minCorrContrast= gd.getNextNumber();
patternDetectParameters.minGridPeriod= gd.getNextNumber();
patternDetectParameters.maxGridPeriod= gd.getNextNumber();
if (use_lwir) {
patternDetectParameters.minGridPeriodLwir= gd.getNextNumber();
patternDetectParameters.maxGridPeriodLwir= gd.getNextNumber();
}
patternDetectParameters.debugX= gd.getNextNumber();
patternDetectParameters.debugY= gd.getNextNumber();
patternDetectParameters.debugRadius= gd.getNextNumber();
patternDetectParameters.use_large_cells= gd.getNextBoolean();
patternDetectParameters.phaseCoeff= gd.getNextNumber();
patternDetectParameters.lowpass_sigma= gd.getNextNumber();
patternDetectParameters.min_frac= gd.getNextNumber();
patternDetectParameters.min_sin= gd.getNextNumber();
patternDetectParameters.no_crazy= gd.getNextBoolean();
return true;
}
public boolean showPatternMinMaxPeriodDialog(MatchSimulatedPattern.PatternDetectParameters patternDetectParameters) {
public boolean showPatternMinMaxPeriodDialog(MatchSimulatedPattern.PatternDetectParameters patternDetectParameters, boolean use_lwir) {
///gaussWidth
GenericDialog gd = new GenericDialog("Min/Max opattern grid period");
gd.addNumericField("Minimal pattern grid period (<=0.0 - do not check)" , patternDetectParameters.minGridPeriod, 2,5,"pix");
gd.addNumericField("Maximal pattern grid period (<=0.0 - do not check)" , patternDetectParameters.maxGridPeriod, 2,5,"pix");
gd.addMessage ("TODO: Calculate min/max from pattern data and distance");
gd.showDialog();
if (gd.wasCanceled()) return false;
patternDetectParameters.minGridPeriod= gd.getNextNumber();
patternDetectParameters.maxGridPeriod= gd.getNextNumber();
return true;
}
GenericDialog gd = new GenericDialog("Min/Max opattern grid period");
gd.addNumericField("Minimal pattern grid period (<=0.0 - do not check)" , patternDetectParameters.minGridPeriod, 2,5,"pix");
gd.addNumericField("Maximal pattern grid period (<=0.0 - do not check)" , patternDetectParameters.maxGridPeriod, 2,5,"pix");
gd.addMessage ("TODO: Calculate min/max from pattern data and distance");
if (use_lwir) {
gd.addNumericField("Minimal pattern grid period for LWIR sensors (<=0.0 - do not check)" , patternDetectParameters.minGridPeriodLwir, 2,5,"pix");
gd.addNumericField("Maximal pattern grid period for LWIR sensors (<=0.0 - do not check)" , patternDetectParameters.maxGridPeriodLwir, 2,5,"pix");
}
gd.showDialog();
if (gd.wasCanceled()) return false;
patternDetectParameters.minGridPeriod= gd.getNextNumber();
patternDetectParameters.maxGridPeriod= gd.getNextNumber();
if (use_lwir) {
patternDetectParameters.minGridPeriodLwir= gd.getNextNumber();
patternDetectParameters.maxGridPeriodLwir= gd.getNextNumber();
}
return true;
}
/* ======================================================================== */
......@@ -6,7 +6,7 @@ package com.elphel.imagej.calibration;
** Copyright (C) 2011-2014 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
**
** DistortionProcessConfiguration.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
......@@ -23,16 +23,17 @@ package com.elphel.imagej.calibration;
**
*/
import ij.IJ;
import ij.Prefs;
import ij.gui.GenericDialog;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Properties;
import com.elphel.imagej.common.WindowTools;
import ij.IJ;
import ij.Prefs;
import ij.gui.GenericDialog;
public class DistortionProcessConfiguration{
public String sourceDirectory="";
public String gridDirectory= "";
......@@ -50,7 +51,7 @@ import com.elphel.imagej.common.WindowTools;
public String selectSourceDirectory(boolean smart, String defaultPath, boolean newAllowed) {
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
newAllowed, // save
"Source (acquired from the camera) image directory", // title
"Select source directory", // button
null, // filter
......@@ -61,7 +62,7 @@ import com.elphel.imagej.common.WindowTools;
public String selectGridFileDirectory(boolean smart, String defaultPath, boolean newAllowed) {
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
newAllowed, // save
"Grid files directory (grid patterns extracted from the images)", // title
"Select grid files directory", // button
null, // filter
......@@ -69,7 +70,7 @@ import com.elphel.imagej.common.WindowTools;
if (dir!=null) this.gridDirectory=dir;
return dir;
}
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"sourceDirectory", this.sourceDirectory);
properties.setProperty(prefix+"gridDirectory", this.gridDirectory);
......@@ -123,9 +124,9 @@ import com.elphel.imagej.common.WindowTools;
gd.addCheckbox ("Show grid files as images", this.showGridImages);
gd.addCheckbox ("Save grid files", this.saveGridImages);
gd.addCheckbox ("Overwrite existing result files", this.overwriteResultFiles);
gd.addNumericField("Debug level", this.debugLevel,0);
WindowTools.addScrollBars(gd);
gd.showDialog();
......@@ -144,7 +145,7 @@ import com.elphel.imagej.common.WindowTools;
this.debugLevel= (int) gd.getNextNumber();
System.out.println("1.newSourceDirectory = "+newSourceDirectory);
System.out.println("1.newGridDirectory = "+ newGridDirectory);
if ((newSourceDirectory.length()==0) || (newSourceDirectory.indexOf('?')>=0))
if ((newSourceDirectory.length()==0) || (newSourceDirectory.indexOf('?')>=0))
newSourceDirectory= selectSourceDirectory(false, this.sourceDirectory, true);
else
newSourceDirectory= selectSourceDirectory(true, newSourceDirectory, true); // if matches, no dialog
......@@ -174,7 +175,7 @@ import com.elphel.imagej.common.WindowTools;
if (this.sourceDirectory.length()==0){
defaultPaths[0]="";
}
CalibrationFileManagement.MultipleExtensionsFileFilter sourceFilter =
new CalibrationFileManagement.MultipleExtensionsFileFilter("",extensions,"Source files");
String [] sourceFiles=null;
......@@ -206,5 +207,26 @@ import com.elphel.imagej.common.WindowTools;
}
return sourceFiles;
}
public String[] selectSourceSets() {
File dir= new File (this.sourceDirectory);
if (this.debugLevel>1) System.out.println("selectSourceSets, dir="+this.sourceDirectory);
if (!dir.exists()) {
String error="Source directory "+this.sourceDirectory+" does not exist.";
IJ.showMessage("No files selected");
if (this.debugLevel>1) System.out.println("selectSourceFiles() ERROR:"+error);
return null;
}
File [] sourceFileSets = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
});
String [] sourceSets = new String[sourceFileSets.length];
for (int i=0;i<sourceSets.length;i++) sourceSets[i]=sourceFileSets[i].getPath();
return sourceSets;
}
}
package com.elphel.imagej.calibration;
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.Prefs;
import ij.gui.GenericDialog;
import ij.io.FileSaver;
import ij.io.Opener;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import java.awt.Rectangle;
import java.io.File;
import java.util.ArrayList;
......@@ -19,14 +9,22 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.SwingUtilities;
import com.elphel.imagej.calibration.CalibrationFileManagement.MultipleExtensionsFileFilter;
import com.elphel.imagej.calibration.SimulationPattern.SimulParameters;
import com.elphel.imagej.common.DoubleFHT;
import com.elphel.imagej.common.DoubleGaussianBlur;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.common.WindowTools;
import com.elphel.imagej.jp4.JP46_Reader_camera;
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.Prefs;
import ij.gui.GenericDialog;
import ij.io.FileSaver;
import ij.io.Opener;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
public class EyesisAberrations {
public double [][][][] pdfKernelMap=null;
JP46_Reader_camera JP4_INSTANCE= new JP46_Reader_camera(false);
......@@ -34,7 +32,7 @@ public class EyesisAberrations {
public AtomicInteger stopRequested=null; // 1 - stop now, 2 - when convenient
public Distortions distortions=null;
public AberrationParameters aberrationParameters=null;
public EyesisAberrations (AtomicInteger stopRequested,
AberrationParameters aberrationParameters){
this.stopRequested=stopRequested;
......@@ -43,7 +41,7 @@ public class EyesisAberrations {
public void setDistortions(Distortions distortions){
this.distortions=distortions;
}
int countExistentFiles(String directory,String [] paths, boolean remove){
int numFiles=0;
for (int i=0;i<paths.length;i++) if (paths[i]!=null){
......@@ -127,7 +125,7 @@ public class EyesisAberrations {
inverseParameters, // size (side of square) of direct PSF kernel
threadsMax, // size (side of square) of reverse PSF kernel
updateStatus,
globalDebugLevel);
globalDebugLevel);
ImagePlus impInvertedPSF = new ImagePlus("interpolated kernel stack", stack);
JP46_Reader_camera jp4_instance= new JP46_Reader_camera(false);
......@@ -139,14 +137,14 @@ public class EyesisAberrations {
if (showResult) {
impInvertedPSF.getProcessor().resetMinAndMax(); // imp_psf will be reused
impInvertedPSF.show();
}
}
if (saveResult){
if (globalDebugLevel>0) System.out.println((numProcessed+1)+" of "+numToProcess+": saving invered (of the file"+srcPaths[nChn]+") kernel to "+resultPaths[nChn]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
FileSaver fs=new FileSaver(impInvertedPSF);
fs.saveAsTiffStack(resultPaths[nChn]);
}
numProcessed++;
if (stopRequested.get()>0) {
if (stopRequested.get()>0) {
if (globalDebugLevel>0) System.out.println("User requested stop");
break;
}
......@@ -162,7 +160,7 @@ public class EyesisAberrations {
}
return true;
}
public ImageStack reversePSFKernelStack(
final ImageStack PSFStack, // stack of 3 32-bit (float) images, made of square kernels
final EyesisAberrations.InverseParameters inverseParameters, // size (side of square) of direct PSF kernel
......@@ -181,6 +179,7 @@ public class EyesisAberrations {
final int numberOfKernelsInChn=tilesY*tilesX;
for (int ithread = 0; ithread < threads.length; ithread++) {
threads[ithread] = new Thread() {
@Override
public void run() {
float [] pixels=null;
double [] kernel= new double[inverseParameters.dSize*inverseParameters.dSize];
......@@ -200,7 +199,7 @@ public class EyesisAberrations {
pixels=(float[]) PSFStack.getPixels(chn+1);
chn0=chn;
}
extractOneKernel( pixels, // array of combined square kernels, each
extractOneKernel( pixels, // array of combined square kernels, each
kernel, // will be filled, should have correct size before call
tilesX, // number of kernels in a row
tileX, // horizontal number of kernel to extract
......@@ -221,12 +220,12 @@ public class EyesisAberrations {
variableSigmas, // array of sigmas to be used for each pixel, matches pixels[]
3.5, // drop calculatin if farther then nSigma
0, // int WOICenterX, // window of interest in pixels[] array - do not generate data outside it
0, // int WOICenterY, //
0, // int WOICenterY, //
inverseParameters.rSize, //int WOIWidth, reduce later
inverseParameters.rSize, //int WOIHeight)
globalDebugLevel);
}
/* reverse PSF kernel */
rKernel= cleanupAndReversePSF (rKernel, // input pixels
inverseParameters,
......@@ -252,7 +251,7 @@ public class EyesisAberrations {
variableSigmas, // array of sigmas to be used for each pixel, matches pixels[]
3.5, // drop calculation if farther then nSigma
0, // int WOICenterX, // window of interest in pixels[] array - do not generate data outside it
0, // int WOICenterY, //
0, // int WOICenterY, //
inverseParameters.rSize, //int WOIWidth, reduce later
inverseParameters.rSize,
globalDebugLevel); //int WOIHeight)
......@@ -280,7 +279,7 @@ public class EyesisAberrations {
}
return outStack;
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
private double [] maskReversePSFKernel( double []rpsf_pixels, // reversed psf, square array
double [] ellipse_coeff, // ellipse coefficients from _direct_ kernel
......@@ -308,8 +307,8 @@ public class EyesisAberrations {
}
/* ======================================================================== */
private double [] createSigmasFromCenter(
int size, // side of square
double sigma_to_radius, // variable blurring - sigma will be proportional distance from the center
......@@ -329,8 +328,8 @@ public class EyesisAberrations {
return sigmas;
}
/* ======================================================================== */
public double [] cleanupAndReversePSF (double [] psf_pixels, // input pixels
EyesisAberrations.InverseParameters inverseParameters, // size (side of square) of direct PSF kernel
......@@ -430,7 +429,7 @@ public class EyesisAberrations {
double [] pixels=null;
/* convert back original dimension array if there was no decimation or debug is set (in that case both sizes arrays will be converted) */
/* Convert fft array back to fht array and
/* Convert fft array back to fht array and
set fht pixels with new values */
pixels=FFTHalf2FHT (fft_complex,size);
/* optionally show the result FHT*/
......@@ -440,7 +439,7 @@ public class EyesisAberrations {
/* return inverted psf pixels */
return pixels;
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* finds cluster (with the center at DC) by flooding from DC, so total energy is cutoff_energy fraction
......@@ -555,7 +554,7 @@ public class EyesisAberrations {
iy=-iy;
}
ix= (ix+size) % size;
floatPixels[i]=(float) clusterMap[iy][ix];
floatPixels[i]=clusterMap[iy][ix];
}
ip.setPixels(floatPixels);
ip.resetMinAndMax();
......@@ -609,9 +608,9 @@ public class EyesisAberrations {
return result;
}
/* ======================================================================== */
/* TODO: REPLACE doubleFHT */
/* converts FHT results (frequency space) to complex numbers of [fftsize/2+1][fftsize] */
......@@ -639,20 +638,20 @@ public class EyesisAberrations {
row2=(fftsize-row1) %fftsize;
for (col1=0;col1 < fftsize;col1++) {
col2=(fftsize-col1) %fftsize;
fht_pixels[row1*fftsize+col1]=(double) (fft[row1][col1][0]-fft[row1][col1][1]);
fht_pixels[row2*fftsize+col2]=(double) (fft[row1][col1][0]+fft[row1][col1][1]);
fht_pixels[row1*fftsize+col1]=fft[row1][col1][0]-fft[row1][col1][1];
fht_pixels[row2*fftsize+col2]=fft[row1][col1][0]+fft[row1][col1][1];
}
}
return fht_pixels;
}
/* interpolate kernels minimizing memory image - use directly the image stack (32-bit, float) with kernels.
Add kernels around by either replication or extrapolation to compensate for "margins" in the original; kernels */
//TODO: FIXME: Does not work if overwrite is disabled
public boolean interpolateKernels(
public boolean interpolateKernels(
AtomicInteger stopRequested, // 1 - stop now, 2 - when convenient
EyesisAberrations.InterpolateParameters interpolateParameters, // INTERPOLATE
EyesisAberrations.MultiFilePSF multiFilePSF , // MULTIFILE_PSF = new EyesisAberrations.MultiFilePSF(
......@@ -734,7 +733,7 @@ public class EyesisAberrations {
if (showResult) {
impInterpolatedPSF.getProcessor().resetMinAndMax(); // imp_psf will be reused
impInterpolatedPSF.show();
}
}
if (saveResult){
if (globalDebugLevel>0) System.out.println((numProcessed+1)+" of "+numToProcess+": saving interpolation result (of the file"+srcPaths[nChn]+") to "+
resultPaths[nChn]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
......@@ -742,7 +741,7 @@ public class EyesisAberrations {
fs.saveAsTiffStack(resultPaths[nChn]);
}
numProcessed++;
if (stopRequested.get()>0) {
if (stopRequested.get()>0) {
if (globalDebugLevel>0) System.out.println("User requested stop");
break;
}
......@@ -798,7 +797,7 @@ public class EyesisAberrations {
int [] inTopLeft=new int [2]; // top left kernel in the input array
double [][] firstFHTColumn=null;
double [][] secondFHTColumn=null;
double [][][] cornerFHT=new double[2][2][interpolateParameters.size*interpolateParameters.size]; //[y][x][pixel]
double [][][] cornerFHT=new double[2][2][interpolateParameters.size*interpolateParameters.size]; //[y][x][pixel]
double [] swapArray=null;
for (chn=0;chn<nChn;chn++) {
......@@ -870,12 +869,12 @@ public class EyesisAberrations {
" outTopLeft[0]="+outTopLeft[0]+" outTopLeft[1]="+outTopLeft[1]);
if (firstFHTColumn==null) { /* First colum needs to be input and calculated*/
extractOneKernel( pixels, // array of combined square kernels, each
extractOneKernel( pixels, // array of combined square kernels, each
cornerFHT[0][0], // will be filled, should have correct size before call
inTilesX, // number of kernels in a row
inTopLeft[0], // horizontal number of kernel to extract
inTopLeft[1]); // vertical number of kernel to extract
extractOneKernel( pixels, // array of combined square kernels, each
extractOneKernel( pixels, // array of combined square kernels, each
cornerFHT[1][0], // will be filled, should have correct size before call
inTilesX, // number of kernels in a row
inTopLeft[0], // horizontal number of kernel to extract
......@@ -893,12 +892,12 @@ public class EyesisAberrations {
if (globalDebugLevel>2) System.out.println(" firstFHTColumn.length="+firstFHTColumn.length);
}
if (secondFHTColumn==null) { /* Last colum needs to be input and calculated*/
extractOneKernel( pixels, // array of combined square kernels, each
extractOneKernel( pixels, // array of combined square kernels, each
cornerFHT[0][1], // will be filled, should have correct size before call
inTilesX, // number of kernels in a row
inTopLeft[0]+1, // horizontal number of kernel to extract
inTopLeft[1]); // vertical number of kernel to extract
extractOneKernel( pixels, // array of combined square kernels, each
extractOneKernel( pixels, // array of combined square kernels, each
cornerFHT[1][1], // will be filled, should have correct size before call
inTilesX, // number of kernels in a row
inTopLeft[0]+1, // horizontal number of kernel to extract
......@@ -953,7 +952,7 @@ public class EyesisAberrations {
}
}
}
}
}
/* prepare result stack to return */
ImageStack outStack=new ImageStack(outTilesX*interpolateParameters.size,outTilesY*interpolateParameters.size);
for (chn=0;chn<nChn;chn++) {
......@@ -962,7 +961,7 @@ public class EyesisAberrations {
return outStack;
}
/* ======================================================================== */
/* Used in interpolateKernelStack() */
/* Used in interpolateKernelStack() */
private void storeOneKernel(
float [] pixels, // float [] array of combined square kernels - will be filled
double [] kernel, // square kernel to store
......@@ -978,8 +977,8 @@ public class EyesisAberrations {
}
/* ======================================================================== */
public String [][] preparePartialKernelsFilesList(
int debugLevel){
DistortionCalibrationData distortionCalibrationData= distortions.fittingStrategy.distortionCalibrationData;
......@@ -1003,7 +1002,7 @@ public class EyesisAberrations {
partialKernelPaths[imgNum]=this.aberrationParameters.partialPrefix+IJ.d2s(distortionCalibrationData.gIP[imgNum].timestamp,6).replace('.','_')+
String.format("-%02d"+this.aberrationParameters.partialSuffix, distortionCalibrationData.gIP[imgNum].channel); // sensor number
// partialKernelPaths[imgNum]=this.aberrationParameters.sourceDirectory+Prefs.getFileSeparator()+filename;
if (debugLevel>2) System.out.println("preparePartialKernelsFilesList() "+imgNum+": "+partialKernelPaths[imgNum]);
}
......@@ -1022,8 +1021,8 @@ public class EyesisAberrations {
IJ.showMessage("Warning",msg);
return null;
}
int numChannels=distortions.fittingStrategy.distortionCalibrationData.getNumChannels(); // number of used channels
String [][] fileList=new String[numChannels][];
for (int numChn=0;numChn<numChannels;numChn++){
......@@ -1059,14 +1058,14 @@ public class EyesisAberrations {
}
/*
int numChannels=this.fittingStrategy.distortionCalibrationData.getNumChannels(); // number of used channels
*/
public boolean createPartialKernels(
AtomicInteger stopRequested, // 1 - stop now, 2 - when convenient
int mapFFTsize, // scanImageForPatterns:FFT size
int fft_overlap,
int fft_size,
int PSF_subpixel,
int PSF_subpixel,
OTFFilterParameters otfFilterParameters,
PSFParameters psfParameters,
int PSFKernelSize, // size of square used in the new map (should be multiple of map step)
......@@ -1116,7 +1115,7 @@ public class EyesisAberrations {
int numChannel=distortionCalibrationData.gIP[imgNum].channel;
if (debugLevel>2){
System.out.println("Image "+imgNum+" channel "+numChannel+" is "+(selectedChannels[numChannel]?"ENABLED":"DISABLED"));
}
}
if (!selectedChannels[numChannel]){
selectedImages[imgNum]=false;
numDeselected++;
......@@ -1139,7 +1138,7 @@ public class EyesisAberrations {
String filename=this.aberrationParameters.sourcePrefix+IJ.d2s(distortionCalibrationData.gIP[imgNum].timestamp,6).replace('.','_')+
String.format("-%02d"+this.aberrationParameters.sourceSuffix, distortionCalibrationData.gIP[imgNum].channel); // sensor number
sourcePaths[imgNum]=this.aberrationParameters.sourceDirectory+Prefs.getFileSeparator()+filename;
File srcFile=new File(sourcePaths[imgNum]);
File srcFile=new File(sourcePaths[imgNum]);
if (!srcFile.exists()){
if (skipMissing) {
if (debugLevel>0) System.out.println("Skipping missing file: "+sourcePaths[imgNum]);
......@@ -1252,13 +1251,13 @@ public class EyesisAberrations {
int iRetry=0;
for (iRetry=0;iRetry<MaxRetries;iRetry++){ // is this retry needed?
try {
double [][][] projectedGrid=null;
double hintTolerance=0.0;
double hintTolerance=0.0;
if (partialToReprojected){ // replace px, py with projected values form the grid
// this.distortions is set to the global LENS_DISTORTIONS
int numGridImage=fileIndices[imgNum];
projectedGrid=distortions.estimateGridOnSensor( // return grid array [v][u][0- x, 1 - y, 2 - u, 3 - v]
projectedGrid=distortions.estimateGridOnSensor( // return grid array [v][u][0- x, 1 - y, 2 - u, 3 - v]
distortions.fittingStrategy.distortionCalibrationData.getImageStation(numGridImage), // station number,
distortions.fittingStrategy.distortionCalibrationData.gIP[numGridImage].channel, // subCamera,
Double.NaN, // goniometerHorizontal, - not used
......@@ -1277,10 +1276,12 @@ public class EyesisAberrations {
}
}
}
int rslt=matchSimulatedPattern.calculateDistortions(
distortionParameters, //
patternDetectParameters,
patternDetectParameters.minGridPeriod/2,
patternDetectParameters.maxGridPeriod/2,
simulParameters,
colorComponents.equalizeGreens,
imp,
......@@ -1313,11 +1314,11 @@ public class EyesisAberrations {
updateStatus,
debugLevel,
loopDebugLevel); // debug level
createPSFMap(
matchSimulatedPattern,
matchSimulatedPattern.applyFlatField (imp), // if grid is flat-field calibrated, apply it (may throw here)
null, // int [][][] sampleList, // optional (or null) 2-d array: list of coordinate pairs (2d - to match existent PSF_KERNEL_MAP structure)
null, // int [][][] sampleList, // optional (or null) 2-d array: list of coordinate pairs (2d - to match existent PSF_KERNEL_MAP structure)
multiFilePSF.overexposedMaxFraction, //MULTIFILE_PSF.overexposedMaxFraction,
simulParameters, //SIMUL, //simulation parameters
mapFFTsize, // MAP_FFT_SIZE, // scanImageForPatterns:FFT size int mapFFTsize, // scanImageForPatterns:FFT size
......@@ -1325,7 +1326,7 @@ public class EyesisAberrations {
fft_overlap, //FFT_OVERLAP, // int fft_overlap,
fft_size, // FFT_SIZE, // int fft_size,
colorComponents, //COMPONENTS, // ColorComponents colorComponents,
PSF_subpixel, //PSF_SUBPIXEL, // int PSF_subpixel,
PSF_subpixel, //PSF_SUBPIXEL, // int PSF_subpixel,
otfFilterParameters, // OTF_FILTER, // OTFFilterParameters otfFilterParameters,
psfParameters, //PSF_PARS, // final PSFParameters psfParameters
psfParameters.minDefinedArea , //PSF_PARS.minDefinedArea, // final double minDefinedArea,
......@@ -1347,20 +1348,20 @@ public class EyesisAberrations {
}
if (iRetry==MaxRetries) {
System.out.println("File "+files[imgNum][1]+ " has problems - finished at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
if (stopRequested.get()>0) {
if (stopRequested.get()>0) {
if (debugLevel>0) System.out.println("User requested stop");
break;
}
continue;
}
ImageStack stack=mergeKernelsToStack(this.pdfKernelMap);
// TODO: Add properties,
// Save configuration (filename with timestamp?) before files from the top class, test directory is writable
if (stack!=null) {
if (debugLevel>0) System.out.println("Saving result to"+files[imgNum][1]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
savePartialKernelStack(
......@@ -1370,11 +1371,11 @@ public class EyesisAberrations {
psfParameters,
correlationSizesUsed);
} else {
System.out.println("File "+files[imgNum][1]+ " has no useful PSF kernels - at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
System.out.println("File "+files[imgNum][1]+ " has no useful PSF kernels - at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
distortions.fittingStrategy.setNoUsefulPSFKernels(fileIndices[imgNum], true); // mark (need to save configuration) not to try them next time
// todo - write a placeholder file (different suffix/prefix) instead of using setNoUsefulPSFKernels()?
// todo - write a placeholder file (different suffix/prefix) instead of using setNoUsefulPSFKernels()?
}
if (stopRequested.get()>0) {
if (stopRequested.get()>0) {
if (debugLevel>0) System.out.println("User requested stop");
break;
}
......@@ -1412,14 +1413,14 @@ public class EyesisAberrations {
}
}
}
ShowDoubleFloatArrays sdfa_instance=new ShowDoubleFloatArrays();
ImagePlus impShow=new ImagePlus("CombinedKernels"); // just to show in the same window?
long startTime=System.nanoTime();
for (int nChn=0; nChn<fileList.length;nChn++) if (fileList[nChn]!=null){
// TODO: add parameters to kernel files
// TODO: add parameters to kernel files
boolean OK=combinePSFKernels (
interpolateParameters, // INTERPOLATE
multiFilePSF , // MULTIFILE_PSF = new EyesisAberrations.MultiFilePSF(
......@@ -1433,7 +1434,7 @@ public class EyesisAberrations {
thisDebugLevel,
globalDebugLevel);
if (OK && (globalDebugLevel>0)) System.out.println("Saved combined kernel for channel "+nChn+" to"+resultPaths[nChn]+ " at "+ IJ.d2s(0.000000001*(System.nanoTime()-startTime),3));
if (stopRequested.get()>0) {
if (stopRequested.get()>0) {
if (globalDebugLevel>0) System.out.println("User requested stop");
break;
}
......@@ -1441,8 +1442,8 @@ public class EyesisAberrations {
}
return true;
}
public boolean combinePSFKernels(
EyesisAberrations.InterpolateParameters interpolateParameters, // INTERPOLATE
EyesisAberrations.MultiFilePSF multiFilePSF , // MULTIFILE_PSF = new EyesisAberrations.MultiFilePSF(
......@@ -1455,7 +1456,7 @@ public class EyesisAberrations {
boolean updateStatus, // UPDATE_STATUS
int thisDebugLevel,
int globalDebugLevel
){
){
double [][][][] psfKernelMap; // will be lost - do we need it outside
double [][][][][] kernelsElllipsePars = new double[filenames.length][][][][]; //x0,y0,a,b,c,area
if (thisDebugLevel>0){
......@@ -1500,7 +1501,7 @@ public class EyesisAberrations {
// int chn, tileY,tileX;
boolean [] channels=new boolean[nChn];
double a;
if (thisDebugLevel>1) {
if (thisDebugLevel>1) {
System.out.println("nFiles="+nFiles);
System.out.println("kWidth="+kWidth);
System.out.println("kHeight="+kHeight);
......@@ -1536,7 +1537,7 @@ public class EyesisAberrations {
}
}
/*
/*
* Combine files - now just average all that are not NaN
*/
int [][] dirs={{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
......@@ -1551,7 +1552,7 @@ public class EyesisAberrations {
if (D.isNaN()) weights[nFile+1][i]=0.0;
}
}
// Set weight to 0.5 if it has zero cells around
// Set weight to 0.5 if it has zero cells around
for (int tileY=0;tileY<kHeight;tileY++) for (int tileX=0;tileX<kWidth;tileX++) {
int index=tileY*kWidth+tileX;
if ( weights[nFile+1][index]>0.0){
......@@ -1562,8 +1563,8 @@ public class EyesisAberrations {
weights[nFile+1][index]=0.5; // multiFilePSF.weightOnBorder; //0.5->0.01;
}
}
}
weights[0][index]+=weights[nFile+1][index];
}
weights[0][index]+=weights[nFile+1][index];
}
}
if (thisDebugLevel>1) sdfa_instance.showArrays(weights, kWidth, kHeight, true, "weights0");
......@@ -1581,7 +1582,7 @@ public class EyesisAberrations {
for (int nFile=0;nFile<nFiles;nFile++) weightsMasked[0][i]+=weightsMasked[nFile+1][i];
}
if (thisDebugLevel>1) sdfa_instance.showArrays(weightsMasked, kWidth, kHeight, true, "weightsMasked");
double [][][] psfRadius=c[5]; // later may remove all other calculations for c[i]?
double [][][] pxfCenterX=c[0]; // some outlayer kernels have large x/y shift with normal radius - remove them too
double [][][] pxfCenterY=c[1];
......@@ -1599,7 +1600,7 @@ public class EyesisAberrations {
int samplesAfterAll= totalNumSamples - ((int) Math.floor(multiFilePSF.maxFracDiscardAll*totalNumSamples));
int numSamples=totalNumSamples;
while (numSamples>samplesAfterAll){ // calculate and remove worst sample until it is close enough to the average or too few samples are left
boolean removeOnlyWorse=numSamples>samplesAfterWorse;
for (int color=0;color<nChn;color++){
......@@ -1634,9 +1635,9 @@ public class EyesisAberrations {
" sumWeights="+IJ.d2s(sumWeights,3));
*/
if (sumWeights>0.0) for (int color=0;color<nChn;color++) {
radiusRatio[color][0][index]/=sumWeights; // average radius, without border-over-non-border cells
pxfCenterX[color][0][index]/=sumWeights;
pxfCenterY[color][0][index]/=sumWeights;
radiusRatio[color][0][index]/=sumWeights; // average radius, without border-over-non-border cells
pxfCenterX[color][0][index]/=sumWeights;
pxfCenterY[color][0][index]/=sumWeights;
}
double [] diffs=new double[nFiles];
double [] diffsXY2=new double[nFiles];
......@@ -1703,18 +1704,18 @@ public class EyesisAberrations {
" worstDiff="+IJ.d2s(worstDiff,3)+
" removeOnlyWorse="+removeOnlyWorse+
" worstFile="+worstFile+" ("+filenames[worstFile]+")");
System.out.println(
" this radius ={"+psfRadius[0][worstFile+1][index]+","+psfRadius[1][worstFile+1][index]+","+psfRadius[2][worstFile+1][index]+"}\n"+
" mean radius ={"+radiusRatio[0][0][index]+","+radiusRatio[1][0][index]+","+radiusRatio[2][0][index]+"}\n"+
" this center X={"+pxfCenterX[0][worstFile+1][index]+","+pxfCenterX[1][worstFile+1][index]+","+pxfCenterX[2][worstFile+1][index]+"}\n"+
" mean center X={"+pxfCenterX[0][0][index]+","+pxfCenterX[1][0][index]+","+pxfCenterX[2][0][index]+"}\n"+
" this center Y={"+pxfCenterY[0][worstFile+1][index]+","+pxfCenterY[1][worstFile+1][index]+","+pxfCenterY[2][worstFile+1][index]+"}\n"+
" mean center Y={"+pxfCenterY[0][0][index]+","+pxfCenterY[1][0][index]+","+pxfCenterY[2][0][index]+"}");
}
if (numSamples<1) break; // nothing left
if (numSamples<1) break; // nothing left
if (worstDiff>multiFilePSF.radiusDiffHigh){
if ( (numSamples==1) && (globalDebugLevel>0)){
System.out.println("PSF size for the cell "+tileX+":"+tileY+", file# "+worstFile+" varies too much from the neighbor cells, so it is removed, creating a gap");
......@@ -1733,14 +1734,14 @@ public class EyesisAberrations {
weights[0][index]+=weights[nFile+1][index];
}
}
// for each channel, each cell - compare radius calculated for neighbors (use masked weights) and the cell
// TODO: Filter out outlayers: Add bonus to cells surrounded by others?
// double [][][][] c= new double[numResults][nChn][nFiles+1][kLength];
// double [][][] numVals=new double[numResults][nChn][kLength];
for (int chn=0;chn<nChn;chn++) {
......@@ -1767,9 +1768,9 @@ public class EyesisAberrations {
for (int i=0;i<kLength;i++){
if (numVals[nOut][chn][i]==0.0 )c[nOut][chn][0][i]=Double.NaN;
// else c[nOut][chn][0][i]/=numVals[nOut][chn][i];
}
}
}
if (multiFilePSF.validateShowEllipse) {
sdfa_instance.showArrays(radiusRatio[chn], kWidth, kHeight, true, "ratio-"+chn);
sdfa_instance.showArrays(c[5][chn],kWidth, kHeight, true, "radius-"+chn);
......@@ -1780,7 +1781,7 @@ public class EyesisAberrations {
sdfa_instance.showArrays(c[3][chn], kWidth, kHeight, true, "y2-"+chn);
sdfa_instance.showArrays(c[4][chn], kWidth, kHeight, true, "xy-"+chn);
sdfa_instance.showArrays(c[6][chn], kWidth, kHeight, true, "area-"+chn);
}
}
}
}
......@@ -1813,7 +1814,7 @@ public class EyesisAberrations {
int filledMissing=0;
//Finalize accumulated kernels - transform them from frequency to space domain
inverseTransformKernels(psfKernelMap);
// should be done after inversion, because filled in kernels are just pointers to original ones
// should be done after inversion, because filled in kernels are just pointers to original ones
if (multiFilePSF.fillMissing) filledMissing=fillMissingKernels (psfKernelMap);
int numMissing=0;
ImageStack mergedStack= mergeKernelsToStack(psfKernelMap,originalSliceLabels);
......@@ -1831,9 +1832,9 @@ public class EyesisAberrations {
for (int tileY=0;tileY<kHeight;tileY++) for (int tileX=0;tileX<kWidth;tileX++) if ((psfKernelMap[tileY][tileX]==null) || (psfKernelMap[tileY][tileX][0]==null)) numMissing++;
ImagePlus imp_psf = new ImagePlus(resultPath, mergedStack);
if (impProtoIndex>=0){
imp_sel=opener.openImage("", filenames[impProtoIndex]);
imp_sel=opener.openImage("", filenames[impProtoIndex]);
jp4_instance.decodeProperiesFromInfo(imp_sel);
// copy properties from the source image
jp4_instance.copyProperties (imp_sel,imp_psf);
......@@ -1889,7 +1890,7 @@ public class EyesisAberrations {
}
return true;
}
private int fillMissingKernels(double [][][][] kernels){
int [][] dirs={{-1,0},{1,0},{0,-1},{0,1}};
List <Integer> kernelList=new ArrayList<Integer>(100);
......@@ -1908,7 +1909,7 @@ public class EyesisAberrations {
(kernels[newTileY][newTileX]!=null) && (kernels[newTileY][newTileX][0]!=null) ) {
kernelList.add(Index);
}
}
}
numMissing++;
}
}
......@@ -1930,7 +1931,7 @@ public class EyesisAberrations {
Index=newTileY*width+newTileX;
kernelList.add(Index);
} else if ((kernels[tileY][tileX]==null) || (kernels[tileY][tileX][0]==null)) { // may be already added
// need to copy - they will be subject to reverse fht ?
// need to copy - they will be subject to reverse fht ?
kernels[tileY][tileX]=kernels[newTileY][newTileX];
System.out.println("fillMissingKernels: filled "+tileX+"/"+tileY);
}
......@@ -1940,9 +1941,9 @@ public class EyesisAberrations {
}
return numMissing;
}
/* ======================================================================== */
//Finalize accumulated kernels - transform them from frequency to space domain
public void inverseTransformKernels(
......@@ -1960,9 +1961,9 @@ public class EyesisAberrations {
}
// Will build global PSF_KERNEL_MAP (each [][][]element should be set to null?
// kernels are supposed to be normalized?
public void accumulatePartialKernelStack(
......@@ -1993,7 +1994,7 @@ public class EyesisAberrations {
boolean debugThis= (index==debugIndex) && (debugLevel>1);
if (theseWeights[index]>0.0){
extractOneKernel(
pixels, // array of combined square kernels, each
pixels, // array of combined square kernels, each
kernel, // will be filled, should have correct size before call
tilesX, // number of kernels in a row
tileX, // horizontal number of kernel to extract
......@@ -2025,8 +2026,8 @@ public class EyesisAberrations {
}
}
public double [][][][] kernelStackToEllipseCoefficients(
ImageStack kernelStack, // Image stack, each slice consists of square kernels of one channel
int size, // size of each kernel (should be square)
......@@ -2044,7 +2045,7 @@ public class EyesisAberrations {
int tileY,tileX, chn; //,subTileY,subTileX;
double [][][][] ellipseCoeffs=new double [tilesY][tilesX][nChn][];
int length=size*size;
double [] kernel=new double[length];
double [] kernel=new double[length];
double max;
int [][]selection;
double [] ec;
......@@ -2053,7 +2054,7 @@ public class EyesisAberrations {
pixels=(float[]) kernelStack.getPixels(chn+1);
for (tileY=0;tileY<tilesY;tileY++) for (tileX=0;tileX<tilesX;tileX++) {
extractOneKernel(
pixels, // array of combined square kernels, each
pixels, // array of combined square kernels, each
kernel, // will be filled, should have correct size before call
tilesX, // number of kernels in a row
tileX, // horizontal number of kernel to extract
......@@ -2080,11 +2081,11 @@ public class EyesisAberrations {
}
return ellipseCoeffs;
}
}
/* ======================================================================== */
private void extractOneKernel(
float [] pixels, // array of combined square kernels, each
float [] pixels, // array of combined square kernels, each
double [] kernel, // will be filled, should have correct size before call
int numHor, // number of kernels in a row
int xTile, // horizontal number of kernel to extract
......@@ -2104,12 +2105,12 @@ public class EyesisAberrations {
for (i=0;i<size;i++) for (j=0;j<size;j++) kernel [i*size+j]=pixels[base+i*pixelsWidth+j];
}
//=======================================================
//=======================================================
public void savePartialKernelStack(
String path,
ImageStack stack,
......@@ -2148,9 +2149,9 @@ public class EyesisAberrations {
FileSaver fs=new FileSaver(impPsf);
fs.saveAsTiffStack(path);
}
private ImageStack mergeKernelsToStack(double [][][][] kernels) {
return mergeKernelsToStack(kernels,null);
......@@ -2223,7 +2224,7 @@ public class EyesisAberrations {
public double [][][][] createPSFMap(
final MatchSimulatedPattern commonMatchSimulatedPattern, // to be cloned in threads, using common data
final ImagePlus imp_sel, // linearized Bayer mosaic image from the camera, GR/BG
final int [][][] sampleList, // optional (or null) 2-d array: list of coordinate pairs (2d - to match existent pdfKernelMap structure)
final int [][][] sampleList, // optional (or null) 2-d array: list of coordinate pairs (2d - to match existent pdfKernelMap structure)
final double overexposedAllowed, // fraction of pixels OK to be overexposed
final SimulationPattern.SimulParameters simulParameters,
final int mapFFTsize, // scanImageForPatterns:FFT size
......@@ -2231,7 +2232,7 @@ public class EyesisAberrations {
final int fft_overlap,
final int fft_size,
final ColorComponents colorComponents,
final int PSF_subpixel,
final int PSF_subpixel,
final OTFFilterParameters otfFilterParameters,
final PSFParameters psfParameters,
final double minDefinedArea,
......@@ -2250,7 +2251,7 @@ public class EyesisAberrations {
runtime.gc();
if (globalDebugLevel>1) System.out.println("--- Free memory="+runtime.freeMemory()+" (of "+runtime.totalMemory()+")");
// Generate hi-res pattern bitmap (one cell)
// Generate hi-res pattern bitmap (one cell)
SimulationPattern simulationPattern= new SimulationPattern();
simulationPattern.debugLevel=globalDebugLevel;
final double [] bitmaskPattern= simulationPattern.patternGenerator(simulParameters);
......@@ -2285,7 +2286,7 @@ public class EyesisAberrations {
// globalDebugLevel=debug_level;
simulationPattern.debugLevel=globalDebugLevel;
int ncell=0;
/* Create array of coordinates of cells to process, fill result array with zeros (to be actually written by threads */
/* Create array of coordinates of cells to process, fill result array with zeros (to be actually written by threads */
final int [][] tilesToProcessXY=new int [numPatternCells][4];
for (nTileY=0;nTileY<PSFBooleanMap.length;nTileY++) for (nTileX=0;nTileX<PSFBooleanMap[0].length;nTileX++){
......@@ -2309,16 +2310,17 @@ public class EyesisAberrations {
final double [] overexposed=(overexposedAllowed>0)?JP4_INSTANCE.overexposedMap (imp_sel):null;
final int mapWidth=imp_sel.getWidth();
final AtomicInteger tilesFinishedAtomic = new AtomicInteger(1); // first finished will be 1
final int debugNumColors=6;
final int debugNumColors=6;
for (int ithread = 0; ithread < threads.length; ithread++) {
// Concurrently run in as many threads as CPUs
threads[ithread] = new Thread() {
@Override
public void run() {
// Each thread processes a few items in the total list
// Each loop iteration within the run method has a unique 'i' number to work with
// and to use as index in the results array:
// double [] sum_kern_el=new double[6]; // just testing
// double [] sum_kern_el=new double[6]; // just testing
int x0,y0,nTX,nTY,nChn;
double [][] kernels;
// change to true (first 2 only?) to separate memory arrays for threads
......@@ -2336,7 +2338,7 @@ public class EyesisAberrations {
double [] windowFullFFTSize=matchSimulatedPattern.initWindowFunction(fft_size*PSF_subpixel,gaussWidth); //=initHamming( fft_size*subpixel);
DoubleFHT fht_instance =new DoubleFHT(); // provide DoubleFHT instance to save on initializations (or null)
double over;
// individual per-thread - will be needed when converted to doubleFHT
// individual per-thread - will be needed when converted to doubleFHT
// MatchSimulatedPattern matchSimulatedPattern=new MatchSimulatedPattern(FFT_SIZE);
for (int nTile = ai.getAndIncrement(); nTile < patternCells; nTile = ai.getAndIncrement()) {
nTX=tilesToProcessXY[nTile][0];
......@@ -2360,7 +2362,7 @@ public class EyesisAberrations {
} else {
if (debugLateralShifts) {
debugLateral[nTY][nTX]= new double [debugNumColors][]; // X/Y shift of the PSF array, in Bayer component pixel coordinates (same as PSF arrays)
}
}
kernels=getPSFKernels(imp_sel,
simArray, //simulation image, scaled PSF_subpixel/2
2*fft_size, // size in pixels (twice fft_size)
......@@ -2371,7 +2373,7 @@ public class EyesisAberrations {
patternDetectParameters,
windowFFTSize, //=initHamming( fft_size) calculate once
windowFullFFTSize,//=initHamming( fft_size*subpixel);
PSF_subpixel, // use finer grid than actual pixels
PSF_subpixel, // use finer grid than actual pixels
simulParameters,
colorComponents, // color channels to process, equalizeGreens
otfFilterParameters,
......@@ -2399,7 +2401,8 @@ public class EyesisAberrations {
}
final int numFinished=tilesFinishedAtomic.getAndIncrement();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
@Override
public void run() {
IJ.showProgress(numFinished,patternCells);
}
});
......@@ -2436,7 +2439,7 @@ public class EyesisAberrations {
for (nTileY=0;nTileY<debugLateral.length;nTileY++) for (nTileX=0;nTileX<debugLateral[0].length;nTileX++) if (debugLateral[nTileY][nTileX]!=null){
if (debugLateral[nTileY][nTileX][cIndex[j]]!=null) dbgLat[layer][nTileY*debugLateral[0].length+nTileX]=debugLateral[nTileY][nTileX][cIndex[j]][i];
} layer++;
}
}
SDFA_INSTANCE.showArrays(dbgLat, debugLateral[0].length, debugLateral.length, true, "lateral"+imp_sel.getTitle(), debugTitles);
/*
debugLateralTile[i][0]=lateralChromatic[i][0];
......@@ -2485,7 +2488,7 @@ public class EyesisAberrations {
}
return pixels;
}
/*
/*
private double [] combineDiagonalGreens (double [] green0, double []green3, int half_width, int half_height) {
int y,x,base;
int base_b=0;
......@@ -2534,7 +2537,7 @@ public class EyesisAberrations {
return pixels;
}
/* inserts zeros between pixels */
/* inserts zeros between pixels */
private double [][] oversampleFFTInput (double[][] input_pixels,
int ratio) {
double [][] pixels=new double[input_pixels.length][];
......@@ -2640,7 +2643,7 @@ public class EyesisAberrations {
MatchSimulatedPattern.PatternDetectParameters patternDetectParameters,
double [] Hamming, //=initHamming( fft_size) calculate once
double [] fullHamming, //=initHamming( fft_size*subpixel);
int subpixel, // use finer grid than actual pixels
int subpixel, // use finer grid than actual pixels
SimulationPattern.SimulParameters simulParameters,
EyesisAberrations.ColorComponents colorComponents,
EyesisAberrations.OTFFilterParameters otfFilterParameters,
......@@ -2654,7 +2657,7 @@ public class EyesisAberrations {
){
boolean debugThis=false; //(y0==384) && ((x0==448) || (x0==512));
if (globalDebugLevel>1){
System.out.println("getPSFKernels(), simArray is "+((simArray==null)?"":"not ")+"null");
System.out.println("getPSFKernels(), simArray is "+((simArray==null)?"":"not ")+"null");
}
if (imp==null) return null; // Maybe convert to double pixel array once to make it faster?
......@@ -2669,16 +2672,18 @@ public class EyesisAberrations {
double [][] simul_pixels;
double [][]wVectors=new double[2][2];
int imgWidth=imp.getWidth();
double [][] dbgSimPix=null;
double [] localBarray;
if ((simArray==null) || (psfParameters.approximateGrid)){ // just for testing
/* Calculate pattern parameters, including distortion */
if (matchSimulatedPattern.PATTERN_GRID==null) {
double[][] distortedPattern= matchSimulatedPattern.findPatternDistorted(input_bayer, // pixel array to process (no windowing!)
patternDetectParameters,
patternDetectParameters.minGridPeriod/2,
patternDetectParameters.maxGridPeriod/2,
true, //(greensToProcess==4), // boolean greens, // this is a pattern for combined greens (diagonal), adjust results accordingly
title); // title prefix to use for debug images
......@@ -2765,10 +2770,10 @@ public class EyesisAberrations {
if (!colorComponents.colorsToCorrect[i]) simul_pixels[i]=null; // removed unused
}
simul_pixels= normalizeAndWindow (simul_pixels, fullHamming);
} else {
Rectangle PSFCellSim=new Rectangle (x0*subpixel/2,y0*subpixel/2,size*subpixel/2,size*subpixel/2);
simul_pixels=new double[6][];
// simulationPattern.debugLevel=globalDebugLevel;
for (i=0;i<simul_pixels.length; i++) {
......@@ -2783,7 +2788,7 @@ public class EyesisAberrations {
//System.out.println("PSFCell.y="+PSFCell.y+" PSFCell.height="+PSFCell.height+" imgWidth="+imgWidth+" PSFCell.x="+PSFCell.x+" PSFCell.width="+PSFCell.width+" matchSimulatedPattern.UV_INDEX.length="+matchSimulatedPattern.UV_INDEX.length);
int index=matchSimulatedPattern.getUVIndex((PSFCell.y+PSFCell.height/2)*imgWidth+(PSFCell.x+PSFCell.width/2));
// int index=matchSimulatedPattern.getUVIndex((PSFCell.y+PSFCell.height/2)*matchSimulatedPattern.getWOI().width+(PSFCell.x+PSFCell.width/2));
if (index<0) {
System.out.println ("Error, No UV pattern @ x="+(PSFCell.x+PSFCell.width/2)+", y="+(PSFCell.y+PSFCell.height/2));
return null;
......@@ -2806,7 +2811,7 @@ public class EyesisAberrations {
//TODO: Need to define wave vectors here - how?
wVectors[0]=matchSimulatedPattern.getDArray(iUV[1],iUV[0],1); //null pointer
wVectors[1]=matchSimulatedPattern.getDArray(iUV[1],iUV[0],2);
// should it be averaged WV?
// should it be averaged WV?
if (globalDebugLevel>2) System.out.println ( " x0="+x0+" y0="+y0);
if (globalDebugLevel>2) SDFA_INSTANCE.showArrays(input_bayer, true, title+"-in");
if (globalDebugLevel>2) SDFA_INSTANCE.showArrays(simul_pixels, true, title+"-S");
......@@ -2820,7 +2825,7 @@ public class EyesisAberrations {
}
simul_pixels= normalizeAndWindow (simul_pixels, fullHamming);
}
input_bayer= normalizeAndWindow (input_bayer, Hamming);
if (subpixel>1) {
input_bayer= oversampleFFTInput (input_bayer,subpixel);
......@@ -2902,7 +2907,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
System.out.println(x0+":"+y0+"1-PSF_shifts.length= "+PSF_shifts.length+" i="+i+" input_bayer.length="+input_bayer.length);
System.out.println("Before: color Component "+i+" PSF_shifts["+i+"][0]="+IJ.d2s(PSF_shifts[i][0],3)+
" PSF_shifts["+i+"][1]="+IJ.d2s(PSF_shifts[i][1],3));
}
}
kernels[i]=combinePSF (inverted[i], // Square array of pixels with multiple repeated PSF (alternating sign)
......@@ -2938,7 +2943,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
System.out.println(x0+":"+y0+"Before: color Component "+i+" PSF_shifts["+i+"][0]="+IJ.d2s(PSF_shifts[i][0],3)+
" PSF_shifts["+i+"][1]="+IJ.d2s(PSF_shifts[i][1],3));
}
}
kernels[i]=combinePSF (inverted[i], // Square array of pixels with multiple repeated PSF (alternating sign)
false, // !master, use ignoreChromatic
PSF_shifts[i], // centerXY[] - will be modified inside combinePSF() if psfParameters.ignoreChromatic is true
......@@ -2992,8 +2997,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
} else {
debugLateralTile[i]=null;
}
}
if (debugThis && (kernels!=null)){
int debugSize=0;
......@@ -3116,7 +3121,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
int debug,
int globalDebugLevel,
String title){
double [] denominatorPixels= forward_OTF? modelPixels.clone(): measuredPixels.clone();
double [] nominatorPixels= forward_OTF? measuredPixels.clone(): modelPixels.clone();
if (fht_instance==null) fht_instance=new DoubleFHT(); // move upstream to reduce number of initializations
......@@ -3170,7 +3175,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
SDFA_INSTANCE.showArrays(mask1, "M1A-"+title);
}
}
/* Mask already includes zeros on ps, so we can just use divisions of FHT*/
/* Mask already includes zeros on ps, so we can just use divisions of FHT*/
//Swapping quadrants of the nominator, so the center will be 0,0
fht_instance.swapQuadrants(nominatorPixels);
//get to frequency domain
......@@ -3178,11 +3183,11 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if ((debug>2) ||((globalDebugLevel>2) && (title!=""))) { /* Increase debug evel later */ // was 3
SDFA_INSTANCE.showArrays(nominatorPixels, title+"-NOM-FHT");
SDFA_INSTANCE.showArrays(denominatorPixels, title+"-DENOM-FHT");
}
}
double [] pixels=fht_instance.divide(nominatorPixels,denominatorPixels);
if ((debug>2) ||((globalDebugLevel>2) && (title!=""))) { /* Increase debug evel later */ // was 3
SDFA_INSTANCE.showArrays(pixels, title+"-DECONV");
}
}
for (i=0;i<pixels.length;i++) {
if (mask[i]==0.0) pixels[i]=0.0; // preventing NaN*0.0
else pixels[i]*=mask[i];
......@@ -3191,7 +3196,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
SDFA_INSTANCE.showArrays(pixels, title+"-MASKED");
double [][] aphase=fht_instance.fht2AmpHase(pixels,true);
SDFA_INSTANCE.showArrays(aphase, true,"AP="+title+"-MASKED");
}
if (gaps_sigma>0.0){
double [][] fft_reIm_centered=fht_instance.fht2ReIm(pixels, true); //0 in the center, full square
......@@ -3210,7 +3215,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
fht_instance.swapQuadrants(fft_reIm_centered[0]); // zero in the corner
fht_instance.swapQuadrants(fft_reIm_centered[1]); // zero in the corner
pixels=fht_instance.FFTHalf2FHT(fft_reIm_centered, size);
//mask_denoise
//mask_denoise
}
/// transform to space
fht_instance.inverseTransform(pixels);
......@@ -3278,7 +3283,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
cloneY=(iy+cloneNy*cloneStep)%size;
cloneX=(ix+cloneNx*cloneStep)%size;
mask[cloneY*size+cloneX]+=psWithZero[iy*size+ix];
}
}
}
/* debug show the mask */
if (globalDebugLevel>2) SDFA_INSTANCE.showArrays(mask, "PS-cloned");
......@@ -3300,14 +3305,14 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
a=(2.0 * mask[i] - th - tl)/(th - tl);
mask[i]=0.5*(1.0-a*a*a);
}
// now mask out zeros on the ps
// now mask out zeros on the ps
if (ps[i]<min) mask[i]=0.0;
else {
mask[i]*=ps[i]/(ps[i]+k2);
}
}
if (globalDebugLevel>2) SDFA_INSTANCE.showArrays(mask, "mask-all");
/* zeros are now for FHT - in the top left corner */
/* zeros are now for FHT - in the top left corner */
fht_instance.swapQuadrants(mask);
return mask;
}
......@@ -3335,7 +3340,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
for (index=0;index<len;index++) absThresh+=windowFunction[index];
absThresh*=threshold;
if (debugLevel>1) System.out.println(" threshold="+threshold+" absThresh="+absThresh);
int y,x,y0,x0;
for (int tileY=0;tileY<tileHeight;tileY++) for (int tileX=0;tileX<tileWidth;tileX++) {
y0=-tileSize/2+margin+tileStep*tileY;
......@@ -3353,19 +3358,19 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
return result;
}
/* ========================================================================
/* ========================================================================
/**
* Mostly done, need to move where szis\
* TODO: currently the shift of the PSF during binning is done with the integer steps. If ignoreChromatic - to all colors
* independently, if it is false - all components are moved in sync, but again - with integer steps. That causes
* mis-match between the PSF calculated in nearly identical runs (i.e. use the data shifted by 2 pixels) caused by 1 pixel shift.
* That can be improved if PSF are shifted smoothly (not so easy though). It is probably already handled when averaging PSF -
* That can be improved if PSF are shifted smoothly (not so easy though). It is probably already handled when averaging PSF -
* amplitude and phase is handled separately so shift should be OK.
*
*
*/
double [] combinePSF (double []pixels, // Square array of pixels with multiple repeated PSF (alternating sign)
boolean master, // force ignoreChromatic
double[] centerXY, // coordinates (x,y) of the center point (will update if ignoreChromatic is true)
......@@ -3439,17 +3444,17 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
debug,
debugLevel);
// true);
if (!master && !psfParameters.ignoreChromatic && !psfParameters.absoluteCenter && psfParameters.centerPSF && (centerXY!=null)){
// System.out.println("1:pixelsPSF.length="+pixelsPSF.length+" outSize+"+outSize);
// TODO: Shift +/- 0.5 Pix here {centerXY[0]-Math.round(centerXY[0]),centerXY[1]-Math.round(centerXY[1])}
// TODO: Shift +/- 0.5 Pix here {centerXY[0]-Math.round(centerXY[0]),centerXY[1]-Math.round(centerXY[1])}
if (fht_instance==null) fht_instance=new DoubleFHT();
// fht_instance.debug=(centerXY[0]-Math.round(centerXY[0]))<-0.4; // just reducing number
// double dx=centerXY[0]-Math.round(centerXY[0]);
// double dy=centerXY[1]-Math.round(centerXY[1]);
// if (dx<-0.4) SDFA_INSTANCE.showArrays(pixelsPSF.clone(), "before:"+dx+":"+dy);
pixelsPSF=fht_instance.translateSubPixel (
pixelsPSF,
-(centerXY[0]-Math.round(centerXY[0])),
......@@ -3515,7 +3520,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
debugLevel);
if (psfParameters.centerPSF && (centerXY!=null)){
// System.out.println("2:pixelsPSF.length="+pixelsPSF.length+" outSize+"+outSize);
// TODO: Shift +/- 0.5 Pix here {centerXY[0]-Math.round(centerXY[0]),centerXY[1]-Math.round(centerXY[1])}
// TODO: Shift +/- 0.5 Pix here {centerXY[0]-Math.round(centerXY[0]),centerXY[1]-Math.round(centerXY[1])}
if (fht_instance==null) fht_instance=new DoubleFHT();
// fht_instance.debug=(centerXY[0]-Math.round(centerXY[0]))<-0.4; // just reducing number
pixelsPSF=fht_instance.translateSubPixel (
......@@ -3549,14 +3554,14 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (debugLevel>2) System.out.println("Centroid after second binPSF: x="+IJ.d2s(centroidXY[0],3)+" y="+IJ.d2s(centroidXY[1],3)+" center was at x="+IJ.d2s(centerXY[0],3)+" y="+IJ.d2s(centerXY[1],3));
}
/* compensate center point and/or add center-symmetrical points if enabled */
double [] rejectedClonesPixels=null;
double [][] modelPSFVectors={{0.5*(g[0][0]+g[1][0]),0.5*(g[0][1]+g[1][1])},
{0.5*(g[0][0]-g[1][0]),0.5*(g[0][1]-g[1][1])}};
/********* removed subtraction of clones *****************************************************************/
/********* removed subtraction of clones *****************************************************************/
rejectedClonesPixels=pixelsPSF; // Maybe fo the opposite?
maskClonesPSF(rejectedClonesPixels, // square pixel array where the model PSF is added
psfParameters.windowFrac, // multiply window by this value
......@@ -3578,7 +3583,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
centroidXY[0], // model PSF center X-coordinate (in pixels[] units, from the center of the array )
centroidXY[1], // same for Y
0, // int WOICenterX, // window of interest in pixels[] array - do not generate data outside it
0, // int WOICenterY, //
0, // int WOICenterY, //
outSize, //int WOIWidth, reduce later
outSize); //int WOIHeight)
......@@ -3590,14 +3595,14 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
for (i=0;i<sigmas.length;i++) {
kk=smoothPixelsPSF[i]/max1;
if (kk>varSigmaTop) sigmas[i]=minSigma;
if (kk>varSigmaTop) sigmas[i]=minSigma;
else sigmas[i] = minSigma+ sigmas[i]*((varSigmaTop-kk)*(varSigmaTop-kk)/varSigmaTop/varSigmaTop);
}
double [] varFilteredPSF=variableGaussBlurr(rejectedClonesPixels, // input square pixel array, preferrably having many exact zeros (they will be skipped)
sigmas, // array of sigmas to be used for each pixel, matches pixels[]
3.5, // drop calculatin if farther then nSigma
0, // int WOICenterX, // window of interest in pixels[] array - do not generate data outside it
0, // int WOICenterY, //
0, // int WOICenterY, //
outSize, //int WOIWidth, reduce later
outSize,
debugLevel); //int WOIHeight)
......@@ -3655,13 +3660,13 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
double [] rslt={a[0]+b[0], a[1]+b[1]};
return rslt;
}
public double [][] matrix2x2_transp(double [][] m ){
double [][] rslt= {{ m[0][0], m[1][0]},
{ m[0][1], m[1][1]}};
return rslt;
}
/* ======================================================================== */
/* zeroes out area outside of the area bound by 4 negative clones (or a fraction of it), either sharp or with Hamming */
private double [] maskClonesPSF(double [] pixels, // square pixel array where the model PSF is added
......@@ -3697,7 +3702,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
double []sigmas, // array of sigmas to be used for each pixel, matches pixels[]
double nSigma, // drop calculatin if farther then nSigma
int WOICenterX, // window of interest in pixels[] array - do not generate data outside it
int WOICenterY, //
int WOICenterY, //
int WOIWidth, //
int WOIHeight,
int globalDebugLevel){ //
......@@ -3760,9 +3765,9 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
return result;
}
/* ======================================================================== */
/* find ellipse approximating section of the PSF, scale ellipse and use it as a mask to remove PSF far wings */
private double [] cutPSFWings (double [] psf_pixels, // direct PSF function, square array, may be proportionally larger than reversed
......@@ -3866,7 +3871,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
double xc, // model PSF center X-coordinate (in pixels[] units, from the center of the array )
double yc, // same for Y
int WOICenterX, // window of interest in pixels[] array - do not generate data outside it
int WOICenterY, //
int WOICenterY, //
int WOIWidth, //
int WOIHeight) {
int size = (int) Math.sqrt(pixels.length);
......@@ -4000,11 +4005,11 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
return result;
}
/* ======================================================================== */
/* finds cluster on the PSF (with the center at specidfied point) by flooding from the specified center, so total energy is cutoff_energy fraction
returns integer array (same dimensions as input) with 1 - selected, 0 - not selected
cutoff_energy: if positive - specifies fraction of total energy, if negative -cutoff_energy is the minimal value of the pixel to be included
cutoff_energy: if positive - specifies fraction of total energy, if negative -cutoff_energy is the minimal value of the pixel to be included
UPDATE: follows gradient from the start point to a local maximum if "cutoff_energy" is negative" */
private int [][] findClusterOnPSF(
double [] psf, // PSF function, square array
......@@ -4148,7 +4153,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
ImageProcessor ip = new FloatProcessor(size,size);
float [] floatPixels = new float [size*size];
for (i=0;i<floatPixels.length;i++) {
floatPixels[i]=(float) clusterMap[i/size][i%size];
floatPixels[i]=clusterMap[i/size][i%size];
}
ip.setPixels(floatPixels);
ip.resetMinAndMax();
......@@ -4219,7 +4224,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
private double [] binPSF(double [] pixels,
double [][] g,
int outSize,
// int decimate, // sub-pixel decimation
// int decimate, // sub-pixel decimation
double minContrast,
double [] centerXY, // coordinates (x,y) of the center point (will be alway subtracted)
double[] symmXY, // coordinates (x,y) of the center of symmetry (to combine with 180 if enabled by symm180)
......@@ -4242,9 +4247,9 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
double [][] xy2uv= {{-2.0*g[0][1]/det_g, 2.0*g[0][0]/det_g},
{-2.0*g[1][1]/det_g, 2.0*g[1][0]/det_g}};
double [][] uv2xy= matrix2x2_scale(matrix2x2_invert(xy2uv),2); // real pixels are twice
double [] pixelsPSF =new double [outSize*outSize];
double [] pixelsPSF =new double [outSize*outSize];
int [] pixelsPSFCount =new int [outSize*outSize];
double [] pixelsPSFWeight =new double [outSize*outSize];
double [] pixelsPSFWeight =new double [outSize*outSize];
double [] center=centerXY;
for (i=0;i<contrastCache.length;i++) {
contrastCache[i]=-1.0;
......@@ -4305,7 +4310,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
/* Do binning itself here */
d=PSF_sign*PSFAtXY(pixels, pixelSize, x,y);
/* map to the segment around 0,0 */
/* map to the segment around 0,0 */
dp=p/2-Math.round(p/2);
dq=q/2-Math.round(q/2);
/* dp, dq are between +/- 0.5 - use them for Hamming windowing -NOT HERE, moved later*/
......@@ -4404,20 +4409,20 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (debug) {
SDFA_INSTANCE.showArrays(debugPixels, title+"_mask_PSF");
double [] doublePixelsPSFCount=new double [pixelsPSF.length];
for (j=0;j<doublePixelsPSFCount.length;j++) doublePixelsPSFCount[j]=(double)pixelsPSFCount[j];
for (j=0;j<doublePixelsPSFCount.length;j++) doublePixelsPSFCount[j]=pixelsPSFCount[j];
SDFA_INSTANCE.showArrays(doublePixelsPSFCount, title+"_PSF_bin_count");
SDFA_INSTANCE.showArrays(pixelsPSFWeight, title+"_PSF_bin_weight");
double [] doubleContrastCache=new double [contrastCache.length];
for (j=0;j<doubleContrastCache.length;j++) doubleContrastCache[j]=(double)((contrastCache[j]>=0.0)?contrastCache[j]:-0.00001);
for (j=0;j<doubleContrastCache.length;j++) doubleContrastCache[j]=(contrastCache[j]>=0.0)?contrastCache[j]:-0.00001;
SDFA_INSTANCE.showArrays(doubleContrastCache, title+"_ContrastCache");
}
return pixelsPSF;
}
/* ======================================================================== */
/* Create a Thread[] array as large as the number of processors available.
* From Stephan Preibisch's Multithreading.java class. See:
......@@ -4441,7 +4446,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
try
{
{
for (int ithread = 0; ithread < threads.length; ++ithread)
threads[ithread].join();
} catch (InterruptedException ie)
......@@ -4466,7 +4471,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public boolean fillMissing; // replace missing kernels with neighbors
public MultiFilePSF (
double overexposedMaxFraction,
double weightOnBorder,
double weightOnBorder,
double radiusDiffLow, // do not remove partial kernel cell if radius differs from average less than by this fraction
double radiusDiffHigh, // remove this cell even if it is the only one
double shiftToRadiusContrib, // Center shift (in pixels) addition to the difference relative to radius difference (in pixels)
......@@ -4480,7 +4485,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
boolean fillMissing
) {
this.overexposedMaxFraction=overexposedMaxFraction;
this.weightOnBorder=weightOnBorder;
this.weightOnBorder=weightOnBorder;
this.radiusDiffLow=radiusDiffLow; // do not remove partial kernel cell if radius differs from average less than by this fraction
this.radiusDiffHigh=radiusDiffHigh; // remove this cell even if it is the only one
this.shiftToRadiusContrib=shiftToRadiusContrib; // Center shift (in pixels) addition to the difference relative to radius difference (in pixels)
......@@ -4525,7 +4530,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
properties.setProperty(prefix+"showWeights",this.showWeights+"");
properties.setProperty(prefix+"fillMissing",this.fillMissing+"");
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"overexposedMaxFraction")!=null) this.overexposedMaxFraction=Double.parseDouble(properties.getProperty(prefix+"overexposedMaxFraction"));
if (properties.getProperty(prefix+"weightOnBorder")!=null) this.weightOnBorder=Double.parseDouble(properties.getProperty(prefix+"weightOnBorder"));
......@@ -4544,7 +4549,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (properties.getProperty(prefix+"validateShowEllipse")!=null)this.validateShowEllipse=Boolean.parseBoolean(properties.getProperty(prefix+"validateShowEllipse"));
if (properties.getProperty(prefix+"showWeights")!=null)this.showWeights=Boolean.parseBoolean(properties.getProperty(prefix+"showWeights"));
if (properties.getProperty(prefix+"fillMissing")!=null)this.fillMissing=Boolean.parseBoolean(properties.getProperty(prefix+"fillMissing"));
}
}
......@@ -4582,15 +4587,15 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public String aberrationsPrefix="kernel-";
public String aberrationsSuffix=".kernel-tiff";
public boolean [] selectedChannels=null;
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"sourceDirectory",this.sourceDirectory);
properties.setProperty(prefix+"partialKernelDirectory",this.partialKernelDirectory);
properties.setProperty(prefix+"psfKernelDirectory",this.psfKernelDirectory);
properties.setProperty(prefix+"aberrationsKernelDirectory",this.aberrationsKernelDirectory);
properties.setProperty(prefix+"autoRestore",this.autoRestore+"");
properties.setProperty(prefix+"calibrationPath",this.calibrationPath);
properties.setProperty(prefix+"strategyPath",this.strategyPath);
......@@ -4606,8 +4611,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
properties.setProperty(prefix+"overwriteResultFiles",this.overwriteResultFiles+"");
properties.setProperty(prefix+"partialToReprojected",this.partialToReprojected+"");
properties.setProperty(prefix+"partialCorrectSensor",this.partialCorrectSensor+"");
properties.setProperty(prefix+"seriesNumber",this.seriesNumber+"");
properties.setProperty(prefix+"allImages",this.allImages+"");
......@@ -4627,14 +4632,14 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
properties.setProperty(prefix+"selectedChannels",sSelectedChannels);
}
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"sourceDirectory")!=null) this.sourceDirectory=properties.getProperty(prefix+"sourceDirectory");
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+"autoRestore")!=null) this.autoRestore=Boolean.parseBoolean(properties.getProperty(prefix+"autoRestore"));
if (properties.getProperty(prefix+"calibrationPath")!=null) this.calibrationPath=properties.getProperty(prefix+"calibrationPath");
if (properties.getProperty(prefix+"strategyPath")!=null) this.strategyPath=properties.getProperty(prefix+"strategyPath");
......@@ -4644,7 +4649,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
this.autoRestoreSensorOverwriteOrientation=Boolean.parseBoolean(properties.getProperty(prefix+"autoRestoreSensorOverwriteOrientation"));
if (properties.getProperty(prefix+"autoRestoreSensorOverwriteDistortion")!=null)
this.autoRestoreSensorOverwriteDistortion=Boolean.parseBoolean(properties.getProperty(prefix+"autoRestoreSensorOverwriteDistortion"));
if (properties.getProperty(prefix+"autoReCalibrate")!=null) this.autoReCalibrate=Boolean.parseBoolean(properties.getProperty(prefix+"autoReCalibrate"));
if (properties.getProperty(prefix+"autoReCalibrateIgnoreLaser")!=null) this.autoReCalibrateIgnoreLaser=Boolean.parseBoolean(properties.getProperty(prefix+"autoReCalibrateIgnoreLaser"));
if (properties.getProperty(prefix+"autoFilter")!=null) this.autoFilter=Boolean.parseBoolean(properties.getProperty(prefix+"autoFilter"));
......@@ -4653,8 +4658,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (properties.getProperty(prefix+"overwriteResultFiles")!=null) this.overwriteResultFiles=Boolean.parseBoolean(properties.getProperty(prefix+"overwriteResultFiles"));
if (properties.getProperty(prefix+"partialToReprojected")!=null) this.partialToReprojected=Boolean.parseBoolean(properties.getProperty(prefix+"partialToReprojected"));
if (properties.getProperty(prefix+"partialCorrectSensor")!=null) this.partialCorrectSensor=Boolean.parseBoolean(properties.getProperty(prefix+"partialCorrectSensor"));
if (properties.getProperty(prefix+"seriesNumber")!=null) this.seriesNumber=Integer.parseInt(properties.getProperty(prefix+"seriesNumber"));
if (properties.getProperty(prefix+"allImages")!=null) this.allImages=Boolean.parseBoolean(properties.getProperty(prefix+"allImages"));
if (properties.getProperty(prefix+"sourcePrefix")!=null) this.sourcePrefix=properties.getProperty(prefix+"sourcePrefix");
......@@ -4667,8 +4672,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
if (properties.getProperty(prefix+"interpolatedPSFSuffix")!=null) this.interpolatedPSFSuffix=properties.getProperty(prefix+"interpolatedPSFSuffix");
if (properties.getProperty(prefix+"aberrationsPrefix")!=null) this.aberrationsPrefix=properties.getProperty(prefix+"aberrationsPrefix");
if (properties.getProperty(prefix+"aberrationsSuffix")!=null) this.aberrationsSuffix=properties.getProperty(prefix+"aberrationsSuffix");
if (properties.getProperty(prefix+"selectedChannels")!=null){
String sSelectedChannels=properties.getProperty(prefix+"selectedChannels");
this.selectedChannels=new boolean[sSelectedChannels.length()];
......@@ -4682,7 +4687,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
* for the paths that are not set or did not change from configured
* @return array of 4 paths
*/
public String [] currentConfigPaths(Distortions distortions, boolean combine){
String currentCalibrationPath=null;
String currentStrategyPath=null;
......@@ -4699,7 +4704,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
} else {
// System.out.println("currentConfigPaths():distortions.fittingStrategy==null");
}
currentGridPath=distortions.patternParameters.pathName;
// System.out.println("currentConfigPaths():currentGridPath="+((currentGridPath==null)?"null":currentGridPath));
......@@ -4748,7 +4753,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
}
return this.selectedChannels;
}
public boolean selectChannelsToProcess(String title, Distortions distortions) {
boolean [] newSelecttion=getChannelSelection(distortions).clone(); //java.lang.NullPointerException
......@@ -4771,7 +4776,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
}
public boolean showDialog(String title, Distortions distortions) {
public boolean showDialog(String title, Distortions distortions) {
String [] currentConfigs;
String []nulls={null,null,null,null};
currentConfigs=(distortions!=null)?currentConfigPaths(distortions, false):nulls;
......@@ -4788,19 +4793,19 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
gd.addCheckbox("Overwrite result files if they exist", this.overwriteResultFiles);
gd.addCheckbox("Use reprojected grids for partial kernel calculation (false - extracted grids)", this.partialToReprojected);
gd.addCheckbox("Apply sensor correction during for partial kernel calculation", this.partialCorrectSensor);
gd.addNumericField("Fitting series number to use for image selection", this.seriesNumber,0);
gd.addCheckbox("Process all enabled image files (false - use selected fitting series)", this.allImages);
gd.addMessage("===== Autoload options (when restoring configuration) =====");
gd.addCheckbox("Autoload additional files on \"Restore\"", this.autoRestore);
gd.addCheckbox("Overwrite all (including position/orientation) SFE parameters from the sensor calibration files (at auto-load) DANGEROUS!", this.autoRestoreSensorOverwriteOrientation);
gd.addCheckbox("Overwrite SFE distortion parameters from the sensor calibration files (at auto-load) DANGEROUS!", this.autoRestoreSensorOverwriteDistortion);
gd.addCheckbox("Re-calibrate grids on autoload", this.autoReCalibrate);
gd.addCheckbox("Ignore laser pointers on recalibrate", this.autoReCalibrateIgnoreLaser);
gd.addCheckbox("Filter grids after restore", this.autoFilter);
gd.addCheckbox("Trust enabled images on input (mark as hintedGrid=2)", this.trustEnabled);
gd.addMessage("Calibration: "+(((this.calibrationPath==null) || (this.calibrationPath.length()==0))?"not configured ":(this.calibrationPath+" "))+
((currentConfigs[0]!=null)?("(current: "+currentConfigs[0]+")"):("") ));
gd.addMessage("Strategy: "+(((this.strategyPath==null) || (this.strategyPath.length()==0))?"not configured ":(this.strategyPath+" "))+
......@@ -4821,18 +4826,18 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
gd.addStringField("Interpolated kernels suffix", this.interpolatedPSFSuffix, 40);
gd.addStringField("Inverted (final) kernels prefix", this.aberrationsPrefix, 40);
gd.addStringField("Inverted (final) kernels suffix", this.aberrationsSuffix, 40);
gd.addCheckbox("Select channels to process", true);
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
this.sourceDirectory= gd.getNextString();
if (gd.getNextBoolean()) selectSourceDirectory(false, this.sourceDirectory, false);
if (gd.getNextBoolean()) selectSourceDirectory(false, this.sourceDirectory, false);
this.partialKernelDirectory=gd.getNextString();
if (gd.getNextBoolean()) selectPartialKernelDirectory(false, this.partialKernelDirectory, false);
if (gd.getNextBoolean()) selectPartialKernelDirectory(false, this.partialKernelDirectory, false);
this.psfKernelDirectory=gd.getNextString();
if (gd.getNextBoolean()) selectPSFKernelDirectory(false, this.psfKernelDirectory, false);
if (gd.getNextBoolean()) selectPSFKernelDirectory(false, this.psfKernelDirectory, false);
this.aberrationsKernelDirectory=gd.getNextString();
if (gd.getNextBoolean()) selectAberrationsKernelDirectory(false, this.aberrationsKernelDirectory, false);
this.noMessageBoxes= gd.getNextBoolean();
......@@ -4848,14 +4853,14 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
this.autoReCalibrateIgnoreLaser=gd.getNextBoolean();
this.autoFilter= gd.getNextBoolean();
this.trustEnabled= gd.getNextBoolean();
if (gd.getNextBoolean()) {
if (currentConfigs[0]!=null) this.calibrationPath=currentConfigs[0];
if (currentConfigs[1]!=null) this.strategyPath= currentConfigs[1];
if (currentConfigs[2]!=null) this.gridPath= currentConfigs[2];
if (currentConfigs[3]!=null) this.sensorsPath= currentConfigs[3];
}
this.sourcePrefix= gd.getNextString();
this.sourceSuffix= gd.getNextString();
this.partialPrefix= gd.getNextString();
......@@ -4872,7 +4877,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public String selectSourceDirectory(boolean smart, String defaultPath, boolean newAllowed) { // normally newAllowed=false
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
newAllowed, // save
"Source (acquired from the camera) image directory", // title
"Select source directory", // button
null, // filter
......@@ -4883,7 +4888,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public String selectPartialKernelDirectory(boolean smart, String defaultPath, boolean newAllowed) {
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
newAllowed, // save
"Partial PSF directory", // title
"Select partial PSF files directory", // button
null, // filter
......@@ -4894,7 +4899,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public String selectPSFKernelDirectory(boolean smart, String defaultPath, boolean newAllowed) {
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
newAllowed, // save
"Combined direct PSF kernel directory", // title
"Select combined kernel directory", // button
null, // filter
......@@ -4905,7 +4910,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public String selectAberrationsKernelDirectory(boolean smart, String defaultPath, boolean newAllowed) {
String dir= CalibrationFileManagement.selectDirectory(
smart,
newAllowed, // save
newAllowed, // save
"Aberrations kernel directory", // title
"Select aberrations kernel directory", // button
null, // filter
......@@ -4914,11 +4919,11 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
return dir;
}
}
public static class ColorComponents {
public boolean [] colorsToCorrect= new boolean[6];
public int referenceComponent; // component to calculate lateral chromatic from (0 - G1, 1 - R, 2 - B, 3 - G2,4 - diagonal greens, 5 - checker greens)
......@@ -4933,7 +4938,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
boolean red,
boolean blue,
boolean green2,
boolean diagonal, // both greens combined in a 45-degree rotated array
boolean diagonal, // both greens combined in a 45-degree rotated array
boolean checker, // both greens combined in a checkerboard pattern
int referenceComponent,
boolean equalizeGreens
......@@ -4988,7 +4993,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
this.thresholdHigh = thresholdHigh;
this.thresholdLow = thresholdLow;
}
public OTFFilterParameters clone() {
@Override
public OTFFilterParameters clone() {
return new OTFFilterParameters(
this.deconvInvert,
this.zerofreqSize,
......@@ -5027,13 +5033,13 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
public double wingsEnergy;
public double wingsEllipseScale;
public double minDefinedArea; // minimal (weighted) fraction of the defined patter pixels in the FFT area
public boolean approximateGrid; // approximate grid with polynomial
public boolean centerPSF; // Center PSF by modifying phase
public boolean approximateGrid; // approximate grid with polynomial
public boolean centerPSF; // Center PSF by modifying phase
public double mask1_sigma;
public double mask1_threshold;
public double gaps_sigma;
public double mask_denoise;
public PSFParameters(double minContrast,
double windowFrac,
......@@ -5067,8 +5073,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
this.wingsEnergy = wingsEnergy;
this.wingsEllipseScale = wingsEllipseScale;
this.minDefinedArea = minDefinedArea; // minimal (weighted) fraction of the defined patter pixels in the FFT area
this.approximateGrid = approximateGrid; // approximate grid with polynomial
this.centerPSF = centerPSF; // approximate grid with polynomial
this.approximateGrid = approximateGrid; // approximate grid with polynomial
this.centerPSF = centerPSF; // approximate grid with polynomial
this.mask1_sigma = mask1_sigma;
this.mask1_threshold = mask1_threshold;
this.gaps_sigma=gaps_sigma;
......@@ -5076,7 +5082,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
}
public PSFParameters clone(){
@Override
public PSFParameters clone(){
return new PSFParameters(
this.minContrast,
this.windowFrac,
......@@ -5288,8 +5295,8 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
this.sigmaToRadiusDirect=Double.parseDouble(properties.getProperty(prefix+"sigmaToRadiusDirect"));
}
}
public static class InterpolateParameters {
public int size; // size of each kernel (should be square)
public int step; // number of subdivisions from input to output
......@@ -5334,7 +5341,7 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
properties.setProperty(prefix+"add_bottom",this.add_bottom+"");
properties.setProperty(prefix+"extrapolate",this.extrapolate+"");
}
public void getProperties(String prefix,Properties properties){
this.size=Integer.parseInt(properties.getProperty(prefix+"size"));
this.step=Integer.parseInt(properties.getProperty(prefix+"step"));
......@@ -5344,10 +5351,10 @@ if (globalDebugLevel>2)globalDebugLevel=0; //***********************************
this.add_bottom=Integer.parseInt(properties.getProperty(prefix+"add_bottom"));
this.extrapolate=Double.parseDouble(properties.getProperty(prefix+"extrapolate"));
}
}
}
......@@ -668,6 +668,8 @@ horizontal axis:
// allow more of grid around pointers?
distortionParameters, //
this.patternDetectParameters,
this.patternDetectParameters.minGridPeriod/2,
this.patternDetectParameters.maxGridPeriod/2,
simulParameters,
equalizeGreens, imp_eq,
this.laserPointers, // null, //LASER_POINTERS, //
......@@ -841,6 +843,8 @@ horizontal axis:
// allow more of grid around pointers?
distortionParameters, //
this.patternDetectParameters,
this.patternDetectParameters.minGridPeriod/2,
this.patternDetectParameters.maxGridPeriod/2,
simulParameters,
equalizeGreens, imp_eq,
this.laserPointers, // null, //LASER_POINTERS, //
......
package com.elphel.imagej.calibration;
/**
**
** LensAdjustment.jave - processing related to focus measurement/adjustment machine
** LensAdjustment.jave - processing related to focus measurement/adjustment machine
**
** Copyright (C) 2011 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
**
** LensAdjustment.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
......@@ -25,7 +25,6 @@ package com.elphel.imagej.calibration;
import java.awt.Rectangle;
import java.util.Properties;
import com.elphel.imagej.calibration.SimulationPattern.SimulParameters;
import com.elphel.imagej.common.ShowDoubleFloatArrays;
import com.elphel.imagej.common.WindowTools;
......@@ -37,7 +36,7 @@ import ij.gui.GenericDialog;
public class LensAdjustment {
private ShowDoubleFloatArrays sdfaInstance =new ShowDoubleFloatArrays(); // just for debugging?
// public int debugLevel=2;
public int updateFocusGrid(
double x0, // lens center on the sensor
double y0, // lens center on the sensor
......@@ -75,18 +74,18 @@ public class LensAdjustment {
distortionParameters.minUVSpan=focusMeasurementParameters.minUVSpan;
distortionParameters.flatFieldCorrection=focusMeasurementParameters.flatFieldCorrection;
distortionParameters.flatFieldExpand=focusMeasurementParameters.flatFieldExpand;
distortionParameters.correlationMinContrast=focusMeasurementParameters.correlationMinContrast;
distortionParameters.correlationMinInitialContrast=focusMeasurementParameters.correlationMinInitialContrast;
distortionParameters.correlationMinAbsoluteContrast=focusMeasurementParameters.correlationMinAbsoluteContrast;
distortionParameters.correlationMinAbsoluteInitialContrast=focusMeasurementParameters.correlationMinAbsoluteInitialContrast;
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) &&
......@@ -118,7 +117,7 @@ public class LensAdjustment {
//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
// Do full
updating=false;
......@@ -127,7 +126,7 @@ public class LensAdjustment {
}
}
int numAbsolutePoints=0;
if (updating) {
if (updating) {
// add new nodes if the appeared after shift of the pattern
if (debug_level>0) { // calculate/print number of defined nodes in the grid
System.out.println("updateFocusGrid(), number of already defined grid cells (before distortions()) = "+matchSimulatedPattern.numDefinedCells());
......@@ -136,6 +135,8 @@ public class LensAdjustment {
null, // is not used in update mode
distortionParameters, //
patternDetectParameters,
patternDetectParameters.minGridPeriod/2,
patternDetectParameters.maxGridPeriod/2,
simulParameters,
equalizeGreens,
imp_eq, // image to process
......@@ -158,6 +159,8 @@ public class LensAdjustment {
numAbsolutePoints=matchSimulatedPattern.calculateDistortions( // allow more of grid around pointers?
distortionParameters, //
patternDetectParameters,
patternDetectParameters.minGridPeriod/2,
patternDetectParameters.maxGridPeriod/2,
simulParameters,
equalizeGreens,
imp_eq,
......@@ -201,7 +204,7 @@ public class LensAdjustment {
return numAbsolutePoints;
}
public static class FocusMeasurementParameters {
public String gridGeometryFile="";
public String initialCalibrationFile="";
......@@ -216,15 +219,15 @@ public class LensAdjustment {
public String serialNumber=""; // camera serial number string
public double sensorTemperature=Double.NaN; // last measured sensor temperature
//other summary results to be saved with parameters
public double result_lastKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from last run
public double result_lastFD20=Double.NaN; // focal distance for 20C, measured from last run
public double result_allHistoryKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from all the measurement histgory
public double result_lastKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from last run
public double result_lastFD20=Double.NaN; // focal distance for 20C, measured from last run
public double result_allHistoryKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from all the measurement histgory
public double result_allHistoryFD20=Double.NaN; // focal distance for 20C, measured from all the measurement histgory
public double result_fDistance=Double.NaN; // last measured focal distance
public double result_tiltX=Double.NaN; // last measured tilt X
public double result_tiltY=Double.NaN; // last measured tilt Y
public double result_R50=Double.NaN; // last measured R50 (average PSF 50% level radius, pixels - somewhat larged than actual because of measurement settings)
public double result_A50=Double.NaN; // last measured A50 (simailar, but R^2 are averaged)
public double result_A50=Double.NaN; // last measured A50 (simailar, but R^2 are averaged)
public double result_B50=Double.NaN; // last measured B50 (simailar, but R^4 are averaged)
public double result_RC50=Double.NaN; // last measured RC50(R50 calculated only for the 2 center samples)
public double result_PX0=Double.NaN; // lens center shift, X
......@@ -237,10 +240,10 @@ public class LensAdjustment {
public int lensSerialLength=4;
public String lensSerial=""; // Lens serial number
public boolean askLensSerial=true; // Ask lens serial on camera power cycle
public double reportTemperature=50; // temperature to report focal length
public double reportTemperature=50; // temperature to report focal length
public boolean showLegacy=false; // Show old focusing parameters (most are not supported anyway)
public boolean includeLensSerial=true; // add lens serial to config filename
public double centerDeltaX=0.0; // required X-difference between lens center and sensor center
public double centerDeltaX=0.0; // required X-difference between lens center and sensor center
public double centerDeltaY=0.0; // required Y-difference between lens center and sensor center
// with the seam in the middle - make even # of samples horizontally
// to be made private or removed
......@@ -258,34 +261,34 @@ public class LensAdjustment {
public boolean showAcquiredImages=false;
public boolean showROI=true;
public boolean showSamples=true;
public boolean showFittedParameters=true;
public boolean useHeadLasers=true;
// when approximating PSF with a second degree polynomial:
public double psf_cutoffEnergy=0.98; //0.5; // disregard pixels outside of this fraction of the total energy
public double psf_cutoffLevel= 0.2; // disregard pixels below this fraction of the maximal value
public int psf_minArea = 10; // continue increasing the selected area, even if beyond psf_cutoffEnergy and psf_cutoffLevel,
// if the selected area is smaller than this (so approximation would work)
public double psf_blurSigma = 0.0; // optionally blur the calculated mask
public double weightRatioRedToGreen=0.7; // Use this data when combining defocusing data from different color PSF
public double weightRatioBlueToGreen=0.2;
public double targetFarNear=0.0; // OBSOLETE target logarithm of average tangential-to-radial resolution
public boolean useRadialTangential=false; // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
public boolean useRadialTangential=false; // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
public double targetMicrons=0.0; // target lens center distance (away from "best focus"
public double toleranceMicrons=0.5; // microns
public double toleranceTilt=0.02; //
public double toleranceTilt=0.02; //
public double toleranceThreshold=3.0; // When each error is under scaled threshold, reduce correction step twice
// public boolean parallelAdjust=true; // move 3 motors parallel after each 3-motor focus/tilt adjustment
public double parallelAdjustThreshold=4.0; // adjust 3 motors parallel if focal distance error in the center exceeds this
// public boolean parallelAdjust=true; // move 3 motors parallel after each 3-motor focus/tilt adjustment
public double parallelAdjustThreshold=4.0; // adjust 3 motors parallel if focal distance error in the center exceeds this
public double motorsSigma=896.0; // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma 1/4 turn
public double motorsSigma3=896.0; // all 3 motors together (focusing center)
public double motorsMinSigma=200.0;// sigma will not drop below this value when fitting walk is getting smaller
public double motorsMinSigma=200.0;// sigma will not drop below this value when fitting walk is getting smaller
public double motorsVarSigmaToTravel=2.0; // when walk is getting smaller, sigma will keep going down proportionally
public double motorsFadeSigma=0.3; // after each step new sigma will have this part of the calculated from the travel
public double motorsFadeSigma=0.3; // after each step new sigma will have this part of the calculated from the travel
public double motorsOverShootToBalance=0.9; //For quadratic maximum the correction will be increased by 1+motorsOverShootToBalance if there are less samples on teh other side
public boolean filterGoodDistance=true; // when measuring tilt, use those with good center with higher weight
public double goodDistanceSigma=5.0; // sigma for the weight function of tilt measurements, depending on the center distance error
......@@ -295,15 +298,15 @@ public class LensAdjustment {
public double probe_M1M2M3= 448.0; // how far to move average of the 3 motors: (M1+M2+M3)/3
public double probe_M3_M1M2=3584.0; // how far to move M3 opposite to M1 and M2: M3-(M1+M2)/2
public double probe_M2_M1= 3584.0; // how far to move M2 opposite to M1: M2-M1
public double sigmaToProbe=1.0; // data from far samples decay proportionally to the probe distances
public boolean useTheBest=true; // adjust from the best known position (false - from the last)
public boolean probeSymmetrical=false; // if true, probe 6 measurements), if false - only 4 (tetrahedron)
public boolean parallelBeforeProbing=true; // move 3 motors before probing around
public double sigmaToProbe=1.0; // data from far samples decay proportionally to the probe distances
public boolean useTheBest=true; // adjust from the best known position (false - from the last)
public boolean probeSymmetrical=false; // if true, probe 6 measurements), if false - only 4 (tetrahedron)
public boolean parallelBeforeProbing=true; // move 3 motors before probing around
public double reProbeDistance=4000.0; // re-run probing around in orthoganal directions, if the current position move farther from the last probing one
public double believeLast=0.0; // coefficient 0.. 1.0. When each ot the 3 parameters is linearized, add shift, so 1.0 the planes will go throug the last sample
public boolean compensateHysteresis=true; // move motors in the same direction to compensate for hysteresis
public double minCorr=100.0; // minimal correction movement to initiate final numFinalCorr moves
public int numFinalCorr=5; // exit if this number of last corrections where below minCorr
......@@ -312,16 +315,16 @@ public class LensAdjustment {
public int maxAutoIterations=25; // exit if history grows above this
public double maxAutoDistance= 10000; // Maximal allowed automatic correction, motor steps
public boolean confirmFirstAuto=true; // ask confirmation after first automatic adjustment step (before moving)
public double motorsPreSigma=3584.0; // when fitting parabola for focusing sharpness in the center, far measurements decay with this sigma
public double maxLinearStep= 3584.0; // If there are insufficient measurements to fit parabola - make this step
public int scanStep=320; // 200; // motor step (all 3 motors) in scan focus mode (signed value)
public int scanNumber=50; // number of scanStep steps to run
public int scanNumberNegative=20; // 15; // number of scanStep steps negative from the start
public int scanNumberNegative=20; // 15; // number of scanStep steps negative from the start
public boolean scanHysteresis=false; // true; // scan both ways
public int scanHysteresisNumber=5; // number of test points for the Hysteresis measurement
public boolean scanTiltEnable=false; //true; // enable scanning tilt
public boolean scanTiltReverse=false; // enable scanning tilt in both directions
public boolean scanMeasureLast=false; // Calculate PSF after last move (to original position)
......@@ -330,45 +333,45 @@ public class LensAdjustment {
public int scanTiltRangeY=14336; // 4 periods
public int scanTiltStepsX=24;
public int scanTiltStepsY=24;
public int motorHysteresis=300;
public double measuredHysteresis=0; // actually measured (will be saved/restored)
public double motorCalm=2; // wait (seconds) after motors reached final position (for the first time) before acquiring image
public double motorCalm=2; // wait (seconds) after motors reached final position (for the first time) before acquiring image
public double linearReductionRatio=4.0/38.0; // sensor travel to motors travel (all 3 together), By design it is 4/38~=0.105
public int motorDebug=0; // 1 show motor moves, 2 - show hysteresis back-ups too
// parameters for appoximating sensor center position
public int lensDistanceNumPoints=1000; // number of points to tabulate center focus parameters vs. focal distance
public int lensDistancePolynomialDegree=8; // polynomial degree to approximate center focus parameters vs. focal distance
public double lensDistanceWeightY=0.5; // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
public int lensDistanceNumPoints=1000; // number of points to tabulate center focus parameters vs. focal distance
public int lensDistancePolynomialDegree=8; // polynomial degree to approximate center focus parameters vs. focal distance
public double lensDistanceWeightY=0.5; // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
public double lensDistanceWeightK=0.0; // 0.0 use 3 distances (to frac-R, frac-B and Y) with teh same weight when fitting, 1.0 - proportional to squared derivatives
public boolean lensDistanceInteractive=true; // Open dialog when calibrating focal distance
public boolean lensDistanceShowResults=true; // show results window from foca
public boolean lensDistanceMoveToGoal=true; // Move to targetMicrons
public boolean powerControlEnable=true;
public double powerControlMaximalTemperature=60.0;
public double powerControlHeaterOnMinutes=10.0;
public double powerControlNeitherOnMinutes=5.0;
public double powerControlFanOnMinutes=15.0;
public String uvLasersIP="192.168.0.236"; // IP address of the camera with UV LEDs and aiming lasers are connected
public int uvLasersBus=0; // 0 if 103641 board is connected to the sensor port (through 10-359), 1 - to 10369
public double [] uvLasersCurrents={40.0,40.0,40.0,40.0}; // default LED on currents (mA)
// the following 3 overwrite SimulParameters members
public double smallestSubPix=0.3; // subdivide pixels down to that fraction when simulating
public double bitmapNonuniforityThreshold=0.1 ; // subdivide pixels until difference between the corners is below this value
public int subdiv=4;
public int subdiv=4;
// overwrites public static class MultiFilePSF.overexposedMaxFraction
public double overexposedMaxFraction=0.1; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
public double overexposedMaxFraction=0.1; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
// overwrites public static class PSFParameters.minDefinedArea
public double minDefinedArea=0.75; // minimal (weighted) fraction of the defined patter pixels in the FFT area
public int PSFKernelSize=32; // size of the detected PSF kernel
public boolean approximateGrid=true; // approximate grid with polynomial
public boolean approximateGrid=true; // approximate grid with polynomial
public boolean centerPSF=true; // Center PSF by modifying phase
public double mask1_sigma= 1.0;
public double mask1_threshold=0.25;
public double gaps_sigma= 1.0;
......@@ -384,24 +387,24 @@ public class LensAdjustment {
public double correlationMinInitialContrast=1.5; // minimal contrast for the pattern of the center (initial point)
public double correlationMinAbsoluteContrast=0.5; // minimal contrast for the pattern to pass, does not compensate for low ligt
public double correlationMinAbsoluteInitialContrast=0.5; // minimal contrast for the pattern of the center (initial point)
public double [] postUVscrewSensitivity={-300,-300,-120}; //{-2.908571735,-3.8198374024,-2.4491867448};
public boolean flatFieldCorrection=true;
public double flatFieldExpand=4.0;
public double thresholdFinish=0.001; // Stop iterations if 2 last steps had less improvement (but not worsening )
public double thresholdFinish=0.001; // Stop iterations if 2 last steps had less improvement (but not worsening )
public int numIterations= 100; // maximal number of iterations
public boolean cameraIsConfigured=false;
public boolean useExtraSensor = true;
public boolean enRoundOff = true; // create round mask to refine lens center position (second LMA run)
public boolean enRoundOff = true; // create round mask to refine lens center position (second LMA run)
public boolean keepCircularMask=false; // keep sensor 0 round mask after running LMA, false - recalculate actual mask
public boolean configureCamera=false; // only valid after dialog
public int [] motorPos=null; // will point to
public double [] ampsSeconds={0.0,0.0,0.0,0.0}; // cumulative Amps*seconds (read only, but will be saved/restored)
public int manufacturingState=0;
// temporary - will re-calculate according to required lens center
public Rectangle getMargins(){
int iXC = (int) Math.round(centerDeltaX);
......@@ -416,10 +419,10 @@ public class LensAdjustment {
hh += (iYC < 0)?iYC:(-iYC);
margins=new Rectangle(ix0+iXC-hw,iy0+iYC-hh,2*hw,2*hh);
}
return margins;
}
public String [] manufacturingStateNames={
"New SFE",
"UV cured (not released)",
......@@ -431,7 +434,7 @@ public class LensAdjustment {
"Epoxy, cured at room temperature",
"Epoxy cured, re-testing later"
};
public int [] manufacturingStateValues={
00, // "New SFE",
10, //"UV cured (not released)",
......@@ -443,7 +446,7 @@ public class LensAdjustment {
70, //"Epoxy, cured at room temperature",
80 //"Epoxy cured, re-testing later"
};
public int [] getManufacturingIndexMod(int value){
if (value<this.manufacturingStateValues[0]) value= this.manufacturingStateValues[0];
for (int i=this.manufacturingStateValues.length-1;i>=0;i--){
......@@ -454,21 +457,21 @@ public class LensAdjustment {
}
return null; // should not get here
}
public FocusMeasurementParameters(int []motorPos){
this.motorPos=motorPos;
}
public void resetResults(){
this.result_lastKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from last run
this.result_lastFD20=Double.NaN; // focal distance for 20C, measured from last run
this.result_allHistoryKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from all the measurement histgory
this.result_lastKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from last run
this.result_lastFD20=Double.NaN; // focal distance for 20C, measured from last run
this.result_allHistoryKT=Double.NaN; // focal distance temperature coefficient (um/C), measured from all the measurement histgory
this.result_allHistoryFD20=Double.NaN; // focal distance for 20C, measured from all the measurement histgory
this.result_fDistance=Double.NaN; // last measured focal distance
this.result_tiltX=Double.NaN; // last measured tilt X
this.result_tiltY=Double.NaN; // last measured tilt Y
this.result_R50=Double.NaN; // last measured R50 (average PSF 50% level radius, pixels - somewhat larged than actual because of measurement settings)
this.result_A50=Double.NaN; // last measured A50 (simailar, but R^2 are averaged)
this.result_A50=Double.NaN; // last measured A50 (simailar, but R^2 are averaged)
this.result_B50=Double.NaN; // last measured B50 (similar, but R^4 are averaged)
this.result_RC50=Double.NaN; // last measured RC50(R50 calculated only for the 2 center samples)
this.result_PX0=Double.NaN; // lens center shift, X
......@@ -490,15 +493,15 @@ public class LensAdjustment {
String serialNumber, // camera serial number string
double sensorTemperature, // last measured sensor temperature
// other summary results to be saved with parameters
double result_lastKT, // focal distance temperature coefficient (um/C), measured from last run
double result_lastFD20, // focal distance for 20C, measured from last run
double result_allHistoryKT, // focal distance temperature coefficient (um/C), measured from all the measurement histgory
double result_lastKT, // focal distance temperature coefficient (um/C), measured from last run
double result_lastFD20, // focal distance for 20C, measured from last run
double result_allHistoryKT, // focal distance temperature coefficient (um/C), measured from all the measurement histgory
double result_allHistoryFD20, // focal distance for 20C, measured from all the measurement histgory
double result_fDistance, // last measured focal distance
double result_tiltX, // last measured tilt X
double result_tiltY, // last measured tilt Y
double result_R50, // last measured R50 (average PSF 50% level radius, pixels - somewhat larged than actual because of measurement settings)
double result_A50, // last measured A50 (simailar, but R^2 are averaged)
double result_A50, // last measured A50 (simailar, but R^2 are averaged)
double result_B50, // last measured B50 (simailar, but R^4 are averaged)
double result_RC50, // last measured RC50(R50 calculated only for the 2 center samples)
double result_PX0, // lens center shift, X
......@@ -511,7 +514,7 @@ public class LensAdjustment {
int manufacturingState, // SFE manufacturing state
boolean askLensSerial,
boolean includeLensSerial, // add lens serial to config filename
double centerDeltaX, // required X-difference between lens center and sensor center
double centerDeltaX, // required X-difference between lens center and sensor center
double centerDeltaY, // required Y-difference between lens center and sensor center
Rectangle margins,
int [] numSamples,
......@@ -525,7 +528,7 @@ public class LensAdjustment {
boolean showAcquiredImages,
boolean showROI,
boolean showSamples,
boolean showFittedParameters,
boolean useHeadLasers,
double psf_cutoffEnergy, // disregard pixels outside of this fraction of the total energy
......@@ -533,21 +536,21 @@ public class LensAdjustment {
int psf_minArea, // continue increasing the selected area, even if beyound psf_cutoffEnergy and psf_cutoffLevel,
// if the selected area is smaller than this (so approximation wpuld work)
double psf_blurSigma, // optionally blur the calculated mask
double weightRatioRedToGreen, // Use this data when combining defocusing data from different color PSF
double weightRatioBlueToGreen,
double targetFarNear, // target logariphm of average tangential-to-radial resolution
boolean useRadialTangential, // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
boolean useRadialTangential, // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
double targetMicrons, // target lens center distance (away from "best focus"
double toleranceMicrons, // microns
double toleranceTilt, //
double toleranceTilt, //
double toleranceThreshold, // When each error is under swcaled thereshold, reduce correxction step twice
double parallelAdjustThreshold, // adjust 3 motors parallel if focal distance error in the center exceeds this
double parallelAdjustThreshold, // adjust 3 motors parallel if focal distance error in the center exceeds this
double motorsSigma, // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma
double motorsSigma3, // all 3 motors together (focusing center)
double motorsMinSigma,// sigma will not drop below this value when fitting walk is getting smaller
double motorsMinSigma,// sigma will not drop below this value when fitting walk is getting smaller
double motorsVarSigmaToTravel, // when walk is getting smaller, sigma will keep going down proportionally
double motorsFadeSigma, // after each step new sigma will have this part of the calculated from the travel
double motorsFadeSigma, // after each step new sigma will have this part of the calculated from the travel
double motorsOverShootToBalance, //For quadratic maximum the correction will be increased by 1+motorsOverShootToBalance if there are less samples on teh other side
boolean filterGoodDistance, // when measuring tilt, use those with good center with higher weight
double goodDistanceSigma, // sigma for the weight function of tilt measurements, depending on the center distance error
......@@ -557,8 +560,8 @@ public class LensAdjustment {
double probe_M1M2M3, // how far to move average of the 3 motors: (M1+M2+M3)/3
double probe_M3_M1M2, // how far to move M3 opposite to M1 and M2: M3-(M1+M2)/2
double probe_M2_M1, // how far to move M2 opposite to M1: M2-M1
double sigmaToProbe, // data from far samples decay proportionally to the probe distances
boolean useTheBest, // adjust from the best known position (false - from the last)
double sigmaToProbe, // data from far samples decay proportionally to the probe distances
boolean useTheBest, // adjust from the best known position (false - from the last)
boolean probeSymmetrical, // if true, probe 6 measurements), if false - only 4 (tetrahedron)
boolean parallelBeforeProbing, // move 3 motors before probing around
double reProbeDistance, // re-run probing around in orthoganal directions, if the current position move farther from the last probing one
......@@ -578,7 +581,7 @@ public class LensAdjustment {
int scanNumberNegative, // of them negative
boolean scanHysteresis, // scan both ways
int scanHysteresisNumber, // number of test points for the Hysteresis measurement
boolean scanTiltEnable, //=true; // enable scanning tilt
boolean scanTiltReverse,
boolean scanMeasureLast,
......@@ -588,15 +591,15 @@ public class LensAdjustment {
int scanTiltStepsX, //=24;
int scanTiltStepsY, //=24;
int motorHysteresis,
double measuredHysteresis, // actually measured (will be saved/restored)
double motorCalm, // wait (seconds) after motors reached final position (for the first time) before acquiring image
double motorCalm, // wait (seconds) after motors reached final position (for the first time) before acquiring image
double linearReductionRatio, // sensor travel to motors travel (all 3 together), By design it is 4/38~=0.105
int motorDebug,// 1 show motor moves, 2 - show hysteresis back-ups too
int lensDistanceNumPoints, // number of points to tabulate center focus parameters vs. focal distance
int lensDistancePolynomialDegree, // polynomial degree to approximate center focus parameters vs. focal distance
double lensDistanceWeightY, // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
int lensDistanceNumPoints, // number of points to tabulate center focus parameters vs. focal distance
int lensDistancePolynomialDegree, // polynomial degree to approximate center focus parameters vs. focal distance
double lensDistanceWeightY, // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
double lensDistanceWeightK, // 0.0 use 3 distances (to frac-R, frac-B and Y) with teh same weight when fitting, 1.0 - proportional to squared derivatives
boolean lensDistanceInteractive, // Open dialog when calibrating focal distance
boolean lensDistanceShowResults, // show results window from foca
......@@ -612,8 +615,8 @@ public class LensAdjustment {
double smallestSubPix, // subdivide pixels down to that fraction when simulating
double bitmapNonuniforityThreshold, // subdivide pixels until difference between the corners is below this value
int subdiv,
double overexposedMaxFraction, // allowed fraction of the overexposed pixels in the PSF kernel measurement area
int subdiv,
double overexposedMaxFraction, // allowed fraction of the overexposed pixels in the PSF kernel measurement area
double minDefinedArea, // minimal (weighted) fraction of the defined patter pixels in the FFT area
int PSFKernelSize,
boolean approximateGrid, // approximate grid with polynomial
......@@ -633,7 +636,7 @@ public class LensAdjustment {
double [] postUVscrewSensitivity, // microns/turn for 3 post-UV fixture adjustment screws
boolean flatFieldCorrection,
double flatFieldExpand,
double thresholdFinish,// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
double thresholdFinish,// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
int numIterations, // maximal number of iterations
boolean cameraIsConfigured,
boolean useExtraSensor,
......@@ -655,15 +658,15 @@ public class LensAdjustment {
this.showResults=showResults; // show focusing (includingh intermediate) results
this.serialNumber=serialNumber; // camera serial number string
this.sensorTemperature=sensorTemperature; // last measured sensor temperature
this.result_lastKT=result_lastKT; // focal distance temperature coefficient (um/C), measured from last run
this.result_lastFD20=result_lastFD20; // focal distance for 20C, measured from last run
this.result_allHistoryKT=result_allHistoryKT; // focal distance temperature coefficient (um/C), measured from all the measurement histgory
this.result_lastKT=result_lastKT; // focal distance temperature coefficient (um/C), measured from last run
this.result_lastFD20=result_lastFD20; // focal distance for 20C, measured from last run
this.result_allHistoryKT=result_allHistoryKT; // focal distance temperature coefficient (um/C), measured from all the measurement histgory
this.result_allHistoryFD20=result_allHistoryFD20; // focal distance for 20C, measured from all the measurement histgory
this.result_fDistance=result_fDistance; // last measured focal distance
this.result_tiltX=result_tiltX; // last measured tilt X
this.result_tiltY=result_tiltY; // last measured tilt Y
this.result_R50=result_R50; // last measured R50 (average PSF 50% level radius, pixels - somewhat larged than actual because of measurement settings)
this.result_A50=result_A50; // last measured A50 (simailar, but R^2 are averaged)
this.result_A50=result_A50; // last measured A50 (simailar, but R^2 are averaged)
this.result_B50=result_B50; // last measured B50 (simailar, but R^4 are averaged)
this.result_RC50=result_RC50; // last measured RC50(R50 calculated only for the 2 center samples)
this.result_PX0=result_PX0; // lens center shift, X
......@@ -676,7 +679,7 @@ public class LensAdjustment {
this.manufacturingState=manufacturingState;
this.askLensSerial=askLensSerial;
this.includeLensSerial=includeLensSerial; // add lens serial to config filename
this.centerDeltaX=centerDeltaX; // required X-difference between lens center and sensor center
this.centerDeltaX=centerDeltaX; // required X-difference between lens center and sensor center
this.centerDeltaY=centerDeltaY; // required Y-difference between lens center and sensor center
this.margins=(Rectangle) margins.clone();
// this.origin=origin.clone(); // top left corner
......@@ -701,17 +704,17 @@ public class LensAdjustment {
this.weightRatioRedToGreen=weightRatioRedToGreen; // Use this data when combining defocusing data from different color PSF
this.weightRatioBlueToGreen=weightRatioBlueToGreen;
this.targetFarNear=targetFarNear; // target logariphm of average tangential-to-radial resolution
this.useRadialTangential=useRadialTangential; // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
this.useRadialTangential=useRadialTangential; // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
this.targetMicrons=targetMicrons; // target lens center distance (away from "best focus"
this.toleranceMicrons=toleranceMicrons; // microns
this.toleranceTilt=toleranceTilt; //
this.toleranceTilt=toleranceTilt; //
this.toleranceThreshold=toleranceThreshold; // When each error is under swcaled thereshold, reduce correxction step twice
this.parallelAdjustThreshold=parallelAdjustThreshold; // adjust 3 motors parallel if focal distance error in the center exceeds this
this.parallelAdjustThreshold=parallelAdjustThreshold; // adjust 3 motors parallel if focal distance error in the center exceeds this
this.motorsSigma=motorsSigma; // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma
this.motorsSigma3=motorsSigma3; // same when 3 motors move together
this.motorsMinSigma=motorsMinSigma; // sigma will not drop below this value when fitting walk is getting smaller
this.motorsMinSigma=motorsMinSigma; // sigma will not drop below this value when fitting walk is getting smaller
this.motorsVarSigmaToTravel=motorsVarSigmaToTravel;// when walk is getting smaller, sigma will keep going down proportionally
this.motorsFadeSigma=motorsFadeSigma; // after each step new sigma will have this part of the calculated from the travel
this.motorsFadeSigma=motorsFadeSigma; // after each step new sigma will have this part of the calculated from the travel
this.motorsOverShootToBalance=motorsOverShootToBalance;//For quadratic maximum the correction will be increased by 1+motorsOverShootToBalance if there are less samples on teh other side
this.filterGoodDistance=filterGoodDistance; // when measuring tilt, use those with good center with higher weight
this.goodDistanceSigma=goodDistanceSigma; // sigma for the weight function of tilt measurements, depending on the center distance error
......@@ -722,7 +725,7 @@ public class LensAdjustment {
this.probe_M3_M1M2=probe_M3_M1M2; // how far to move M3 opposite to M1 and M2: M3-(M1+M2)/2
this.probe_M2_M1=probe_M2_M1; // how far to move M2 opposite to M1: M2-M1
this.sigmaToProbe=sigmaToProbe; // data from far samples decay proportionally to the probe distances
this.useTheBest=useTheBest; // adjust from the best known position (false - from the last)
this.useTheBest=useTheBest; // adjust from the best known position (false - from the last)
this.probeSymmetrical=probeSymmetrical; // if true, probe 6 measurements), if false - only 4 (tetrahedron)
this.parallelBeforeProbing=parallelBeforeProbing; // move 3 motors before probing around
this.reProbeDistance=reProbeDistance; // re-run probing around in orthoganal directions, if the current position move farther from the last probing one
......@@ -742,7 +745,7 @@ public class LensAdjustment {
this.scanNumberNegative=scanNumberNegative; // of them negative
this.scanHysteresis=scanHysteresis; // scan both ways
this.scanHysteresisNumber=scanHysteresisNumber; // number of test points for the Hysteresis measurement
this.scanTiltEnable=scanTiltEnable; //=true; // enable scanning tilt
this.scanTiltReverse=scanTiltReverse;
this.scanMeasureLast=scanMeasureLast;
......@@ -751,15 +754,15 @@ public class LensAdjustment {
this.scanTiltRangeY=scanTiltRangeY; //, //=14336; // 4 periods
this.scanTiltStepsX=scanTiltStepsX; //=24;
this.scanTiltStepsY=scanTiltStepsY; //=24;
this.motorHysteresis=motorHysteresis;
this.measuredHysteresis=measuredHysteresis; // actually measured (will be saved/restored)
this.motorCalm=motorCalm; // wait (seconds) after motors reached final position (for the first time) before acquiring image
this.motorCalm=motorCalm; // wait (seconds) after motors reached final position (for the first time) before acquiring image
this.linearReductionRatio=linearReductionRatio; // sensor travel to motors travel (all 3 together), By design it is 4/38~=0.105
this.motorDebug=motorDebug;// 1 show motor moves, 2 - show hysteresis back-ups too
this.lensDistanceNumPoints=lensDistanceNumPoints; // number of points to tabulate center focus parameters vs. focal distance
this.lensDistancePolynomialDegree=lensDistancePolynomialDegree; // polynomial degree to approximate center focus parameters vs. focal distance
this.lensDistanceWeightY=lensDistanceWeightY; // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
this.lensDistanceNumPoints=lensDistanceNumPoints; // number of points to tabulate center focus parameters vs. focal distance
this.lensDistancePolynomialDegree=lensDistancePolynomialDegree; // polynomial degree to approximate center focus parameters vs. focal distance
this.lensDistanceWeightY=lensDistanceWeightY; // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
this.lensDistanceWeightK=lensDistanceWeightK; // 0.0 use 3 distances (to frac-R, frac-B and Y) with teh same weight when fitting, 1.0 - proportional to squared derivatives
this.lensDistanceInteractive=lensDistanceInteractive; // Open dialog when calibrating focal distance
this.lensDistanceShowResults=lensDistanceShowResults; // show results window from foca
......@@ -774,12 +777,12 @@ public class LensAdjustment {
this.uvLasersCurrents=uvLasersCurrents.clone(); // default LED on currents (mA)
this.smallestSubPix=smallestSubPix;
this.bitmapNonuniforityThreshold=bitmapNonuniforityThreshold;
this.subdiv=subdiv;
this.overexposedMaxFraction=overexposedMaxFraction;
this.subdiv=subdiv;
this.overexposedMaxFraction=overexposedMaxFraction;
this.minDefinedArea=minDefinedArea;
this.PSFKernelSize=PSFKernelSize;
this.approximateGrid = approximateGrid; // approximate grid with polynomial
this.centerPSF = centerPSF; // approximate grid with polynomial
this.centerPSF = centerPSF; // approximate grid with polynomial
this.mask1_sigma = mask1_sigma;
this.mask1_threshold = mask1_threshold;
this.gaps_sigma=gaps_sigma;
......@@ -795,7 +798,7 @@ public class LensAdjustment {
this.postUVscrewSensitivity=postUVscrewSensitivity.clone(); // microns/turn for 3 post-UV fixture adjustment screws
this.flatFieldCorrection=flatFieldCorrection;
this.flatFieldExpand=flatFieldExpand;
this.thresholdFinish=thresholdFinish;// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
this.thresholdFinish=thresholdFinish;// (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
this.numIterations=numIterations; // maximal number of iterations
this.cameraIsConfigured=cameraIsConfigured;
this.useExtraSensor=useExtraSensor;
......@@ -806,7 +809,8 @@ public class LensAdjustment {
this.reportTemperature=reportTemperature;
this.showLegacy=showLegacy;
}
public FocusMeasurementParameters clone(){
@Override
public FocusMeasurementParameters clone(){
return new FocusMeasurementParameters(
this.gridGeometryFile,
this.initialCalibrationFile,
......@@ -819,15 +823,15 @@ public class LensAdjustment {
this.showResults, // show focusing (includingh intermediate) results
this.serialNumber, // camera serial number string
this.sensorTemperature, // last measured sensor temperature
this.result_lastKT, // focal distance temperature coefficient (um/C), measured from last run
this.result_lastFD20, // focal distance for 20C, measured from last run
this.result_allHistoryKT, // focal distance temperature coefficient (um/C), measured from all the measurement histgory
this.result_lastKT, // focal distance temperature coefficient (um/C), measured from last run
this.result_lastFD20, // focal distance for 20C, measured from last run
this.result_allHistoryKT, // focal distance temperature coefficient (um/C), measured from all the measurement histgory
this.result_allHistoryFD20, // focal distance for 20C, measured from all the measurement histgory
this.result_fDistance, // last measured focal distance
this.result_tiltX, // last measured tilt X
this.result_tiltY, // last measured tilt Y
this.result_R50, // last measured R50 (average PSF 50% level radius, pixels - somewhat larged than actual because of measurement settings)
this.result_A50, // last measured A50 (simailar, but R^2 are averaged)
this.result_A50, // last measured A50 (simailar, but R^2 are averaged)
this.result_B50, // last measured B50 (simailar, but R^4 are averaged)
this.result_RC50, // last measured RC50(R50 calculated only for the 2 center samples)
this.result_PX0, // lens center shift, X
......@@ -840,7 +844,7 @@ public class LensAdjustment {
this.manufacturingState,
this.askLensSerial,
this.includeLensSerial, // add lens serial to config filename
this.centerDeltaX, // required X-difference between lens center and sensor center
this.centerDeltaX, // required X-difference between lens center and sensor center
this.centerDeltaY, // required Y-difference between lens center and sensor center
this.margins,
this.numSamples,
......@@ -863,18 +867,18 @@ public class LensAdjustment {
this.weightRatioRedToGreen, // Use this data when combining defocusing data from different color PSF
this.weightRatioBlueToGreen,
this.targetFarNear, // target logariphm of average tangential-to-radial resolution
this.useRadialTangential, // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
this.useRadialTangential, // Use targetFarNear (radial/tangential resolution) as a proxy for the distance
this.targetMicrons, // target lens center distance (away from "best focus"
this.toleranceMicrons, // microns
this.toleranceTilt, //
this.toleranceTilt, //
this.toleranceThreshold, // When each error is under swcaled thereshold, reduce correxction step twice
this.parallelAdjustThreshold, // adjust 3 motors parallel if focal distance error in the center exceeds this
this.parallelAdjustThreshold, // adjust 3 motors parallel if focal distance error in the center exceeds this
this.motorsSigma, // when fitting planes for far/near, tiltX and tiltY the weights of the samples decay with this sigma
this.motorsSigma3, // same when 3 motors move together
this.motorsMinSigma, // sigma will not drop below this value when fitting walk is getting smaller
this.motorsMinSigma, // sigma will not drop below this value when fitting walk is getting smaller
this.motorsVarSigmaToTravel, // when walk is getting smaller, sigma will keep going down proportionally
this.motorsFadeSigma, // after each step new sigma will have this part of the calculated from the travel
this.motorsFadeSigma, // after each step new sigma will have this part of the calculated from the travel
this.motorsOverShootToBalance, //For quadratic maximum the correction will be increased by 1+motorsOverShootToBalance if there are less samples on teh other side
this.filterGoodDistance, // when measuring tilt, use those with good center with higher weight
this.goodDistanceSigma, // sigma for the weight function of tilt measurements, depending on the center distance error
......@@ -884,8 +888,8 @@ public class LensAdjustment {
this.probe_M1M2M3, // how far to move average of the 3 motors: (M1+M2+M3)/3
this.probe_M3_M1M2, // how far to move M3 opposite to M1 and M2: M3-(M1+M2)/2
this.probe_M2_M1, // how far to move M2 opposite to M1: M2-M1
this.sigmaToProbe, // data from far samples decay proportionally to the probe distances
this.useTheBest, // adjust from the best known position (false - from the last)
this.sigmaToProbe, // data from far samples decay proportionally to the probe distances
this.useTheBest, // adjust from the best known position (false - from the last)
this.probeSymmetrical, // if true, probe 6 measurements), if false - only 4 (tetrahedron)
this.parallelBeforeProbing, // move 3 motors before probing around
this.reProbeDistance, // re-run probing around in orthoganal directions, if the current position move farther from the last probing one
......@@ -905,7 +909,7 @@ public class LensAdjustment {
this.scanNumberNegative, // of them negative
this.scanHysteresis, // scan both ways
this.scanHysteresisNumber, // number of test points for the Hysteresis measurement
this.scanTiltEnable, // enable scanning tilt
this.scanTiltReverse,
this.scanMeasureLast,
......@@ -915,14 +919,14 @@ public class LensAdjustment {
this.scanTiltStepsX,
this.scanTiltStepsY,
this.motorHysteresis,
this.measuredHysteresis, // actually measured (will be saved/restored)
this.motorCalm, // wait (seconds) after motors reached final position (for the first time) before acquiring image
this.motorCalm, // wait (seconds) after motors reached final position (for the first time) before acquiring image
this.linearReductionRatio, // sensor travel to motors travel (all 3 together), By design it is 4/38~=0.105
this.motorDebug, // 1 show motor moves, 2 - show hysteresis back-ups too
this.lensDistanceNumPoints, // number of points to tabulate center focus parameters vs. focal distance
this.lensDistancePolynomialDegree, // polynomial degree to approximate center focus parameters vs. focal distance
this.lensDistanceWeightY, // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
this.lensDistanceNumPoints, // number of points to tabulate center focus parameters vs. focal distance
this.lensDistancePolynomialDegree, // polynomial degree to approximate center focus parameters vs. focal distance
this.lensDistanceWeightY, // normalize overall sharpness (that depends on the lens quality and/or PSF parameters) to differential ones
this.lensDistanceWeightK, // 0.0 use 3 distances (to frac-R, frac-B and Y) with teh same weight when fitting, 1.0 - proportional to squared derivatives
this.lensDistanceInteractive, // Open dialog when calibrating focal distance
this.lensDistanceShowResults, // show results window from foca
......@@ -938,8 +942,8 @@ public class LensAdjustment {
this.smallestSubPix,
this.bitmapNonuniforityThreshold,
this.subdiv,
this.overexposedMaxFraction,
this.subdiv,
this.overexposedMaxFraction,
this.minDefinedArea,
this.PSFKernelSize,
this.approximateGrid,
......@@ -959,7 +963,7 @@ public class LensAdjustment {
this.postUVscrewSensitivity,
this.flatFieldCorrection,
this.flatFieldExpand,
this.thresholdFinish,
this.thresholdFinish,
this.numIterations,
this.cameraIsConfigured,
this.useExtraSensor,
......@@ -991,7 +995,7 @@ public class LensAdjustment {
if (!Double.isNaN(this.result_A50))properties.setProperty(prefix+"result_A50",this.result_A50+"");
if (!Double.isNaN(this.result_B50))properties.setProperty(prefix+"result_B50",this.result_B50+"");
if (!Double.isNaN(this.result_RC50))properties.setProperty(prefix+"result_RC50",this.result_RC50+"");
if (!Double.isNaN(this.result_PX0))properties.setProperty(prefix+"result_PX0",this.result_PX0+"");
if (!Double.isNaN(this.result_PY0))properties.setProperty(prefix+"result_PY0",this.result_PY0+"");
if (!Double.isNaN(this.result_PSI))properties.setProperty(prefix+"result_PSI",this.result_PSI+"");
......@@ -1019,7 +1023,7 @@ public class LensAdjustment {
properties.setProperty(prefix+"maxCorr",this.maxCorr+"");
properties.setProperty(prefix+"showHistoryDetails",this.showHistoryDetails+"");
properties.setProperty(prefix+"showHistorySamples",this.showHistorySamples+"");
properties.setProperty(prefix+"showHistorySingleLine",this.showHistorySingleLine+"");
properties.setProperty(prefix+"showAcquiredImages",this.showAcquiredImages+"");
properties.setProperty(prefix+"showROI",this.showROI+"");
......@@ -1048,13 +1052,13 @@ public class LensAdjustment {
properties.setProperty(prefix+"motorsVarSigmaToTravel",this.motorsVarSigmaToTravel+"");
properties.setProperty(prefix+"motorsFadeSigma",this.motorsFadeSigma+"");
properties.setProperty(prefix+"motorsOverShootToBalance",this.motorsOverShootToBalance+"");
properties.setProperty(prefix+"filterGoodDistance",this.filterGoodDistance+"");
properties.setProperty(prefix+"goodDistanceSigma",this.goodDistanceSigma+"");
properties.setProperty(prefix+"goodTiltSigma",this.goodTiltSigma+"");
properties.setProperty(prefix+"maxStep",this.maxStep+"");
properties.setProperty(prefix+"probeStep",this.probeStep+"");
properties.setProperty(prefix+"probe_M1M2M3",this.probe_M1M2M3+"");
properties.setProperty(prefix+"probe_M3_M1M2",this.probe_M3_M1M2+"");
properties.setProperty(prefix+"probe_M2_M1",this.probe_M2_M1+"");
......@@ -1099,20 +1103,20 @@ public class LensAdjustment {
properties.setProperty(prefix+"lensDistanceInteractive",this.lensDistanceInteractive+"");
properties.setProperty(prefix+"lensDistanceShowResults",this.lensDistanceShowResults+"");
properties.setProperty(prefix+"lensDistanceMoveToGoal",this.lensDistanceMoveToGoal+"");
properties.setProperty(prefix+"powerControlEnable",this.powerControlEnable+"");
properties.setProperty(prefix+"powerControlMaximalTemperature",this.powerControlMaximalTemperature+"");
properties.setProperty(prefix+"powerControlHeaterOnMinutes",this.powerControlHeaterOnMinutes+"");
properties.setProperty(prefix+"powerControlNeitherOnMinutes",this.powerControlNeitherOnMinutes+"");
properties.setProperty(prefix+"powerControlFanOnMinutes",this.powerControlFanOnMinutes+"");
properties.setProperty(prefix+"uvLasersIP",this.uvLasersIP);
properties.setProperty(prefix+"uvLasersBus",this.uvLasersBus+"");
properties.setProperty(prefix+"uvLasersCurrents_0",this.uvLasersCurrents[0]+"");
properties.setProperty(prefix+"uvLasersCurrents_1",this.uvLasersCurrents[1]+"");
properties.setProperty(prefix+"uvLasersCurrents_2",this.uvLasersCurrents[2]+"");
properties.setProperty(prefix+"uvLasersCurrents_3",this.uvLasersCurrents[3]+"");
properties.setProperty(prefix+"smallestSubPix",this.smallestSubPix+"");
properties.setProperty(prefix+"bitmapNonuniforityThreshold",this.bitmapNonuniforityThreshold+"");
properties.setProperty(prefix+"subdiv",this.subdiv+"");
......@@ -1129,7 +1133,7 @@ public class LensAdjustment {
properties.setProperty(prefix+"correlationSize",this.correlationSize+"");
properties.setProperty(prefix+"correlationGaussWidth",this.correlationGaussWidth+"");
properties.setProperty(prefix+"minUVSpan",this.minUVSpan+"");
properties.setProperty(prefix+"correlationMinContrast",this.correlationMinContrast+"");
properties.setProperty(prefix+"correlationMinInitialContrast",this.correlationMinInitialContrast+"");
properties.setProperty(prefix+"correlationMinAbsoluteContrast",this.correlationMinAbsoluteContrast+"");
......@@ -1141,11 +1145,11 @@ public class LensAdjustment {
properties.setProperty(prefix+"flatFieldExpand",this.flatFieldExpand+"");
properties.setProperty(prefix+"thresholdFinish",this.thresholdFinish+"");
properties.setProperty(prefix+"numIterations",this.numIterations+"");
for (int i=0;i<this.ampsSeconds.length;i++)
for (int i=0;i<this.ampsSeconds.length;i++)
properties.setProperty(prefix+"ampsSeconds_"+i,this.ampsSeconds[i]+"");
properties.setProperty(prefix+"reportTemperature",this.reportTemperature+"");
properties.setProperty(prefix+"showLegacy",this.showLegacy+"");
}
}
public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"gridGeometryFile")!=null)
this.gridGeometryFile=properties.getProperty(prefix+"gridGeometryFile");
......@@ -1160,11 +1164,11 @@ public class LensAdjustment {
if (properties.getProperty(prefix+"useLMAMetrics")!=null)
this.useLMAMetrics=Boolean.parseBoolean(properties.getProperty(prefix+"useLMAMetrics"));
if (properties.getProperty(prefix+"serialNumber")!=null)
this.serialNumber=properties.getProperty(prefix+"serialNumber");
// this.serialNumber is only written, but never read from the configuration file (only from devivce)
if (properties.getProperty(prefix+"sensorTemperature")!=null) this.sensorTemperature=Double.parseDouble(properties.getProperty(prefix+"sensorTemperature"));
else this.sensorTemperature=Double.NaN;
if (properties.getProperty(prefix+"result_lastKT")!=null) this.result_lastKT=Double.parseDouble(properties.getProperty(prefix+"result_lastKT"));
......@@ -1260,7 +1264,7 @@ public class LensAdjustment {
this.useExtraSensor=Boolean.parseBoolean(properties.getProperty(prefix+"useExtraSensor"));
if (properties.getProperty(prefix+"enRoundOff")!=null)
this.enRoundOff = Boolean.parseBoolean(properties.getProperty(prefix+"enRoundOff"));
if (properties.getProperty(prefix+"keepCircularMask")!=null)
this.keepCircularMask=Boolean.parseBoolean(properties.getProperty(prefix+"keepCircularMask"));
if (properties.getProperty(prefix+"psf_cutoffEnergy")!=null)
......@@ -1301,20 +1305,20 @@ public class LensAdjustment {
this.motorsFadeSigma=Double.parseDouble(properties.getProperty(prefix+"motorsFadeSigma"));
if (properties.getProperty(prefix+"motorsOverShootToBalance")!=null)
this.motorsOverShootToBalance=Double.parseDouble(properties.getProperty(prefix+"motorsOverShootToBalance"));
if (properties.getProperty(prefix+"filterGoodDistance")!=null)
this.filterGoodDistance=Boolean.parseBoolean(properties.getProperty(prefix+"filterGoodDistance"));
if (properties.getProperty(prefix+"goodDistanceSigma")!=null)
this.goodDistanceSigma=Double.parseDouble(properties.getProperty(prefix+"goodDistanceSigma"));
if (properties.getProperty(prefix+"goodTiltSigma")!=null)
this.goodTiltSigma=Double.parseDouble(properties.getProperty(prefix+"goodTiltSigma"));
if (properties.getProperty(prefix+"maxStep")!=null)
this.maxStep=Double.parseDouble(properties.getProperty(prefix+"maxStep"));
if (properties.getProperty(prefix+"probeStep")!=null)
this.probeStep=Double.parseDouble(properties.getProperty(prefix+"probeStep"));
if (properties.getProperty(prefix+"probe_M1M2M3")!=null)
this.probe_M1M2M3=Double.parseDouble(properties.getProperty(prefix+"probe_M1M2M3"));
if (properties.getProperty(prefix+"probe_M3_M1M2")!=null)
......@@ -1368,14 +1372,14 @@ public class LensAdjustment {
this.scanTiltEnable=Boolean.parseBoolean(properties.getProperty(prefix+"scanTiltEnable"));
if (properties.getProperty(prefix+"scanTiltReverse")!=null)
this.scanTiltReverse=Boolean.parseBoolean(properties.getProperty(prefix+"scanTiltReverse"));
if (properties.getProperty(prefix+"scanMeasureLast")!=null)
this.scanMeasureLast=Boolean.parseBoolean(properties.getProperty(prefix+"scanMeasureLast"));
if (properties.getProperty(prefix+"scanRunLMA")!=null)
this.scanRunLMA=Boolean.parseBoolean(properties.getProperty(prefix+"scanRunLMA"));
if (properties.getProperty(prefix+"scanTiltRangeX")!=null)
this.scanTiltRangeX=Integer.parseInt(properties.getProperty(prefix+"scanTiltRangeX"));
if (properties.getProperty(prefix+"scanTiltRangeY")!=null)
......@@ -1384,7 +1388,7 @@ public class LensAdjustment {
this.scanTiltStepsX=Integer.parseInt(properties.getProperty(prefix+"scanTiltStepsX"));
if (properties.getProperty(prefix+"scanTiltStepsY")!=null)
this.scanTiltStepsY=Integer.parseInt(properties.getProperty(prefix+"scanTiltStepsY"));
if (properties.getProperty(prefix+"motorHysteresis")!=null)
this.motorHysteresis=Integer.parseInt(properties.getProperty(prefix+"motorHysteresis"));
if (properties.getProperty(prefix+"measuredHysteresis")!=null)
......@@ -1410,7 +1414,7 @@ public class LensAdjustment {
if (properties.getProperty(prefix+"lensDistanceMoveToGoal")!=null)
this.lensDistanceMoveToGoal=Boolean.parseBoolean(properties.getProperty(prefix+"lensDistanceMoveToGoal"));
if (properties.getProperty(prefix+"powerControlEnable")!=null)
this.powerControlEnable=Boolean.parseBoolean(properties.getProperty(prefix+"powerControlEnable"));
if (properties.getProperty(prefix+"powerControlMaximalTemperature")!=null)
......@@ -1421,7 +1425,7 @@ public class LensAdjustment {
this.powerControlNeitherOnMinutes=Double.parseDouble(properties.getProperty(prefix+"powerControlNeitherOnMinutes"));
if (properties.getProperty(prefix+"powerControlFanOnMinutes")!=null)
this.powerControlFanOnMinutes=Double.parseDouble(properties.getProperty(prefix+"powerControlFanOnMinutes"));
if (properties.getProperty(prefix+"uvLasersIP")!=null)
this.uvLasersIP=properties.getProperty(prefix+"uvLasersIP");
if (properties.getProperty(prefix+"uvLasersBus")!=null)
......@@ -1434,7 +1438,7 @@ public class LensAdjustment {
this.uvLasersCurrents[2]=Double.parseDouble(properties.getProperty(prefix+"uvLasersCurrents_2"));
if (properties.getProperty(prefix+"uvLasersCurrents_3")!=null)
this.uvLasersCurrents[3]=Double.parseDouble(properties.getProperty(prefix+"uvLasersCurrents_3"));
if (properties.getProperty(prefix+"smallestSubPix")!=null)
this.smallestSubPix=Double.parseDouble(properties.getProperty(prefix+"smallestSubPix"));
if (properties.getProperty(prefix+"bitmapNonuniforityThreshold")!=null)
......@@ -1522,7 +1526,7 @@ public class LensAdjustment {
int manIndex= gd.getNextChoiceIndex();
int manMod= (int) gd.getNextNumber();
this.askLensSerial= gd.getNextBoolean();
this.centerDeltaX= gd.getNextNumber();
this.centerDeltaX= gd.getNextNumber();
this.centerDeltaY= gd.getNextNumber();
if (manMod<0) manMod=0;
else if (manMod>maxMod) manMod=maxMod;
......@@ -1542,7 +1546,7 @@ public class LensAdjustment {
}
}
}
// subset of showDialog() - only set parameters realated to scanning
// subset of showDialog() - only set parameters realated to scanning
public boolean showScanningSetup(String title) {
GenericDialog gd = new GenericDialog(title);
gd.addNumericField("Motor single movement (all 3 motors) in scan focus mode (signed value)", this.scanStep, 0,7,"motors steps");
......@@ -1556,8 +1560,8 @@ public class LensAdjustment {
gd.addCheckbox ("Scan for tilt measurement in both directions", this.scanTiltReverse);
gd.addCheckbox ("Calculate PSF after returning to the initial position", this.scanMeasureLast);
gd.addCheckbox ("Calculate model parameters after scanning", this.scanRunLMA);
gd.addNumericField("Full range of scanning motors tilting in X-direction", this.scanTiltRangeX, 0,7,"motors steps");
gd.addNumericField("Full range of scanning motors tilting in Y-direction", this.scanTiltRangeY, 0,7,"motors steps");
gd.addNumericField("Number of stops measurements when tilting in X-deirection", this.scanTiltStepsX, 0);
......@@ -1580,23 +1584,23 @@ public class LensAdjustment {
this.scanTiltReverse= gd.getNextBoolean();
this.scanMeasureLast= gd.getNextBoolean();
this.scanRunLMA= gd.getNextBoolean();
this.scanTiltRangeX= (int) gd.getNextNumber();
this.scanTiltRangeY= (int) gd.getNextNumber();
this.scanTiltStepsX= (int) gd.getNextNumber();
this.scanTiltStepsY= (int) gd.getNextNumber();
this.motorHysteresis= (int) gd.getNextNumber();
return true;
return true;
}
public boolean showDialog(String title) {
public boolean showDialog(String title) {
GenericDialog gd = new GenericDialog(title);
// this.serialNumber, // camera serial number string
gd.addMessage("Sensor board serial number is "+(((this.serialNumber==null)||(this.serialNumber==""))?"not specified":this.serialNumber));
gd.addStringField ("Comment to add to the result files", this.comment,80);
gd.addStringField ("Lens serial number",this.lensSerial);
int [] manufacturingIndexMod=getManufacturingIndexMod(this.manufacturingState);
gd. addChoice("Manufacturing state", this.manufacturingStateNames, this.manufacturingStateNames[manufacturingIndexMod[0]]);
int maxMod=9;
......@@ -1605,7 +1609,7 @@ public class LensAdjustment {
}
gd.addNumericField("Optional manufacturing state modifier (0.."+maxMod+")", manufacturingIndexMod[1], 0,1,"");
gd.addCheckbox ("Ask lens serial number on each camera power cycle",this.askLensSerial);
gd.addCheckbox ("Add lens serial number to filenames",this.includeLensSerial);
gd.addNumericField("Required X-shift between the lens axis and the sensor center", this.centerDeltaX, 0,4,"pix (180 for tilted)");
......@@ -1669,8 +1673,8 @@ public class LensAdjustment {
gd.addNumericField("Maximal allowed single-step focusing adjustment", this.maxStep, 1,7,"motors steps");
gd.addNumericField("How far to go to probe around the current point to measure derivatives", this.probeStep, 1,7,"motors steps");
gd.addNumericField("How far too move average of the 3 motors: (M1+M2+M3)/3 during probing", this.probe_M1M2M3, 1,7,"motors steps");
gd.addNumericField("How far to move M3 opposite to M1 and M2: M3-(M1+M2)/2 during probing", this.probe_M3_M1M2, 1,7,"motors steps");
gd.addNumericField("How far to move M2 opposite to M1: M2-M1 during probing", this.probe_M2_M1, 1,7,"motors steps");
......@@ -1693,20 +1697,20 @@ public class LensAdjustment {
gd.addCheckbox ("Open dialog when calibrating focal distance", this.lensDistanceInteractive);
gd.addCheckbox ("Show results window from focal distance calibration", this.lensDistanceShowResults);
gd.addCheckbox ("Move motors together to the requested microns from the \"best focus\"", this.lensDistanceMoveToGoal);
gd.addCheckbox ("Enable power control for heater and fan", this.powerControlEnable);
gd.addNumericField("Maximal allowed temperature", this.powerControlMaximalTemperature, 3,5,"C");
gd.addNumericField("Heater ON time", this.powerControlHeaterOnMinutes, 1,5,"min");
gd.addNumericField("Both heater and fan OFF time", this.powerControlNeitherOnMinutes, 1,5,"min");
gd.addNumericField("Fan ON time", this.powerControlFanOnMinutes, 1,5,"min");
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.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.addMessage("");
gd.addNumericField("Minimal correction movement to initiate final series of corrections - focus/tilt mode", this.minCorr, 1,5,"motors steps");
gd.addNumericField("Finish if this number of last corrections where below minimum (previous input) - focus/tilt mode",this.numFinalCorr, 0);
......@@ -1720,25 +1724,25 @@ public class LensAdjustment {
gd.addNumericField("Motor single movement (all 3 motors) in scan focus mode (signed value)", this.scanStep, 0,7,"motors steps");
gd.addNumericField("Number of scan steps during (center) focus scanning", this.scanNumber, 0);
gd.addNumericField("... of them - in the negative direction (closer lens to sensor)", this.scanNumberNegative, 0);
gd.addCheckbox ("Scan focus in 2 directions, after the calibration estimate hysteresis (play)", this.scanHysteresis);
gd.addNumericField("Number of scan steps during hysteresis (play) measurement", this.scanHysteresisNumber, 0);
gd.addCheckbox ("Scan for tilt measurement (approximately preserving center)", this.scanTiltEnable);
gd.addCheckbox ("Scan for tilt measurement in both directions", this.scanTiltReverse);
gd.addCheckbox ("Calculate PSF after returning to the initial position", this.scanMeasureLast);
gd.addNumericField("Full range of scanning motors tilting in X-direction", this.scanTiltRangeX, 0,7,"motors steps");
gd.addNumericField("Full range of scanning motors tilting in Y-direction", this.scanTiltRangeY, 0,7,"motors steps");
gd.addNumericField("Number of stops measurements when tilting in X-deirection", this.scanTiltStepsX, 0);
gd.addNumericField("Number of stops measurements when tilting in Y-deirection", this.scanTiltStepsY, 0);
gd.addMessage ("The following parameters overwrite some defined for aberration measurements in other dialogs");
gd.addNumericField("Smallest fraction to subdivide pixels at simulation", this.smallestSubPix, 3,5,"sensor pix");
gd.addNumericField("Maximal difference of the pattern value in the corners that triggers subdivision", this.bitmapNonuniforityThreshold, 3);
gd.addNumericField("Subdivide simulated pattern by:", this.subdiv, 0);
gd.addNumericField("Allowed overexposed pixels (fraction of the area) ",this.overexposedMaxFraction,3); // 0.005; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
gd.addNumericField("Allowed overexposed pixels (fraction of the area) ",this.overexposedMaxFraction,3); // 0.005; // allowed fraction of the overexposed pixels in the PSF kernel measurement area
gd.addNumericField("Min fraction of the FFT square (weighted) to have defined pattern", this.minDefinedArea, 3);
gd.addNumericField ("PSF kernel size", this.PSFKernelSize, 0);
gd.addCheckbox ("Approximate pattern grid with a polynomial",this.approximateGrid); // true; // ignore lateral chromatic aberration (center OTF to 0,0)
......@@ -1764,24 +1768,24 @@ public class LensAdjustment {
for (int i=0;i<this.postUVscrewSensitivity.length;i++){
gd.addNumericField("Screw "+i+" sensitivity", this.postUVscrewSensitivity[i], 4,6,"um/turn CW");
}
gd.addMessage("-----");
gd.addNumericField("Report focal length at this temperature", this.reportTemperature, 1,5,"C");
gd.addCheckbox ("Show legacy focusing parameters (most are already not supported anyway)", this.showLegacy);
if (!Double.isNaN(this.sensorTemperature)) gd.addMessage("Last measured sensor temperature is "+this.sensorTemperature+" C");
if (!Double.isNaN(this.result_lastKT)) gd.addMessage("Temperature focal distance coefficient measured in last run is "+this.result_lastKT+"microns/C");
if (!Double.isNaN(this.result_lastFD20)) gd.addMessage("Focal distance @20C measured at last run is "+this.result_lastFD20+" microns");
if (!Double.isNaN(this.result_lastKT) && !Double.isNaN(this.result_lastFD20)){
gd.addMessage("Focal distance @"+this.reportTemperature+"C measured at last run is "+
(this.result_lastFD20+(this.reportTemperature-20.0)*this.result_lastKT)+" microns");
(this.result_lastFD20+(this.reportTemperature-20.0)*this.result_lastKT)+" microns");
}
if (!Double.isNaN(this.result_allHistoryKT)) gd.addMessage("Temperature focal distance coefficient calculated from all measurements is "+this.result_allHistoryKT+" microns");
if (!Double.isNaN(this.result_allHistoryFD20)) gd.addMessage("Focal distance @20C calculated from all measurements is "+this.result_allHistoryFD20+" microns");
if (!Double.isNaN(this.result_allHistoryKT) && !Double.isNaN(this.result_allHistoryFD20)){
gd.addMessage("Focal distance @"+this.reportTemperature+"C calculated from all measurements is "+
(this.result_allHistoryFD20+(this.reportTemperature-20.0)*this.result_allHistoryKT)+" microns");
(this.result_allHistoryFD20+(this.reportTemperature-20.0)*this.result_allHistoryKT)+" microns");
}
if (!Double.isNaN(this.result_fDistance)) gd.addMessage("Focal distance is "+this.result_fDistance+" microns");
if (!Double.isNaN(this.result_tiltX)) gd.addMessage("Horizontal angular/tangential asymmetry "+this.result_tiltX);
......@@ -1790,7 +1794,7 @@ public class LensAdjustment {
if (!Double.isNaN(this.result_A50)) gd.addMessage("Same, but with averaged r^2: "+this.result_A50+" C");
if (!Double.isNaN(this.result_B50)) gd.addMessage("Same, but with averaged r^4: "+this.result_B50+" C");
if (!Double.isNaN(this.result_RC50)) gd.addMessage("Average PSF 50% radius for center samples "+this.result_RC50+" pixels");
if (!Double.isNaN(this.result_PX0)) gd.addMessage("Lens center X-coordinate on the sensor "+this.result_PX0+" pixels");
if (!Double.isNaN(this.result_PY0)) gd.addMessage("Lens center Y-coordinate on the sensor "+this.result_PY0+" pixels");
if (!Double.isNaN(this.result_PSI)) gd.addMessage("SFE rotation relative to target (clockwise - positive) "+this.result_PSI+" degrees");
......@@ -1798,7 +1802,7 @@ public class LensAdjustment {
if (!Double.isNaN(this.result_FocalLength)) gd.addMessage("Lens focal length "+this.result_FocalLength+" mm");
gd.addMessage("Cumulative currents that ran through UV LEDs:");
for (int i=0;i<this.ampsSeconds.length;i++) gd.addMessage("UV LED "+(i+1)+":"+IJ.d2s(this.ampsSeconds[i],3)+" coulombs (amp-seconds)");
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return false;
......@@ -1807,17 +1811,17 @@ public class LensAdjustment {
if (this.lensSerial.length()>0){
while (this.lensSerial.length()<lensSerialLength) this.lensSerial="0"+this.lensSerial;
}
int manIndex= gd.getNextChoiceIndex();
int manMod= (int) gd.getNextNumber();
if (manMod<0) manMod=0;
else if (manMod>maxMod) manMod=maxMod;
this.manufacturingState=this.manufacturingStateValues[manIndex]+manMod; // here no restriction on the order - can go backwards
this.askLensSerial= gd.getNextBoolean();
this.includeLensSerial= gd.getNextBoolean();
this.centerDeltaX= gd.getNextNumber();
this.centerDeltaX= gd.getNextNumber();
this.centerDeltaY= gd.getNextNumber();
this.gridGeometryFile= gd.getNextString();
......@@ -1861,7 +1865,7 @@ public class LensAdjustment {
this.weightRatioRedToGreen= gd.getNextNumber();
this.weightRatioBlueToGreen= gd.getNextNumber();
this.targetFarNear= gd.getNextNumber();
this.useRadialTangential= gd.getNextBoolean();
this.useRadialTangential= gd.getNextBoolean();
this.targetMicrons= gd.getNextNumber();
this.toleranceMicrons= gd.getNextNumber();
this.toleranceTilt= gd.getNextNumber();
......@@ -1869,9 +1873,9 @@ public class LensAdjustment {
this.parallelAdjustThreshold= gd.getNextNumber();
this.motorsSigma= gd.getNextNumber();
this.motorsSigma3= gd.getNextNumber();
this.motorsMinSigma= gd.getNextNumber();
this.motorsMinSigma= gd.getNextNumber();
this.motorsVarSigmaToTravel= gd.getNextNumber();
this.motorsFadeSigma= gd.getNextNumber();
this.motorsFadeSigma= gd.getNextNumber();
this.motorsOverShootToBalance= gd.getNextNumber();
this.filterGoodDistance= gd.getNextBoolean();
this.goodDistanceSigma= gd.getNextNumber();
......@@ -1881,8 +1885,8 @@ public class LensAdjustment {
this.probe_M1M2M3= gd.getNextNumber();
this.probe_M3_M1M2= gd.getNextNumber();
this.probe_M2_M1= gd.getNextNumber();
this.sigmaToProbe= gd.getNextNumber();
this.useTheBest= gd.getNextBoolean();
this.sigmaToProbe= gd.getNextNumber();
this.useTheBest= gd.getNextBoolean();
this.probeSymmetrical= gd.getNextBoolean();
this.parallelBeforeProbing= gd.getNextBoolean();
this.reProbeDistance= gd.getNextNumber();
......@@ -1905,14 +1909,14 @@ public class LensAdjustment {
this.powerControlHeaterOnMinutes= gd.getNextNumber();
this.powerControlNeitherOnMinutes= gd.getNextNumber();
this.powerControlFanOnMinutes= gd.getNextNumber();
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();
this.minCorr= gd.getNextNumber();
this.numFinalCorr= (int) gd.getNextNumber();
this.minCorrPre= gd.getNextNumber();
......@@ -1927,7 +1931,7 @@ public class LensAdjustment {
this.scanNumberNegative= (int) gd.getNextNumber();
this.scanHysteresis= gd.getNextBoolean();
this.scanHysteresisNumber= (int) gd.getNextNumber();
this.scanTiltEnable= gd.getNextBoolean();
this.scanTiltReverse= gd.getNextBoolean();
this.scanMeasureLast= gd.getNextBoolean();
......@@ -1935,12 +1939,12 @@ public class LensAdjustment {
this.scanTiltRangeY= (int) gd.getNextNumber();
this.scanTiltStepsX= (int) gd.getNextNumber();
this.scanTiltStepsY= (int) gd.getNextNumber();
this.smallestSubPix= gd.getNextNumber();
this.bitmapNonuniforityThreshold=gd.getNextNumber();
this.subdiv= (int) gd.getNextNumber();
this.overexposedMaxFraction= gd.getNextNumber();
this.overexposedMaxFraction= gd.getNextNumber();
this.minDefinedArea= gd.getNextNumber();
this.PSFKernelSize= (int) gd.getNextNumber();
this.approximateGrid= gd.getNextBoolean();
......@@ -1969,13 +1973,13 @@ public class LensAdjustment {
return true;
}
/* ======================================================================== */
//returns triads - x,y,distance from the lens center
//returns triads - x,y,distance from the lens center
public double [][][] sampleCoordinates(
double x0, // lens center on the sensor
double y0){ // lens center on the sensor
int ix0=(int) Math.round(x0);
int iy0=(int) Math.round(y0);
// Rectangle woi=new Rectangle(this.margins);
Rectangle woi=this.getMargins();
// System.out.println("Selection Rectangle("+woi.x+", "+woi.y+", "+woi.width+", "+woi.height+ ")");
......@@ -2007,7 +2011,7 @@ public class LensAdjustment {
woi.width-=this.sampleSize;
woi.height-=this.sampleSize;
// System.out.println("Selection - sample centers: Rectangle("+woi.x+", "+woi.y+", "+woi.width+", "+woi.height+ ")");
double [][][] sampleCoord=new double[this.numSamples[1]][this.numSamples[0]][3];
int y,x;
for (int i=0;i<this.numSamples[1];i++){
......@@ -2027,7 +2031,7 @@ public class LensAdjustment {
sampleCoord[i][j][2]=Math.sqrt((x-x0)*(x-x0)+(y-y0)*(y-y0)); // distance from tyhe center
}
}
/*
/*
for (int i=0;i<this.numSamples[1];i++){
for (int j=0;j<this.numSamples[0];j++){
System.out.println ("i="+i+" j="+j+" sampleCoord[i][j][0]="+sampleCoord[i][j][0]+" sampleCoord[i][j][1]="+sampleCoord[i][j][1]);
......@@ -2079,12 +2083,12 @@ public class LensAdjustment {
// System.out.println(s);
// System.out.println(sb.toString());
return sb.toString();
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -124,15 +124,7 @@ public class DoubleFHT {
public boolean transform(double [] data, boolean inverse) {
//IJ.log("transform: "+maxN+" "+inverse);
updateMaxN(data);
// maxN = (int) Math.sqrt(data.length);
// if ((S==null) || (S.length!=(maxN/4))) {
// makeSinCosTables(maxN);
// makeBitReverseTable(maxN);
// tempArr = new double[maxN];
// }
// float[] fht = (float[])getPixels();
rc2DFHT(data, inverse, this.maxN);
// isFrequencyDomain = !inverse;
return true;
}
......@@ -141,21 +133,15 @@ public class DoubleFHT {
double lowPass){
return createFrequencyFilter(null,highPass,lowPass);
}
/* public double []createFrequencyFilter(
double [] data,
double highPass,
double lowPass){
return createFrequencyFilter(data.length,highPass,lowPass);
}
*/
public double [] createFrequencyFilter(
public double [] createFrequencyFilter(
double [] data, //int n,
double highPass,
double lowPass){
if (data !=null) updateMaxN(data);
// int n;
if ((this.freqMask!=null) && (this.freqPass[0]==highPass) && (this.freqPass[0]==lowPass)) return this.freqMask;
if ((this.freqMask!=null) && (this.freqPass[0]==highPass) && (this.freqPass[1]==lowPass)) return this.freqMask;
this.freqMask= new double [(this.maxN+1)*this.maxN/2+1];
double [] lo=new double[this.maxN];
double [] hi=new double[this.maxN];
......@@ -177,12 +163,9 @@ public class DoubleFHT {
if (j>this.maxN/2) j=this.maxN-j;
this.freqMask[index]=(1.0-hi[i]*hi[j])*lo[i]*lo[j];
}
// this.freqMaskN=n;
this.freqPass=new double[2];
this.freqPass[0]=highPass;
this.freqPass[1]=lowPass;
// this.freqMask_cache[this.ln2]=this.freqMask;
// this.freqPass_cache[this.ln2]=this.freqPass;
return this.freqMask;
}
/**
......@@ -195,49 +178,6 @@ public class DoubleFHT {
*/
public double [] shift(double [] data, double dx, double dy){
return shift(data, 1, dx, dy);
/*
updateMaxN(data);
double sX=2*Math.PI*dx/this.maxN;
double sY=2*Math.PI*dy/this.maxN;
int halfN=this.maxN/2;
double [] cosDX = new double[this.maxN];
double [] sinDX = new double[this.maxN];
double [] cosDY = new double[halfN+1];
double [] sinDY = new double[halfN+1];
for (int i=0;i<=halfN;i++){ // need less?
cosDX[i]=Math.cos(sX*i);
sinDX[i]=Math.sin(sX*i);
cosDY[i]=Math.cos(sY*i);
sinDY[i]=Math.sin(sY*i);
}
for (int i=1;i<halfN;i++){ // need less?
cosDX[this.maxN-i]= cosDX[i];
sinDX[this.maxN-i]=-sinDX[i];
}
swapQuadrants(data);
if (!transform(data,false)) return null; // direct FHT
for (int row =0; row<=halfN; row++) {
int rowMod = (this.maxN - row) % this.maxN;
int maxCol=(row<halfN)?(this.maxN-1):halfN;
for (int col=0; col<=maxCol; col++) {
int colMod = (this.maxN - col) % this.maxN;
int index= row * this.maxN + col;
int indexMod=rowMod * this.maxN + colMod;
double re=0.5*(data[index]+data[indexMod]);
double im=0.5*(data[index]-data[indexMod]);
if ((col==halfN) || (row==halfN)) im=0;
double cosDelta= cosDX[col]*cosDY[row] - sinDX[col]*sinDY[row]; // cos(deltaX)*cos(deltaY)-sin(deltaX)*sin(deltaY)
double sinDelta= sinDX[col]*cosDY[row] + cosDX[col]*sinDY[row]; // sin(deltaX)*cos(deltaY)+cos(deltaX)*sin(deltaY)
double reMod=re*cosDelta-im*sinDelta;
double imMod=re*sinDelta+im*cosDelta;
data[index]= reMod+imMod;
data[indexMod]=reMod-imMod;
}
}
if (!transform(data,true)) return null; // inverse FHT
swapQuadrants(data);
return data;
*/
}
/**
* Upsample input array by padding in the frequency domain
......@@ -247,30 +187,6 @@ public class DoubleFHT {
*/
public double [] upsample( double [] first, int scale){
return shift (first, scale, 0.0, 0.0);
/*
if (scale <=1) return first.clone();
updateMaxN(first);
swapQuadrants(first);
if (!transform(first,false)) return null; // direct FHT
int halfN=this.maxN/2;
int shift=this.maxN*(scale-1);
int scaledN=this.maxN*scale;
double [] result =new double [first.length*scale*scale];
for (int i=0;i<result.length;i++) result [i]=0.0;
double scale2=scale*scale;
for (int i=0;i<first.length;i++){
int iy=i/this.maxN;
int ix=i%this.maxN;
if (ix>halfN) ix+=shift;
if (iy>halfN) iy+=shift;
result[scaledN*iy+ix]=scale2*first[i];
}
updateMaxN(result);
if (!transform(result,true)) return null; // inverse FHT
swapQuadrants(result);
return result;
*/
}
/**
......@@ -408,6 +324,54 @@ public class DoubleFHT {
swapQuadrants(first);
return first;
}
public double [] phaseCorrelate (
double [] first,
double phaseCoeff,
double high_pass,
double low_pass) { // high/low pass filtering
return phaseCorrelate(first, phaseCoeff, high_pass, low_pass, null);
}
public double [] phaseCorrelate (
double [] first,
double phaseCoeff,
double high_pass,
double low_pass, // high/low pass filtering
double [] fht_save){ //null-OK
updateMaxN(first);
double [] filter = null;
if ((high_pass >0) || (low_pass > 0)) {
filter = createFrequencyFilter(high_pass, low_pass);
}
return phaseCorrelate(first, phaseCoeff, filter,fht_save);
}
public double [] phaseCorrelate (
double [] first,
double phaseCoeff,
double [] filter) { // high/low pass filtering
return phaseCorrelate(first, phaseCoeff, filter, null);
}
public double [] phaseCorrelate (
double [] first,
double phaseCoeff,
double [] filter, // high/low pass filtering
double [] fht_save){ //null-OK
updateMaxN(first);
swapQuadrants(first);
if (!transform(first,false)) return null; // direct FHT
if (fht_save != null) {
System.arraycopy(first, 0, fht_save, 0, first.length);
}
first= phaseMultiplyNorm(first, first, phaseCoeff); // correlation, not convolution
if (filter!=null) multiplyByReal(first, filter);
transform(first,true) ; // inverse transform
swapQuadrants(first);
return first;
}
//
public double [] applyFreqFilter(
double [] first,
double [] filter
......@@ -2024,6 +1988,7 @@ public class DoubleFHT {
return product;
}
public double [] phaseMultiply(double [] h1, double [] h2, double phaseCoeff) {
int rowMod, colMod;
double h2e, h2o,d;
......@@ -2041,6 +2006,54 @@ public class DoubleFHT {
return product;
}
public double [] phaseMultiplyNorm(double [] h1, double [] h2, double phaseCoeff) {
int size = maxN;
int size2 = size >> 1;
int size21 = size*size2;
int rowMod, colMod, base, baseMod;
double h2e, h2o;
double[] product = new double[size*size];
for (int r =0; r<size; r++) {
rowMod = (size - r) % size;
for (int c=0; c<size; c++) {
colMod = (size - c) % size;
h2e = (h2[r * size + c] + h2[rowMod * size + colMod]) / 2;
h2o = (h2[r * size + c] - h2[rowMod * size + colMod]) / 2;
product[r * size + c] = (h1[r * size + c] * h2e - h1[rowMod * size + colMod] * h2o);
}
}
double [] amplitude = calculateAmplitudeHalf(product);
double avg_ampl = 0.0;
for (int row = 1; row < size2; row++) {
base = row*size;
for (int col = 0; col < size; col++) {
avg_ampl += amplitude[col+base];
}
}
avg_ampl *= 2;
for (int col = 0; col < size; col++) {
avg_ampl += amplitude[col] + amplitude[col + size21];
}
avg_ampl /= size*size;
double aoffs = (1.0 - phaseCoeff) * avg_ampl;
double ampl;
for (int row = 0; row <= size2; row++) {
base = row*size;
rowMod = (size - row) % size;
baseMod = rowMod * size;
for (int col = 0; col < size; col++) {
ampl = phaseCoeff * amplitude[col+base] + aoffs;
product[col+base] /= ampl;
if ((row > 0) && (row < size2)) {
colMod = (size - col) % size;
product[colMod + baseMod] /= ampl;
}
}
}
return product;
}
// Multiply by real array (i.e. filtering in frequency domain). Array m length should be at least maxN*maxN/2+1
public void multiplyByReal(double [] h, double [] m) {
......@@ -2094,6 +2107,17 @@ public class DoubleFHT {
swapQuadrants(amp);
return amp;
}
public double [] calculateAmplitudeHalf(double [] fht) {
int size=(int) Math.sqrt(fht.length);
int size2 = (size >>1) +1;
double[] amp = new double[size* size2];
for (int row=0; row<size2; row++) {
amplitude(row, size, fht, amp);
}
return amp;
}
public double [] calculateAmplitude2(double [] fht) {
int size=(int) Math.sqrt(fht.length);
double[] amp = new double[size*size];
......@@ -2133,8 +2157,6 @@ public class DoubleFHT {
row2=(fftsize-row1) %fftsize;
for (col1=0;col1<fftsize;col1++) {
col2=(fftsize-col1) %fftsize;
// fftHalf[row1][col1]= complex( 0.5*(fht_pixels[row1*fftsize+col1] + fht_pixels[row2*fftsize+col2]),
// 0.5*(fht_pixels[row2*fftsize+col2] - fht_pixels[row1*fftsize+col1]));
fftHalf[row1][col1][0]= 0.5*(fht_pixels[row1*fftsize+col1] + fht_pixels[row2*fftsize+col2]);
fftHalf[row1][col1][1]= 0.5*(fht_pixels[row2*fftsize+col2] - fht_pixels[row1*fftsize+col1]);
}
......
......@@ -112,6 +112,30 @@ import ij.process.ImageProcessor;
return;
} else showArrays(pixels, width, height, titles);
}
public void showComplex(double[][][] cpixels, String title) {
int height = cpixels.length;
int width = cpixels[0].length;
double [][]pixels = new double [height*width][];
int indx = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[indx++] = cpixels[y][x];
}
}
showComplex(pixels, width, title);
}
public void showComplex(double[][] cpixels, int width, String title) {
int height = cpixels.length/width;
double [][]pixels = new double [2][cpixels.length];
for (int i = 0; i< cpixels.length; i++) {
pixels[0][i]= cpixels[i][0];
pixels[1][i]= cpixels[i][1];
}
String [] titles = {"Re", "Im"};
showArrays(pixels, width, height, true, title, titles);
}
public void showArrays(float[][] pixels, int width, int height, boolean asStack, String title, String [] titles) {
int i,j;
......
......@@ -1407,7 +1407,12 @@ Exception in thread "Thread-3564" java.lang.ArrayIndexOutOfBoundsException: 8970
NodeList allNodes=doc.getDocumentElement().getElementsByTagName("*");
for (int i=0;i<allNodes.getLength();i++) {
String name= allNodes.item(i).getNodeName();
String value=allNodes.item(i).getFirstChild().getNodeValue();
String value="";
try {
value=allNodes.item(i).getFirstChild().getNodeValue();
} catch(Exception e) {
}
imp.setProperty(name, value);
}
......
......@@ -26,10 +26,14 @@
*/
package com.elphel.imagej.lwir;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Properties;
import com.elphel.imagej.common.GenericJTabbedDialog;
import ij.Prefs;
public class LwirReaderParameters {
private boolean parameters_updated = false;
protected int avg_number = 4; // number of measurements to average
......@@ -49,6 +53,7 @@ public class LwirReaderParameters {
protected double vnir_gain_g = 2.0;
protected double vnir_gain_rg = 0.7705; // 1.116; halogen/fluorescent
protected double vnir_gain_bg = 2.401; // 1.476;
protected boolean [] selected_channels = {true, true, true, true, true, true, true, true};
/*
protected double [] vnir_exp_corr = {1.0, 1.0, 1.0, 1.0};
......@@ -70,7 +75,7 @@ public class LwirReaderParameters {
protected int vnir_lag = 1; // frames
protected double max_mismatch_ms = 0.05;
protected int max_frame_diff = 1; // 2;
protected int debug_level = 0;//-3: OFF, -2:Fatal, -1:ERROR, 0:WARN, 1:INFO,2:DEBUG
protected int debug_level = 0;//-3: OFF, -2:Fatal, -1:ERROR, 0:WARN, 1:INFO,2:DEBUG
// --- interface methods
......@@ -106,6 +111,7 @@ public class LwirReaderParameters {
properties.setProperty(prefix+"max_mismatch_ms", this.max_mismatch_ms+"");
properties.setProperty(prefix+"max_frame_diff", this.max_frame_diff+"");
properties.setProperty(prefix+"debug_level", this.debug_level+"");
properties.setProperty(prefix+"selected_channels", arr_to_str(this.selected_channels));
}
......@@ -134,6 +140,7 @@ public class LwirReaderParameters {
if (properties.getProperty(prefix+"max_mismatch_ms")!=null) this.max_mismatch_ms=Double.parseDouble(properties.getProperty(prefix+"max_mismatch_ms"));
if (properties.getProperty(prefix+"max_frame_diff")!=null) this.max_frame_diff=Integer.parseInt(properties.getProperty(prefix+"max_frame_diff"));
if (properties.getProperty(prefix+"debug_level")!=null) this.debug_level=Integer.parseInt(properties.getProperty(prefix+"debug_level"));
if (properties.getProperty(prefix+"selected_channels")!=null) this.selected_channels=str_to_barr(properties.getProperty(prefix+"selected_channels"));
parameters_updated = true;
}
@Override
......@@ -163,6 +170,7 @@ public class LwirReaderParameters {
lrp.max_mismatch_ms= this.max_mismatch_ms;
lrp.max_frame_diff= this.max_frame_diff;
lrp.debug_level= this.debug_level;
lrp.selected_channels = this.selected_channels.clone();
return lrp;
}
......@@ -198,7 +206,8 @@ public class LwirReaderParameters {
(lrp.vnir_lag == this.vnir_lag) &&
(lrp.max_mismatch_ms == this.max_mismatch_ms) &&
(lrp.max_frame_diff == this.max_frame_diff) &&
(lrp.debug_level == this.debug_level);
(lrp.debug_level == this.debug_level) &&
(java.util.Arrays.equals(lrp.selected_channels, this.selected_channels));
}
@Override
......@@ -225,6 +234,7 @@ public class LwirReaderParameters {
result = prime * result + arr_to_str(vnir_exp_corr).hashCode();
result = prime * result + arr_to_str(vnir_gcorr_rbgb).hashCode();
result = prime * result + (new Integer(lwir_trig_dly)).hashCode();
result = prime * result + arr_to_str(selected_channels).hashCode();
// next are not needed to be programmed to the cameras
// result = prime * result + (new Integer(vnir_lag)).hashCode();
// result = prime * result + (new Double(max_mismatch_ms)).hashCode();
......@@ -241,7 +251,7 @@ public class LwirReaderParameters {
gd.addStringField ("LWIR channels", arr_to_str(this.lwir_channels), 20, "Space-separated list of used LWIR camera channels, such as '0 1 2 3'");
gd.addStringField ("VNIR channels", arr_to_str(this.vnir_channels), 20, "Space-separated list of used visible range camera channels, such as '0 1 2 3'");
gd.addCheckbox ("LWIR telemetry", this.lwir_telemetry, "Set LWIR sesnors to provide telemetry data in the last 2 lines (may become mandatory later)");
gd.addNumericField("VNIR quality", this.vnir_quality, 3,6,"ms", "Visible range camera JPEG compression quality (all channels)");
gd.addNumericField("VNIR quality", this.vnir_quality, 3,6,"%", "Visible range camera JPEG compression quality (all channels)");
gd.addCheckbox ("VNIR undo white balance", this.vnir_scale, "Undo in-camera white balancing");
gd.addCheckbox ("VNIR autoexposure", this.vnir_autoexp, "Enable autoexposure for the visible range camera");
gd.addNumericField("VNIR vnir_max_autoexp_ms", this.vnir_max_autoexp_ms, 3,6,"ms", "Visible range camera maximal exposure in autoexposure mode");
......@@ -256,12 +266,13 @@ public class LwirReaderParameters {
gd.addNumericField("VNIR lag", this.vnir_lag, 0,3,"","Visible camera lag (in frames) relative to LWIR one");
gd.addNumericField("Max mismatch", this.max_mismatch_ms, 3,6,"ms","Maximal mismatch between image timestamps. Larger mismatch requires LWIR sinsor reinitialization");
gd.addNumericField("Max frame diff",this.max_frame_diff, 0,3,"","Maximal difference in frames between simultaneously acquired channels as calculated from the timestamps");
gd.addNumericField("Debug level", this.debug_level, 0,3,"","Image acquisition log level: -3: OFF, -2:FATAL, -1:ERROR, 0:WARN, 1:INFO, 2:DEBUG");
gd.addNumericField("Debug level", this.debug_level, 0,3,"","Image acquisition log level: -3: OFF, -2:FATAL, -1:ERROR, 0:WARN, 1:INFO, 2:DEBUG");
gd.addStringField ("Selected channels", arr_to_str(this.selected_channels), 20, "Space-separated channel selection (1 - selected, 0 - unselected)");
}
public void dialogAnswers(GenericJTabbedDialog gd) {
this.avg_number = (int) gd.getNextNumber();
this.lwir_ffc = gd.getNextBoolean();
this.lwir_ffc = gd.getNextBoolean();
this.avg_all = gd.getNextBoolean();
this.lwir_ip = gd.getNextString();
this.vnir_ip = gd.getNextString();
......@@ -284,6 +295,7 @@ public class LwirReaderParameters {
this.max_mismatch_ms = gd.getNextNumber();
this.max_frame_diff = (int) gd.getNextNumber();
this.debug_level = (int) gd.getNextNumber();
this.selected_channels = str_to_barr(gd.getNextString());
parameters_updated = true;
}
......@@ -307,6 +319,80 @@ public class LwirReaderParameters {
parameters_updated = false;
}
public boolean [] getSelected(){
return selected_channels;
}
public boolean [] getSelectedLwir(){
boolean [] sel = selected_channels.clone();
for (int i = lwir_channels.length; i < sel.length; i++ ) {
sel[i] = false;
}
return sel;
}
public boolean [] getSelectedVnir(){
boolean [] sel = selected_channels.clone();
for (int i = 0; i < lwir_channels.length; i++ ) {
sel[i] = false;
}
return sel;
}
public String [] getSourceFilesFlat(String [] sets, boolean[] channels) {
int num_sel = 0;
for (boolean s: channels) if (s) num_sel++;
String [] files = new String [sets.length * num_sel];
int indx = 0;
for (String set:sets) {
for (int i = 0; i < channels.length; i++) if (channels[i]) {
String file_base = set;
if (set.indexOf(Prefs.getFileSeparator()) >=0) {
file_base = set.substring(set.lastIndexOf(Prefs.getFileSeparator())+1);
}
files[indx++] =set + Prefs.getFileSeparator()+ file_base+"_"+i+".tiff";
}
}
return files;
}
// Image set may have different timestamps, only lwir0 matches
public String [][] getSourceFiles(String [] sets, boolean[] channels) {
String [][] files = new String [sets.length][channels.length];
for (int nset= 0; nset < sets.length; nset++) {
// read all files in the directory
File set_dir = new File(sets[nset]);
File [] channel_files = set_dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
if (!(new File(current, name).isFile()) || !name.endsWith(".tiff")) return false;
String base = name.substring(0, name.lastIndexOf(".tiff"));
int undr = base.lastIndexOf("_");
if (undr < 0) return false;
int chn = -1;
try {
chn = Integer.parseInt(base.substring(undr + 1));
} catch (Exception e) {
}
return chn >= 0;
}
});
for (File f: channel_files) {
String base = f.getName().substring(0, f.getName().lastIndexOf(".tiff"));
int undr = base.lastIndexOf("_");
int chn = Integer.parseInt(base.substring(undr + 1));
if ((chn >= 0) && (chn < channels.length) && channels[chn]) {
files[nset][chn] = f.getPath();
}
}
}
return files;
}
// --- internal methods
private String arr_to_str(int [] arr) {
......@@ -321,6 +407,23 @@ public class LwirReaderParameters {
return s.trim();
}
private String arr_to_str(boolean [] arr) {
String s = "";
for (boolean c:arr) s+= (c?1:0)+" ";
return s.trim();
}
private boolean [] str_to_barr(String s) {
int [] iarr = str_to_iarr(s);
if (iarr == null) return null;
boolean [] barr = new boolean [iarr.length];
for (int i = 0; i < barr.length; i++) {
barr[i] = iarr[i] != 0;
}
return barr;
}
private int [] str_to_iarr(String s) {
String [] sa;
if (s.indexOf(",") >= 0) {
......@@ -349,4 +452,22 @@ public class LwirReaderParameters {
return darr;
}
public boolean [] selectSourceChannels(){
return selectSourceChannels(selected_channels);
}
public boolean [] selectSourceChannels(boolean [] sel) {
GenericJTabbedDialog gd = new GenericJTabbedDialog("Set CLT parameters",300,500);
for (int i = 0; i < sel.length; i++) {
gd.addCheckbox ("Channel "+i, sel[i], "Enable processing camera channel "+i);
}
gd.showDialog();
if (gd.wasCanceled()) return null;
for (int i = 0; i < sel.length; i++) {
sel[i] = gd.getNextBoolean();
}
return sel;
}
}
......@@ -640,7 +640,7 @@ the type of pixel data in this file getPixelType()
}
// copied from JP46_Reader_camera.java
public ImagePlus encodeProperiesToInfo(ImagePlus imp){
public static ImagePlus encodeProperiesToInfo(ImagePlus imp){
String info="<?xml version=\"1.0\" encoding=\"UTF-8\"?><properties>";
Set<Object> jp4_set;
Properties jp4_prop;
......@@ -661,7 +661,7 @@ the type of pixel data in this file getPixelType()
return imp;
}
public boolean decodeProperiesFromInfo(ImagePlus imp){
public static boolean decodeProperiesFromInfo(ImagePlus imp){
if (imp.getProperty("Info")==null) return false;
String xml= (String) imp.getProperty("Info");
......@@ -684,11 +684,15 @@ the type of pixel data in this file getPixelType()
NodeList allNodes=doc.getDocumentElement().getElementsByTagName("*");
for (int i=0;i<allNodes.getLength();i++) {
String name= allNodes.item(i).getNodeName();
String value=allNodes.item(i).getFirstChild().getNodeValue();
imp.setProperty(name, value);
// System.out.print(name+" -> ");
String value = "";
try {
value=allNodes.item(i).getFirstChild().getNodeValue();
} catch (Exception e) {
}
// System.out.println(value);
imp.setProperty(name, value);
}
return true;
}
......
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