00001
00002 #include "omnicamera/LadybugProcNodelet.h"
00003
00004 #include <boost/format.hpp>
00005 #include <pluginlib/class_list_macros.h>
00006 #include <cv_bridge/cv_bridge.h>
00007 #include <opencv2/imgproc/imgproc.hpp>
00008 #include <sensor_msgs/image_encodings.h>
00009
00010 #define USE_MT_NODE_HANDLE
00011
00012 namespace omnicamera {
00013
00014 void LadybugProcNodelet::onInit() {
00015 NODELET_INFO("LadybugImageProcNodelet::onInit");
00016
00017 #ifdef USE_MT_NODE_HANDLE
00018 ros::NodeHandle nh = getMTNodeHandle();
00019 ros::NodeHandle pnh = getMTPrivateNodeHandle();
00020 #else
00021 ros::NodeHandle nh = getNodeHandle();
00022 ros::NodeHandle pnh = getPrivateNodeHandle();
00023 #endif
00024
00025 pnh.param("in_width", inWidth, 1616);
00026 pnh.param("in_height", inHeight, 1232);
00027 NODELET_INFO("Input image size: %dx%d.", inWidth, inHeight);
00028
00029 pnh.param("out_width", outWidth, 960);
00030 pnh.param("out_height", outHeight, 480);
00031 NODELET_INFO("Output image size: %dx%d.", outWidth, outHeight);
00032
00033 pnh.param("alpha", alpha, true);
00034 NODELET_INFO("Alpha blending: %s.", alpha ? "enabled" : "disabled");
00035
00036 pnh.param("radius", radius, 20);
00037 NODELET_INFO("Sphere radius: %d.", radius);
00038
00039 pnh.param("lut_path", lutPath, string("LUT_img_%dx%d_pano_%dx%dr%d_%s%d.pgm"));
00040 NODELET_INFO("LUT path template: %s.", lutPath.data());
00041
00042 lookupTablesLoaded = false;
00043
00044 image_transport::ImageTransport it(nh);
00045 string imageTopic = nh.resolveName("image", true);
00046 NODELET_INFO("Subscribing to topic %s...", imageTopic.data());
00047 imageSub = it.subscribe(imageTopic, 1, &LadybugProcNodelet::imageCallback, this);
00048
00049 outPub = it.advertise("pano", 1);
00050 camPub = nh.advertise<sensor_msgs::CameraInfo>("camera_info", 1);
00051
00052 boost::format imageOutFmt("image_%i");
00053 boost::format camInfoFmt("camera_info_%i");
00054 for (int i = 0; i < 6; i++) {
00055 string imageOutTopic = nh.resolveName((imageOutFmt % i).str(), true);
00056 string camInfoTopic = nh.resolveName((camInfoFmt % i).str(), true);
00057 NODELET_INFO("Advertising topics %s and %s...", imageOutTopic.data(), camInfoTopic.data());
00058 outPubs[i] = it.advertise(imageOutTopic, 1);
00059 camPubs[i] = nh.advertise<sensor_msgs::CameraInfo>(camInfoTopic, 1);
00060 }
00061 }
00062
00063 void LadybugProcNodelet::imageCallback(const sensor_msgs::ImageConstPtr& msg) {
00064 NODELET_INFO("LadybugProcNodelet::imageCallback");
00065
00066 NODELET_INFO("LadybugProcNodelet::imageCallback: Loading look-up tables.");
00067 if (!lookupTablesLoaded) {
00068 NODELET_INFO("Loading look-up tables...");
00069 stitcher.clearLookupTables();
00070 for (int iCam = 1; iCam <= 6; iCam++) {
00071 int len = 1024;
00072 char xPath[len], yPath[len], aPath[len];
00073 snprintf(xPath, len, lutPath.data(), inWidth, inHeight, outWidth, outHeight, radius, "x", iCam);
00074 snprintf(yPath, len, lutPath.data(), inWidth, inHeight, outWidth, outHeight, radius, "y", iCam);
00075 snprintf(aPath, len, lutPath.data(), inWidth, inHeight, outWidth, outHeight, radius, "a", iCam);
00076 NODELET_INFO("Camera %i look-up tables: %s, %s, %s.", iCam, xPath, yPath, aPath);
00077 stitcher.addLookupTables(string(xPath), string(yPath), string(aPath));
00078 }
00079 lookupTablesLoaded = true;
00080 }
00081
00082 NODELET_INFO("LadybugProcNodelet::imageCallback: Converting message to CvImage.");
00083 cv_bridge::CvImageConstPtr cvPtr;
00084 try {
00085 cvPtr = cv_bridge::toCvShare(msg);
00086 } catch (cv_bridge::Exception& e) {
00087 NODELET_ERROR("cv_bridge exception: %s", e.what());
00088 return;
00089 }
00090
00091 NODELET_INFO("LadybugProcNodelet::imageCallback: Checking encoding.");
00092 bool stitch = true;
00093 if (cvPtr->encoding.compare(sensor_msgs::image_encodings::BGR8)) {
00094 NODELET_ERROR("Encoding not supported: %s.", cvPtr->encoding.data());
00095 stitch = false;
00096 }
00097
00098 NODELET_INFO("LadybugProcNodelet::imageCallback: Checking image dimensions.");
00099 if (cvPtr->image.rows != inHeight || cvPtr->image.cols != inWidth) {
00100 NODELET_ERROR("Unexpected image dimensions: %dx%d.", cvPtr->image.cols, cvPtr->image.rows);
00101 stitch = false;
00102 }
00103
00104 if (stitch && false) {
00105 NODELET_INFO("Stitching started.");
00106 stitcher.stitchImage(cvPtr->image, pano);
00107 NODELET_INFO("Stitching finished.");
00108
00109 NODELET_INFO("LadybugProcNodelet::imageCallback: Preparing and sending pano message.");
00110 cv_bridge::CvImage out;
00111 out.encoding = sensor_msgs::image_encodings::BGR8;
00112 out.header = msg->header;
00113 out.image = pano;
00114 outPub.publish(out.toImageMsg());
00115
00116 NODELET_INFO("Sending camera info.");
00117 sensor_msgs::CameraInfo camMsg;
00118 camMsg.header = out.header;
00119 camMsg.height = out.image.rows;
00120 camMsg.width = out.image.cols;
00121 camPub.publish(camMsg);
00122 }
00123
00124 NODELET_INFO("Sawing started.");
00125 ladySaw.saw(cvPtr->image, cams);
00126 NODELET_INFO("Sawing finished.");
00127
00128 vector<int> camsOut = ladySaw.getCamsOut();
00129 for (int i = 0; i < (int) camsOut.size(); i++) {
00130 NODELET_INFO("LadybugProcNodelet::imageCallback: Publishing image %i.", i);
00131 int iCam = camsOut[i];
00132
00133 cv_bridge::CvImage out;
00134 out.encoding = cvPtr->encoding;
00135 out.header = msg->header;
00136 out.image = cams[i];
00137 NODELET_INFO("LadybugProcNodelet::imageCallback: before publishing image %i.", i);
00138 outPubs[iCam].publish(out.toImageMsg());
00139 NODELET_INFO("LadybugProcNodelet::imageCallback: after publishing image %i.", i);
00140
00141 sensor_msgs::CameraInfo camMsg;
00142 camMsg.header = out.header;
00143 camMsg.height = out.image.rows;
00144 camMsg.width = out.image.cols;
00145 camPubs[iCam].publish(camMsg);
00146 }
00147 }
00148
00149 }
00150
00151 PLUGINLIB_DECLARE_CLASS(omnicamera, ladybug_proc, omnicamera::LadybugProcNodelet, nodelet::Nodelet)