fix parameters in this BA

445 views
Skip to first unread message

James WONG

unread,
Nov 2, 2021, 3:08:59 AM11/2/21
to Ceres Solver
hi all,
for (int i = 0; i < bal_problem.num_observations(); ++i) {
ceres::CostFunction *cost_function;

// Each Residual block takes a point and a camera as input
// and outputs a 2 dimensional Residual
cost_function = SnavelyReprojectionError::Create(observations[2 * i + 0], observations[2 * i + 1]);

// If enabled use Huber's loss function.
ceres::LossFunction *loss_function = new ceres::TrivialLoss();

// Each observation corresponds to a pair of a camera and a point
// which are identified by camera_index()[i] and point_index()[i]
// respectively.
double *camera = cameras + camera_block_size * bal_problem.camera_index()[i];
double *point = points + point_block_size * bal_problem.point_index()[i];

problem.AddResidualBlock(cost_function, loss_function, camera, point);
}

Codes above is the main part of  codes creating a BA problem. The pointer camera points the first parameters of each camera. There is 9 parameters of each camera. The first 6 are external parameters, which I want to optimize, but the last 3 are internal parameters I want  fixed.I  do not know how to fix the last 3 parameters.
I have tried subsetParameterization() and setParameterBlockConstant(),
however ,because I was not good at Ceres , I have not succeeded.
Could you help me ?Thanks very much!

Sameer Agarwal

unread,
Nov 2, 2021, 9:27:53 AM11/2/21
to ceres-...@googlegroups.com
Can you share the exact code that you are using when you try to use subsetparameterization? 
and what happens when you use it?

Sameer


--
You received this message because you are subscribed to the Google Groups "Ceres Solver" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceres-solver...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ceres-solver/d882684f-7c16-4be3-9ae2-a9577e919611n%40googlegroups.com.

James WONG

unread,
Nov 2, 2021, 10:12:33 PM11/2/21
to Ceres Solver
thank you Sameer 
I just want to fix the focal length and distortion parameters K1, K2 of each camera. I don’t know how to rewrite it.
 I used the follow method to directly fix all the parameters of a camera.  Can you help me how to rewrite?

if (i == 0) {
problem.SetParameterBlockConstant(bal_problem.mutable_camera_for_observation(i));
}

My procedure is as follows:
  
#include <cstdio>
#include <iostream>
#include<fstream>
#include "ceres/ceres.h"
#include "ceres/rotation.h"
#include "bal_problem.h"


