You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

416 lines
11 KiB

/*****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2022 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "camera.h"
namespace vcg {
template<class S>
Camera<S>::Camera() :
FocalMm(0.f),
ViewportPx(vcg::Point2<int>(0, 0)),
PixelSizeMm(vcg::Point2<S>(0.0, 0.0)),
CenterPx(vcg::Point2<S>(0.0, 0.0)),
DistorCenterPx(vcg::Point2<S>(0.0, 0.0)),
cameraType(PERSPECTIVE)
{
k[0] = k[1] = k[2] = k[3] = 0;
}
template<class S>
template<class Q>
Camera<S> Camera<S>::Construct(const Camera<Q>& t)
{
Camera n;
n.FocalMm = t.FocalMm;
n.ViewportPx.Import(t.ViewportPx);
n.PixelSizeMm.Import(t.PixelSizeMm);
n.CenterPx.Import(t.CenterPx);
n.DistorCenterPx.Import(t.DistorCenterPx);
n.cameraType = t.cameraType;
n.k[0] = t.k[0];
n.k[1] = t.k[1];
n.k[2] = t.k[2];
n.k[3] = t.k[3];
return n;
}
template<class S>
void Camera<S>::SetOrtho(S l, S r, S b, S t, vcg::Point2<int> viewport)
{
cameraType = ORTHO;
ViewportPx = viewport;
PixelSizeMm[0] = (r - l) / (S) ViewportPx[0];
PixelSizeMm[1] = (t - b) / (S) ViewportPx[1];
CenterPx[0] = -l / (r - l) * (S) ViewportPx[0];
CenterPx[1] = -b / (t - b) * (S) ViewportPx[1];
}
template<class S>
bool Camera<S>::IsOrtho() const
{
return (cameraType == ORTHO);
}
/**
* @brief Set the camera specifying the perspective view
*/
template<class S>
void Camera<S>::SetPerspective(S AngleDeg, S AspectRatio, S Focal, vcg::Point2<int> Viewport)
{
cameraType = PERSPECTIVE;
S halfsize[2];
halfsize[1] = tan(math::ToRad(AngleDeg / 2.0f)) * Focal;
halfsize[0] = halfsize[1] * AspectRatio;
SetFrustum(-halfsize[0], halfsize[0], -halfsize[1], halfsize[1], Focal, Viewport);
}
/**
* @brief set the camera specifying the cavalieri view
*/
template<class S>
void Camera<S>::SetCavalieri(S sx, S dx, S bt, S tp, S Focal, vcg::Point2<int> Viewport)
{
cameraType = CAVALIERI;
SetFrustum(sx, dx, bt, tp, Focal, Viewport);
}
/**
* @brief set the camera specifying the isometric view
*/
template<class S>
void Camera<S>::SetIsometric(S sx, S dx, S bt, S tp, S Focal, vcg::Point2<int> Viewport)
{
cameraType = ISOMETRIC;
SetFrustum(sx, dx, bt, tp, Focal, Viewport);
}
/**
* @brief set the camera specifying the frustum view
*/
template<class S>
void Camera<S>::SetFrustum(S sx, S dx, S bt, S tp, S Focal, vcg::Point2<int> Viewport)
{
S vp[2];
vp[0] = dx - sx;
vp[1] = tp - bt;
ViewportPx[0] = Viewport[0];
if (vp[1] != -1)
ViewportPx[1] = Viewport[1]; // the user specified the viewport
else
ViewportPx[1] = ViewportPx[0]; // default viewport
PixelSizeMm[0] = vp[0] / (S) Viewport[0];
PixelSizeMm[1] = vp[1] / (S) Viewport[1];
CenterPx[0] = -sx / vp[0] * (S) Viewport[0];
CenterPx[1] = -bt / vp[1] * (S) Viewport[1];
FocalMm = Focal;
}
/**
* @brief returns the projection matrix
* @param nearVal
* @param farVal
* @return
*/
template<class S>
vcg::Matrix44<S> Camera<S>::GetMatrix(S nearVal, S farVal)
{
S left, right, bottom, top, nr;
GetFrustum(left, right, bottom, top, nr);
if (cameraType == PERSPECTIVE) {
S ratio = nearVal / nr;
left *= ratio;
right *= ratio;
bottom *= ratio;
top *= ratio;
}
vcg::Matrix44<S> m;
m[0][0] = 2.0 * nearVal / (right - left);
m[0][1] = 0;
m[0][2] = (right + left) / (right - left);
m[0][3] = 0;
m[1][0] = 0;
m[1][1] = 2 * nearVal / (top - bottom);
m[1][2] = (top + bottom) / (top - bottom);
m[1][3] = 0;
m[2][0] = 0;
m[2][1] = 0;
m[2][2] = -(farVal + nearVal) / (farVal - nearVal);
m[2][3] = -2 * farVal * nearVal / (farVal - nearVal);
m[3][0] = 0;
m[3][1] = 0;
m[3][2] = -1;
m[3][3] = 0;
return m;
}
/**
* @brief returns the frustum
*/
template<class S>
void Camera<S>::GetFrustum(S& sx, S& dx, S& bt, S& tp, S& nr) const
{
dx = CenterPx.X() * PixelSizeMm.X(); // scaled center
sx = -((S) ViewportPx.X() - CenterPx.X()) * PixelSizeMm.X();
bt = -CenterPx.Y() * PixelSizeMm.Y();
tp = ((S) ViewportPx.Y() - CenterPx.Y()) * PixelSizeMm.Y();
nr = FocalMm;
}
/**
* @brief project a point from 3d CAMERA space to the camera's plane
*/
template<class S>
vcg::Point2<S> Camera<S>::Project(const vcg::Point3<S>& p) const
{
vcg::Point2<S> q = Point2<S>(p[0], p[1]);
if (!IsOrtho()) {
q[0] *= FocalMm / p.Z();
q[1] *= FocalMm / p.Z();
if (k[0] != 0) {
vcg::Point2<S> d;
d = UndistortedToDistorted(q);
q = d;
}
}
return q;
}
/**
* @brief unproject a point from the camera 2d plane [-1,-1]x[1,1] (plus depth) to 3d CAMERA space
*/
template<class S>
vcg::Point3<S> Camera<S>::UnProject(const vcg::Point2<S>& p, const S& d) const
{
vcg::Point3<S> np = Point3<S>(p[0], p[1], d);
if (!IsOrtho()) {
if (k[0] != 0) {
vcg::Point2<S> d = Point2<S>(p[0], p[1]);
vcg::Point2<S> u = DistortedToUndistorted(d);
np[0] = u[0];
np[1] = u[1];
}
np[0] /= FocalMm / d;
np[1] /= FocalMm / d;
}
return np;
}
/**
* @brief transforms local plane coords to vieport (pixel) coords
*/
template<class S>
vcg::Point2<S> Camera<S>::LocalToViewportPx(const vcg::Point2<S>& p) const
{
vcg::Point2<S> np;
np[0] = (p[0] / PixelSizeMm.X()) + CenterPx.X();
np[1] = (p[1] / PixelSizeMm.Y()) + CenterPx.Y();
return np;
}
/**
* @brief transforms vieport (pixel) coords to local plane coords
*/
template<class S>
vcg::Point2<S> Camera<S>::ViewportPxToLocal(const vcg::Point2<S>& p) const
{
vcg::Point2<S> ps;
ps[0] = (p[0] - CenterPx.X()) * PixelSizeMm.X();
ps[1] = (p[1] - CenterPx.Y()) * PixelSizeMm.Y();
return ps;
}
/**
* @brief transforms vieport (pixel) coords to [-1 1] coords
*/
template<class S>
vcg::Point2<S> Camera<S>::ViewportPxTo_neg1_1(const vcg::Point2<S>& p) const
{
vcg::Point2<S> ps;
ps[0] =
2.0f * ((p[0] - CenterPx.X()) * PixelSizeMm.X()) / (PixelSizeMm.X() * (S) ViewportPx[0]);
ps[1] =
2.0f * ((p[1] - CenterPx.Y()) * PixelSizeMm.Y()) / (PixelSizeMm.Y() * (S) ViewportPx[1]);
return ps;
}
/**
* @brief transforms [-1 1] coords to vieport (pixel) coords MICHELE IO
*/
template<class S>
vcg::Point2<S> Camera<S>::Neg1_1ToViewportPx(const vcg::Point2<S>& p) const
{
vcg::Point2<S> ps;
ps[0] =
((PixelSizeMm.X() * (S) ViewportPx[0] * p[0]) / (2.0f * PixelSizeMm.X())) + CenterPx.X();
ps[1] =
((PixelSizeMm.Y() * (S) ViewportPx[1] * p[1]) / (2.0f * PixelSizeMm.Y())) + CenterPx.Y();
return ps;
}
/**
* @brief transforms local plane coords to [0-1] coords
*/
template<class S>
vcg::Point2<S> Camera<S>::LocalTo_0_1(const vcg::Point2<S>& p) const
{
vcg::Point2<S> ps;
ps[0] = (p[0] / PixelSizeMm.X() + CenterPx.X()) / (S) ViewportPx[0];
ps[1] = (p[1] / PixelSizeMm.Y() + CenterPx.Y()) / (S) ViewportPx[1];
return ps;
}
/**
* @brief transforms local plane coords to [-1 1] coords
*/
template<class S>
vcg::Point2<S> Camera<S>::LocalTo_neg1_1(const vcg::Point2<S>& p) const
{
vcg::Point2<S> ps;
ps[0] = 2.0f * p[0] / (PixelSizeMm.X() * (S) ViewportPx[0]);
ps[1] = 2.0f * p[1] / (PixelSizeMm.Y() * (S) ViewportPx[1]);
return ps;
}
/**
* @brief transforms an undistorted 2D camera plane point in a distorted 2D camera plane point
*/
template<class Scalar>
vcg::Point2<Scalar> Camera<Scalar>::UndistortedToDistorted(vcg::Point2<Scalar> u) const
{
vcg::Point2<Scalar> dis;
vcg::Point2<Scalar> dc = ViewportPxTo_neg1_1(DistorCenterPx);
const Scalar SQRT3 = Scalar(1.732050807568877293527446341505872366943);
const Scalar CBRT = Scalar(0.33333333333333333333333);
Scalar Ru, Rd, lambda, c, d, Q, R, D, S, T, sinT, cosT;
if (((u[0] - dc[0]) == 0 && (u[1] - dc[1]) == 0) || k[0] == 0) {
dis[0] = u[0];
dis[1] = u[1];
return dis;
}
Ru = hypot((u[0] - dc[0]), (u[1] - dc[1])); /* SQRT(Xu*Xu+Yu*Yu) */
c = 1 / k[0];
d = -c * Ru;
Q = c / 3;
R = -d / 2;
if (R < 0)
D = pow(Q, 3) + sqrt(-R);
else
D = pow(Q, 3) + sqrt(R);
if (D >= 0) /* one real root */
{
D = sqrt(D);
S = pow((R + D), CBRT);
if (R >= D)
T = pow((R - D), CBRT);
else
T = -pow(abs((int) (R - D)), CBRT); // MODIFICATO DA ME
Rd = S + T;
if (Rd < 0)
Rd = sqrt(-1 / (3 * k[0]));
}
else /* three real roots */
{
D = sqrt(-D);
S = pow((Scalar) (hypot(R, D)), (Scalar) CBRT);
T = atan2(D, R) / 3;
// SinCos(T, sinT, cosT);
sinT = sin(T);
cosT = cos(T);
/* the larger positive root is 2*S*cos(T) */
/* the smaller positive root is -S*cos(T) + SQRT(3)*S*sin(T) */
/* the negative root is -S*cos(T) - SQRT(3)*S*sin(T) */
Rd = -S * cosT + SQRT3 * S * sinT; /* use the smaller positive root */
}
lambda = Rd / Ru;
dis[0] = u[0] * lambda;
dis[1] = u[1] * lambda;
return dis;
}
/**
* @brief transforms a distorted 2D camera plane point in an undistorted 2D camera plane point
*/
template<class S>
vcg::Point2<S> Camera<S>::DistortedToUndistorted(vcg::Point2<S> d) const
{
vcg::Point2<S> u;
vcg::Point2<S> dc = ViewportPxTo_neg1_1(DistorCenterPx);
S r = sqrt(pow((d[0] - dc[0]), 2) + pow((d[1] - dc[1]), 2));
u[0] = d[0] * (1 - k[0] * r * r);
u[1] = d[1] * (1 - k[0] * r * r);
return u;
}
template<class S>
bool Camera<S>::operator==(const Camera<S> &oth) const
{
return
FocalMm == oth.FocalMm &&
ViewportPx == oth.ViewportPx &&
PixelSizeMm == oth.PixelSizeMm &&
CenterPx == oth.CenterPx &&
DistorCenterPx == oth.DistorCenterPx &&
k == oth.k &&
cameraType == oth.cameraType;
}
template<class S>
bool Camera<S>::operator!=(const Camera<S> &oth) const
{
return !(*this == oth);
}
} // namespace vcg