Commit 1b78d16a authored by Andrey Filippov's avatar Andrey Filippov

more cartesian mode support

parent 1d2d14af
...@@ -3322,7 +3322,7 @@ if (MORE_BUTTONS) { ...@@ -3322,7 +3322,7 @@ if (MORE_BUTTONS) {
GenericDialog gd = new GenericDialog("Select sensor number"); GenericDialog gd = new GenericDialog("Select sensor number");
gd.addCheckbox("Save all sensors", true); gd.addCheckbox("Save all sensors", true);
gd.addNumericField("Number of sensor/channel to save calibration (if \"all\" is not selected)", 0,0); gd.addNumericField("Number of sensor/channel to save calibration (if \"all\" is not selected)", 0,0);
gd.addCheckbox("Save non-calibared sensors", false); gd.addCheckbox("Save non-calibrated sensors", false);
gd.showDialog(); gd.showDialog();
if (gd.wasCanceled()) return; if (gd.wasCanceled()) return;
boolean allFiles=gd.getNextBoolean(); boolean allFiles=gd.getNextBoolean();
...@@ -569,6 +569,10 @@ import org.apache.commons.configuration.XMLConfiguration; ...@@ -569,6 +569,10 @@ import org.apache.commons.configuration.XMLConfiguration;
return -1; return -1;
} }
public int getNumDescriptions(){
return this.parameterDescriptions.length;
}
/** /**
* Initialize data from scratch using filenames "grid-<timestamp-seconds>_<timestamp-microseconds>-<channel-number>.tiff * Initialize data from scratch using filenames "grid-<timestamp-seconds>_<timestamp-microseconds>-<channel-number>.tiff
* @param filenames List of grid filenames (2-slice TIFFs) * @param filenames List of grid filenames (2-slice TIFFs)
......
...@@ -3318,7 +3318,7 @@ For each point in the image ...@@ -3318,7 +3318,7 @@ For each point in the image
for (int i=0;i<lensParNames.length;i++)header+="\t"+lensParNames[i]; for (int i=0;i<lensParNames.length;i++)header+="\t"+lensParNames[i];
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (int parNum=0;parNum<this.lensDistortionParameters.getNumInputs();parNum++){ for (int parNum=0;parNum<this.lensDistortionParameters.getNumInputs();parNum++){
sb.append(parNum+"\t"+fittingStrategy.distortionCalibrationData.parameterDescriptions[parNum][0]+"\tderivative"); sb.append(parNum+"\t"+fittingStrategy.distortionCalibrationData.descrField(parNum,0)+"\tderivative");
for (int i=0;i<lensParNames.length;i++) sb.append("\t"+derivatives_true[parNum][i]); for (int i=0;i<lensParNames.length;i++) sb.append("\t"+derivatives_true[parNum][i]);
sb.append("\n"); sb.append("\n");
sb.append("\t \tdelta"); sb.append("\t \tdelta");
...@@ -4225,10 +4225,10 @@ List calibration ...@@ -4225,10 +4225,10 @@ List calibration
} }
sb.append("\n"); sb.append("\n");
for (int parNumber=0;parNumber<fittingStrategy.distortionCalibrationData.parameterDescriptions.length;parNumber++){ for (int parNumber=0;parNumber<fittingStrategy.distortionCalibrationData.getNumDescriptions();parNumber++){
sb.append( sb.append(
fittingStrategy.distortionCalibrationData.parameterDescriptions[parNumber][0]+"\t"+ fittingStrategy.distortionCalibrationData.descrField(parNumber,0)+"\t"+
fittingStrategy.distortionCalibrationData.parameterDescriptions[parNumber][2]); fittingStrategy.distortionCalibrationData.descrField(parNumber,2));
for (int imgIndex=0;imgIndex<numImages;imgIndex++){ for (int imgIndex=0;imgIndex<numImages;imgIndex++){
int imgNum=imgIndices[imgIndex]; // image number int imgNum=imgIndices[imgIndex]; // image number
// sb.append("\t"+IJ.d2s(fittingStrategy.distortionCalibrationData.pars[imgNum][parNumber],3+extraDecimals)); // TODO: make an array of decimals per parameter // sb.append("\t"+IJ.d2s(fittingStrategy.distortionCalibrationData.pars[imgNum][parNumber],3+extraDecimals)); // TODO: make an array of decimals per parameter
...@@ -5334,7 +5334,7 @@ List calibration ...@@ -5334,7 +5334,7 @@ List calibration
int iState=(state[0]?1:0)+(state[1]?2:0); int iState=(state[0]?1:0)+(state[1]?2:0);
GenericDialog gd = new GenericDialog("Levenberg-Marquardt algorithm step"); GenericDialog gd = new GenericDialog("Levenberg-Marquardt algorithm step");
String [][] parameterDescriptions=fittingStrategy.distortionCalibrationData.parameterDescriptions; // String [][] parameterDescriptions=fittingStrategy.distortionCalibrationData.parameterDescriptions;
gd.addMessage("Current state="+states[iState]); gd.addMessage("Current state="+states[iState]);
gd.addMessage("Iteration step="+this.iterationStepNumber); gd.addMessage("Iteration step="+this.iterationStepNumber);
...@@ -5345,8 +5345,11 @@ List calibration ...@@ -5345,8 +5345,11 @@ List calibration
int parNum=fittingStrategy.parameterMap[i][1]; int parNum=fittingStrategy.parameterMap[i][1];
int imgNum=fittingStrategy.parameterMap[i][0]; int imgNum=fittingStrategy.parameterMap[i][0];
double delta= this.nextVector[i] - this.currentVector[i]; double delta= this.nextVector[i] - this.currentVector[i];
gd.addMessage(i+": "+parameterDescriptions[parNum][0]+ // gd.addMessage(i+": "+parameterDescriptions[parNum][0]+
"["+imgNum+"]("+parameterDescriptions[parNum][2]+") "+IJ.d2s(this.currentVector[i],3)+ // "["+imgNum+"]("+parameterDescriptions[parNum][2]+") "+IJ.d2s(this.currentVector[i],3)+
// " + "+IJ.d2s(delta,3)+" = "+IJ.d2s(this.nextVector[i],3));
gd.addMessage(i+": "+fittingStrategy.distortionCalibrationData.descrField(parNum,0)+
"["+imgNum+"]("+fittingStrategy.distortionCalibrationData.descrField(parNum,2)+") "+IJ.d2s(this.currentVector[i],3)+
" + "+IJ.d2s(delta,3)+" = "+IJ.d2s(this.nextVector[i],3)); " + "+IJ.d2s(delta,3)+" = "+IJ.d2s(this.nextVector[i],3));
} }
} }
...@@ -5957,6 +5960,7 @@ List calibration ...@@ -5957,6 +5960,7 @@ List calibration
// set properties sufficient to un-apply distortions to the image // set properties sufficient to un-apply distortions to the image
// First - corrections // First - corrections
EyesisSubCameraParameters subCam=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor]; EyesisSubCameraParameters subCam=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor];
subCam.updateCartesian(); // recalculate other parameters
double entrancePupilForward=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.entrancePupilForward[stationNumber]; double entrancePupilForward=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.entrancePupilForward[stationNumber];
imp.setProperty("VERSION", "1.0"); imp.setProperty("VERSION", "1.0");
imp.setProperty("comment_arrays", "Array corrections from acquired image to radially distorted, in pixels"); imp.setProperty("comment_arrays", "Array corrections from acquired image to radially distorted, in pixels");
...@@ -5984,17 +5988,28 @@ List calibration ...@@ -5984,17 +5988,28 @@ List calibration
imp.setProperty("px0", ""+subCam.px0); imp.setProperty("px0", ""+subCam.px0);
imp.setProperty("py0", ""+subCam.py0); imp.setProperty("py0", ""+subCam.py0);
imp.setProperty("comment_azimuth", "lens center azimuth, CW from top, degrees"); imp.setProperty("comment_azimuth", "lens center azimuth, CW from top, degrees");
imp.setProperty("height", ""+subCam.height);
imp.setProperty("comment_elevation", "lens elevation from horizontal, positive - above horizon, degrees");
imp.setProperty("elevation", ""+subCam.theta);
imp.setProperty("comment_roll", "lens rotation around the lens axis. Positive - CW looking to the target, degrees");
imp.setProperty("roll", ""+subCam.psi);
imp.setProperty("comment_cartesian", "Use cartesian coordinates for the sensor in the camera CS (forward, right,aheading), instead of (radius, azimuth, heading)");
imp.setProperty("cartesian", ""+subCam.cartesian);
// cartesian parameters
imp.setProperty("comment_forward", "lens forward (towards target) displacement in the camera CS");
imp.setProperty("forward", ""+subCam.forward);
imp.setProperty("comment_right", "lens right (looking towards target) displacement in the camera CS");
imp.setProperty("right", ""+subCam.right);
imp.setProperty("comment_aheading", "lens axis horizontal direction, degrees. Positive - CW from the target (looking from top)");
imp.setProperty("aheading", ""+subCam.heading);
// cylindrical parameters
imp.setProperty("azimuth", ""+subCam.azimuth); imp.setProperty("azimuth", ""+subCam.azimuth);
imp.setProperty("comment_radius", "lens center distance from the camera vertical axis, mm"); imp.setProperty("comment_radius", "lens center distance from the camera vertical axis, mm");
imp.setProperty("radius", ""+subCam.radius); imp.setProperty("radius", ""+subCam.radius);
imp.setProperty("comment_height", "lens center vertical position from the head center, mm"); imp.setProperty("comment_height", "lens center vertical position from the head center, mm");
imp.setProperty("height", ""+subCam.height);
imp.setProperty("comment_heading", "lens heading - added to azimuth"); imp.setProperty("comment_heading", "lens heading - added to azimuth");
imp.setProperty("heading", ""+subCam.phi); imp.setProperty("heading", ""+subCam.phi);
imp.setProperty("comment_elevation", "lens elevation from horizontal, positive - above horizon, degrees");
imp.setProperty("elevation", ""+subCam.theta);
imp.setProperty("comment_roll", "lens rotation around the lens axis. Positive - CW looking to the target, degrees");
imp.setProperty("roll", ""+subCam.psi);
imp.setProperty("comment_channel", "number of the sensor (channel) in the camera"); imp.setProperty("comment_channel", "number of the sensor (channel) in the camera");
imp.setProperty("channel", ""+numSensor); imp.setProperty("channel", ""+numSensor);
...@@ -6173,6 +6188,18 @@ List calibration ...@@ -6173,6 +6188,18 @@ List calibration
if (imp.getProperty("heading") !=null) subCam.phi= Double.parseDouble((String) imp.getProperty("heading")); if (imp.getProperty("heading") !=null) subCam.phi= Double.parseDouble((String) imp.getProperty("heading"));
if (imp.getProperty("elevation")!=null) subCam.theta= Double.parseDouble((String) imp.getProperty("elevation")); if (imp.getProperty("elevation")!=null) subCam.theta= Double.parseDouble((String) imp.getProperty("elevation"));
if (imp.getProperty("roll")!=null) subCam.psi= Double.parseDouble((String) imp.getProperty("roll")); if (imp.getProperty("roll")!=null) subCam.psi= Double.parseDouble((String) imp.getProperty("roll"));
if (imp.getProperty("forward") !=null) subCam.forward= Double.parseDouble((String) imp.getProperty("forward"));
if (imp.getProperty("right") !=null) subCam.right= Double.parseDouble((String) imp.getProperty("right"));
if (imp.getProperty("aheading") !=null) subCam.heading= Double.parseDouble((String) imp.getProperty("aheading"));
if (imp.getProperty("cartesian") !=null) {
subCam.cartesian= Boolean.parseBoolean((String) imp.getProperty("cartesian"));
subCam.updateCartesian(); // recalculate other parameters (they may or may nort be provided
} else {
subCam.cartesian = false;
}
// Update intrinsic image parameters // Update intrinsic image parameters
this.lensDistortionParameters.pixelSize=subCam.pixelSize; this.lensDistortionParameters.pixelSize=subCam.pixelSize;
this.lensDistortionParameters.distortionRadius=subCam.distortionRadius; this.lensDistortionParameters.distortionRadius=subCam.distortionRadius;
...@@ -9406,12 +9433,12 @@ M * V = B ...@@ -9406,12 +9433,12 @@ M * V = B
String [] parameterUnits; String [] parameterUnits;
if (useActualParameters) { if (useActualParameters) {
parameterNames=new String[fittingStrategy.distortionCalibrationData.parameterDescriptions.length]; parameterNames=new String[fittingStrategy.distortionCalibrationData.getNumDescriptions()];
parameterUnits=new String[fittingStrategy.distortionCalibrationData.parameterDescriptions.length]; parameterUnits=new String[fittingStrategy.distortionCalibrationData.getNumDescriptions()];
for (int i=0;i<parameterNames.length;i++){ for (int i=0;i<parameterNames.length;i++){
// TODO: move to DdistortionCalibrationData methods() // TODO: move to DdistortionCalibrationData methods()
parameterNames[i]=fittingStrategy.distortionCalibrationData.parameterDescriptions[i][0]; parameterNames[i]=fittingStrategy.distortionCalibrationData.descrField(i,0);
parameterUnits[i]=fittingStrategy.distortionCalibrationData.parameterDescriptions[i][2]; parameterUnits[i]=fittingStrategy.distortionCalibrationData.descrField(i,2);
} }
} else { } else {
parameterNames=lensDistortionParameters.getAllNames(); parameterNames=lensDistortionParameters.getAllNames();
......
...@@ -262,7 +262,8 @@ I* - special case when the subcamera is being adjusted/replaced. How to deal wit ...@@ -262,7 +262,8 @@ I* - special case when the subcamera is being adjusted/replaced. How to deal wit
int nPar=this.parameterList[j][1]; int nPar=this.parameterList[j][1];
int nSub=this.parameterList[j][0]; int nSub=this.parameterList[j][0];
String hconfigName=sSeries+".parameterMode."+ String hconfigName=sSeries+".parameterMode."+
this.distortionCalibrationData.parameterDescriptions[nPar][0]+ this.distortionCalibrationData.parameterDescriptions[nPar][0]+ // here intentionally left parameterDescriptions[][], not descrField
// so switching Cartesian on/off will not make make strategy invalid
(this.distortionCalibrationData.isSubcameraParameter(nPar)?("_sub"+nSub):""); (this.distortionCalibrationData.isSubcameraParameter(nPar)?("_sub"+nSub):"");
// System.out.println("Setting this.parameterMode["+i+"]["+j+"] from " +hconfigName); // System.out.println("Setting this.parameterMode["+i+"]["+j+"] from " +hconfigName);
if (hConfig.getString(hconfigName)!=null) this.parameterMode[i][j]=Integer.parseInt(hConfig.getString(hconfigName)); if (hConfig.getString(hconfigName)!=null) this.parameterMode[i][j]=Integer.parseInt(hConfig.getString(hconfigName));
......
import ij.IJ;
/**
**
** GeometryCorrection - geometry correction for multiple sensors sharing the same
** lens radial distortion model
**
** Copyright (C) 2016 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** GeometryCorrection.java is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
** -----------------------------------------------------------------------------**
**
*/
public class GeometryCorrection {
// public double azimuth; // azimuth of the lens entrance pupil center, degrees, clockwise looking from top
// public double radius; // mm, distance from the rotation axis
// public double height; // mm, up - from the origin point
// public double phi; // degrees, optical axis from azimuth/r vector, clockwise heading
// public double theta; // degrees, optical axis from the eyesis horizon, positive - up elevation
// public double psi; // degrees, rotation (of the sensor) around the optical axis. Positive if camera is rotated clockwise looking to the target roll
public double focalLength=4.5;
public double pixelSize= 2.2; //um
public double distortionRadius= 2.8512; // mm - half width of the sensor
public double distortionA8=0.0; //r^8 (normalized to focal length or to sensor half width?)
public double distortionA7=0.0; //r^7 (normalized to focal length or to sensor half width?)
public double distortionA6=0.0; //r^6 (normalized to focal length or to sensor half width?)
public double distortionA5=0.0; //r^5 (normalized to focal length or to sensor half width?)
public double distortionA=0.0; // r^4 (normalized to focal length or to sensor half width?)
public double distortionB=0.0; // r^3
public double distortionC=0.0; // r^2
public double px0=1296.0; // center of the lens on the sensor, pixels
public double py0=968.0; // center of the lens on the sensor, pixels
private double [] rByRDist=null;
private double stepR=0.001;
private double maxR=2.0; // calculate up to this*distortionRadius
public void setDistortion() {
// imp.setProperty("distortion_formula", "(normalized by distortionRadius in mm) Rdist/R=A8*R^7+A7*R^6+A6*R^5+A5*R^4+A*R^3+B*R^2+C*R+(1-A6-A7-A6-A5-A-B-C)");
// imp.setProperty("distortionRadius", ""+subCam.distortionRadius);
}
/*
if (this.rByRDist==null){
calcReverseDistortionTable();
}
double rND2R=getRByRDist(rD/this.distortionRadius,debugThis);
x*= rND2R; // positive - right
y*=-rND2R; // positive - up
*/
// Copied from PixelMapping
/**
* Calculate reverse distortion table - from pixel radius to non-distorted radius
* Rdist/R=A5*R^4+A*R^3+B*R^2+C*R+(1-A5-A-B-C)
* @return false if distortion is too high
*/
public boolean calcReverseDistortionTable(){
boolean debugThis=false; //true;
double delta=1E-8;
double minDerivative=0.1;
int numIterations=1000;
double drDistDr=1.0;
// public double distortionA5=0.0; //r^5 (normalized to focal length or to sensor half width?)
// public double distortionA=0.0; // r^4 (normalized to focal length or to sensor half width?)
// public double distortionB=0.0; // r^3
// public double distortionC=0.0; // r^2
boolean use8=(this.distortionA8!=0.0) || (this.distortionA7!=0.0) || (this.distortionA6!=0.0);
double d=1.0-this.distortionA8-this.distortionA7-this.distortionA6-this.distortionA5-this.distortionA-this.distortionB-this.distortionC;
double rPrev=0.0;
this.rByRDist=new double [(int) Math.ceil(this.maxR/this.stepR)+1];
for (int j=1;j<this.rByRDist.length;j++) this.rByRDist[j]=Double.NaN;
this.rByRDist[0]=1.0/d;
boolean bailOut=false;
if (debugThis) System.out.println("calcReverseDistortionTable()");
for (int i=1;i<this.rByRDist.length;i++) {
double rDist=this.stepR*i;
double r=rPrev+this.stepR/drDistDr;
// if (debugThis) System.out.println("calcReverseDistortionTable() i="+i+" rDist="+rDist+" r="+r+" rPrev="+rPrev);
for (int iteration=0;iteration<numIterations;iteration++){
double k;
if (use8){
k=(((((((this.distortionA8)*r+this.distortionA7)*r+this.distortionA6)*r+this.distortionA5)*r + this.distortionA)*r+this.distortionB)*r+this.distortionC)*r+d;
drDistDr=(((((((8*this.distortionA8)*r + 7*this.distortionA7)*r + 6*this.distortionA6)*r + 5*this.distortionA5)*r + 4*this.distortionA)*r+3*this.distortionB)*r+2*this.distortionC)*r+d;
} else {
k=(((this.distortionA5*r + this.distortionA)*r+this.distortionB)*r+this.distortionC)*r+d;
drDistDr=(((5*this.distortionA5*r + 4*this.distortionA)*r+3*this.distortionB)*r+2*this.distortionC)*r+d;
}
double rD=r*k;
if (drDistDr<minDerivative) {
bailOut=true;
break; // too high distortion
}
if (Math.abs(rD-rDist)<delta) break; // success
r+=(rDist-rD)/drDistDr;
}
if (bailOut) {
if (debugThis) System.out.println("calcReverseDistortionTable() i="+i+" Bailing out, drDistDr="+drDistDr);
return false;
}
rPrev=r;
this.rByRDist[i]=r/rDist;
if (debugThis) System.out.println("calcReverseDistortionTable() i="+i+" rDist="+rDist+" r="+r+" rPrev="+rPrev+" this.rByRDist[i]="+this.rByRDist[i]);
}
return true;
}
public double getRByRDist(double rDist, boolean debug){
// add exceptions;
if (this.rByRDist==null) {
if (debug)System.out.println("getRByRDist("+IJ.d2s(rDist,3)+"): this.rByRDist==null");
return Double.NaN;
}
if (rDist<0) {
if (debug)System.out.println("getRByRDist("+IJ.d2s(rDist,3)+"): rDist<0");
return Double.NaN;
}
int index=(int) Math.floor(rDist/this.stepR);
if (index>=(this.rByRDist.length-1)) {
if (debug) System.out.println("getRByRDist("+IJ.d2s(rDist,3)+"): index="+index+">="+(this.rByRDist.length-1));
return Double.NaN;
}
double result=this.rByRDist[index]+(this.rByRDist[index+1]-this.rByRDist[index])*(rDist/this.stepR-index);
if (Double.isNaN(result)){
if (debug) System.out.println("this.rByRDist["+index+"]="+this.rByRDist[index]);
if (debug) System.out.println("this.rByRDist["+(index+1)+"]="+this.rByRDist[index+1]);
if (debug) System.out.println("rDist="+rDist);
if (debug) System.out.println("(rDist/this.stepR="+(rDist/this.stepR));
}
return result;
}
}
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