// Read a Bundle Adjustment in the Large dataset.
class BALProblem {
public:
~BALProblem() {
delete[] point_index_;
delete[] camera_index_;
delete[] observations_;
delete[] parameters_;
}
int num_observations()       const { return num_observations_; }
const double* observations() const { return observations_; }
double* mutable_cameras() { return parameters_; }
double* mutable_points() { return parameters_ + 9 * num_cameras_; }
double* mutable_camera_for_observation(int i) {
return mutable_cameras() + camera_index_[i] * 9;
}
double* mutable_point_for_observation(int i) {
return mutable_points() + point_index_[i] * 3;
}
bool LoadFile(const char* filename) {
FILE* fptr = fopen(filename, "r");
if (fptr == NULL) {
return false;
};
FscanfOrDie(fptr, "%d", &num_cameras_);
FscanfOrDie(fptr, "%d", &num_points_);
FscanfOrDie(fptr, "%d", &num_observations_);
point_index_ = new int[num_observations_];
camera_index_ = new int[num_observations_];
observations_ = new double[2 * num_observations_];
num_parameters_ = 9 * num_cameras_ + 3 * num_points_;
parameters_ = new double[num_parameters_];
parameters_1 = parameters_;
for (int i = 0; i < num_observations_; ++i) {
FscanfOrDie(fptr, "%d", camera_index_ + i);
FscanfOrDie(fptr, "%d", point_index_ + i);
for (int j = 0; j < 2; ++j) {
FscanfOrDie(fptr, "%lf", observations_ + 2 * i + j);
}
}

for (int i = 0; i < num_parameters_; ++i) {
FscanfOrDie(fptr, "%lf", parameters_ + i);
}

return true;
}
void point_print()
{
for (int j = 0; j < num_cameras_; j++)
{
std::cout << "optimization" << j << "camera information:" << "\n";
for (int i = 0 + j * 9; i < 9 + j * 9; i++)
{
std::cout << *(parameters_1 + i) << "\n";
}
}
for (int a = 0; a < num_points_; a++)
{
std::cout << "optimization" << a << "3Dpoint information:" << "\n";
for (int b = 9 * num_cameras_ + a * 3; b < 9 * num_cameras_ + 3 * (a + 1); b++)
{
std::cout << *(parameters_1 + b) << "\n";
}
}

}
private:
template<typename T>
void FscanfOrDie(FILE *fptr, const char *format, T *value) {
int num_scanned = fscanf(fptr, format, value);
if (num_scanned != 1) {
LOG(FATAL) << "Invalid UW data file.";
}
}
int num_cameras_;
int num_points_;
int num_observations_;
int num_parameters_;
int* point_index_;
int* camera_index_;
double* observations_;
double* parameters_;
double* parameters_1;
};
struct SnavelyReprojectionError {
SnavelyReprojectionError(double observed_x, double observed_y)
: observed_x(observed_x), observed_y(observed_y) {}
template <typename T>
bool operator()(const T* const camera,
const T* const point,
T* residuals) const {

T p[3];
ceres::AngleAxisRotatePoint(camera, point, p);
// camera[3,4,5] are the translation.
p[0] += camera[3];
p[1] += camera[4];
p[2] += camera[5];

//std::cout << "p[0]:" << p[0] << "\n" << "p[1]:" << p[1] << "\n" << "p[2]:" << p[2] << "\n";


T xp =- p[0] / p[2];
T yp =- p[1] / p[2];

//std::cout << "xp:" << xp << "\n" << "yp:" << yp << "\n" << "\n";

const T& l1 = camera[7];
const T& l2 = camera[8];
T r2 = xp * xp + yp * yp;
T distortion = 1.0 + r2 * (l1 + l2 * r2);

//std::cout << "r2:" << r2 << " " << "distortion:" << distortion << "\n" << "\n";

// Compute final projected point position.
const T& focal = camera[6];
T predicted_x = focal * distortion * xp;
T predicted_y = focal * distortion * yp;
//std::cout << "predicted_x:" << predicted_x << "\n" << "predicted_y:" << predicted_y <<"\n"<<"\n";
// The error is the difference between the predicted and observed position.
residuals[0] = predicted_x - observed_x;
residuals[1] = predicted_y - observed_y;
return true;
}
// Factory to hide the construction of the CostFunction object from
// the client code.

static ceres::CostFunction* Create(const double observed_x,
const double observed_y)
{
return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
new SnavelyReprojectionError(observed_x, observed_y)));
}
double observed_x;
double observed_y;
};


int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
BALProblem bal_problem;
if (!bal_problem.LoadFile("C:\\02.txt")) {
std::cerr << "ERROR: unable to open file " << "\n";
return 1;
}

const double* observations = bal_problem.observations();

ceres::Problem problem;
for (int i = 0; i < bal_problem.num_observations(); ++i) {

ceres::CostFunction* cost_function =
SnavelyReprojectionError::Create(observations[2 * i + 0],
observations[2 * i + 1]);
problem.AddResidualBlock(cost_function,
NULL /* squared loss */,
bal_problem.mutable_camera_for_observation(i),
bal_problem.mutable_point_for_observation(i));
if (i == 0) {
problem.SetParameterBlockConstant(bal_problem.mutable_camera_for_observation(i));
}
}
//solve

ceres::Solver::Options options;
options.linear_solver_type = ceres::DENSE_SCHUR;
options.minimizer_progress_to_stdout = true;
options.max_num_iterations = 1000;
options.function_tolerance = 1e-5;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
std::cout << summary.FullReport() << "\n";

bal_problem.point_print();

}




Sameer Agarwal

unread,
Nov 4, 2021, 9:48:28 AM11/4/21
to ceres-...@googlegroups.com
Hi James,
Lets look at the following fragment of code.

for (int i = 0; i < bal_problem.num_observations(); ++i) {
ceres::CostFunction* cost_function =
SnavelyReprojectionError::Create(observations[2 * i + 0],
observations[2 * i + 1]);
problem.AddResidualBlock(cost_function,
NULL /* squared loss */,
bal_problem.mutable_camera_for_observation(i),
bal_problem.mutable_point_for_observation(i));
if (i == 0) {
problem.SetParameterBlockConstant(bal_problem.mutable_camera_for_observation(i));
}
}

