blob: b71e05a0a011047dfd4747ccdc55575978407bc7 [file] [log] [blame] [edit]
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/*
* File "ba_b_tapenade_generated.c" is generated by Tapenade 3.14 (r7259) from this file.
* To reproduce such a generation you can use Tapenade CLI
* (can be downloaded from http://www-sop.inria.fr/tropics/tapenade/downloading.html)
*
* After installing use the next command to generate a file:
*
* tapenade -b -o ba_tapenade -head "compute_reproj_error(err)/(cam X) compute_zach_weight_error(err)/(w)" ba.c
*
* This will produce a file "ba_tapenade_b.c" which content will be the same as the content of "ba_b_tapenade_generated.c",
* except one-line header. Moreover a log-file "ba_tapenade_b.msg" will be produced.
*
* NOTE: the code in "ba_b_tapenade_generated.c" is wrong and won't work.
* REPAIRED SOURCE IS STORED IN THE FILE "ba_b.c".
* You can either use diff tool or read "ba_b.c" header to figure out what changes was performed to fix the code.
*
* NOTE: you can also use Tapenade web server (http://tapenade.inria.fr:8080/tapenade/index.jsp)
* for generating but the result can be slightly different.
*/
#include "../adbench/ba.h"
extern "C" {
#include "ba.h"
/* ===================================================================== */
/* UTILS */
/* ===================================================================== */
double sqsum(int n, double const* x)
{
int i;
double res = 0;
for (i = 0; i < n; i++)
{
res = res + x[i] * x[i];
}
return res;
}
void cross(double const* a, double const* b, double* out)
{
out[0] = a[1] * b[2] - a[2] * b[1];
out[1] = a[2] * b[0] - a[0] * b[2];
out[2] = a[0] * b[1] - a[1] * b[0];
}
/* ===================================================================== */
/* MAIN LOGIC */
/* ===================================================================== */
// rot: 3 rotation parameters
// pt: 3 point to be rotated
// rotatedPt: 3 rotated point
// this is an efficient evaluation (part of
// the Ceres implementation)
// easy to understand calculation in matlab:
// theta = sqrt(sum(w. ^ 2));
// n = w / theta;
// n_x = au_cross_matrix(n);
// R = eye(3) + n_x*sin(theta) + n_x*n_x*(1 - cos(theta));
void rodrigues_rotate_point(double const* __restrict rot, double const* __restrict pt, double *__restrict rotatedPt)
{
int i;
double sqtheta = sqsum(3, rot);
if (sqtheta != 0)
{
double theta, costheta, sintheta, theta_inverse;
double w[3], w_cross_pt[3], tmp;
theta = sqrt(sqtheta);
costheta = cos(theta);
sintheta = sin(theta);
theta_inverse = 1.0 / theta;
for (i = 0; i < 3; i++)
{
w[i] = rot[i] * theta_inverse;
}
cross(w, pt, w_cross_pt);
tmp = (w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) *
(1. - costheta);
for (i = 0; i < 3; i++)
{
rotatedPt[i] = pt[i] * costheta + w_cross_pt[i] * sintheta + w[i] * tmp;
}
}
else
{
double rot_cross_pt[3];
cross(rot, pt, rot_cross_pt);
for (i = 0; i < 3; i++)
{
rotatedPt[i] = pt[i] + rot_cross_pt[i];
}
}
}
void radial_distort(double const* rad_params, double *proj)
{
double rsq, L;
rsq = sqsum(2, proj);
L = 1. + rad_params[0] * rsq + rad_params[1] * rsq * rsq;
proj[0] = proj[0] * L;
proj[1] = proj[1] * L;
}
void project(double const* __restrict cam, double const* __restrict X, double* __restrict proj)
{
double const* C = &cam[3];
double Xo[3], Xcam[3];
Xo[0] = X[0] - C[0];
Xo[1] = X[1] - C[1];
Xo[2] = X[2] - C[2];
rodrigues_rotate_point(&cam[0], Xo, Xcam);
proj[0] = Xcam[0] / Xcam[2];
proj[1] = Xcam[1] / Xcam[2];
radial_distort(&cam[9], proj);
proj[0] = proj[0] * cam[6] + cam[7];
proj[1] = proj[1] * cam[6] + cam[8];
}
// cam: 11 camera in format [r1 r2 r3 C1 C2 C3 f u0 v0 k1 k2]
// r1, r2, r3 are angle - axis rotation parameters(Rodrigues)
// [C1 C2 C3]' is the camera center
// f is the focal length in pixels
// [u0 v0]' is the principal point
// k1, k2 are radial distortion parameters
// X: 3 point
// feats: 2 feature (x,y coordinates)
// reproj_err: 2
// projection function:
// Xcam = R * (X - C)
// distorted = radial_distort(projective2euclidean(Xcam), radial_parameters)
// proj = distorted * f + principal_point
// err = sqsum(proj - measurement)
void compute_reproj_error(
double const* __restrict cam,
double const* __restrict X,
double const* __restrict w,
double const* __restrict feat,
double * __restrict err
)
{
double proj[2];
project(cam, X, proj);
err[0] = (*w)*(proj[0] - feat[0]);
err[1] = (*w)*(proj[1] - feat[1]);
}
void compute_zach_weight_error(double const* w, double* err)
{
*err = 1 - (*w)*(*w);
}
// n number of cameras
// m number of points
// p number of observations
// cams: 11*n cameras in format [r1 r2 r3 C1 C2 C3 f u0 v0 k1 k2]
// r1, r2, r3 are angle - axis rotation parameters(Rodrigues)
// [C1 C2 C3]' is the camera center
// f is the focal length in pixels
// [u0 v0]' is the principal point
// k1, k2 are radial distortion parameters
// X: 3*m points
// obs: 2*p observations (pairs cameraIdx, pointIdx)
// feats: 2*p features (x,y coordinates corresponding to observations)
// reproj_err: 2*p errors of observations
// w_err: p weight "error" terms
void ba_objective(
int n,
int m,
int p,
double const* cams,
double const* X,
double const* w,
int const* obs,
double const* feats,
double* reproj_err,
double* w_err
)
{
int i;
for (i = 0; i < p; i++)
{
int camIdx = obs[i * 2 + 0];
int ptIdx = obs[i * 2 + 1];
compute_reproj_error(
&cams[camIdx * BA_NCAMPARAMS],
&X[ptIdx * 3],
&w[i],
&feats[i * 2],
&reproj_err[2 * i]
);
}
for (i = 0; i < p; i++)
{
compute_zach_weight_error(&w[i], &w_err[i]);
}
}
extern int enzyme_const;
extern int enzyme_dup;
extern int enzyme_dupnoneed;
void __enzyme_autodiff(...) noexcept;
void dcompute_reproj_error(
double const* cam,
double * dcam,
double const* X,
double * dX,
double const* w,
double * wb,
double const* feat,
double *err,
double *derr
)
{
__enzyme_autodiff(compute_reproj_error,
enzyme_dup, cam, dcam,
enzyme_dup, X, dX,
enzyme_dup, w, wb,
enzyme_const, feat,
enzyme_dupnoneed, err, derr);
}
void dcompute_zach_weight_error(double const* w, double* dw, double* err, double* derr) {
__enzyme_autodiff(compute_zach_weight_error,
enzyme_dup, w, dw,
enzyme_dupnoneed, err, derr);
}
}
//! Tapenade
extern "C" {
#include <adBuffer.h>
/*
Differentiation of sqsum in reverse (adjoint) mode:
gradient of useful results: *x sqsum
with respect to varying inputs: *x
Plus diff mem management of: x:in
=====================================================================
UTILS
===================================================================== */
void sqsum_b(int n, const double *x, double *xb, double sqsumb) {
int i;
double res = 0;
double resb = 0.0;
double sqsum;
resb = sqsumb;
for (i = n-1; i > -1; --i)
xb[i] = xb[i] + 2*x[i]*resb;
}
/* =====================================================================
UTILS
===================================================================== */
double sqsum_nodiff(int n, const double *x) {
int i;
double res = 0;
for (i = 0; i < n; ++i)
res = res + x[i]*x[i];
return res;
}
/*
Differentiation of cross in reverse (adjoint) mode:
gradient of useful results: *out *a *b
with respect to varying inputs: *a *b
Plus diff mem management of: out:in a:in b:in
*/
void cross_b(const double *a, double *ab, const double *b, double *bb, double
*out, double *outb) {
ab[0] = ab[0] + b[1]*outb[2];
bb[1] = bb[1] + a[0]*outb[2];
ab[1] = ab[1] - b[0]*outb[2];
bb[0] = bb[0] - a[1]*outb[2];
outb[2] = 0.0;
ab[2] = ab[2] + b[0]*outb[1];
bb[0] = bb[0] + a[2]*outb[1];
ab[0] = ab[0] - b[2]*outb[1];
bb[2] = bb[2] - a[0]*outb[1];
outb[1] = 0.0;
ab[1] = ab[1] + b[2]*outb[0];
bb[2] = bb[2] + a[1]*outb[0];
ab[2] = ab[2] - b[1]*outb[0];
bb[1] = bb[1] - a[2]*outb[0];
}
void cross_nodiff(const double *a, const double *b, double *out) {
out[0] = a[1]*b[2] - a[2]*b[1];
out[1] = a[2]*b[0] - a[0]*b[2];
out[2] = a[0]*b[1] - a[1]*b[0];
}
/*
Differentiation of rodrigues_rotate_point in reverse (adjoint) mode:
gradient of useful results: *rot *rotatedPt
with respect to varying inputs: *rot *pt
Plus diff mem management of: rot:in rotatedPt:in pt:in
=====================================================================
MAIN LOGIC
===================================================================== */
// rot: 3 rotation parameters
// pt: 3 point to be rotated
// rotatedPt: 3 rotated point
// this is an efficient evaluation (part of
// the Ceres implementation)
// easy to understand calculation in matlab:
// theta = sqrt(sum(w. ^ 2));
// n = w / theta;
// n_x = au_cross_matrix(n);
// R = eye(3) + n_x*sin(theta) + n_x*n_x*(1 - cos(theta));
void rodrigues_rotate_point_b(const double *rot, double *rotb, const double *
pt, double *ptb, double *rotatedPt, double *rotatedPtb) {
int i;
double sqtheta;
double sqthetab;
int ii1;
sqtheta = sqsum_nodiff(3, rot);
if (sqtheta != 0) {
double theta, costheta, sintheta, theta_inverse;
double w[3], w_cross_pt[3], tmp;
double tempb;
theta = sqrt(sqtheta);
costheta = cos(theta);
sintheta = sin(theta);
theta_inverse = 1.0/theta;
double thetab, costhetab, sinthetab, theta_inverseb;
double wb[3], w_cross_ptb[3], tmpb;
for (i = 0; i < 3; ++i)
w[i] = rot[i]*theta_inverse;
cross_nodiff(w, pt, w_cross_pt);
tmp = (w[0]*pt[0]+w[1]*pt[1]+w[2]*pt[2])*(1.-costheta);
for (i = 0; i < 3; i++) /* TFIX */
ptb[i] = 0.0;
for (ii1 = 0; ii1 < 3; ++ii1)
w_cross_ptb[ii1] = 0.0;
for (ii1 = 0; ii1 < 3; ++ii1)
wb[ii1] = 0.0;
costhetab = 0.0;
tmpb = 0.0;
sinthetab = 0.0;
for (i = 2; i > -1; --i) {
ptb[i] = ptb[i] + costheta*rotatedPtb[i];
costhetab = costhetab + pt[i]*rotatedPtb[i];
w_cross_ptb[i] = w_cross_ptb[i] + sintheta*rotatedPtb[i];
sinthetab = sinthetab + w_cross_pt[i]*rotatedPtb[i];
wb[i] = wb[i] + tmp*rotatedPtb[i];
tmpb = tmpb + w[i]*rotatedPtb[i];
rotatedPtb[i] = 0.0;
}
tempb = (1.-costheta)*tmpb;
wb[0] = wb[0] + pt[0]*tempb;
ptb[0] = ptb[0] + w[0]*tempb;
wb[1] = wb[1] + pt[1]*tempb;
ptb[1] = ptb[1] + w[1]*tempb;
wb[2] = wb[2] + pt[2]*tempb;
ptb[2] = ptb[2] + w[2]*tempb;
costhetab = costhetab - (w[0]*pt[0]+w[1]*pt[1]+w[2]*pt[2])*tmpb;
cross_b(w, wb, pt, ptb, w_cross_pt, w_cross_ptb);
theta_inverseb = 0.0;
for (i = 2; i > -1; --i) {
rotb[i] = rotb[i] + theta_inverse*wb[i];
theta_inverseb = theta_inverseb + rot[i]*wb[i];
wb[i] = 0.0;
}
thetab = cos(theta)*sinthetab - sin(theta)*costhetab - theta_inverseb/
(theta*theta);
if (sqtheta == 0.0)
sqthetab = 0.0;
else
sqthetab = thetab/(2.0*sqrt(sqtheta));
} else {
{
double rot_cross_pt[3];
double rot_cross_ptb[3];
for (i = 0; i < 3; i++) /* TFIX */
ptb[i] = 0.0;
for (ii1 = 0; ii1 < 3; ++ii1)
rot_cross_ptb[ii1] = 0.0;
for (i = 2; i > -1; --i) {
ptb[i] = ptb[i] + rotatedPtb[i];
rot_cross_ptb[i] = rot_cross_ptb[i] + rotatedPtb[i];
rotatedPtb[i] = 0.0;
}
cross_b(rot, rotb, pt, ptb, rot_cross_pt, rot_cross_ptb);
}
sqthetab = 0.0;
}
sqsum_b(3, rot, rotb, sqthetab);
}
/* =====================================================================
MAIN LOGIC
===================================================================== */
// rot: 3 rotation parameters
// pt: 3 point to be rotated
// rotatedPt: 3 rotated point
// this is an efficient evaluation (part of
// the Ceres implementation)
// easy to understand calculation in matlab:
// theta = sqrt(sum(w. ^ 2));
// n = w / theta;
// n_x = au_cross_matrix(n);
// R = eye(3) + n_x*sin(theta) + n_x*n_x*(1 - cos(theta));
void rodrigues_rotate_point_nodiff(const double *rot, const double *pt, double
*rotatedPt) {
int i;
double sqtheta;
sqtheta = sqsum_nodiff(3, rot);
if (sqtheta != 0) {
double theta, costheta, sintheta, theta_inverse;
double w[3], w_cross_pt[3], tmp;
theta = sqrt(sqtheta);
costheta = cos(theta);
sintheta = sin(theta);
theta_inverse = 1.0/theta;
for (i = 0; i < 3; ++i)
w[i] = rot[i]*theta_inverse;
cross_nodiff(w, pt, w_cross_pt);
tmp = (w[0]*pt[0]+w[1]*pt[1]+w[2]*pt[2])*(1.-costheta);
for (i = 0; i < 3; ++i)
rotatedPt[i] = pt[i]*costheta + w_cross_pt[i]*sintheta + w[i]*tmp;
} else {
double rot_cross_pt[3];
cross_nodiff(rot, pt, rot_cross_pt);
for (i = 0; i < 3; ++i)
rotatedPt[i] = pt[i] + rot_cross_pt[i];
}
}
/*
Differentiation of radial_distort in reverse (adjoint) mode:
gradient of useful results: *rad_params *proj
with respect to varying inputs: *rad_params *proj
Plus diff mem management of: rad_params:in proj:in
*/
void radial_distort_b(const double *rad_params, double *rad_paramsb, double *
proj, double *projb) {
double rsq, L;
double rsqb, Lb;
rsq = sqsum_nodiff(2, proj);
L = 1. + rad_params[0]*rsq + rad_params[1]*rsq*rsq;
pushReal8(proj[0]);
proj[0] = proj[0]*L;
Lb = proj[1]*projb[1];
projb[1] = L*projb[1];
popReal8(&(proj[0]));
Lb = Lb + proj[0]*projb[0];
projb[0] = L*projb[0];
rad_paramsb[0] = rad_paramsb[0] + rsq*Lb;
rsqb = (rad_params[1]*2*rsq+rad_params[0])*Lb;
rad_paramsb[1] = rad_paramsb[1] + rsq*rsq*Lb;
sqsum_b(2, proj, projb, rsqb);
}
void radial_distort_nodiff(const double *rad_params, double *proj) {
double rsq, L;
rsq = sqsum_nodiff(2, proj);
L = 1. + rad_params[0]*rsq + rad_params[1]*rsq*rsq;
proj[0] = proj[0]*L;
proj[1] = proj[1]*L;
}
/*
Differentiation of project in reverse (adjoint) mode:
gradient of useful results: *proj
with respect to varying inputs: *cam *X
Plus diff mem management of: cam:in X:in proj:in
*/
void project_b(const double *cam, double *camb, const double *X, double *Xb,
double *proj, double *projb) {
double *C = const_cast<double*>(&(cam[3]));
double *Cb = const_cast<double*>(&(camb[3]));
double Xo[3], Xcam[3];
double Xob[3], Xcamb[3];
int ii1;
double tempb;
double tempb0;
for (ii1 = 0; ii1 < BA_NCAMPARAMS; ii1++) /* TFIX */
camb[ii1] = 0.0;
for (ii1 = 0; ii1 < 3; ii1++)
Xb[ii1] = 0.0;
Xo[0] = X[0] - C[0];
Xo[1] = X[1] - C[1];
Xo[2] = X[2] - C[2];
rodrigues_rotate_point_nodiff(&(cam[0]), Xo, Xcam);
proj[0] = Xcam[0]/Xcam[2];
proj[1] = Xcam[1]/Xcam[2];
pushReal8Array(proj, 2); /* TFIX */
radial_distort_nodiff(&(cam[9]), proj);
pushReal8(proj[0]);
proj[0] = proj[0]*cam[6] + cam[7];
camb[6] = camb[6] + proj[1]*projb[1];
camb[8] = camb[8] + projb[1];
projb[1] = cam[6]*projb[1];
popReal8(&(proj[0]));
camb[6] = camb[6] + proj[0]*projb[0];
camb[7] = camb[7] + projb[0];
projb[0] = cam[6]*projb[0];
popReal8Array(proj, 2); /* TFIX */
radial_distort_b(&(cam[9]), &(camb[9]), proj, projb);
for (ii1 = 0; ii1 < 3; ++ii1)
Xcamb[ii1] = 0.0;
tempb = projb[1]/Xcam[2];
Xcamb[1] = Xcamb[1] + tempb;
Xcamb[2] = Xcamb[2] - Xcam[1]*tempb/Xcam[2];
projb[1] = 0.0;
tempb0 = projb[0]/Xcam[2];
Xcamb[0] = Xcamb[0] + tempb0;
Xcamb[2] = Xcamb[2] - Xcam[0]*tempb0/Xcam[2];
rodrigues_rotate_point_b(&(cam[0]), &(camb[0]), Xo, Xob, Xcam, Xcamb);
Xb[2] = Xb[2] + Xob[2];
Cb[2] = Cb[2] - Xob[2];
Xob[2] = 0.0;
Xb[1] = Xb[1] + Xob[1];
Cb[1] = Cb[1] - Xob[1];
Xob[1] = 0.0;
Xb[0] = Xb[0] + Xob[0];
Cb[0] = Cb[0] - Xob[0];
}
void project_nodiff(const double *cam, const double *X, double *proj) {
const double *C = &(cam[3]);
double Xo[3], Xcam[3];
Xo[0] = X[0] - C[0];
Xo[1] = X[1] - C[1];
Xo[2] = X[2] - C[2];
rodrigues_rotate_point_nodiff(&(cam[0]), Xo, Xcam);
proj[0] = Xcam[0]/Xcam[2];
proj[1] = Xcam[1]/Xcam[2];
radial_distort_nodiff(&(cam[9]), proj);
proj[0] = proj[0]*cam[6] + cam[7];
proj[1] = proj[1]*cam[6] + cam[8];
}
/*
Differentiation of compute_reproj_error in reverse (adjoint) mode:
gradient of useful results: *err
with respect to varying inputs: *err *w *cam *X
RW status of diff variables: *err:in-out *w:out *cam:out *X:out
Plus diff mem management of: err:in w:in cam:in X:in
*/
// cam: 11 camera in format [r1 r2 r3 C1 C2 C3 f u0 v0 k1 k2]
// r1, r2, r3 are angle - axis rotation parameters(Rodrigues)
// [C1 C2 C3]' is the camera center
// f is the focal length in pixels
// [u0 v0]' is the principal point
// k1, k2 are radial distortion parameters
// X: 3 point
// feats: 2 feature (x,y coordinates)
// reproj_err: 2
// projection function:
// Xcam = R * (X - C)
// distorted = radial_distort(projective2euclidean(Xcam), radial_parameters)
// proj = distorted * f + principal_point
// err = sqsum(proj - measurement)
void compute_reproj_error_b(const double *cam, double *camb, const double *X,
double *Xb, const double *w, double *wb, const double *feat, double *
err, double *errb) {
double proj[2];
double projb[2];
int ii1;
pushReal8Array(proj, 2);
project_nodiff(cam, X, proj);
for (ii1 = 0; ii1 < 2; ++ii1)
projb[ii1] = 0.0;
*wb = (proj[1]-feat[1])*errb[1];
projb[1] = projb[1] + (*w)*errb[1];
errb[1] = 0.0;
*wb = *wb + (proj[0]-feat[0])*errb[0];
projb[0] = projb[0] + (*w)*errb[0];
errb[0] = 0.0;
popReal8Array(proj, 2);
project_b(cam, camb, X, Xb, proj, projb);
}
/*
Differentiation of compute_zach_weight_error in reverse (adjoint) mode:
gradient of useful results: *err
with respect to varying inputs: *err *w
RW status of diff variables: *err:in-out *w:out
Plus diff mem management of: err:in w:in
*/
void compute_zach_weight_error_b(const double *w, double *wb, double *err,
double *errb) {
*wb = -(2*(*w)*(*errb));
*errb = 0.0;
}
}
#include <adept_source.h>
#include <adept.h>
#include <adept_arrays.h>
using adept::adouble;
using adept::aVector;
namespace adeptTest {
template<typename T>
void cross(
const T* const a,
const T* const b,
T* out)
{
out[0] = a[1] * b[2] - a[2] * b[1];
out[1] = a[2] * b[0] - a[0] * b[2];
out[2] = a[0] * b[1] - a[1] * b[0];
}
////////////////////////////////////////////////////////////
//////////////////// Declarations //////////////////////////
////////////////////////////////////////////////////////////
// cam: 11 camera in format [r1 r2 r3 C1 C2 C3 f u0 v0 k1 k2]
// r1, r2, r3 are angle - axis rotation parameters(Rodrigues)
// [C1 C2 C3]' is the camera center
// f is the focal length in pixels
// [u0 v0]' is the principal point
// k1, k2 are radial distortion parameters
// X: 3 point
// feats: 2 feature (x,y coordinates)
// reproj_err: 2
// projection function:
// Xcam = R * (X - C)
// distorted = radial_distort(projective2euclidean(Xcam), radial_parameters)
// proj = distorted * f + principal_point
// err = sqsum(proj - measurement)
template<typename T>
void computeReprojError(
const T* const cam,
const T* const X,
const T* const w,
const double* const feat,
T *err);
// w: 1
// w_err: 1
template<typename T>
void computeZachWeightError(const T* const w, T* err);
// n number of cameras
// m number of points
// p number of observations
// cams: 11*n cameras in format [r1 r2 r3 C1 C2 C3 f u0 v0 k1 k2]
// r1, r2, r3 are angle - axis rotation parameters(Rodrigues)
// [C1 C2 C3]' is the camera center
// f is the focal length in pixels
// [u0 v0]' is the principal point
// k1, k2 are radial distortion parameters
// X: 3*m points
// obs: 2*p observations (pairs cameraIdx, pointIdx)
// feats: 2*p features (x,y coordinates corresponding to observations)
// reproj_err: 2*p errors of observations
// w_err: p weight "error" terms
// projection function:
// Xcam = R * (X - C)
// distorted = radial_distort(projective2euclidean(Xcam), radial_parameters)
// proj = distorted * f + principal_point
// err = sqsum(proj - measurement)
template<typename T>
void ba_objective(int n, int m, int p,
const T* const cams,
const T* const X,
const T* const w,
const int* const obs,
const double* const feats,
T* reproj_err,
T* w_err);
// rot: 3 rotation parameters
// pt: 3 point to be rotated
// rotatedPt: 3 rotated point
// this is an efficient evaluation (part of
// the Ceres implementation)
// easy to understand calculation in matlab:
// theta = sqrt(sum(w. ^ 2));
// n = w / theta;
// n_x = au_cross_matrix(n);
// R = eye(3) + n_x*sin(theta) + n_x*n_x*(1 - cos(theta));
template<typename T>
void rodrigues_rotate_point(
const T* const rot,
const T* const pt,
T *rotatedPt);
////////////////////////////////////////////////////////////
//////////////////// Definitions ///////////////////////////
////////////////////////////////////////////////////////////
template<typename T>
T sqsum(int n, const T* const x)
{
T res = 0;
for (int i = 0; i < n; i++)
res = res + x[i] * x[i];
return res;
}
template<typename T>
void rodrigues_rotate_point(
const T* const rot,
const T* const pt,
T *rotatedPt)
{
T sqtheta = sqsum(3, rot);
if (sqtheta != 0)
{
T theta, costheta, sintheta, theta_inverse,
w[3], w_cross_pt[3], tmp;
theta = sqrt(sqtheta);
costheta = cos(theta);
sintheta = sin(theta);
theta_inverse = 1.0 / theta;
for (int i = 0; i < 3; i++)
w[i] = rot[i] * theta_inverse;
cross(w, pt, w_cross_pt);
tmp = (w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) *
(1. - costheta);
for (int i = 0; i < 3; i++)
rotatedPt[i] = pt[i] * costheta + w_cross_pt[i] * sintheta + w[i] * tmp;
}
else
{
T rot_cross_pt[3];
cross(rot, pt, rot_cross_pt);
for (int i = 0; i < 3; i++)
rotatedPt[i] = pt[i] + rot_cross_pt[i];
}
}
template<typename T>
void radial_distort(
const T* const rad_params,
T *proj)
{
T rsq, L;
rsq = sqsum(2, proj);
L = 1. + rad_params[0] * rsq + rad_params[1] * rsq * rsq;
proj[0] = proj[0] * L;
proj[1] = proj[1] * L;
}
template<typename T>
void project(const T* const cam,
const T* const X,
T* proj)
{
const T* const C = &cam[3];
T Xo[3], Xcam[3];
Xo[0] = X[0] - C[0];
Xo[1] = X[1] - C[1];
Xo[2] = X[2] - C[2];
rodrigues_rotate_point(&cam[0], Xo, Xcam);
proj[0] = Xcam[0] / Xcam[2];
proj[1] = Xcam[1] / Xcam[2];
radial_distort(&cam[9], proj);
proj[0] = proj[0] * cam[6] + cam[7];
proj[1] = proj[1] * cam[6] + cam[8];
}
template<typename T>
void computeReprojError(
const T* const cam,
const T* const X,
const T* const w,
const double* const feat,
T *err)
{
T proj[2];
project(cam, X, proj);
err[0] = (*w)*(proj[0] - feat[0]);
err[1] = (*w)*(proj[1] - feat[1]);
}
template<typename T>
void computeZachWeightError(const T* const w, T* err)
{
*err = 1 - (*w)*(*w);
}
template<typename T>
void ba_objective(int n, int m, int p,
const T* const cams,
const T* const X,
const T* const w,
const int* const obs,
const double* const feats,
T* reproj_err,
T* w_err)
{
for (int i = 0; i < p; i++)
{
int camIdx = obs[i * 2 + 0];
int ptIdx = obs[i * 2 + 1];
computeReprojError(&cams[camIdx * BA_NCAMPARAMS], &X[ptIdx * 3],
&w[i], &feats[i * 2], &reproj_err[2 * i]);
}
for (int i = 0; i < p; i++)
{
computeZachWeightError(&w[i], &w_err[i]);
}
}
};
void adept_compute_reproj_error(
double const* cam,
double * dcam,
double const* X,
double * dX,
double const* w,
double * wb,
double const* feat,
double *err,
double *derr
)
{
adept::Stack stack;
adouble acam[BA_NCAMPARAMS];
adept::set_values(acam, BA_NCAMPARAMS, cam);
adouble aX[3];
adept::set_values(aX, 3, X);
adouble aw;
aw.set_value(*w);
adouble areproj_err[2];
stack.new_recording();
adeptTest::computeReprojError(acam, aX, &aw, feat, areproj_err);
for(unsigned i=0; i<2; i++) areproj_err[i].set_gradient(derr[i]);
stack.compute_adjoint();
*wb = aw.get_gradient();
adept::get_gradients(aX, 3, dX);
adept::get_gradients(acam, BA_NCAMPARAMS, dcam);
}
void adept_compute_zach_weight_error(double const* w, double* dw, double* err, double* derr) {
adept::Stack stack;
adouble aw;
aw.set_value(*w);
adouble aw_err;
stack.new_recording();
adeptTest::computeZachWeightError(&aw, &aw_err);
aw_err.set_gradient(1.);
stack.compute_adjoint();
*dw = aw.get_gradient();
}