/***************************************************************************** * 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 Camera::Camera() : FocalMm(0.f), ViewportPx(vcg::Point2(0, 0)), PixelSizeMm(vcg::Point2(0.0, 0.0)), CenterPx(vcg::Point2(0.0, 0.0)), DistorCenterPx(vcg::Point2(0.0, 0.0)), cameraType(PERSPECTIVE) { k[0] = k[1] = k[2] = k[3] = 0; } template template Camera Camera::Construct(const Camera& 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 void Camera::SetOrtho(S l, S r, S b, S t, vcg::Point2 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 bool Camera::IsOrtho() const { return (cameraType == ORTHO); } /** * @brief Set the camera specifying the perspective view */ template void Camera::SetPerspective(S AngleDeg, S AspectRatio, S Focal, vcg::Point2 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 void Camera::SetCavalieri(S sx, S dx, S bt, S tp, S Focal, vcg::Point2 Viewport) { cameraType = CAVALIERI; SetFrustum(sx, dx, bt, tp, Focal, Viewport); } /** * @brief set the camera specifying the isometric view */ template void Camera::SetIsometric(S sx, S dx, S bt, S tp, S Focal, vcg::Point2 Viewport) { cameraType = ISOMETRIC; SetFrustum(sx, dx, bt, tp, Focal, Viewport); } /** * @brief set the camera specifying the frustum view */ template void Camera::SetFrustum(S sx, S dx, S bt, S tp, S Focal, vcg::Point2 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 vcg::Matrix44 Camera::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 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 void Camera::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 vcg::Point2 Camera::Project(const vcg::Point3& p) const { vcg::Point2 q = Point2(p[0], p[1]); if (!IsOrtho()) { q[0] *= FocalMm / p.Z(); q[1] *= FocalMm / p.Z(); if (k[0] != 0) { vcg::Point2 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 vcg::Point3 Camera::UnProject(const vcg::Point2& p, const S& d) const { vcg::Point3 np = Point3(p[0], p[1], d); if (!IsOrtho()) { if (k[0] != 0) { vcg::Point2 d = Point2(p[0], p[1]); vcg::Point2 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 vcg::Point2 Camera::LocalToViewportPx(const vcg::Point2& p) const { vcg::Point2 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 vcg::Point2 Camera::ViewportPxToLocal(const vcg::Point2& p) const { vcg::Point2 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 vcg::Point2 Camera::ViewportPxTo_neg1_1(const vcg::Point2& p) const { vcg::Point2 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 vcg::Point2 Camera::Neg1_1ToViewportPx(const vcg::Point2& p) const { vcg::Point2 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 vcg::Point2 Camera::LocalTo_0_1(const vcg::Point2& p) const { vcg::Point2 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 vcg::Point2 Camera::LocalTo_neg1_1(const vcg::Point2& p) const { vcg::Point2 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 vcg::Point2 Camera::UndistortedToDistorted(vcg::Point2 u) const { vcg::Point2 dis; vcg::Point2 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 vcg::Point2 Camera::DistortedToUndistorted(vcg::Point2 d) const { vcg::Point2 u; vcg::Point2 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 bool Camera::operator==(const Camera &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 bool Camera::operator!=(const Camera &oth) const { return !(*this == oth); } } // namespace vcg