This chunk of code not only adds residual blocks to the problem, but also adds the required parameter blocks to the problem. Which is why you are able to call 

problem.SetParameterBlockConstant(bal_problem.mutable_camera_for_observation(i))

and set this parameter block constant. This is not a great code style to just call SetParameterBlockConstant on the first observation's camera, because unless you know that your data is structured in a particular way, you do not know which camera is being set constant. But this is a minor point.

Suppose you know the camera whose parameters you want to set constant.

Start by constructing a SubsetParameterization as

auto param = new ceres::SubsetParameterization(9, {6, 7, 8});

which holds parameters 6, 7, 8 corresponding to focal length, k1 and k2 constant and then call

problem.SetParameterization(camera_ptr, param);

Sameer

James WONG

unread,
Nov 4, 2021, 10:31:23 PM11/4/21
to Ceres Solver
HI Sameer,
Regarding my code, how should I modify it? I keep reporting errors according to what you wrote. It may be that I don’t understand the ceres library functions and need your help urgently.
thank you.

James WONG

unread,
Nov 5, 2021, 3:10:15 AM11/5/21
to Ceres Solver
Hi,Sameer,

Error message :
F20211105 14:56:36.950634 36320 parameter_block.h:170] Check failed: local_parameterization_ == NULL Can't re-set the local parameterization; it leads to ambiguous ownership. Current local parameterization is: 00000297D55B7520
*** Check failure stack trace: ***
    @   00007FFDE440A81B  void __cdecl google::SetApplicationFingerprint(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __ptr64)
    @   00007FFDE440A713  void __cdecl google::SetApplicationFingerprint(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __ptr64)
    @   00007FFDE4409EE5  void __cdecl google::SetApplicationFingerprint(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __ptr64)
    @   00007FFDE440BBB1  void __cdecl google::SetApplicationFingerprint(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __ptr64)
    @   00007FFDC3FCC61F  public: virtual bool __cdecl ceres::HomogeneousVectorParameterization::Plus(double const * __ptr64,double const * __ptr64,double * __ptr64)const __ptr64
    @   00007FFDC3FAB6FD  public: virtual bool __cdecl ceres::HomogeneousVectorParameterization::Plus(double const * __ptr64,double const * __ptr64,double * __ptr64)const __ptr64
    @   00007FFDC3FA83D7  public: virtual bool __cdecl ceres::HomogeneousVectorParameterization::Plus(double const * __ptr64,double const * __ptr64,double * __ptr64)const __ptr64
    @   00007FF759FD42BD  main
    @   00007FF759FD51E4  invoke_main
    @   00007FF759FD508E  __scrt_common_main_seh
    @   00007FF759FD4F4E  __scrt_common_main
    @   00007FF759FD5279  mainCRTStartup
    @   00007FFE278F7034  BaseThreadInitThunk
    @   00007FFE283A2651  RtlUserThreadStart


ceres::Problem problem;
for (int i = 0; i < bal_problem.num_observations(); ++i) {
ceres::CostFunction* cost_function =
SnavelyReprojectionError::Create(observations[2 * i + 0],
observations[2 * i + 1]);
problem.AddResidualBlock(cost_function,
NULL /* squared loss */,
bal_problem.mutable_camera_for_observation(i),
bal_problem.mutable_point_for_observation(i));
auto param = new ceres::SubsetParameterization(9, { 6,7,8 });
problem.SetParameterization(bal_problem.mutable_camera_for_observation(i), param);

Sameer Agarwal

unread,
Nov 5, 2021, 7:38:14 AM11/5/21
to ceres-...@googlegroups.com
you are doing this inside the loop. You cannot do this. This is what I meant by saying that trying to blindly operate on cameras for an observation inside the loop is a bad idea. Also you are doing this for every camera.

outside the loop do the following.

double* camera1 = bal_problem->mutable_cameras();
double* camera2 = camera1 + 9;
problem.SetParameterBlockConstant(camera1);
auto param = new ceres::SubsetParameterization(9, {6, 7, 8});
problem.SetParameterization(camera2, param);

Reply all
Reply to author
Forward
0 new messages