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

more cartesian mode support

parent 1d2d14af
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3322,7 +3322,7 @@ if (MORE_BUTTONS) {
		    GenericDialog gd = new GenericDialog("Select sensor number");
		    gd.addCheckbox("Save all sensors", true);
			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();
		    if (gd.wasCanceled()) return;
		    boolean allFiles=gd.getNextBoolean();
+4 −0
Original line number Diff line number Diff line
@@ -569,6 +569,10 @@ import org.apache.commons.configuration.XMLConfiguration;
        	return -1;
        }
        
        public int getNumDescriptions(){
        	return this.parameterDescriptions.length;
        }

/**
 * Initialize data from scratch using filenames "grid-<timestamp-seconds>_<timestamp-microseconds>-<channel-number>.tiff        
 * @param filenames List of grid filenames (2-slice TIFFs)
+43 −16
Original line number Diff line number Diff line
@@ -3318,7 +3318,7 @@ For each point in the image
	    for (int i=0;i<lensParNames.length;i++)header+="\t"+lensParNames[i];
	    StringBuffer sb = new StringBuffer();
	    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]);
	    	sb.append("\n");
	    	sb.append("\t \tdelta");
@@ -4225,10 +4225,10 @@ List calibration
			}
			sb.append("\n");
			
			for (int parNumber=0;parNumber<fittingStrategy.distortionCalibrationData.parameterDescriptions.length;parNumber++){
			for (int parNumber=0;parNumber<fittingStrategy.distortionCalibrationData.getNumDescriptions();parNumber++){
				sb.append(
						fittingStrategy.distortionCalibrationData.parameterDescriptions[parNumber][0]+"\t"+
						fittingStrategy.distortionCalibrationData.parameterDescriptions[parNumber][2]);
						fittingStrategy.distortionCalibrationData.descrField(parNumber,0)+"\t"+
						fittingStrategy.distortionCalibrationData.descrField(parNumber,2));
				for (int imgIndex=0;imgIndex<numImages;imgIndex++){
					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
@@ -5334,7 +5334,7 @@ List calibration
    	int iState=(state[0]?1:0)+(state[1]?2:0);
    
	    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("Iteration step="+this.iterationStepNumber);
    	
@@ -5345,8 +5345,11 @@ List calibration
    			int parNum=fittingStrategy.parameterMap[i][1];
    			int imgNum=fittingStrategy.parameterMap[i][0];
    			double delta= this.nextVector[i] - this.currentVector[i];
    			gd.addMessage(i+": "+parameterDescriptions[parNum][0]+
    					"["+imgNum+"]("+parameterDescriptions[parNum][2]+") "+IJ.d2s(this.currentVector[i],3)+
//    			gd.addMessage(i+": "+parameterDescriptions[parNum][0]+
//    					"["+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));
    		}
    	}
@@ -5957,6 +5960,7 @@ List calibration
        // set properties sufficient to un-apply distortions to the image
   		// First - corrections
    	EyesisSubCameraParameters subCam=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.eyesisSubCameras[stationNumber][numSensor];
    	subCam.updateCartesian(); // recalculate other parameters
    	double entrancePupilForward=fittingStrategy.distortionCalibrationData.eyesisCameraParameters.entrancePupilForward[stationNumber];
    	imp.setProperty("VERSION",  "1.0");
    	imp.setProperty("comment_arrays",  "Array corrections from acquired image to radially distorted, in pixels");
@@ -5984,17 +5988,28 @@ List calibration
    	imp.setProperty("px0", ""+subCam.px0);
    	imp.setProperty("py0", ""+subCam.py0);
    	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("comment_radius", "lens center distance from the camera vertical axis, mm");
    	imp.setProperty("radius",  ""+subCam.radius);
    	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("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("channel",  ""+numSensor);
@@ -6173,6 +6188,18 @@ List calibration
        	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("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        
        	this.lensDistortionParameters.pixelSize=subCam.pixelSize;
        	this.lensDistortionParameters.distortionRadius=subCam.distortionRadius;
@@ -9406,12 +9433,12 @@ M * V = B
    	String [] parameterUnits;
    	
    	if (useActualParameters) {
    		parameterNames=new String[fittingStrategy.distortionCalibrationData.parameterDescriptions.length];
    		parameterUnits=new String[fittingStrategy.distortionCalibrationData.parameterDescriptions.length];
    		parameterNames=new String[fittingStrategy.distortionCalibrationData.getNumDescriptions()];
    		parameterUnits=new String[fittingStrategy.distortionCalibrationData.getNumDescriptions()];
    		for (int i=0;i<parameterNames.length;i++){
    			// TODO: move to DdistortionCalibrationData methods()
    			parameterNames[i]=fittingStrategy.distortionCalibrationData.parameterDescriptions[i][0];
    			parameterUnits[i]=fittingStrategy.distortionCalibrationData.parameterDescriptions[i][2];
    			parameterNames[i]=fittingStrategy.distortionCalibrationData.descrField(i,0);
    			parameterUnits[i]=fittingStrategy.distortionCalibrationData.descrField(i,2);
    		}
    	} else {
    		parameterNames=lensDistortionParameters.getAllNames();
+2 −1
Original line number Diff line number Diff line
@@ -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 nSub=this.parameterList[j][0];
        			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):"");
//        			System.out.println("Setting this.parameterMode["+i+"]["+j+"] from " +hconfigName);
        			if (hConfig.getString(hconfigName)!=null)  this.parameterMode[i][j]=Integer.parseInt(hConfig.getString(hconfigName));
+159 −0
Original line number Diff line number Diff line
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;
	
}



}