blob: 79714f6ad9b019f9e9cda835b878533ea2b21087 [file] [log] [blame]
Sascha Haeberling1d2624a2013-07-23 19:00:21 -07001.. highlight:: c++
2
3.. default-domain:: cpp
4
5.. _chapter-tutorial:
6
7========
8Tutorial
9========
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070010
Carlos Hernandez79397c22014-08-07 17:51:38 -070011Ceres solves robustified non-linear bounds constrained least squares
12problems of the form
13
14.. math:: :label: ceresproblem
15
16 \min_{\mathbf{x}} &\quad \frac{1}{2}\sum_{i} \rho_i\left(\left\|f_i\left(x_{i_1}, ... ,x_{i_k}\right)\right\|^2\right) \\
17 \text{s.t.} &\quad l_j \le x_j \le u_j
18
19Problems of this form comes up in a broad range of areas across
20science and engineering - from `fitting curves`_ in statistics, to
21constructing `3D models from photographs`_ in computer vision.
22
23.. _fitting curves: http://en.wikipedia.org/wiki/Nonlinear_regression
24.. _3D models from photographs: http://en.wikipedia.org/wiki/Bundle_adjustment
25
26In this chapter we will learn how to solve :eq:`ceresproblem` using
27Ceres Solver. Full working code for all the examples described in this
28chapter and more can be found in the `examples
29<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/>`_
30directory.
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070031
32The expression
33:math:`\rho_i\left(\left\|f_i\left(x_{i_1},...,x_{i_k}\right)\right\|^2\right)`
34is known as a ``ResidualBlock``, where :math:`f_i(\cdot)` is a
35:class:`CostFunction` that depends on the parameter blocks
36:math:`\left[x_{i_1},... , x_{i_k}\right]`. In most optimization
37problems small groups of scalars occur together. For example the three
38components of a translation vector and the four components of the
39quaternion that define the pose of a camera. We refer to such a group
40of small scalars as a ``ParameterBlock``. Of course a
Carlos Hernandez79397c22014-08-07 17:51:38 -070041``ParameterBlock`` can just be a single parameter. :math:`l_j` and
42:math:`u_j` are bounds on the parameter block :math:`x_j`.
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070043
44:math:`\rho_i` is a :class:`LossFunction`. A :class:`LossFunction` is
45a scalar function that is used to reduce the influence of outliers on
Carlos Hernandez79397c22014-08-07 17:51:38 -070046the solution of non-linear least squares problems.
47
48As a special case, when :math:`\rho_i(x) = x`, i.e., the identity
49function, and :math:`l_j = -\infty` and :math:`u_j = \infty` we get
50the more familiar `non-linear least squares problem
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070051<http://en.wikipedia.org/wiki/Non-linear_least_squares>`_.
52
Carlos Hernandez79397c22014-08-07 17:51:38 -070053.. math:: \frac{1}{2}\sum_{i} \left\|f_i\left(x_{i_1}, ... ,x_{i_k}\right)\right\|^2.
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070054 :label: ceresproblem2
55
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070056.. _section-hello-world:
57
58Hello World!
59============
60
61To get started, consider the problem of finding the minimum of the
62function
63
64.. math:: \frac{1}{2}(10 -x)^2.
65
66This is a trivial problem, whose minimum is located at :math:`x = 10`,
67but it is a good place to start to illustrate the basics of solving a
68problem with Ceres [#f1]_.
69
70The first step is to write a functor that will evaluate this the
71function :math:`f(x) = 10 - x`:
72
73.. code-block:: c++
74
75 struct CostFunctor {
76 template <typename T>
77 bool operator()(const T* const x, T* residual) const {
78 residual[0] = T(10.0) - x[0];
79 return true;
80 }
81 };
82
83The important thing to note here is that ``operator()`` is a templated
84method, which assumes that all its inputs and outputs are of some type
Carlos Hernandez79397c22014-08-07 17:51:38 -070085``T``. The use of templating here allows Ceres to call
86``CostFunctor::operator<T>()``, with ``T=double`` when just the value
87of the residual is needed, and with a special type ``T=Jet`` when the
88Jacobians are needed. In :ref:`section-derivatives` we will discuss the
Sascha Haeberling1d2624a2013-07-23 19:00:21 -070089various ways of supplying derivatives to Ceres in more detail.
90
91Once we have a way of computing the residual function, it is now time
92to construct a non-linear least squares problem using it and have
93Ceres solve it.
94
95.. code-block:: c++
96
97 int main(int argc, char** argv) {
98 google::InitGoogleLogging(argv[0]);
99
100 // The variable to solve for with its initial value.
101 double initial_x = 5.0;
102 double x = initial_x;
103
104 // Build the problem.
105 Problem problem;
106
107 // Set up the only cost function (also known as residual). This uses
108 // auto-differentiation to obtain the derivative (jacobian).
109 CostFunction* cost_function =
110 new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
111 problem.AddResidualBlock(cost_function, NULL, &x);
112
113 // Run the solver!
114 Solver::Options options;
115 options.linear_solver_type = ceres::DENSE_QR;
116 options.minimizer_progress_to_stdout = true;
117 Solver::Summary summary;
118 Solve(options, &problem, &summary);
119
120 std::cout << summary.BriefReport() << "\n";
121 std::cout << "x : " << initial_x
122 << " -> " << x << "\n";
123 return 0;
124 }
125
126:class:`AutoDiffCostFunction` takes a ``CostFunctor`` as input,
127automatically differentiates it and gives it a :class:`CostFunction`
128interface.
129
130Compiling and running `examples/helloworld.cc
131<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/helloworld.cc>`_
132gives us
133
134.. code-block:: bash
135
Carlos Hernandez79397c22014-08-07 17:51:38 -0700136 iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
137 0 4.512500e+01 0.00e+00 9.50e+00 0.00e+00 0.00e+00 1.00e+04 0 5.33e-04 3.46e-03
138 1 4.511598e-07 4.51e+01 9.50e-04 9.50e+00 1.00e+00 3.00e+04 1 5.00e-04 4.05e-03
139 2 5.012552e-16 4.51e-07 3.17e-08 9.50e-04 1.00e+00 9.00e+04 1 1.60e-05 4.09e-03
140 Ceres Solver Report: Iterations: 2, Initial cost: 4.512500e+01, Final cost: 5.012552e-16, Termination: CONVERGENCE
141 x : 0.5 -> 10
Sascha Haeberling1d2624a2013-07-23 19:00:21 -0700142
143Starting from a :math:`x=5`, the solver in two iterations goes to 10
144[#f2]_. The careful reader will note that this is a linear problem and
145one linear solve should be enough to get the optimal value. The
146default configuration of the solver is aimed at non-linear problems,
147and for reasons of simplicity we did not change it in this example. It
148is indeed possible to obtain the solution to this problem using Ceres
149in one iteration. Also note that the solver did get very close to the
150optimal function value of 0 in the very first iteration. We will
151discuss these issues in greater detail when we talk about convergence
152and parameter settings for Ceres.
153
154.. rubric:: Footnotes
155
156.. [#f1] `examples/helloworld.cc
157 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/helloworld.cc>`_
158
159.. [#f2] Actually the solver ran for three iterations, and it was
160 by looking at the value returned by the linear solver in the third
161 iteration, it observed that the update to the parameter block was too
162 small and declared convergence. Ceres only prints out the display at
163 the end of an iteration, and terminates as soon as it detects
164 convergence, which is why you only see two iterations here and not
165 three.
166
167.. _section-derivatives:
168
169
170Derivatives
171===========
172
173Ceres Solver like most optimization packages, depends on being able to
174evaluate the value and the derivatives of each term in the objective
175function at arbitrary parameter values. Doing so correctly and
176efficiently is essential to getting good results. Ceres Solver
177provides a number of ways of doing so. You have already seen one of
178them in action --
179Automatic Differentiation in `examples/helloworld.cc
180<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/helloworld.cc>`_
181
182We now consider the other two possibilities. Analytic and numeric
183derivatives.
184
185
186Numeric Derivatives
187-------------------
188
189In some cases, its not possible to define a templated cost functor,
190for example when the evaluation of the residual involves a call to a
191library function that you do not have control over. In such a
192situation, numerical differentiation can be used. The user defines a
193functor which computes the residual value and construct a
194:class:`NumericDiffCostFunction` using it. e.g., for :math:`f(x) = 10 - x`
195the corresponding functor would be
196
197.. code-block:: c++
198
199 struct NumericDiffCostFunctor {
200 bool operator()(const double* const x, double* residual) const {
201 residual[0] = 10.0 - x[0];
202 return true;
203 }
204 };
205
206Which is added to the :class:`Problem` as:
207
208.. code-block:: c++
209
210 CostFunction* cost_function =
211 new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1, 1>(
212 new NumericDiffCostFunctor)
213 problem.AddResidualBlock(cost_function, NULL, &x);
214
215Notice the parallel from when we were using automatic differentiation
216
217.. code-block:: c++
218
219 CostFunction* cost_function =
220 new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
221 problem.AddResidualBlock(cost_function, NULL, &x);
222
223The construction looks almost identical to the one used for automatic
224differentiation, except for an extra template parameter that indicates
225the kind of finite differencing scheme to be used for computing the
226numerical derivatives [#f3]_. For more details see the documentation
227for :class:`NumericDiffCostFunction`.
228
229**Generally speaking we recommend automatic differentiation instead of
230numeric differentiation. The use of C++ templates makes automatic
231differentiation efficient, whereas numeric differentiation is
232expensive, prone to numeric errors, and leads to slower convergence.**
233
234
235Analytic Derivatives
236--------------------
237
238In some cases, using automatic differentiation is not possible. For
239example, it may be the case that it is more efficient to compute the
240derivatives in closed form instead of relying on the chain rule used
241by the automatic differentiation code.
242
243In such cases, it is possible to supply your own residual and jacobian
244computation code. To do this, define a subclass of
245:class:`CostFunction` or :class:`SizedCostFunction` if you know the
246sizes of the parameters and residuals at compile time. Here for
247example is ``SimpleCostFunction`` that implements :math:`f(x) = 10 -
248x`.
249
250.. code-block:: c++
251
252 class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
253 public:
254 virtual ~QuadraticCostFunction() {}
255 virtual bool Evaluate(double const* const* parameters,
256 double* residuals,
257 double** jacobians) const {
258 const double x = parameters[0][0];
259 residuals[0] = 10 - x;
260
261 // Compute the Jacobian if asked for.
262 if (jacobians != NULL && jacobians[0] != NULL) {
263 jacobians[0][0] = -1;
264 }
265 return true;
266 }
267 };
268
269
270``SimpleCostFunction::Evaluate`` is provided with an input array of
271``parameters``, an output array ``residuals`` for residuals and an
272output array ``jacobians`` for Jacobians. The ``jacobians`` array is
273optional, ``Evaluate`` is expected to check when it is non-null, and
274if it is the case then fill it with the values of the derivative of
275the residual function. In this case since the residual function is
276linear, the Jacobian is constant [#f4]_ .
277
278As can be seen from the above code fragments, implementing
279:class:`CostFunction` objects is a bit tedious. We recommend that
280unless you have a good reason to manage the jacobian computation
281yourself, you use :class:`AutoDiffCostFunction` or
282:class:`NumericDiffCostFunction` to construct your residual blocks.
283
284More About Derivatives
285----------------------
286
287Computing derivatives is by far the most complicated part of using
288Ceres, and depending on the circumstance the user may need more
289sophisticated ways of computing derivatives. This section just
290scratches the surface of how derivatives can be supplied to
291Ceres. Once you are comfortable with using
292:class:`NumericDiffCostFunction` and :class:`AutoDiffCostFunction` we
293recommend taking a look at :class:`DynamicAutoDiffCostFunction`,
294:class:`CostFunctionToFunctor`, :class:`NumericDiffFunctor` and
295:class:`ConditionedCostFunction` for more advanced ways of
296constructing and computing cost functions.
297
298.. rubric:: Footnotes
299
300.. [#f3] `examples/helloworld_numeric_diff.cc
301 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/helloworld_numeric_diff.cc>`_.
302
303.. [#f4] `examples/helloworld_analytic_diff.cc
304 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/helloworld_analytic_diff.cc>`_.
305
306
307.. _section-powell:
308
309Powell's Function
310=================
311
312Consider now a slightly more complicated example -- the minimization
313of Powell's function. Let :math:`x = \left[x_1, x_2, x_3, x_4 \right]`
314and
315
316.. math::
317
318 \begin{align}
319 f_1(x) &= x_1 + 10x_2 \\
320 f_2(x) &= \sqrt{5} (x_3 - x_4)\\
321 f_3(x) &= (x_2 - 2x_3)^2\\
322 f_4(x) &= \sqrt{10} (x_1 - x_4)^2\\
323 F(x) &= \left[f_1(x),\ f_2(x),\ f_3(x),\ f_4(x) \right]
324 \end{align}
325
326
327:math:`F(x)` is a function of four parameters, has four residuals
328and we wish to find :math:`x` such that :math:`\frac{1}{2}\|F(x)\|^2`
329is minimized.
330
331Again, the first step is to define functors that evaluate of the terms
332in the objective functor. Here is the code for evaluating
333:math:`f_4(x_1, x_4)`:
334
335.. code-block:: c++
336
337 struct F4 {
338 template <typename T>
339 bool operator()(const T* const x1, const T* const x4, T* residual) const {
340 residual[0] = T(sqrt(10.0)) * (x1[0] - x4[0]) * (x1[0] - x4[0]);
341 return true;
342 }
343 };
344
345
346Similarly, we can define classes ``F1``, ``F2`` and ``F4`` to evaluate
347:math:`f_1(x_1, x_2)`, :math:`f_2(x_3, x_4)` and :math:`f_3(x_2, x_3)`
348respectively. Using these, the problem can be constructed as follows:
349
350
351.. code-block:: c++
352
353 double x1 = 3.0; double x2 = -1.0; double x3 = 0.0; double x4 = 1.0;
354
355 Problem problem;
356
357 // Add residual terms to the problem using the using the autodiff
358 // wrapper to get the derivatives automatically.
359 problem.AddResidualBlock(
360 new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), NULL, &x1, &x2);
361 problem.AddResidualBlock(
362 new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), NULL, &x3, &x4);
363 problem.AddResidualBlock(
364 new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), NULL, &x2, &x3)
365 problem.AddResidualBlock(
366 new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), NULL, &x1, &x4);
367
368
369Note that each ``ResidualBlock`` only depends on the two parameters
370that the corresponding residual object depends on and not on all four
371parameters. Compiling and running `examples/powell.cc
372<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/powell.cc>`_
373gives us:
374
375.. code-block:: bash
376
Carlos Hernandez79397c22014-08-07 17:51:38 -0700377 Initial x1 = 3, x2 = -1, x3 = 0, x4 = 1
378 iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
379 0 1.075000e+02 0.00e+00 1.55e+02 0.00e+00 0.00e+00 1.00e+04 0 4.95e-04 2.30e-03
380 1 5.036190e+00 1.02e+02 2.00e+01 2.16e+00 9.53e-01 3.00e+04 1 4.39e-05 2.40e-03
381 2 3.148168e-01 4.72e+00 2.50e+00 6.23e-01 9.37e-01 9.00e+04 1 9.06e-06 2.43e-03
382 3 1.967760e-02 2.95e-01 3.13e-01 3.08e-01 9.37e-01 2.70e+05 1 8.11e-06 2.45e-03
383 4 1.229900e-03 1.84e-02 3.91e-02 1.54e-01 9.37e-01 8.10e+05 1 6.91e-06 2.48e-03
384 5 7.687123e-05 1.15e-03 4.89e-03 7.69e-02 9.37e-01 2.43e+06 1 7.87e-06 2.50e-03
385 6 4.804625e-06 7.21e-05 6.11e-04 3.85e-02 9.37e-01 7.29e+06 1 5.96e-06 2.52e-03
386 7 3.003028e-07 4.50e-06 7.64e-05 1.92e-02 9.37e-01 2.19e+07 1 5.96e-06 2.55e-03
387 8 1.877006e-08 2.82e-07 9.54e-06 9.62e-03 9.37e-01 6.56e+07 1 5.96e-06 2.57e-03
388 9 1.173223e-09 1.76e-08 1.19e-06 4.81e-03 9.37e-01 1.97e+08 1 7.87e-06 2.60e-03
389 10 7.333425e-11 1.10e-09 1.49e-07 2.40e-03 9.37e-01 5.90e+08 1 6.20e-06 2.63e-03
390 11 4.584044e-12 6.88e-11 1.86e-08 1.20e-03 9.37e-01 1.77e+09 1 6.91e-06 2.65e-03
391 12 2.865573e-13 4.30e-12 2.33e-09 6.02e-04 9.37e-01 5.31e+09 1 5.96e-06 2.67e-03
392 13 1.791438e-14 2.69e-13 2.91e-10 3.01e-04 9.37e-01 1.59e+10 1 7.15e-06 2.69e-03
393
394 Ceres Solver v1.10.0 Solve Report
395 ----------------------------------
396 Original Reduced
397 Parameter blocks 4 4
398 Parameters 4 4
399 Residual blocks 4 4
400 Residual 4 4
401
402 Minimizer TRUST_REGION
403
404 Dense linear algebra library EIGEN
405 Trust region strategy LEVENBERG_MARQUARDT
406
407 Given Used
408 Linear solver DENSE_QR DENSE_QR
409 Threads 1 1
410 Linear solver threads 1 1
411
412 Cost:
413 Initial 1.075000e+02
414 Final 1.791438e-14
415 Change 1.075000e+02
416
417 Minimizer iterations 14
418 Successful steps 14
419 Unsuccessful steps 0
420
421 Time (in seconds):
422 Preprocessor 0.002
423
424 Residual evaluation 0.000
425 Jacobian evaluation 0.000
426 Linear solver 0.000
427 Minimizer 0.001
428
429 Postprocessor 0.000
430 Total 0.005
431
432 Termination: CONVERGENCE (Gradient tolerance reached. Gradient max norm: 3.642190e-11 <= 1.000000e-10)
433
434 Final x1 = 0.000292189, x2 = -2.92189e-05, x3 = 4.79511e-05, x4 = 4.79511e-05
Sascha Haeberling1d2624a2013-07-23 19:00:21 -0700435
436It is easy to see that the optimal solution to this problem is at
437:math:`x_1=0, x_2=0, x_3=0, x_4=0` with an objective function value of
438:math:`0`. In 10 iterations, Ceres finds a solution with an objective
439function value of :math:`4\times 10^{-12}`.
440
441
442.. rubric:: Footnotes
443
444.. [#f5] `examples/powell.cc
445 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/powell.cc>`_.
446
447
448.. _section-fitting:
449
450Curve Fitting
451=============
452
453The examples we have seen until now are simple optimization problems
454with no data. The original purpose of least squares and non-linear
455least squares analysis was fitting curves to data. It is only
456appropriate that we now consider an example of such a problem
457[#f6]_. It contains data generated by sampling the curve :math:`y =
458e^{0.3x + 0.1}` and adding Gaussian noise with standard deviation
459:math:`\sigma = 0.2`. Let us fit some data to the curve
460
461.. math:: y = e^{mx + c}.
462
463We begin by defining a templated object to evaluate the
464residual. There will be a residual for each observation.
465
466.. code-block:: c++
467
468 struct ExponentialResidual {
469 ExponentialResidual(double x, double y)
470 : x_(x), y_(y) {}
471
472 template <typename T>
473 bool operator()(const T* const m, const T* const c, T* residual) const {
474 residual[0] = T(y_) - exp(m[0] * T(x_) + c[0]);
475 return true;
476 }
477
478 private:
479 // Observations for a sample.
480 const double x_;
481 const double y_;
482 };
483
484Assuming the observations are in a :math:`2n` sized array called
485``data`` the problem construction is a simple matter of creating a
486:class:`CostFunction` for every observation.
487
488
489.. code-block:: c++
490
491 double m = 0.0;
492 double c = 0.0;
493
494 Problem problem;
495 for (int i = 0; i < kNumObservations; ++i) {
496 CostFunction* cost_function =
497 new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
498 new ExponentialResidual(data[2 * i], data[2 * i + 1]));
499 problem.AddResidualBlock(cost_function, NULL, &m, &c);
500 }
501
502Compiling and running `examples/curve_fitting.cc
503<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/curve_fitting.cc>`_
504gives us:
505
506.. code-block:: bash
507
Carlos Hernandez79397c22014-08-07 17:51:38 -0700508 iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time
509 0 1.211734e+02 0.00e+00 3.61e+02 0.00e+00 0.00e+00 1.00e+04 0 5.34e-04 2.56e-03
510 1 1.211734e+02 -2.21e+03 0.00e+00 7.52e-01 -1.87e+01 5.00e+03 1 4.29e-05 3.25e-03
511 2 1.211734e+02 -2.21e+03 0.00e+00 7.51e-01 -1.86e+01 1.25e+03 1 1.10e-05 3.28e-03
512 3 1.211734e+02 -2.19e+03 0.00e+00 7.48e-01 -1.85e+01 1.56e+02 1 1.41e-05 3.31e-03
513 4 1.211734e+02 -2.02e+03 0.00e+00 7.22e-01 -1.70e+01 9.77e+00 1 1.00e-05 3.34e-03
514 5 1.211734e+02 -7.34e+02 0.00e+00 5.78e-01 -6.32e+00 3.05e-01 1 1.00e-05 3.36e-03
515 6 3.306595e+01 8.81e+01 4.10e+02 3.18e-01 1.37e+00 9.16e-01 1 2.79e-05 3.41e-03
516 7 6.426770e+00 2.66e+01 1.81e+02 1.29e-01 1.10e+00 2.75e+00 1 2.10e-05 3.45e-03
517 8 3.344546e+00 3.08e+00 5.51e+01 3.05e-02 1.03e+00 8.24e+00 1 2.10e-05 3.48e-03
518 9 1.987485e+00 1.36e+00 2.33e+01 8.87e-02 9.94e-01 2.47e+01 1 2.10e-05 3.52e-03
519 10 1.211585e+00 7.76e-01 8.22e+00 1.05e-01 9.89e-01 7.42e+01 1 2.10e-05 3.56e-03
520 11 1.063265e+00 1.48e-01 1.44e+00 6.06e-02 9.97e-01 2.22e+02 1 2.60e-05 3.61e-03
521 12 1.056795e+00 6.47e-03 1.18e-01 1.47e-02 1.00e+00 6.67e+02 1 2.10e-05 3.64e-03
522 13 1.056751e+00 4.39e-05 3.79e-03 1.28e-03 1.00e+00 2.00e+03 1 2.10e-05 3.68e-03
523 Ceres Solver Report: Iterations: 13, Initial cost: 1.211734e+02, Final cost: 1.056751e+00, Termination: CONVERGENCE
524 Initial m: 0 c: 0
525 Final m: 0.291861 c: 0.131439
Sascha Haeberling1d2624a2013-07-23 19:00:21 -0700526
527Starting from parameter values :math:`m = 0, c=0` with an initial
528objective function value of :math:`121.173` Ceres finds a solution
529:math:`m= 0.291861, c = 0.131439` with an objective function value of
530:math:`1.05675`. These values are a a bit different than the
531parameters of the original model :math:`m=0.3, c= 0.1`, but this is
532expected. When reconstructing a curve from noisy data, we expect to
533see such deviations. Indeed, if you were to evaluate the objective
534function for :math:`m=0.3, c=0.1`, the fit is worse with an objective
535function value of :math:`1.082425`. The figure below illustrates the fit.
536
537.. figure:: least_squares_fit.png
538 :figwidth: 500px
539 :height: 400px
540 :align: center
541
542 Least squares curve fitting.
543
544
545.. rubric:: Footnotes
546
547.. [#f6] `examples/curve_fitting.cc
548 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/curve_fitting.cc>`_
549
550
551Robust Curve Fitting
552=====================
553
554Now suppose the data we are given has some outliers, i.e., we have
555some points that do not obey the noise model. If we were to use the
556code above to fit such data, we would get a fit that looks as
557below. Notice how the fitted curve deviates from the ground truth.
558
559.. figure:: non_robust_least_squares_fit.png
560 :figwidth: 500px
561 :height: 400px
562 :align: center
563
564To deal with outliers, a standard technique is to use a
565:class:`LossFunction`. Loss functions, reduce the influence of
566residual blocks with high residuals, usually the ones corresponding to
567outliers. To associate a loss function in a residual block, we change
568
569.. code-block:: c++
570
571 problem.AddResidualBlock(cost_function, NULL , &m, &c);
572
573to
574
575.. code-block:: c++
576
577 problem.AddResidualBlock(cost_function, new CauchyLoss(0.5) , &m, &c);
578
579:class:`CauchyLoss` is one of the loss functions that ships with Ceres
580Solver. The argument :math:`0.5` specifies the scale of the loss
581function. As a result, we get the fit below [#f7]_. Notice how the
582fitted curve moves back closer to the ground truth curve.
583
584.. figure:: robust_least_squares_fit.png
585 :figwidth: 500px
586 :height: 400px
587 :align: center
588
589 Using :class:`LossFunction` to reduce the effect of outliers on a
590 least squares fit.
591
592
593.. rubric:: Footnotes
594
595.. [#f7] `examples/robust_curve_fitting.cc
596 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/robust_curve_fitting.cc>`_
597
598
599Bundle Adjustment
600=================
601
602One of the main reasons for writing Ceres was our need to solve large
603scale bundle adjustment problems [HartleyZisserman]_, [Triggs]_.
604
605Given a set of measured image feature locations and correspondences,
606the goal of bundle adjustment is to find 3D point positions and camera
607parameters that minimize the reprojection error. This optimization
608problem is usually formulated as a non-linear least squares problem,
609where the error is the squared :math:`L_2` norm of the difference between
610the observed feature location and the projection of the corresponding
6113D point on the image plane of the camera. Ceres has extensive support
612for solving bundle adjustment problems.
613
614Let us solve a problem from the `BAL
615<http://grail.cs.washington.edu/projects/bal/>`_ dataset [#f8]_.
616
617The first step as usual is to define a templated functor that computes
618the reprojection error/residual. The structure of the functor is
619similar to the ``ExponentialResidual``, in that there is an
620instance of this object responsible for each image observation.
621
622Each residual in a BAL problem depends on a three dimensional point
623and a nine parameter camera. The nine parameters defining the camera
624are: three for rotation as a Rodriques' axis-angle vector, three
625for translation, one for focal length and two for radial distortion.
626The details of this camera model can be found the `Bundler homepage
627<http://phototour.cs.washington.edu/bundler/>`_ and the `BAL homepage
628<http://grail.cs.washington.edu/projects/bal/>`_.
629
630.. code-block:: c++
631
632 struct SnavelyReprojectionError {
633 SnavelyReprojectionError(double observed_x, double observed_y)
634 : observed_x(observed_x), observed_y(observed_y) {}
635
636 template <typename T>
637 bool operator()(const T* const camera,
638 const T* const point,
639 T* residuals) const {
640 // camera[0,1,2] are the angle-axis rotation.
641 T p[3];
642 ceres::AngleAxisRotatePoint(camera, point, p);
643 // camera[3,4,5] are the translation.
644 p[0] += camera[3]; p[1] += camera[4]; p[2] += camera[5];
645
646 // Compute the center of distortion. The sign change comes from
647 // the camera model that Noah Snavely's Bundler assumes, whereby
648 // the camera coordinate system has a negative z axis.
649 T xp = - p[0] / p[2];
650 T yp = - p[1] / p[2];
651
652 // Apply second and fourth order radial distortion.
653 const T& l1 = camera[7];
654 const T& l2 = camera[8];
655 T r2 = xp*xp + yp*yp;
656 T distortion = T(1.0) + r2 * (l1 + l2 * r2);
657
658 // Compute final projected point position.
659 const T& focal = camera[6];
660 T predicted_x = focal * distortion * xp;
661 T predicted_y = focal * distortion * yp;
662
663 // The error is the difference between the predicted and observed position.
664 residuals[0] = predicted_x - T(observed_x);
665 residuals[1] = predicted_y - T(observed_y);
666 return true;
667 }
668
669 // Factory to hide the construction of the CostFunction object from
670 // the client code.
671 static ceres::CostFunction* Create(const double observed_x,
672 const double observed_y) {
673 return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
674 new SnavelyReprojectionError(observed_x, observed_y)));
675 }
676
677 double observed_x;
678 double observed_y;
679 };
680
681
682Note that unlike the examples before, this is a non-trivial function
683and computing its analytic Jacobian is a bit of a pain. Automatic
684differentiation makes life much simpler. The function
685:func:`AngleAxisRotatePoint` and other functions for manipulating
686rotations can be found in ``include/ceres/rotation.h``.
687
688Given this functor, the bundle adjustment problem can be constructed
689as follows:
690
691.. code-block:: c++
692
693 ceres::Problem problem;
694 for (int i = 0; i < bal_problem.num_observations(); ++i) {
695 ceres::CostFunction* cost_function =
Carlos Hernandez79397c22014-08-07 17:51:38 -0700696 SnavelyReprojectionError::Create(
697 bal_problem.observations()[2 * i + 0],
698 bal_problem.observations()[2 * i + 1]);
Sascha Haeberling1d2624a2013-07-23 19:00:21 -0700699 problem.AddResidualBlock(cost_function,
700 NULL /* squared loss */,
701 bal_problem.mutable_camera_for_observation(i),
702 bal_problem.mutable_point_for_observation(i));
703 }
704
705
706Notice that the problem construction for bundle adjustment is very
707similar to the curve fitting example -- one term is added to the
708objective function per observation.
709
710Since this large sparse problem (well large for ``DENSE_QR`` anyways),
711one way to solve this problem is to set
712:member:`Solver::Options::linear_solver_type` to
713``SPARSE_NORMAL_CHOLESKY`` and call :member:`Solve`. And while this is
714a reasonable thing to do, bundle adjustment problems have a special
715sparsity structure that can be exploited to solve them much more
716efficiently. Ceres provides three specialized solvers (collectively
717known as Schur-based solvers) for this task. The example code uses the
718simplest of them ``DENSE_SCHUR``.
719
720.. code-block:: c++
721
722 ceres::Solver::Options options;
723 options.linear_solver_type = ceres::DENSE_SCHUR;
724 options.minimizer_progress_to_stdout = true;
725 ceres::Solver::Summary summary;
726 ceres::Solve(options, &problem, &summary);
727 std::cout << summary.FullReport() << "\n";
728
729For a more sophisticated bundle adjustment example which demonstrates
730the use of Ceres' more advanced features including its various linear
731solvers, robust loss functions and local parameterizations see
732`examples/bundle_adjuster.cc
733<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/bundle_adjuster.cc>`_
734
735
736.. rubric:: Footnotes
737
738.. [#f8] `examples/simple_bundle_adjuster.cc
739 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/simple_bundle_adjuster.cc>`_
740
741
742Other Examples
743==============
744
745Besides the examples in this chapter, the `example
746<https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/>`_
747directory contains a number of other examples:
748
749#. `bundle_adjuster.cc
750 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/bundle_adjuster.cc>`_
751 shows how to use the various features of Ceres to solve bundle
752 adjustment problems.
753
754#. `circle_fit.cc
755 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/circle_fit.cc>`_
756 shows how to fit data to a circle.
757
758#. `denoising.cc
759 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/denoising.cc>`_
760 implements image denoising using the `Fields of Experts
761 <http://www.gris.informatik.tu-darmstadt.de/~sroth/research/foe/index.html>`_
762 model.
763
764#. `nist.cc
765 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/nist.cc>`_
766 implements and attempts to solves the `NIST
767 <http://www.itl.nist.gov/div898/strd/nls/nls_main.shtm>`_
768 non-linear regression problems.
769
770#. `libmv_bundle_adjuster.cc
771 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/libmv_bundle_adjuster.cc>`_
772 is the bundle adjustment algorithm used by `Blender <www.blender.org>`_/libmv.