PanolutVirtualCameraNodelet.cpp
Go to the documentation of this file.
00001 
00002 #include "omnicamera/PanolutVirtualCameraNodelet.h"
00003 
00004 #include <ros/package.h>
00005 #include <tf/transform_broadcaster.h>
00006 #include <cv_bridge/cv_bridge.h>
00007 #include <pluginlib/class_list_macros.h>
00008 #include <sensor_msgs/image_encodings.h>
00009 
00010 #include "omnicamera/panolut_virtual_camera_common.h"
00011 
00012 //#define USE_MT_NODE_HANDLE
00013 
00014 using ros::NodeHandle;
00015 using omnicamera::rotationMatrix;
00016 using omnicamera::panTiltToCart;
00017 using omnicamera::cartToPanTilt;
00018 using omnicamera::cameraInverse;
00019 using omnicamera::updateVcamStitcher;
00020 
00021 namespace omnicamera {
00022 
00023 const int PanolutVirtualCameraNodelet::N_CAMS = 6;
00024 
00025 PanolutVirtualCameraNodelet::PanolutVirtualCameraNodelet() {
00026 //  NODELET_INFO("PanolutVirtualCameraNodelet::PanolutVirtualCameraNodelet");
00027 }
00028 
00029 void PanolutVirtualCameraNodelet::setup(NodeHandle &nh, NodeHandle & pnh) {
00030 //  NODELET_INFO("PanolutVirtualCameraNodelet::setup");
00031 
00032   pnh.param("in_width", inWidth, 1616);
00033   pnh.param("in_height", inHeight, 7392);
00034   NODELET_INFO("Input image size: %dx%d.", inWidth, inHeight);
00035 
00036   pnh.param("pano_width", panoWidth, 960);
00037   pnh.param("pano_height", panoHeight, 480);
00038   NODELET_INFO("Panorama size: %dx%d.", panoWidth, panoHeight);
00039   pnh.param("frame_id", frameId, string("ptz"));
00040   pnh.param("parent_frame_id", parentFrameId, string("omnicam"));
00041 
00042   pnh.param("alpha", alpha, true);
00043   NODELET_INFO("Alpha blending: %s.", alpha ? "enabled" : "disabled");
00044 
00045   pnh.param("equalize_hist", equalizeHist, false);
00046   NODELET_INFO("Equalize histogram: %s.", equalizeHist ? "enabled" : "disabled");
00047 
00048   pnh.param("radius", radius, 20);
00049   NODELET_INFO("Sphere radius: %d.", radius);
00050 
00051   std::string omnicameraPath = ros::package::getPath("omnicamera");
00052   pnh.param("lut_format", lutPath, string("/res/lut/LUT_img_%dx%d_pano_%dx%dr%d_%s%d.png"));
00053   lutPath = omnicameraPath + lutPath;
00054   NODELET_INFO("LUT path template: %s.", lutPath.data());
00055 
00056   pano.clearLookupTables();
00057   vcam.clearLookupTables();
00058   for (int iCam = 1; iCam <= N_CAMS; iCam++) {
00059     int len = 1024;
00060     char xPath[len], yPath[len], aPath[len];
00061     snprintf(xPath, len, lutPath.data(), inWidth, inHeight, panoWidth, panoHeight, radius, "x", iCam);
00062     snprintf(yPath, len, lutPath.data(), inWidth, inHeight, panoWidth, panoHeight, radius, "y", iCam);
00063     snprintf(aPath, len, lutPath.data(), inWidth, inHeight, panoWidth, panoHeight, radius, "a", iCam);
00064     NODELET_INFO("Camera %d look-up tables: %s, %s, %s.", iCam, xPath, yPath, aPath);
00065     pano.addLookupTables(string(xPath), string(yPath), string(aPath));
00066     vcam.addLookupTables(Mat(0, 0, CV_16UC1), Mat(0, 0, CV_16UC1), Mat(0, 0, CV_8UC1));
00067   }
00068   pano.fixBounds(inWidth, inHeight);
00069 
00070   pnh.param("viewport_width",   vcamConfig.viewportWidth,   512);
00071   pnh.param("viewport_height",  vcamConfig.viewportHeight,  512);
00072   pnh.param("pan",              vcamConfig.pan,             0.);
00073   pnh.param("tilt",             vcamConfig.tilt,            0.);
00074   pnh.param("horizontal_fov",   vcamConfig.horizontalFov,   90.);
00075   pnh.param("vertical_fov",     vcamConfig.verticalFov,     90.);
00076   NODELET_INFO("Virtual camera settings: Viewport width: %i, height: %i, pan: %f, tilt: %f, horizontal fov: %f, vertical fov: %f.",
00077       vcamConfig.viewportWidth, vcamConfig.viewportHeight, vcamConfig.pan, vcamConfig.tilt, vcamConfig.horizontalFov, vcamConfig.verticalFov);
00078 
00079   updateTransform();
00080 
00081   updateVcamStitcher(pano, panoWidth, panoHeight, vcamConfig, vcam);
00082   vcam.fixBounds(inWidth, inHeight);
00083   // Update camera info "template".
00084   camMsg.width = vcamConfig.viewportWidth;
00085   camMsg.height = vcamConfig.viewportHeight;
00086   Mat K;
00087   cameraMatrix(vcamConfig.horizontalFov / 180 * M_PI, vcamConfig.verticalFov / 180 * M_PI, vcamConfig.viewportWidth, vcamConfig.viewportHeight, K);
00088   for (int r = 0; r < K.rows; r++) {
00089     for (int c = 0; c < K.cols; c++) {
00090       camMsg.K[r * 3 + c] = K.at<double>(r, c);
00091     }
00092   }
00093   for (int r = 0; r < K.rows; r++) {
00094     for (int c = 0; c < K.cols; c++) {
00095       camMsg.P[r * 4 + c] = K.at<double>(r, c);
00096     }
00097     camMsg.P[r * 4 + 3] = 0; // No translation.
00098   }
00099   for (int i = 0; i < 9; i++) {
00100     camMsg.R[i] = 0;
00101   }
00102   camMsg.R[0] = 1;
00103   camMsg.R[4] = 1;
00104   camMsg.R[8] = 1;
00105 
00106 //  image_transport::ImageTransport it(nh);
00107   it.reset(new image_transport::ImageTransport(nh));
00108   imageSubcriber = it->subscribe("in", 1, &PanolutVirtualCameraNodelet::imageCallback, this);
00109   outPub = it->advertise("out", 1);
00110   camPub = nh.advertise<sensor_msgs::CameraInfo>("camera_info", 1);
00111 
00112   tfPublisherTimer = nh.createTimer(ros::Duration(0.01), &PanolutVirtualCameraNodelet::tfPublisherCallback, this);
00113   virtualCameraConfigSubscriber = nh.subscribe("config", 1, &PanolutVirtualCameraNodelet::virtualCameraConfigCallback, this);
00114   getVirtualCameraConfigServer = nh.advertiseService("get_config", &PanolutVirtualCameraNodelet::getVirtualCameraConfigService, this);
00115 }
00116 
00117 void PanolutVirtualCameraNodelet::onInit() {
00118   NODELET_INFO("Initializing PanolutVirtualCameraNodelet...");
00119 
00120 #ifdef USE_MT_NODE_HANDLE
00121     ros::NodeHandle &nh = getMTNodeHandle();
00122     ros::NodeHandle &pnh = getMTPrivateNodeHandle();
00123 #else
00124   ros::NodeHandle &nh = getNodeHandle();
00125   ros::NodeHandle &pnh = getPrivateNodeHandle();
00126 #endif
00127 
00128   setup(nh, pnh);
00129 }
00130 
00131 void PanolutVirtualCameraNodelet::tfPublisherCallback(const ros::TimerEvent& event) {
00132   static tf::TransformBroadcaster br;
00133   br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), parentFrameId, frameId));
00134 }
00135 
00136 void PanolutVirtualCameraNodelet::updateTransform() {
00137   transform.setOrigin(tf::Vector3(0.0, 0.0, 0.0));
00138   tf::Quaternion parent2cam = tf::createQuaternionFromRPY(0.0, -vcamConfig.tilt / 180 * M_PI, vcamConfig.pan / 180 * M_PI);
00139   tf::Quaternion cam2image(-0.5, 0.5, -0.5, 0.5);
00140   transform.setRotation(parent2cam * cam2image);
00141 }
00142 
00143 void PanolutVirtualCameraNodelet::virtualCameraConfigCallback(const VirtualCameraConfig::ConstPtr& msg) {
00144   NODELET_DEBUG("PanolutVirtualCameraNodelet::virtualCameraConfigCallback: Entering...");
00145 
00146   vcamConfig = *msg;
00147   // Fix vcam config.
00148   if (vcamConfig.horizontalFov < 1) vcamConfig.horizontalFov = 1;
00149   if (vcamConfig.horizontalFov > 179) vcamConfig.horizontalFov = 179;
00150   if (vcamConfig.verticalFov < 1) vcamConfig.verticalFov = 1;
00151   if (vcamConfig.verticalFov > 179) vcamConfig.verticalFov = 179;
00152   if (vcamConfig.viewportWidth < 1) vcamConfig.viewportWidth = 1;
00153   if (vcamConfig.viewportHeight < 1) vcamConfig.viewportHeight = 1;
00154   if (vcamConfig.imageUpdateInterval < 0) vcamConfig.viewportHeight = 0;
00155 
00156   updateTransform();
00157 
00158   updateVcamStitcher(pano, panoWidth, panoHeight, vcamConfig, vcam);
00159   vcam.fixBounds(inWidth, inHeight);
00160 
00161   camMsg.width = vcamConfig.viewportWidth;
00162   camMsg.height = vcamConfig.viewportHeight;
00163   Mat K;
00164   cameraMatrix(vcamConfig.horizontalFov / 180 * M_PI, vcamConfig.verticalFov / 180 * M_PI, vcamConfig.viewportWidth, vcamConfig.viewportHeight, K);
00165   for (int r = 0; r < K.rows; r++) {
00166     for (int c = 0; c < K.cols; c++) {
00167       camMsg.K[r * 3 + c] = K.at<double>(r, c);
00168     }
00169   }
00170   for (int r = 0; r < K.rows; r++) {
00171     for (int c = 0; c < K.cols; c++) {
00172       camMsg.P[r * 4 + c] = K.at<double>(r, c);
00173     }
00174     camMsg.P[r * 4 + 3] = 0; // No translation.
00175   }
00176 
00177   NODELET_DEBUG("PanolutVirtualCameraNodelet::virtualCameraConfigCallback: Leaving...");
00178 }
00179 
00180 bool PanolutVirtualCameraNodelet::getVirtualCameraConfigService(GetVirtualCameraConfig::Request& request, GetVirtualCameraConfig::Response& response) {
00181   response.config = vcamConfig;
00182   return true;
00183 }
00184 
00185 void PanolutVirtualCameraNodelet::imageCallback(const sensor_msgs::ImageConstPtr& msg) {
00186 //  NODELET_INFO("imageCallback: Entering...");
00187 
00188   if (outPub.getNumSubscribers() == 0 && camPub.getNumSubscribers() == 0) {
00189     return;
00190   }
00191 
00192   cv_bridge::CvImageConstPtr cvPtr;
00193   try {
00194     cvPtr = cv_bridge::toCvShare(msg);
00195     if (cvPtr->encoding.compare(sensor_msgs::image_encodings::BGR8)) {
00196       NODELET_ERROR("Encoding not supported: %s.", cvPtr->encoding.data());
00197       return;
00198     }
00199   } catch (cv_bridge::Exception& e) {
00200     NODELET_ERROR("cv_bridge exception: %s", e.what());
00201     return;
00202   }
00203 
00204   if (cvPtr->image.rows != inHeight || cvPtr->image.cols != inWidth) {
00205     NODELET_ERROR("Unexpected image dimensions: %dx%d.", cvPtr->image.cols, cvPtr->image.rows);
00206   }
00207 
00208   Mat image;
00209   vcam.stitchImage(cvPtr->image, image);
00210 
00211   cv_bridge::CvImage out;
00212   out.encoding = sensor_msgs::image_encodings::BGR8;
00213   out.header = msg->header;
00214   out.header.frame_id = frameId;
00215   if (equalizeHist) {
00216     // Equalize histogram before publishing.
00217     ros::Time t1 = ros::Time::now();
00218     Mat hsv;
00219     cv::cvtColor(image, hsv, CV_BGR2HSV);
00220     std::vector<Mat> hsvChannels;
00221     cv::split(hsv, hsvChannels);
00222     Mat vOut;
00223     cv::equalizeHist(hsvChannels[2], vOut);
00224     hsvChannels[2] = vOut;
00225     cv::merge(hsvChannels, hsv);
00226     cv::cvtColor(hsv, image, CV_HSV2BGR);
00227     NODELET_DEBUG("Histogram equalization: %.3f s.", (ros::Time::now() - t1).toSec());
00228   }
00229   out.image = image;
00230   outPub.publish(out.toImageMsg());
00231 
00232   camMsg.header = out.header;
00233   camMsg.height = out.image.rows;
00234   camMsg.width = out.image.cols;
00235   camPub.publish(camMsg);
00236 
00237 //  NODELET_INFO("imageCallback: Returning...");
00238 }
00239 
00240 } // namespace omnicamera
00241 
00242 PLUGINLIB_DECLARE_CLASS(omnicamera, panolut_virtual_camera, omnicamera::PanolutVirtualCameraNodelet, nodelet::Nodelet)
 All Classes Namespaces Files Functions Variables Typedefs Defines


omnicamera
Author(s): Tomas Petricek / petrito1@cmp.felk.cvut.cz
autogenerated on Tue Dec 10 2013 14:26:53