https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Ugo Jardonnet <ugo.jardonnet(a)lrde.epita.fr>
Sandbox: ICP: various tools and improvments.
* sandbox/jardonnet/test/icp.cc: Fix regression (output registred.pbm).
* sandbox/jardonnet/registration/tools.hh:
Add multiple 2d to 3d and 3d to 2d conversion .
* sandbox/jardonnet/registration/quat7.hh:
Rewrite Covariance matrix computation.
* sandbox/jardonnet/registration/frankel_young.hh:
New, resolve linear equation Ax = b. Useless for icp.
* sandbox/jardonnet/registration/power_it.hh:
Find greatest eigen value, should be more efficient than jacobi ?.
* sandbox/jardonnet/registration/icp.hh:
Add intermediate image outputs.
mln/algebra/quat.hh | 2
sandbox/jardonnet/registration/cloud.hh | 2
sandbox/jardonnet/registration/frankel_young.hh | 46 ++++++++++
sandbox/jardonnet/registration/icp.hh | 14 ++-
sandbox/jardonnet/registration/jacobi.hh | 6 -
sandbox/jardonnet/registration/power_it.hh | 41 +++++++++
sandbox/jardonnet/registration/quat7.hh | 38 +++++++-
sandbox/jardonnet/registration/tools.hh | 109 ++++++++++++++++--------
sandbox/jardonnet/test/icp.cc | 33 +++----
9 files changed, 233 insertions(+), 58 deletions(-)
Index: mln/algebra/quat.hh
--- mln/algebra/quat.hh (revision 1847)
+++ mln/algebra/quat.hh (working copy)
@@ -186,7 +186,7 @@
quat conj() const;
/// Give the invert.
- quat inv() const; // FIXME: Rename inv as invert.
+ quat inv() const; //FIXME: rename invert.
/// Transform into unit quaternion.
quat& set_unit();
Index: sandbox/jardonnet/test/icp.cc
--- sandbox/jardonnet/test/icp.cc (revision 1847)
+++ sandbox/jardonnet/test/icp.cc (working copy)
@@ -41,27 +41,30 @@
closest_point<mln_point_(I3d)> fun(x, box_<point3d>(1000,1000,1));
lazy_image< closest_point<mln_point_(I3d)> > map(fun);
- registration::icp(c, map);
+ quat7<3> q = registration::icp(c, map);
#ifndef NDEBUG
std::cout << "closest_point(Ck[i]) = " << fun.i <<
std::endl;
std::cout << "Pts processed = " << registration::pts
<< std::endl;
#endif
- // //init output image
- // //FIXME: Should be
- // //mln_concrete(I) output(res.bbox()) = convert::to_image<I>(res)?
- // const box_<point2d> box2d(1000,1000,0);
- // image2d<bool> output(box2d, 1);
-
- // //to 2d : projection (FIXME:if 3d)
- // for (size_t i = 0; i < res.npoints(); i++)
- // {
- // point2d p(res[i][0], res[i][1]);
- // if (output.has(p))
- // output(p) = true;
- // }
+ //init output image
+ //FIXME: Should be
+ //mln_concrete(I) output(res.bbox()) = convert::to_image<I>(res)?
+
+ q.apply_on(c, c);
+
+ const box_<point2d> box2d(1000,1000);
+ image2d<bool> output(box2d, 1);
+
+ //to 2d : projection (FIXME:if 3d)
+ for (size_t i = 0; i < c.npoints(); i++)
+ {
+ point2d p(c[i][0], c[i][1]);
+ if (output.has(p))
+ output(p) = true;
+ }
- //io::pbm::save("./+registred.pbm");
+ io::pbm::save(output, "registred.pbm");
}
Index: sandbox/jardonnet/registration/jacobi.hh
--- sandbox/jardonnet/registration/jacobi.hh (revision 1847)
+++ sandbox/jardonnet/registration/jacobi.hh (working copy)
@@ -17,7 +17,7 @@
#define rotateJacobi(a,i,j,k,l) g=a(i,j);h=a(k,l);a(i,j)=g-s*(h+g*tau); \
a(k,l)=h+s*(g-h*tau);
- void jacobi(algebra::mat<4,4,float> a, algebra::quat& q)
+ algebra::quat jacobi(algebra::mat<4,4,float> a)
{
float dd, d[4];
algebra::mat<4,4,float> v(literal::zero);
@@ -46,12 +46,12 @@
iq = ip;
dd = d[ip];
}
- q = algebra::quat(v(0,iq),
+ algebra::quat q(v(0,iq),
v(1,iq),
v(2,iq),
v(3,iq));
q.set_unit();
- return;
+ return q;
}
if (i < 4) {
i++;
Index: sandbox/jardonnet/registration/power_it.hh
--- sandbox/jardonnet/registration/power_it.hh (revision 0)
+++ sandbox/jardonnet/registration/power_it.hh (revision 0)
@@ -0,0 +1,41 @@
+#ifndef POWER_IT_HH
+# define POWER_IT_HH
+
+
+#include <mln/algebra/mat.hh>
+#include <cmath>
+#include "misc.hh"
+
+// from num. rec. in C
+
+
+namespace mln
+{
+
+ algebra::quat power_it(algebra::mat<4,4,float> A)
+ {
+ float normex = 1.;
+
+ algebra::vec<4,float> x0(literal::zero);
+ algebra::vec<4,float> b(literal::zero);
+
+ algebra::vec<4,float> x(literal::zero);
+ for (int i = 0; i < 4; i++)
+ x[i] = 1.;
+
+ while (fabs(norm::l2(x) - norm::l2(x0)) > 1e-6)
+ {
+ x0 = x;
+ normex = norm::l2(x);
+ b = x / normex;
+ x = A * b;
+ }
+ normex = norm::l2(x);
+
+ algebra::quat q(x / normex);
+ q.set_unit();
+ return q;
+ }
+}
+
+#endif /* POWER_IT_HH */
Index: sandbox/jardonnet/registration/tools.hh
--- sandbox/jardonnet/registration/tools.hh (revision 1847)
+++ sandbox/jardonnet/registration/tools.hh (working copy)
@@ -17,12 +17,17 @@
typedef P result;
closest_point(const p_array<P>& X, const box_<P>& box)
- : X(X), box(box), i(0)
+ : X(X), box(box)
+
+#ifndef NDEBUG
+ , i(0)
+#endif
+
{ }
result
//inline
- operator () (const P& Ck)
+ operator () (const P& Ck) const
{
#ifndef NDEBUG
@@ -45,14 +50,17 @@
return algebra::to_point<P>(best_x);
}
- const box_<P>& domain()
+ const box_<P>& domain() const
{
return box;
}
const p_array<P>& X;
const box_<P> box;
+
+#ifndef NDEBUG
mutable unsigned i;
+#endif
};
@@ -74,7 +82,7 @@
const mln_result(F)
//inline
- operator() (const typename F::input& p)
+ operator () (const typename F::input& p) const
{
mln_precondition(fun.domain().has(p));
//FIXME: What about domain?
@@ -86,31 +94,12 @@
}
//FIXME: 3d -> //mln_dim(ml_input(input))
- image3d<mln_result(F)> value;
- image3d<bool> is_known;
+ mutable image3d<mln_result(F)> value;
+ mutable image3d<bool> is_known;
F& fun;
};
-// // Point
-
-// template <typename P>
-// P min(const P& a, const P& b)
-// {
-// if (a > b)
-// return b;
-// return a;
-// }
-
-// template <typename P>
-// P max(const P& a, const P& b)
-// {
-// if (a < b)
-// return b;
-// return a;
-// }
-
-
// Box
template <typename P>
@@ -142,6 +131,7 @@
namespace convert
{
+ // to_p_array
template <typename I>
inline
p_array<mln_point(I)>
@@ -158,23 +148,74 @@
return a;
}
+ template < typename P >
+ inline
+ box_<point2d>
+ to_box2d(const box_<P>& b)
+ {
+ point2d pmin(b.pmin()[0], b.pmin()[1]);
+ point2d pmax(b.pmax()[0], b.pmax()[1]);
+
+ return box_<point2d>(pmin, pmax);
+ }
+
+
//FIXME: to write
- /*
- template <typename A>
+ template <typename P>
inline
- image2d<mln_value(A)>
- to_image2d(const A& a)
+ image2d<bool>
+ to_image2d(const p_array<P>& a)
{
- image2d<mln_value(A)> img(a.bbox());
+ image2d<bool> output (to_box2d(a.bbox()), 0);
for (size_t i = 0; i < a.npoints(); i++)
{
- point2d p(res[i][0], res[i][1]);
- //FIXME: BOF
- //if (output.has(p))
+ point2d p(a[i][0], a[i][1]);
+ if (output.has(p))
output(p) = true;
}
+ return output;
+ }
+
+ // to_pointNd
+
+ //FIXME: Should we really provide this
+ //point3d -> point2d
+ template <typename T>
+ inline
+ point_<grid::square, T>
+ to_point2d(const point_<grid::cube, T>& p)
+ {
+ return point_<grid::square, T>(p[0], p[1]);
+ }
+ //point2d -> point2d
+ template <typename T>
+ inline
+ point_<grid::square, T>&
+ to_point2d(const point_<grid::square, T>& p)
+ {
+ return p;
+ }
+
+ //point2d -> point3d
+ template <typename T>
+ inline
+ point_<grid::cube, T>
+ to_point3d(const point_<grid::square, T>& p)
+ {
+ return point_<grid::cube, T>(p[0], p[1], 0);
+ }
+ //point3d -> point3d
+ template <typename T>
+ inline
+ point_<grid::cube, T>&
+ to_point3d(const point_<grid::cube, T>& p)
+ {
+ return p;
}
- */
+
+
+ // to_imageNd
+
//const return a const
template <typename T>
Index: sandbox/jardonnet/registration/quat7.hh
--- sandbox/jardonnet/registration/quat7.hh (revision 1847)
+++ sandbox/jardonnet/registration/quat7.hh (working copy)
@@ -10,6 +10,8 @@
# include "rotation.hh"
# include "jacobi.hh"
+# include "power_it.hh"
+# include "frankel_young.hh"
# include <mln/norm/l2.hh>
@@ -115,6 +117,8 @@
}
Mk /= C.npoints();
+
+ /*
const algebra::mat<P::dim,P::dim,float> Ak = Mk - trans(Mk);
const float v[3] = {Ak(1,2), Ak(2,0), Ak(0,1)};
@@ -127,14 +131,42 @@
put(D, 1,0, Qk);
put(Mk + trans(Mk) - algebra::mat<P::dim,P::dim,float>::identity() * tr(Mk),
1,1, Qk);
+ */
- algebra::quat qR(literal::zero);
+ algebra::vec<3,float> a;
+ a[0] = Mk(1,2) - Mk(2,1);
+ a[1] = Mk(2,0) - Mk(0,2);
+ a[2] = Mk(0,1) - Mk(1,0);
+
+ algebra::mat<4,4,float> Qk(literal::zero);
+ float t = tr(Mk);
+
+ Qk(0,0) = t;
+ for (int i = 1; i < 4; i++)
+ {
+ Qk(i,0) = a[i - 1];
+ Qk(0,i) = a[i - 1];
+ for (int j = 1; j < 4; j++)
+ if (i == j)
+ Qk(i,j) = 2 * Mk(i - 1,i - 1) - t;
+ }
+ Qk(1,2) = Mk(0,1) + Mk(1,0);
+ Qk(2,1) = Mk(0,1) + Mk(1,0);
+
+ Qk(1,3) = Mk(0,2) + Mk(2,0);
+ Qk(3,1) = Mk(0,2) + Mk(2,0);
+
+ Qk(2,3) = Mk(1,2) + Mk(2,1);
+ Qk(3,2) = Mk(1,2) + Mk(2,1);
+
+ algebra::quat qR(literal::zero);
+ qR = jacobi(Qk);
+ //std::cout << qR << std::endl;
+ //qR = power_it(Qk);
//std::cout << qR << std::endl;
- jacobi(Qk, qR);
// qT
-
const algebra::vec<P::dim,float> qT = mu_Xk - rotate(qR, mu_C);
return quat7<P::dim>(qR, qT);
Index: sandbox/jardonnet/registration/frankel_young.hh
--- sandbox/jardonnet/registration/frankel_young.hh (revision 0)
+++ sandbox/jardonnet/registration/frankel_young.hh (revision 0)
@@ -0,0 +1,46 @@
+#ifndef _FRANKEL_YOUNG_HH
+# define _FRANKEL_YOUNG_HH
+
+//Successive over-relaxation (SOR) is a numerical method used to speed up
+//convergence of the Gauss-Seidel method for solving a linear system of
+//equations.
+
+namespace mln
+{
+
+ algebra::quat frankel_young(algebra::mat<4,4,float> a, float w)
+ {
+ //Inputs: A , b, w
+ //Output: phi
+
+ algebra::vec<4,float> phi(literal::zero);
+ algebra::vec<4,float> old_phi(literal::zero);
+
+ algebra::vec<4,float> b;
+ for (int i = 0; i < 4; i++)
+ b[i] = phi[i] = a(i,i);
+
+ //Choose an initial guess phi to the solution
+ while (fabs(norm::l2(old_phi) - norm::l2(phi)) > 1e-6)
+ {
+ old_phi = phi;
+ for (int i = 1; i < 4; i++)
+ {
+ float sigma = 0;
+
+ for (int j = 1; j < i-1; j++)
+ sigma += a(i,j) * phi[i];
+
+ for (int j = i + 1; j < 4; j++)
+ sigma += a(i,j) * phi[i];
+
+ phi[i] = (1 - w) * phi[i] + w / a(i,i) * (b[i] - sigma);
+ }
+ }
+ algebra::quat q(phi);
+ q.set_unit();
+ return q;
+ }
+}
+
+#endif /* _FRANKEL_YOUNG_HH */
Index: sandbox/jardonnet/registration/cloud.hh
--- sandbox/jardonnet/registration/cloud.hh (revision 1847)
+++ sandbox/jardonnet/registration/cloud.hh (working copy)
@@ -56,7 +56,7 @@
{
algebra::vec<3,float> a1f = a1[i];
algebra::vec<3,float> a2f = a2[i];
- f += norm::l2_distance(a1f,a2f);
+ f += norm::l2(a1f - a2f);
}
return f / a1.npoints();
}
Index: sandbox/jardonnet/registration/icp.hh
--- sandbox/jardonnet/registration/icp.hh (revision 1847)
+++ sandbox/jardonnet/registration/icp.hh (working copy)
@@ -33,6 +33,9 @@
* \brief image registration
*/
+# include <iostream>
+# include <string>
+
# include <mln/algebra/quat.hh>
# include <mln/algebra/vec.hh>
# include <mln/make/w_window.hh>
@@ -111,6 +114,15 @@
err = rms(Ck, Xk);
#ifndef NDEBUG
+
+ {
+ using namespace std;
+ image2d<bool> img = convert::to_image2d(Ck);
+ stringstream oss;
+ oss << "reg" << k << ".pbm";
+ io::pbm::save(img, oss.str());
+ }
+
//plot file
std::cout << k << '\t' << err << '\t'
<< (qk - old_qk).sqr_norm() << '\t'
@@ -138,8 +150,8 @@
{
trace::entering("registration::icp");
- mln_precondition(cloud.npoints() != 0);
mln_precondition(P::dim == 3);
+ mln_precondition(cloud.npoints() != 0);
//init rigid transform qk
quat7<P::dim> qk;