00001
00002 #include <ros/ros.h>
00003 #include <cv_bridge/cv_bridge.h>
00004 #include <image_transport/image_transport.h>
00005 #include <opencv2/imgproc/imgproc.hpp>
00006 #include <sensor_msgs/image_encodings.h>
00007
00008 #include "omnicamera_msgs/GetVirtualCameraConfig.h"
00009 #include "omnicamera/panolut_virtual_camera_common.h"
00010
00011
00012
00013 using cv::Mat_;
00014 using omnicamera_msgs::GetVirtualCameraConfig;
00015
00016 using omnicamera::rotationMatrix;
00017 using omnicamera::panTiltToCart;
00018 using omnicamera::cartToPanTilt;
00019 using omnicamera::cameraInverse;
00020 using omnicamera::updateVcamStitcher;
00021
00022 namespace {
00023 const int N_CAMS = 6;
00024 int inWidth, inHeight;
00025 int panoWidth, panoHeight;
00026 bool alpha;
00027 int radius;
00028 string lutPath;
00029
00030 omnicamera::LookupStitcher pano;
00031 omnicamera::LookupStitcher vcam;
00032 image_transport::Publisher outPub;
00033 ros::Publisher camPub;
00034
00038 VirtualCameraConfig vcamConfig;
00039
00040 bool getVirtualCameraConfigService(GetVirtualCameraConfig::Request& request, GetVirtualCameraConfig::Response& response) {
00041 response.config = vcamConfig;
00042 return true;
00043 }
00044
00045 void virtualCameraConfigCallback(const VirtualCameraConfig::ConstPtr& msg) {
00046 updateVcamStitcher(pano, panoWidth, panoHeight, *msg, vcam);
00047 }
00048
00049 void imageCallback(const sensor_msgs::ImageConstPtr& msg) {
00050 ROS_INFO("imageCallback: Entering...");
00051
00052 cv_bridge::CvImageConstPtr cvPtr;
00053 try {
00054 cvPtr = cv_bridge::toCvShare(msg);
00055 if (cvPtr->encoding.compare(sensor_msgs::image_encodings::BGR8)) {
00056 ROS_ERROR("Encoding not supported: %s.", cvPtr->encoding.data());
00057 return;
00058 }
00059 } catch (cv_bridge::Exception& e) {
00060 ROS_ERROR("cv_bridge exception: %s", e.what());
00061 return;
00062 }
00063
00064 if (cvPtr->image.rows != inHeight || cvPtr->image.cols != inWidth) {
00065 ROS_ERROR("Unexpected image dimensions: %dx%d.", cvPtr->image.cols, cvPtr->image.rows);
00066 }
00067
00068 Mat image;
00069 vcam.stitchImage(cvPtr->image, image);
00070
00071 cv_bridge::CvImage out;
00072 out.encoding = sensor_msgs::image_encodings::BGR8;
00073 out.header = msg->header;
00074 out.image = image;
00075 outPub.publish(out.toImageMsg());
00076
00077 sensor_msgs::CameraInfo camMsg;
00078 camMsg.header = out.header;
00079 camMsg.height = out.image.rows;
00080 camMsg.width = out.image.cols;
00081 camPub.publish(camMsg);
00082
00083 ROS_INFO("imageCallback: Returning...");
00084 }
00085
00086 }
00087
00088 int main(int argc, char ** argv) {
00089
00090 ros::init(argc, argv, "img2pano");
00091 ros::NodeHandle nh;
00092
00093
00094 ros::NodeHandle pnh("~");
00095 pnh.param("in_width", inWidth, 1616);
00096 pnh.param("in_height", inHeight, 1232);
00097 ROS_INFO("Input image size: %dx%d.", inWidth, inHeight);
00098
00099 pnh.param("pano_width", panoWidth, 960);
00100 pnh.param("pano_height", panoHeight, 480);
00101 ROS_INFO("Panorama size: %dx%d.", panoWidth, panoHeight);
00102
00103 pnh.param("alpha", alpha, true);
00104 ROS_INFO("Alpha blending: %s.", alpha ? "enabled" : "disabled");
00105
00106 pnh.param("radius", radius, 20);
00107 ROS_INFO("Sphere radius: %d.", radius);
00108
00109 pnh.param("lut_path", lutPath, string("LUT_img_%dx%d_pano_%dx%dr%d_%s%d.png"));
00110 ROS_INFO("LUT path template: %s.", lutPath.data());
00111
00112 pano.clearLookupTables();
00113 vcam.clearLookupTables();
00114 for (int iCam = 1; iCam <= N_CAMS; iCam++) {
00115 int len = 1024;
00116 char xPath[len], yPath[len], aPath[len];
00117 snprintf(xPath, len, lutPath.data(), inWidth, inHeight, panoWidth, panoHeight, radius, "x", iCam);
00118 snprintf(yPath, len, lutPath.data(), inWidth, inHeight, panoWidth, panoHeight, radius, "y", iCam);
00119 snprintf(aPath, len, lutPath.data(), inWidth, inHeight, panoWidth, panoHeight, radius, "a", iCam);
00120 ROS_INFO("Camera %d look-up tables: %s, %s, %s.", iCam, xPath, yPath, aPath);
00121 pano.addLookupTables(string(xPath), string(yPath), string(aPath));
00122 vcam.addLookupTables(Mat(0, 0, CV_16UC1), Mat(0, 0, CV_16UC1), Mat(0, 0, CV_8UC1));
00123 }
00124
00125 image_transport::ImageTransport it(nh);
00126 image_transport::Subscriber sub = it.subscribe("in", 1, imageCallback);
00127 outPub = it.advertise("out", 1);
00128 camPub = nh.advertise<sensor_msgs::CameraInfo>("camera_info", 1);
00129
00130 ros::Subscriber virtualCameraConfigSubscriber = nh.subscribe("config", 1, virtualCameraConfigCallback);
00131 ros::ServiceServer getVirtualCameraConfigServer = nh.advertiseService("get_config", getVirtualCameraConfigService);
00132
00133 vcamConfig.viewportWidth = 640;
00134 vcamConfig.viewportHeight = 480;
00135 vcamConfig.pan = 0.0;
00136 vcamConfig.tilt = 0.0;
00137 vcamConfig.horizontalFov = 90.0;
00138 vcamConfig.verticalFov = 90.0 * 3 / 4;
00139
00140 updateVcamStitcher(pano, panoWidth, panoHeight, vcamConfig, vcam);
00141
00142 ros::spin();
00143
00144 return 0;
00145 }