in opensfm/src/geometry/camera_distortions_functions.h [523:608]
static void ForwardDerivatives(const T* point, const T* k, T* distorted,
T* jacobian) {
constexpr int stride = Stride<DERIV_PARAMS>();
const auto& k1 = k[static_cast<int>(K1)];
const auto& k2 = k[static_cast<int>(K2)];
const auto& k3 = k[static_cast<int>(K3)];
const auto& k4 = k[static_cast<int>(K4)];
const auto& k5 = k[static_cast<int>(K5)];
const auto& k6 = k[static_cast<int>(K6)];
const auto& p1 = k[static_cast<int>(P1)];
const auto& p2 = k[static_cast<int>(P2)];
const auto& s0 = k[static_cast<int>(S0)];
const auto& s1 = k[static_cast<int>(S1)];
const auto& s2 = k[static_cast<int>(S2)];
const auto& s3 = k[static_cast<int>(S3)];
const auto& x = point[0];
const auto& y = point[1];
const auto x2 = x * x;
const auto y2 = y * y;
const auto r2 = x2 + y2;
const auto r2_2 = r2 * r2;
const auto r2_3 = r2_2 * r2;
const auto r2_4 = r2_3 * r2;
const auto r2_5 = r2_4 * r2;
// Compute tangential distortion separatedly
const auto dx_dxt = T(2.0) * y * p1 + T(6.0) * p2 * x;
const auto dx_dyt = T(2.0) * x * p1 + T(2.0) * p2 * y;
const auto dy_dxt = dx_dyt; // == dx_dyt
const auto dy_dyt = T(2.0) * x * p2 + T(6.0) * p1 * y;
// Compute thin prism distortion separately as well
const auto dx_dx_tp = s0 * T(2.0) * x + s1 * T(4.0) * x * r2;
const auto dx_dy_tp = s0 * T(2.0) * y + s1 * T(4.0) * y * r2;
const auto dy_dx_tp = s2 * T(2.0) * x + s3 * T(4.0) * x * r2;
const auto dy_dy_tp = s2 * T(2.0) * y + s3 * T(4.0) * y * r2;
// Computing the deriv. of the rad dist. p(x,y):
// For x: d x * p(x,y)/ dx = p(x,y) + x * dp(x,y)/dy
// and simplify dp(x,y)/dx = dp/dr * dr/dx
const auto p = Disto62::RadialDistortion(r2, k1, k2, k3, k4, k5, k6);
const auto dr_dx = T(2.0) * x; // dr/dx = (x^2 + y^2)' = 2x
const auto dr_dy = T(2.0) * y; // dr/dy = (x^2 + y^2)' = 2y
const auto dp_dr = k1 + T(2.0) * k2 * r2 + T(3.0) * k3 * r2_2 +
T(4.0) * k4 * r2_3 + T(5.0) * k5 * r2_4 +
T(6.0) * k6 * r2_5;
jacobian[0] = p + x * dp_dr * dr_dx + dx_dxt + dx_dx_tp;
jacobian[1] = x * dp_dr * dr_dy + dx_dyt + dx_dy_tp;
jacobian[stride + 0] = y * dp_dr * dr_dx + dy_dxt + dy_dx_tp;
jacobian[stride + 1] = p + y * dp_dr * dr_dy + dy_dyt + dy_dy_tp;
if (DERIV_PARAMS) {
const auto r2_6 = r2_5 * r2;
// K1 - K6
jacobian[2] = x * r2;
jacobian[3] = x * r2_2;
jacobian[4] = x * r2_3;
jacobian[5] = x * r2_4;
jacobian[6] = x * r2_5;
jacobian[7] = x * r2_6;
// P1 - P2
jacobian[8] = T(2.0) * x * y;
jacobian[9] = T(3.0) * x2 + y2;
// S0 - S3
jacobian[10] = r2;
jacobian[11] = r2_2;
jacobian[12] = 0.0;
jacobian[13] = 0.0;
// K1 - K6
jacobian[stride + 2] = y * r2;
jacobian[stride + 3] = y * r2_2;
jacobian[stride + 4] = y * r2_3;
jacobian[stride + 5] = y * r2_4;
jacobian[stride + 6] = y * r2_5;
jacobian[stride + 7] = y * r2_6;
// P1 - P2
jacobian[stride + 8] = T(3.0) * y2 + x2;
jacobian[stride + 9] = jacobian[8];
// S0 - S3
jacobian[stride + 10] = 0.0;
jacobian[stride + 11] = 0.0;
jacobian[stride + 12] = r2;
jacobian[stride + 13] = r2_2;
}
Forward(point, k, distorted);
}