00001
00002 #include <ros/ros.h>
00003 #include <cv_bridge/cv_bridge.h>
00004 #include <image_transport/image_transport.h>
00005 #include <opencv2/core/core.hpp>
00006 #include <opencv2/imgproc/imgproc.hpp>
00007
00008 #include "omnicamera/panolut_virtual_camera_common.h"
00009
00010 using cv::Mat_;
00011
00012 namespace omnicamera {
00013
00014 void rotationMatrix(const double x, const double y, const double z, const double angle, Mat &R) {
00015
00016 double norm = sqrt(x*x + y*y + z*z);
00017 double ux = x / norm;
00018 double uy = y / norm;
00019 double uz = z / norm;
00020 double c = cos(angle);
00021 double s = sin(angle);
00022
00023 R = (Mat_<double>(3, 3) <<
00024 c+ux*ux*(1-c), ux*uy*(1-c)+uz*s, uz*ux*(1-c)-uy*s,
00025 ux*uy*(1-c)-uz*s, c+uy*uy*(1-c), uz*uy*(1-c)+ux*s,
00026 ux*uz*(1-c)+uy*s, uy*uz*(1-c)-ux*s, c+uz*uz*(1-c));
00027 }
00028
00029 void panTiltToCart(const double pan, const double tilt, double &x, double &y, double &z) {
00030 x = cos(tilt) * cos(pan);
00031 y = cos(tilt) * sin(pan);
00032 z = sin(tilt);
00033 }
00034
00035 void cartToPanTilt(const double x, const double y, const double z, double &pan, double &tilt) {
00036 tilt = atan2(z, hypot(x, y));
00037 pan = atan2(y, x);
00038 }
00039
00040 void cameraMatrix(const double fovx, const double fovy, const double width, const double height, Mat &camMat) {
00041 double fx = 1 / tan(fovx / 2);
00042 double fy = 1 / tan(fovy / 2);
00043 double mx = width / 2;
00044 double my = height / 2;
00045 camMat = (Mat_<double> (3, 3) <<
00046 fx * mx, 0, mx,
00047 0, fy * my, my,
00048 0, 0, 1);
00049 }
00050
00051 void cameraInverse(const double pan, const double tilt, const double fovx, const double fovy, const double width, const double height, Mat &camInv) {
00052 double x, y, z;
00053 panTiltToCart(pan, tilt, x, y, z);
00054
00055
00056
00057
00058 Mat panR, tiltR, camR1, camR2;
00059 rotationMatrix(0, 0, 1, pan, panR);
00060 rotationMatrix(0, 1, 0, -tilt, tiltR);
00061 Mat camInWorld = (Mat_<double>(3, 3) << 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0);
00062 Mat camR = camInWorld * tiltR * panR;
00063
00064 Mat K;
00065 cameraMatrix(fovx, fovy, width, height, K);
00066
00067 camInv = (K * camR).inv(cv::DECOMP_SVD);
00068 }
00069
00070 void updateVcamStitcher(const omnicamera::LookupStitcher &pano, const int panoWidth, const int panoHeight, const VirtualCameraConfig &vcamConfig, omnicamera::LookupStitcher &vcam) {
00071
00072 if (vcam.lutX[0].cols != vcamConfig.viewportWidth || vcam.lutY[0].rows != vcamConfig.viewportHeight) {
00073 for (int i = 0; i < pano.getLutCount(); i++) {
00074 vcam.lutX[i].create(vcamConfig.viewportHeight, vcamConfig.viewportWidth, CV_16UC1);
00075 vcam.lutY[i].create(vcamConfig.viewportHeight, vcamConfig.viewportWidth, CV_16UC1);
00076 vcam.lutA[i].create(vcamConfig.viewportHeight, vcamConfig.viewportWidth, CV_8UC1);
00077 }
00078 }
00079
00080 Mat camInv;
00081 double panRad = vcamConfig.pan / 180.0 * M_PI;
00082 double tiltRad = vcamConfig.tilt / 180.0 * M_PI;
00083 double fovxRad = vcamConfig.horizontalFov / 180.0 * M_PI;
00084 double fovyRad = vcamConfig.verticalFov / 180.0 * M_PI;
00085 cameraInverse(panRad, tiltRad, fovxRad, fovyRad, vcamConfig.viewportWidth, vcamConfig.viewportHeight, camInv);
00086
00087 Mat p = Mat_<double>(3, 1);
00088 Mat d = Mat_<double>(3, 1);
00089 for (int r = 0; r < vcamConfig.viewportHeight; r++) {
00090 for (int c = 0; c < vcamConfig.viewportWidth; c++) {
00091
00092
00093 p.at<double>(0, 0) = c;
00094 p.at<double>(1, 0) = r;
00095 p.at<double>(2, 0) = 1;
00096
00097
00098 d = camInv * p;
00099 d = d / cv::norm(d);
00100
00101
00102 double x, y, z, pan, tilt;
00103 x = d.at<double>(0, 0);
00104 y = d.at<double>(1, 0);
00105 z = d.at<double>(2, 0);
00106 cartToPanTilt(x, y, z, pan, tilt);
00107
00108
00109
00110 int panox = (int) round((0.5 + -pan / (2 * M_PI)) * (panoWidth - 1));
00111 int panoy = (int) round((0.5 + -tilt / M_PI) * (panoHeight - 1));
00112 panox = std::max(panox, 0);
00113 panox = std::min(panoWidth - 1, panox);
00114 panoy = std::max(panoy, 0);
00115 panoy = std::min(panoHeight - 1, panoy);
00116
00117 for (int i = 0; i < pano.getLutCount(); i++) {
00118 vcam.lutX[i].at<ushort>(r, c) = pano.lutX[i].at<ushort>(panoy, panox);
00119 vcam.lutY[i].at<ushort>(r, c) = pano.lutY[i].at<ushort>(panoy, panox);
00120 vcam.lutA[i].at<uchar>(r, c) = pano.lutA[i].at<uchar>(panoy, panox);
00121 }
00122 }
00123 }
00124 }
00125
00126 }