package cz.cuni.lf1.lge.ThunderSTORM.calibration;
import static cz.cuni.lf1.lge.ThunderSTORM.util.MathProxy.*;
import org.apache.commons.math3.analysis.ParametricUnivariateFunction;
import org.apache.commons.math3.fitting.CurveFitter;
import org.apache.commons.math3.optim.*;
import org.apache.commons.math3.optim.nonlinear.vector.jacobian.LevenbergMarquardtOptimizer;
// sigma(z) = a*(z-c)^2 + b + d*(z-c)^3
public class PolynomialCalibration extends DefocusCalibration {
transient DefocusFunction s1Par, s2Par;
public PolynomialCalibration() {
super(DefocusFunctionPoly.name);
s1Par = null;
s2Par = null;
}
public PolynomialCalibration(double angle, Homography.TransformationMatrix biplanetransform, double w01, double a1, double b1, double c1, double d1, double w02, double a2, double b2, double c2, double d2) {
super(DefocusFunctionPoly.name, angle, biplanetransform, w01, a1, b1, c1, d1, w02, a2, b2, c2, d2);
s1Par = null;
s2Par = null;
}
public PolynomialCalibration(double angle, Homography.TransformationMatrix biplaneTransformation, DefocusFunction sigma1Params, DefocusFunction sigma2Params) {
super(DefocusFunctionPoly.name, angle, biplaneTransformation, sigma1Params.getW0(), sigma1Params.getA(), sigma1Params.getB(), sigma1Params.getC(), sigma1Params.getD(),
sigma2Params.getW0(), sigma2Params.getA(), sigma2Params.getB(), sigma2Params.getC(), sigma2Params.getD());
s1Par = sigma1Params;
s2Par = sigma2Params;
}
// ---------------- SIGMA -------------- //
@Override
public double evalDefocus(double z, double w0, double a, double b, double c, double d) {
return b + a*sqr(z - c) + d*pow(z - c,3);
}
private double dw(double z, double w0, double a, double b, double c, double d) {
double zsubz0 = z - c;
return 2*a*zsubz0 + 3*d*zsubz0;
}
@Override
public double dwx(double z) {
return dw(z, w01, a1, b1, c1, d1);
}
@Override
public double dwy(double z) {
return dw(z, w02, a2, b2, c2, d2);
}
// ---------------- SIGMA^2 -------------- //
@Override
public double evalDefocus2(double z, double w0, double a, double b, double c, double d) {
return sqr(evalDefocus(z, w0, a, b, c, d));
}
private double dw2(double z, double w0, double a, double b, double c, double d) {
double zc1 = z - c, zc2 = zc1 * zc1, zc3 = zc2 * zc1;
return ((4*a*zc1 + 6*d*zc2) * (a*zc2 + b + d*zc3));
}
@Override
public double dwx2(double z) {
return dw2(z, w01, a1, b1, c1, d1);
}
@Override
public double dwy2(double z) {
return dw2(z, w02, a2, b2, c2, d2);
}
@Override
public DaostormCalibration getDaoCalibration() {
ParametricUnivariateFunction sqrtFn = new DefocusFunctionSqrt().getFittingFunction();
ParametricUnivariateFunction polyFn = new DefocusFunctionPoly().getFittingFunction();
CurveFitter<ParametricUnivariateFunction> fitter1 = new CurveFitter<ParametricUnivariateFunction>(new LevenbergMarquardtOptimizer(new SimplePointChecker(10e-10, 10e-10)));
CurveFitter<ParametricUnivariateFunction> fitter2 = new CurveFitter<ParametricUnivariateFunction>(new LevenbergMarquardtOptimizer(new SimplePointChecker(10e-10, 10e-10)));
double [] polyParams1 = new double[] {w01, c1, a1, b1, d1};
double [] polyParams2 = new double[] {w02, c2, a2, b2, d2};
double zRange = ceil(2*(abs(c1)+abs(c2))); // -zRange:+zRange
for(double z = -zRange; z <= zRange; z += 5.0) {
fitter1.addObservedPoint(z, polyFn.value(z, polyParams1));
fitter2.addObservedPoint(z, polyFn.value(z, polyParams2));
}
double [] parSigma1 = fitter1.fit(1000, sqrtFn, new double[] {2.0, c1, 0.0, 0.0, zRange/2.0});
double [] parSigma2 = fitter2.fit(1000, sqrtFn, new double[] {2.0, c2, 0.0, 0.0, zRange/2.0});
return new DaostormCalibration(angle, homography, parSigma1[0], parSigma1[2], parSigma1[3], parSigma1[1], parSigma1[4],
parSigma2[0], parSigma2[2], parSigma2[3], parSigma2[1], parSigma2[4]);
}
}