|
|
|
|
|
#ifndef DLIB_POINT_TrANSFORMS_H_ |
|
#define DLIB_POINT_TrANSFORMS_H_ |
|
|
|
#include "point_transforms_abstract.h" |
|
#include "../algs.h" |
|
#include "vector.h" |
|
#include "../matrix.h" |
|
#include "../matrix/matrix_la.h" |
|
#include "../optimization/optimization.h" |
|
#include "rectangle.h" |
|
#include "drectangle.h" |
|
#include <vector> |
|
#include <cmath> |
|
|
|
namespace dlib |
|
{ |
|
|
|
|
|
|
|
class point_rotator |
|
{ |
|
public: |
|
point_rotator ( |
|
) |
|
{ |
|
sin_angle = 0; |
|
cos_angle = 1; |
|
} |
|
|
|
point_rotator ( |
|
const double& angle |
|
) |
|
{ |
|
sin_angle = std::sin(angle); |
|
cos_angle = std::cos(angle); |
|
} |
|
|
|
template <typename T> |
|
const dlib::vector<T,2> operator() ( |
|
const dlib::vector<T,2>& p |
|
) const |
|
{ |
|
double x = cos_angle*p.x() - sin_angle*p.y(); |
|
double y = sin_angle*p.x() + cos_angle*p.y(); |
|
|
|
return dlib::vector<double,2>(x,y); |
|
} |
|
|
|
const matrix<double,2,2> get_m( |
|
) const |
|
{ |
|
matrix<double,2,2> temp; |
|
temp = cos_angle, -sin_angle, |
|
sin_angle, cos_angle; |
|
return temp; |
|
} |
|
|
|
inline friend void serialize (const point_rotator& item, std::ostream& out) |
|
{ |
|
serialize(item.sin_angle, out); |
|
serialize(item.cos_angle, out); |
|
} |
|
|
|
inline friend void deserialize (point_rotator& item, std::istream& in) |
|
{ |
|
deserialize(item.sin_angle, in); |
|
deserialize(item.cos_angle, in); |
|
} |
|
|
|
private: |
|
double sin_angle; |
|
double cos_angle; |
|
}; |
|
|
|
|
|
|
|
class point_transform |
|
{ |
|
public: |
|
|
|
point_transform ( |
|
) |
|
{ |
|
sin_angle = 0; |
|
cos_angle = 1; |
|
translate.x() = 0; |
|
translate.y() = 0; |
|
} |
|
|
|
point_transform ( |
|
const double& angle, |
|
const dlib::vector<double,2>& translate_ |
|
) |
|
{ |
|
sin_angle = std::sin(angle); |
|
cos_angle = std::cos(angle); |
|
translate = translate_; |
|
} |
|
|
|
template <typename T> |
|
const dlib::vector<T,2> operator() ( |
|
const dlib::vector<T,2>& p |
|
) const |
|
{ |
|
double x = cos_angle*p.x() - sin_angle*p.y(); |
|
double y = sin_angle*p.x() + cos_angle*p.y(); |
|
|
|
return dlib::vector<double,2>(x,y) + translate; |
|
} |
|
|
|
const matrix<double,2,2> get_m( |
|
) const |
|
{ |
|
matrix<double,2,2> temp; |
|
temp = cos_angle, -sin_angle, |
|
sin_angle, cos_angle; |
|
return temp; |
|
} |
|
|
|
const dlib::vector<double,2> get_b( |
|
) const { return translate; } |
|
|
|
inline friend void serialize (const point_transform& item, std::ostream& out) |
|
{ |
|
serialize(item.sin_angle, out); |
|
serialize(item.cos_angle, out); |
|
serialize(item.translate, out); |
|
} |
|
|
|
inline friend void deserialize (point_transform& item, std::istream& in) |
|
{ |
|
deserialize(item.sin_angle, in); |
|
deserialize(item.cos_angle, in); |
|
deserialize(item.translate, in); |
|
} |
|
|
|
private: |
|
double sin_angle; |
|
double cos_angle; |
|
dlib::vector<double,2> translate; |
|
}; |
|
|
|
|
|
|
|
class point_transform_affine |
|
{ |
|
public: |
|
|
|
point_transform_affine ( |
|
) |
|
{ |
|
m = identity_matrix<double>(2); |
|
b.x() = 0; |
|
b.y() = 0; |
|
} |
|
|
|
point_transform_affine ( |
|
const matrix<double,2,2>& m_, |
|
const dlib::vector<double,2>& b_ |
|
) :m(m_), b(b_) |
|
{ |
|
} |
|
|
|
const dlib::vector<double,2> operator() ( |
|
const dlib::vector<double,2>& p |
|
) const |
|
{ |
|
return m*p + b; |
|
} |
|
|
|
const matrix<double,2,2>& get_m( |
|
) const { return m; } |
|
|
|
const dlib::vector<double,2>& get_b( |
|
) const { return b; } |
|
|
|
inline friend void serialize (const point_transform_affine& item, std::ostream& out) |
|
{ |
|
serialize(item.m, out); |
|
serialize(item.b, out); |
|
} |
|
|
|
inline friend void deserialize (point_transform_affine& item, std::istream& in) |
|
{ |
|
deserialize(item.m, in); |
|
deserialize(item.b, in); |
|
} |
|
|
|
private: |
|
matrix<double,2,2> m; |
|
dlib::vector<double,2> b; |
|
}; |
|
|
|
|
|
|
|
class rectangle_transform |
|
{ |
|
public: |
|
|
|
rectangle_transform ( |
|
) |
|
{ |
|
} |
|
|
|
rectangle_transform ( |
|
const point_transform_affine& tform_ |
|
) :tform(tform_) |
|
{ |
|
} |
|
|
|
drectangle operator() ( |
|
const drectangle& r |
|
) const |
|
{ |
|
dpoint tl = r.tl_corner(); |
|
dpoint tr = r.tr_corner(); |
|
dpoint bl = r.bl_corner(); |
|
dpoint br = r.br_corner(); |
|
|
|
|
|
|
|
double new_area = (1+length(tform(tl)-tform(tr)))*(1+length(tform(tl)-tform(bl))); |
|
|
|
|
|
|
|
|
|
drectangle temp; |
|
temp += tform(tl); |
|
temp += tform(tr); |
|
temp += tform(bl); |
|
temp += tform(br); |
|
|
|
|
|
double scale = std::sqrt(new_area/temp.area()); |
|
|
|
return centered_rect(center(temp), std::round(temp.width()*scale), std::round(temp.height()*scale)); |
|
} |
|
|
|
rectangle operator() ( |
|
const rectangle& r |
|
) const |
|
{ |
|
return (*this)(drectangle(r)); |
|
} |
|
|
|
const point_transform_affine& get_tform( |
|
) const { return tform; } |
|
|
|
inline friend void serialize (const rectangle_transform& item, std::ostream& out) |
|
{ |
|
serialize(item.tform, out); |
|
} |
|
|
|
inline friend void deserialize (rectangle_transform& item, std::istream& in) |
|
{ |
|
deserialize(item.tform, in); |
|
} |
|
|
|
private: |
|
point_transform_affine tform; |
|
}; |
|
|
|
|
|
|
|
inline point_transform_affine operator* ( |
|
const point_transform_affine& lhs, |
|
const point_transform_affine& rhs |
|
) |
|
{ |
|
return point_transform_affine(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b()); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine inv ( |
|
const point_transform_affine& trans |
|
) |
|
{ |
|
matrix<double,2,2> im = inv(trans.get_m()); |
|
return point_transform_affine(im, -im*trans.get_b()); |
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
point_transform_affine find_affine_transform ( |
|
const std::vector<dlib::vector<T,2> >& from_points, |
|
const std::vector<dlib::vector<T,2> >& to_points |
|
) |
|
{ |
|
|
|
DLIB_ASSERT(from_points.size() == to_points.size() && |
|
from_points.size() >= 3, |
|
"\t point_transform_affine find_affine_transform(from_points, to_points)" |
|
<< "\n\t Invalid inputs were given to this function." |
|
<< "\n\t from_points.size(): " << from_points.size() |
|
<< "\n\t to_points.size(): " << to_points.size() |
|
); |
|
|
|
matrix<double,3,0> P(3, from_points.size()); |
|
matrix<double,2,0> Q(2, from_points.size()); |
|
|
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
P(0,i) = from_points[i].x(); |
|
P(1,i) = from_points[i].y(); |
|
P(2,i) = 1; |
|
|
|
Q(0,i) = to_points[i].x(); |
|
Q(1,i) = to_points[i].y(); |
|
} |
|
|
|
const matrix<double,2,3> m = Q*pinv(P); |
|
return point_transform_affine(subm(m,0,0,2,2), colm(m,2)); |
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
point_transform_affine find_similarity_transform ( |
|
const std::vector<dlib::vector<T,2> >& from_points, |
|
const std::vector<dlib::vector<T,2> >& to_points |
|
) |
|
{ |
|
|
|
DLIB_ASSERT(from_points.size() == to_points.size() && |
|
from_points.size() >= 2, |
|
"\t point_transform_affine find_similarity_transform(from_points, to_points)" |
|
<< "\n\t Invalid inputs were given to this function." |
|
<< "\n\t from_points.size(): " << from_points.size() |
|
<< "\n\t to_points.size(): " << to_points.size() |
|
); |
|
|
|
|
|
|
|
|
|
|
|
dlib::vector<double,2> mean_from, mean_to; |
|
double sigma_from = 0, sigma_to = 0; |
|
matrix<double,2,2> cov; |
|
cov = 0; |
|
|
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
mean_from += from_points[i]; |
|
mean_to += to_points[i]; |
|
} |
|
mean_from /= from_points.size(); |
|
mean_to /= from_points.size(); |
|
|
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
sigma_from += length_squared(from_points[i] - mean_from); |
|
sigma_to += length_squared(to_points[i] - mean_to); |
|
cov += (to_points[i] - mean_to)*trans(from_points[i] - mean_from); |
|
} |
|
|
|
sigma_from /= from_points.size(); |
|
sigma_to /= from_points.size(); |
|
cov /= from_points.size(); |
|
|
|
matrix<double,2,2> u, v, s, d; |
|
svd(cov, u,d,v); |
|
s = identity_matrix(cov); |
|
if (det(cov) < 0 || (det(cov) == 0 && det(u)*det(v)<0)) |
|
{ |
|
if (d(1,1) < d(0,0)) |
|
s(1,1) = -1; |
|
else |
|
s(0,0) = -1; |
|
} |
|
|
|
matrix<double,2,2> r = u*s*trans(v); |
|
double c = 1; |
|
if (sigma_from != 0) |
|
c = 1.0/sigma_from * trace(d*s); |
|
vector<double,2> t = mean_to - c*r*mean_from; |
|
|
|
return point_transform_affine(c*r, t); |
|
} |
|
|
|
|
|
|
|
class point_transform_projective |
|
{ |
|
public: |
|
|
|
point_transform_projective ( |
|
) |
|
{ |
|
m = identity_matrix<double>(3); |
|
} |
|
|
|
point_transform_projective ( |
|
const matrix<double,3,3>& m_ |
|
) :m(m_) |
|
{ |
|
} |
|
|
|
point_transform_projective ( |
|
const point_transform_affine& tran |
|
) |
|
{ |
|
set_subm(m, 0,0, 2,2) = tran.get_m(); |
|
set_subm(m, 0,2, 2,1) = tran.get_b(); |
|
m(2,0) = 0; |
|
m(2,1) = 0; |
|
m(2,2) = 1; |
|
} |
|
|
|
|
|
const dlib::vector<double,2> operator() ( |
|
const dlib::vector<double,2>& p |
|
) const |
|
{ |
|
dlib::vector<double,3> temp(p); |
|
temp.z() = 1; |
|
temp = m*temp; |
|
if (temp.z() != 0) |
|
temp = temp/temp.z(); |
|
return temp; |
|
} |
|
|
|
const matrix<double,3,3>& get_m( |
|
) const { return m; } |
|
|
|
inline friend void serialize (const point_transform_projective& item, std::ostream& out) |
|
{ |
|
serialize(item.m, out); |
|
} |
|
|
|
inline friend void deserialize (point_transform_projective& item, std::istream& in) |
|
{ |
|
deserialize(item.m, in); |
|
} |
|
|
|
private: |
|
matrix<double,3,3> m; |
|
}; |
|
|
|
|
|
|
|
inline point_transform_projective operator* ( |
|
const point_transform_projective& lhs, |
|
const point_transform_projective& rhs |
|
) |
|
{ |
|
return point_transform_projective(lhs.get_m()*rhs.get_m()); |
|
} |
|
|
|
|
|
|
|
inline point_transform_projective inv ( |
|
const point_transform_projective& trans |
|
) |
|
{ |
|
return point_transform_projective(inv(trans.get_m())); |
|
} |
|
|
|
|
|
|
|
namespace impl_proj |
|
{ |
|
|
|
inline point_transform_projective find_projective_transform_basic ( |
|
const std::vector<dlib::vector<double,2> >& from_points, |
|
const std::vector<dlib::vector<double,2> >& to_points |
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
DLIB_ASSERT(from_points.size() == to_points.size() && |
|
from_points.size() >= 4, |
|
"\t point_transform_projective find_projective_transform_basic(from_points, to_points)" |
|
<< "\n\t Invalid inputs were given to this function." |
|
<< "\n\t from_points.size(): " << from_points.size() |
|
<< "\n\t to_points.size(): " << to_points.size() |
|
); |
|
|
|
matrix<double,9,9> accum, u, v; |
|
matrix<double,9,1> w; |
|
matrix<double,2,9> B; |
|
accum = 0; |
|
B = 0; |
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
dlib::vector<double,3> f = from_points[i]; |
|
f.z() = 1; |
|
dlib::vector<double,3> t = to_points[i]; |
|
t.z() = 1; |
|
|
|
set_subm(B,0,0,1,3) = t.y()*trans(f); |
|
set_subm(B,1,0,1,3) = trans(f); |
|
|
|
set_subm(B,0,3,1,3) = -t.x()*trans(f); |
|
set_subm(B,1,6,1,3) = -t.x()*trans(f); |
|
|
|
accum += trans(B)*B; |
|
} |
|
|
|
svd2(true, false, accum, u, w, v); |
|
long j = index_of_min(w); |
|
|
|
return point_transform_projective(reshape(colm(u,j),3,3)); |
|
} |
|
|
|
|
|
|
|
struct obj |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
obj( |
|
const std::vector<dlib::vector<double,2> >& from_points_, |
|
const std::vector<dlib::vector<double,2> >& to_points_ |
|
) : |
|
from_points(from_points_) , |
|
to_points(to_points_) |
|
{} |
|
const std::vector<dlib::vector<double,2> >& from_points; |
|
const std::vector<dlib::vector<double,2> >& to_points; |
|
|
|
double operator() ( |
|
const matrix<double,9,1>& p |
|
) const |
|
{ |
|
point_transform_projective tran(reshape(p,3,3)); |
|
|
|
double sum = 0; |
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
sum += length_squared(tran(from_points[i]) - to_points[i]); |
|
} |
|
return sum; |
|
} |
|
}; |
|
|
|
struct obj_der |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
obj_der( |
|
const std::vector<dlib::vector<double,2> >& from_points_, |
|
const std::vector<dlib::vector<double,2> >& to_points_ |
|
) : |
|
from_points(from_points_) , |
|
to_points(to_points_) |
|
{} |
|
const std::vector<dlib::vector<double,2> >& from_points; |
|
const std::vector<dlib::vector<double,2> >& to_points; |
|
|
|
matrix<double,9,1> operator() ( |
|
const matrix<double,9,1>& p |
|
) const |
|
{ |
|
const matrix<double,3,3> H = reshape(p,3,3); |
|
|
|
matrix<double,3,3> grad; |
|
grad = 0; |
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
dlib::vector<double,3> from, to; |
|
from = from_points[i]; |
|
from.z() = 1; |
|
to = to_points[i]; |
|
to.z() = 1; |
|
|
|
matrix<double,3,1> w = H*from; |
|
const double scale = (w(2) != 0) ? (1.0/w(2)) : (1); |
|
w *= scale; |
|
matrix<double,3,1> residual = (w-to)*2*scale; |
|
|
|
grad(0,0) += from.x()*residual(0); |
|
grad(0,1) += from.y()*residual(0); |
|
grad(0,2) += residual(0); |
|
|
|
grad(1,0) += from.x()*residual(1); |
|
grad(1,1) += from.y()*residual(1); |
|
grad(1,2) += residual(1); |
|
|
|
grad(2,0) += -(from.x()*w(0)*residual(0) + from.x()*w(1)*residual(1)); |
|
grad(2,1) += -(from.y()*w(0)*residual(0) + from.y()*w(1)*residual(1)); |
|
grad(2,2) += -( w(0)*residual(0) + w(1)*residual(1)); |
|
|
|
} |
|
return reshape_to_column_vector(grad); |
|
} |
|
}; |
|
} |
|
|
|
|
|
|
|
inline point_transform_projective find_projective_transform ( |
|
const std::vector<dlib::vector<double,2> >& from_points, |
|
const std::vector<dlib::vector<double,2> >& to_points |
|
) |
|
{ |
|
using namespace impl_proj; |
|
|
|
DLIB_ASSERT(from_points.size() == to_points.size() && |
|
from_points.size() >= 4, |
|
"\t point_transform_projective find_projective_transform(from_points, to_points)" |
|
<< "\n\t Invalid inputs were given to this function." |
|
<< "\n\t from_points.size(): " << from_points.size() |
|
<< "\n\t to_points.size(): " << to_points.size() |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
point_transform_projective tran1 = find_projective_transform_basic(from_points, to_points); |
|
point_transform_affine tran2 = find_affine_transform(from_points, to_points); |
|
|
|
|
|
double error1 = 0; |
|
double error2 = 0; |
|
for (unsigned long i = 0; i < from_points.size(); ++i) |
|
{ |
|
error1 += length_squared(tran1(from_points[i])-to_points[i]); |
|
error2 += length_squared(tran2(from_points[i])-to_points[i]); |
|
} |
|
matrix<double,9,1> params; |
|
|
|
if (error1 < error2) |
|
params = reshape_to_column_vector(tran1.get_m()); |
|
else |
|
params = reshape_to_column_vector(point_transform_projective(tran2).get_m()); |
|
|
|
|
|
|
|
|
|
obj o(from_points, to_points); |
|
obj_der der(from_points, to_points); |
|
find_min(bfgs_search_strategy(), |
|
objective_delta_stop_strategy(1e-6,100), |
|
o, |
|
der, |
|
params, |
|
0); |
|
|
|
return point_transform_projective(reshape(params,3,3)); |
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
const dlib::vector<T,2> rotate_point ( |
|
const dlib::vector<T,2>& center, |
|
const dlib::vector<T,2>& p, |
|
double angle |
|
) |
|
{ |
|
point_rotator rot(angle); |
|
return rot(p-center)+center; |
|
} |
|
|
|
|
|
|
|
inline matrix<double,2,2> rotation_matrix ( |
|
double angle |
|
) |
|
{ |
|
const double ca = std::cos(angle); |
|
const double sa = std::sin(angle); |
|
|
|
matrix<double,2,2> m; |
|
m = ca, -sa, |
|
sa, ca; |
|
return m; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
class point_transform_affine3d |
|
{ |
|
public: |
|
|
|
point_transform_affine3d ( |
|
) |
|
{ |
|
m = identity_matrix<double>(3); |
|
b.x() = 0; |
|
b.y() = 0; |
|
} |
|
|
|
point_transform_affine3d ( |
|
const matrix<double,3,3>& m_, |
|
const dlib::vector<double,3>& b_ |
|
) :m(m_), b(b_) |
|
{ |
|
} |
|
|
|
const dlib::vector<double,3> operator() ( |
|
const dlib::vector<double,3>& p |
|
) const |
|
{ |
|
return m*p + b; |
|
} |
|
|
|
const matrix<double,3,3>& get_m( |
|
) const { return m; } |
|
|
|
const dlib::vector<double,3>& get_b( |
|
) const { return b; } |
|
|
|
inline friend void serialize (const point_transform_affine3d& item, std::ostream& out) |
|
{ |
|
serialize(item.m, out); |
|
serialize(item.b, out); |
|
} |
|
|
|
inline friend void deserialize (point_transform_affine3d& item, std::istream& in) |
|
{ |
|
deserialize(item.m, in); |
|
deserialize(item.b, in); |
|
} |
|
|
|
private: |
|
matrix<double,3,3> m; |
|
dlib::vector<double,3> b; |
|
}; |
|
|
|
|
|
|
|
inline point_transform_affine3d operator* ( |
|
const point_transform_affine3d& lhs, |
|
const point_transform_affine& rhs |
|
) |
|
{ |
|
matrix<double,3,3> m; |
|
m = 0; |
|
set_subm(m, get_rect(rhs.get_m())) = rhs.get_m(); |
|
vector<double,3> b = rhs.get_b(); |
|
|
|
return point_transform_affine3d(lhs.get_m()*m, lhs.get_m()*b+lhs.get_b()); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine3d operator* ( |
|
const point_transform_affine3d& lhs, |
|
const point_transform_affine3d& rhs |
|
) |
|
{ |
|
return point_transform_affine3d(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b()); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine3d inv ( |
|
const point_transform_affine3d& trans |
|
) |
|
{ |
|
matrix<double,3,3> im = inv(trans.get_m()); |
|
return point_transform_affine3d(im, -im*trans.get_b()); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine3d rotate_around_x ( |
|
double angle |
|
) |
|
{ |
|
const double ca = std::cos(angle); |
|
const double sa = std::sin(angle); |
|
|
|
matrix<double,3,3> m; |
|
m = 1, 0, 0, |
|
0, ca, -sa, |
|
0, sa, ca; |
|
|
|
vector<double,3> b; |
|
|
|
return point_transform_affine3d(m,b); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine3d rotate_around_y ( |
|
double angle |
|
) |
|
{ |
|
const double ca = std::cos(angle); |
|
const double sa = std::sin(angle); |
|
|
|
matrix<double,3,3> m; |
|
m = ca, 0, sa, |
|
0, 1, 0, |
|
-sa, 0, ca; |
|
|
|
vector<double,3> b; |
|
|
|
return point_transform_affine3d(m,b); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine3d rotate_around_z ( |
|
double angle |
|
) |
|
{ |
|
const double ca = std::cos(angle); |
|
const double sa = std::sin(angle); |
|
|
|
matrix<double,3,3> m; |
|
m = ca, -sa, 0, |
|
sa, ca, 0, |
|
0, 0, 1; |
|
|
|
vector<double,3> b; |
|
|
|
return point_transform_affine3d(m,b); |
|
} |
|
|
|
|
|
|
|
inline point_transform_affine3d translate_point ( |
|
const vector<double,3>& delta |
|
) |
|
{ |
|
return point_transform_affine3d(identity_matrix<double>(3),delta); |
|
} |
|
|
|
inline point_transform_affine3d translate_point ( |
|
double x, |
|
double y, |
|
double z |
|
) |
|
{ |
|
return translate_point(vector<double>(x,y,z)); |
|
} |
|
|
|
|
|
|
|
class camera_transform |
|
{ |
|
|
|
public: |
|
|
|
camera_transform ( |
|
) |
|
{ |
|
*this = camera_transform(vector<double>(1,1,1), |
|
vector<double>(0,0,0), |
|
vector<double>(0,0,1), |
|
90, |
|
1); |
|
} |
|
|
|
camera_transform ( |
|
const vector<double>& camera_pos_, |
|
const vector<double>& camera_looking_at_, |
|
const vector<double>& camera_up_direction_, |
|
const double camera_field_of_view_, |
|
const unsigned long num_pixels_ |
|
) |
|
{ |
|
|
|
DLIB_CASSERT(0 < camera_field_of_view_ && camera_field_of_view_ < 180, |
|
"\t camera_transform::camera_transform()" |
|
<< "\n\t Invalid inputs were given to this function." |
|
<< "\n\t camera_field_of_view_: " << camera_field_of_view_ |
|
); |
|
|
|
camera_pos = camera_pos_; |
|
camera_looking_at = camera_looking_at_; |
|
camera_up_direction = camera_up_direction_; |
|
camera_field_of_view = camera_field_of_view_; |
|
num_pixels = num_pixels_; |
|
|
|
dlib::vector<double> X,Y,Z; |
|
Z = (camera_looking_at - camera_pos).normalize(); |
|
Y = camera_up_direction - dot(camera_up_direction,Z)*Z; |
|
Y = Y.normalize(); |
|
X = Z.cross(Y); |
|
|
|
set_rowm(proj,0) = trans(X); |
|
|
|
set_rowm(proj,1) = -trans(Y); |
|
set_rowm(proj,2) = trans(Z); |
|
|
|
width = num_pixels/2.0; |
|
dist_scale = width/std::tan(pi/180*camera_field_of_view/2); |
|
} |
|
|
|
vector<double> get_camera_pos() const { return camera_pos; } |
|
vector<double> get_camera_looking_at() const { return camera_looking_at; } |
|
vector<double> get_camera_up_direction()const { return camera_up_direction; } |
|
double get_camera_field_of_view() const { return camera_field_of_view; } |
|
unsigned long get_num_pixels() const { return num_pixels; } |
|
|
|
inline dpoint operator() ( |
|
const vector<double>& p, |
|
double& scale, |
|
double& distance |
|
) const |
|
{ |
|
vector<double> temp = p-camera_pos; |
|
temp = proj*temp; |
|
distance = temp.z(); |
|
scale = dist_scale/(temp.z()>0 ? temp.z() : 1e-9); |
|
temp.x() = temp.x()*scale + width; |
|
temp.y() = temp.y()*scale + width; |
|
return temp; |
|
} |
|
|
|
dpoint operator() ( |
|
const vector<double>& p |
|
) const |
|
{ |
|
double scale, distance; |
|
return (*this)(p,scale,distance); |
|
} |
|
|
|
inline friend void serialize (const camera_transform& item, std::ostream& out) |
|
{ |
|
serialize(item.camera_pos, out); |
|
serialize(item.camera_looking_at, out); |
|
serialize(item.camera_up_direction, out); |
|
serialize(item.camera_field_of_view, out); |
|
serialize(item.num_pixels, out); |
|
serialize(item.proj, out); |
|
serialize(item.dist_scale, out); |
|
serialize(item.width, out); |
|
} |
|
|
|
inline friend void deserialize (camera_transform& item, std::istream& in) |
|
{ |
|
deserialize(item.camera_pos, in); |
|
deserialize(item.camera_looking_at, in); |
|
deserialize(item.camera_up_direction, in); |
|
deserialize(item.camera_field_of_view, in); |
|
deserialize(item.num_pixels, in); |
|
deserialize(item.proj, in); |
|
deserialize(item.dist_scale, in); |
|
deserialize(item.width, in); |
|
} |
|
|
|
private: |
|
|
|
vector<double> camera_pos; |
|
vector<double> camera_looking_at; |
|
vector<double> camera_up_direction; |
|
double camera_field_of_view; |
|
unsigned long num_pixels; |
|
matrix<double,3,3> proj; |
|
double dist_scale; |
|
double width; |
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
|