omnicamera.cpp
Go to the documentation of this file.
00001 /*
00002  * omnicamera.cpp
00003  *
00004  *  Created on: Jul 29, 2010
00005  *      Author: petrito1@cmp.felk.cvut.cz
00006  *
00007  * ROS node providing various image topics from Ladybug 3 camera.
00008  *
00009  * Single-lens virtual camera (e.g. used with virtual_camera_display node):
00010  * virtual_camera/image - publishing virtual camera images
00011  * virtual_camera/config - subscribed for virtual camera configuration
00012  * virtual_camera/get_config - service for getting current configuration
00013  *
00014  * Composite color image:
00015  * camera/image - publishing composite color images--6 landscape images sta
00016  * camera0/image - publishing color images from individual sensors, as portrait images.
00017  * camera1/image
00018  * camera2/image
00019  * camera3/image
00020  * camera4/image
00021  * camera5/image
00022  *
00023  * TODO: Publish raw images, color images, stitched panos etc. according
00024  * to registered subscribers.
00025  */
00026 
00027 #include <cv_bridge/CvBridge.h>
00028 #include <GL/glew.h> // glew.h must be included before gl.h
00029 #include <GL/gl.h>
00030 #include <GL/glut.h>
00031 #include <image_transport/image_transport.h>
00032 #include <math.h>
00033 #include <opencv2/core/core.hpp>
00034 #include <opencv2/highgui/highgui.hpp>
00035 #include <ros/ros.h>
00036 #include <sys/param.h>
00037 #include <sys/times.h>
00038 
00039 #include "Camera.h"
00040 #include "CameraContext.h"
00041 #include "CameraException.h"
00042 #include "LadybugCamera.h"
00043 #include "LadybugVirtualCamera.h"
00044 
00045 #include "omnicamera_msgs/GetLadybugCameraConfig.h"
00046 #include "omnicamera_msgs/GetVirtualCameraConfig.h"
00047 #include "omnicamera_msgs/VirtualCameraConfig.h"
00048 #include "omnicamera_msgs/LadybugCameraConfig.h"
00049 
00050 using std::string;
00051 
00052 using nifti::dc1394::Camera;
00053 using nifti::dc1394::CameraContext;
00054 using nifti::dc1394::CameraException;
00055 using nifti::dc1394::LadybugCamera;
00056 using nifti::ladybug::LadybugVirtualCamera;
00057 
00058 using omnicamera_msgs::GetVirtualCameraConfig;
00059 using omnicamera_msgs::GetLadybugCameraConfig;
00060 using omnicamera_msgs::LadybugCameraConfig;
00061 using omnicamera_msgs::VirtualCameraConfig;
00062 
00063 namespace {
00064 LadybugVirtualCamera virtualCamera;
00065 bool virtualCameraEnabled = false;
00066 LadybugCamera camera;
00067 LadybugCameraConfig ladybugCameraConfig;
00068 VirtualCameraConfig virtualCameraConfig;
00069 sensor_msgs::CvBridge bridge;
00070 
00071 double imageUpdateInterval = 5.0;
00072 
00076 pthread_mutex_t virtualCameraMutex;
00077 void lockVirtualCamera();
00078 void unlockVirtualCamera();
00079 
00080 bool
00081 getLadybugCameraConfigService(GetLadybugCameraConfig::Request& request, GetLadybugCameraConfig::Response& response);
00082 void ladybugCameraConfigCallback(const LadybugCameraConfig::ConstPtr& msg);
00083 
00084 bool
00085 getVirtualCameraConfigService(GetVirtualCameraConfig::Request& request, GetVirtualCameraConfig::Response& response);
00086 void virtualCameraConfigCallback(const VirtualCameraConfig::ConstPtr& msg);
00087 
00088 void logDuration(string message, tms t1, long r1);
00089 }
00090 
00091 int main(int argc, char** argv) {
00092 
00093   ros::init(argc, argv, "omnicamera");
00094   ros::NodeHandle nodeHandle;
00095 
00096   for (int i = 0; i < argc; i++) {
00097           printf("%d: %s\n", i, argv[i]);
00098   }
00099 
00100   // Check and parse command-line arguments.
00101   string meshFile;
00102   string alphamaskPrefix;
00103   if (argc < 3) {
00104     printf("Not enough arguments. Virtual camera is not used.\n");
00105     printf("Usage:   omnicamera_node <mesh file path> <alphamask file prefix>\n");
00106     printf("Example: omnicamera_node mesh.txt alphamask\n");
00107   } else {
00108     virtualCameraEnabled = true;
00109     meshFile = string(argv[1]);
00110     alphamaskPrefix = string(argv[2]);
00111     glutInit(&argc, argv);
00112   }
00113 
00114   pthread_mutex_init(&virtualCameraMutex, NULL);
00115 
00116   ros::Subscriber virtualCameraConfigSubscriber;
00117   ros::ServiceServer getVirtualCameraConfigServer;
00118   if (virtualCameraEnabled) {
00119     virtualCameraConfigSubscriber = nodeHandle.subscribe("virtual_camera/config", 1,
00120         virtualCameraConfigCallback);
00121     getVirtualCameraConfigServer = nodeHandle.advertiseService("virtual_camera/get_config",
00122         getVirtualCameraConfigService);
00123   }
00124 
00125   ros::Subscriber ladybugCameraConfigSubscriber = nodeHandle.subscribe("ladybug_camera/config", 1,
00126       ladybugCameraConfigCallback);
00127   ros::ServiceServer getLadybugCameraConfigServer = nodeHandle.advertiseService("ladybug_camera/get_config",
00128       getLadybugCameraConfigService);
00129 
00130   image_transport::ImageTransport it(nodeHandle);
00131   image_transport::Publisher virtualCameraPub = it.advertise("virtual_camera/image", 1);
00132 
00133   image_transport::Publisher cameraPub = it.advertise("camera/image", 1);
00134 
00135   image_transport::Publisher sensorPubs[LadybugCamera::NUM_CAMERAS] = { it.advertise("camera0/image", 1), it.advertise(
00136       "camera1/image", 1), it.advertise("camera2/image", 1), it.advertise("camera3/image", 1), it.advertise(
00137       "camera4/image", 1), it.advertise("camera5/image", 1) };
00138 
00139   ros::Publisher cameraInfoPubs[LadybugCamera::NUM_CAMERAS] = {
00140       nodeHandle.advertise<sensor_msgs::CameraInfo>("camera0/camera_info", 1),
00141       nodeHandle.advertise<sensor_msgs::CameraInfo>("camera1/camera_info", 1),
00142       nodeHandle.advertise<sensor_msgs::CameraInfo>("camera2/camera_info", 1),
00143       nodeHandle.advertise<sensor_msgs::CameraInfo>("camera3/camera_info", 1),
00144       nodeHandle.advertise<sensor_msgs::CameraInfo>("camera4/camera_info", 1),
00145       nodeHandle.advertise<sensor_msgs::CameraInfo>("camera5/camera_info", 1) };
00146 
00147   string cameraFrameIds[LadybugCamera::NUM_CAMERAS] = { "tflbcamera0", "tflbcamera1", "tflbcamera2", "tflbcamera3", "tflbcamera4", "tflbcamera5" };
00148 
00149   try {
00150 
00151     if (virtualCameraEnabled) {
00152       virtualCamera.initialize(true);
00153       virtualCamera.loadMesh(meshFile);
00154       virtualCamera.loadAlphamask(alphamaskPrefix);
00155     }
00156 
00157     CameraContext context;
00158 
00159     // TODO: Move serial number to ROS param.
00160     // Use default GUID to use the first camera in the list.
00161     camera = context.getLadybugCamera(0);
00162     camera.resetBus();
00163     sleep(3);
00164     camera.reset();
00165 
00166     //    camera.setup();
00167     camera.setOperationMode(DC1394_OPERATION_MODE_LEGACY);
00168     camera.setIsoSpeed(DC1394_ISO_SPEED_400);
00169 //    camera.setOperationMode(DC1394_OPERATION_MODE_1394B);
00170 //    camera.setIsoSpeed(DC1394_ISO_SPEED_800);
00171 //    dc1394video_mode_t videoMode = DC1394_VIDEO_MODE_FORMAT7_0;
00172     dc1394video_mode_t videoMode = DC1394_VIDEO_MODE_FORMAT7_2;
00173     camera.setVideoMode(videoMode);
00174     camera.setSelectedImages(LadybugCamera::ALL_CAMERAS);
00175     // Workaround for new firewire stack until it can handle larger packet size.
00176     // According to https://ieee1394.wiki.kernel.org/index.php/Release_Notes
00177     // the max. size it can handle pre 2.6.38 is even smaller (4080).
00178 //    camera.setFormat7Roi(videoMode, 8192);
00179     camera.setFormat7Roi(videoMode, 4096);
00180     camera.setBayerMethod(DC1394_BAYER_METHOD_SIMPLE);
00181 //    camera.setBayerMethod(DC1394_BAYER_METHOD_HQLINEAR);
00182 
00183     camera.setupCapture();
00184     camera.startVideoTransmission();
00185 
00186     struct tms t2;
00187     long r1 = 0l;
00188     long r2 = 0l;
00189     
00190     uint32_t seq = 0;
00191     ros::Rate r(5);
00192     while (nodeHandle.ok()) {
00193       ros::spinOnce();
00194 
00195       cv::Mat compositeImage;
00196       uint64_t timestamp;
00197       camera.captureColorMat(compositeImage, timestamp, true);
00198       
00199       // Fix aspect ratio to 4x3 for half-height images etc.
00200       if (videoMode == DC1394_VIDEO_MODE_FORMAT7_2 || videoMode == DC1394_VIDEO_MODE_FORMAT7_3) {
00201         cv::Mat dst;
00202         cv::resize(compositeImage, dst, cv::Size(compositeImage.cols / 2, compositeImage.rows), 0, 0, CV_INTER_NN);
00203         compositeImage = dst;
00204       }
00205 
00206       ros::Time imageTime = ros::Time(static_cast<double>(timestamp) / 1000000.0);
00207 
00208       if (cameraPub.getNumSubscribers() > 0) {
00209         IplImage iplImage = compositeImage;
00210         sensor_msgs::ImagePtr msg = bridge.cvToImgMsg(&iplImage, "bgr8");
00211 //        msg->header.frame_id = "/tfladylink";
00212         msg->header.frame_id = "/omni_frame";
00213         msg->header.seq = seq;
00214         msg->header.stamp = imageTime;
00215         cameraPub.publish(msg);
00216       }
00217 
00218       int iImage = -1;
00219       for (int i = 0; i < LadybugCamera::NUM_CAMERAS; i++) {
00220         if (!camera.areImagesSelected(LadybugCamera::CAMERAS[i])) {
00221           continue;
00222         }
00223         iImage++;
00224         if (sensorPubs[i].getNumSubscribers() > 0) {
00225           int imageHeight = compositeImage.rows / camera.getNumSelectedImages();
00226 
00227           // Publish portrait images.
00228           cv::Mat image = compositeImage(cv::Rect(0, iImage * imageHeight, compositeImage.cols, imageHeight)).t();
00229           // Flip the image horizontally.
00230           cv::flip(image, image, 1);
00231 
00232           IplImage iplSensorImage = image;
00233           sensor_msgs::ImagePtr msg = bridge.cvToImgMsg(&iplSensorImage, "bgr8");
00234           msg->header.frame_id = cameraFrameIds[i];
00235           msg->header.seq = seq;
00236           msg->header.stamp = imageTime;
00237 
00238           sensorPubs[i].publish(msg);
00239 
00240           sensor_msgs::CameraInfo cameraInfoMsg;
00241           cameraInfoMsg.header.frame_id = cameraFrameIds[i];
00242           cameraInfoMsg.height = image.rows;
00243           cameraInfoMsg.width = image.cols;
00244           cameraInfoPubs[i].publish(cameraInfoMsg);
00245         }
00246       }
00247 
00248       if (virtualCameraEnabled && virtualCameraPub.getNumSubscribers() > 0) {
00249         r2 = times(&t2);
00250         if ((double) (r2 - r1) / HZ >= imageUpdateInterval) {
00251           r1 = r2;
00252           virtualCamera.setImages(compositeImage);
00253           logDuration("Updating virtual camera images", t2, r2);
00254         }
00255 
00256         r2 = times(&t2);
00257         cv::Mat virtualView;
00258         virtualCamera.renderView(virtualView);
00259         logDuration("Rendering view", t2, r2);
00260 
00261         r2 = times(&t2);
00262         IplImage iplImage = virtualView.operator _IplImage();
00263 //        sensor_msgs::ImagePtr msg = sensor_msgs::CvBridge::cvToImgMsg(&iplImage);
00264         sensor_msgs::ImagePtr msg = bridge.cvToImgMsg(&iplImage, "bgr8");
00265 //        sensor_msgs::ImagePtr msg = bridge.cvToImgMsg(&iplImage);
00266 //        msg->header.frame_id = "/tfladylink";
00267         msg->header.frame_id = "/omni_frame";
00268         msg->header.seq = seq;
00269         msg->header.stamp = ros::Time::now();
00270         virtualCameraPub.publish(msg);
00271         logDuration("Publishing images", t2, r2);
00272       }
00273 
00274       seq++;
00275       r.sleep();
00276     }
00277 
00278     // Clean up.
00279     camera.stopVideoTransmission();
00280     camera.stopCapture();
00281     camera.releaseAll();
00282 
00283   } catch (CameraException& e) {
00284     ROS_ERROR("Camera exception: %s %s", e.what(), e.getErrorString().data());
00285     unlockVirtualCamera();
00286     return -1;
00287   } catch (std::runtime_error& e) {
00288     ROS_ERROR("Runtime error: %s", e.what());
00289     unlockVirtualCamera();
00290     return -2;
00291   } catch (...) {
00292     ROS_ERROR("Unexpected exception occurred.");
00293     unlockVirtualCamera();
00294     return -3;
00295   }
00296 
00297   return 0;
00298 }
00299 
00300 namespace {
00301 void lockVirtualCamera() {
00302   pthread_mutex_lock(&virtualCameraMutex);
00303 }
00304 void unlockVirtualCamera() {
00305   pthread_mutex_unlock(&virtualCameraMutex);
00306 }
00307 
00308 bool getVirtualCameraConfigService(GetVirtualCameraConfig::Request& request, GetVirtualCameraConfig::Response& response) {
00309   ROS_DEBUG("getVirtualCameraConfigService called");
00310   // There is nothing interesting in the request...
00311   // Fill the response with current values. Prevent returning inconsistent state.
00312   lockVirtualCamera();
00313 
00314   int viewportWidth, viewportHeight;
00315   virtualCamera.getViewport(&viewportWidth, &viewportHeight);
00316   response.config.viewportWidth = viewportWidth;
00317   response.config.viewportHeight = viewportHeight;
00318   response.config.pan = virtualCamera.getPan();
00319   response.config.tilt = virtualCamera.getTilt();
00320   response.config.horizontalFov = virtualCamera.getHorizontalFov();
00321   response.config.verticalFov = virtualCamera.getVerticalFov();
00322 
00323   response.config.imageUpdateInterval = imageUpdateInterval;
00324 
00325   unlockVirtualCamera();
00326 
00327   return true;
00328 }
00329 
00330 void virtualCameraConfigCallback(const VirtualCameraConfig::ConstPtr& msg) {
00331   ROS_DEBUG("virtualCameraConfigCallback called");
00332   // Prevent concurrent modification.
00333   lockVirtualCamera();
00334 
00335   virtualCamera.setViewport(msg->viewportWidth, msg->viewportHeight);
00336   virtualCamera.setPan(msg->pan);
00337   virtualCamera.setTilt(msg->tilt);
00338   virtualCamera.setHorizontalFov(msg->horizontalFov);
00339   virtualCamera.setVerticalFov(msg->verticalFov);
00340 
00341   imageUpdateInterval = msg->imageUpdateInterval;
00342 
00343   unlockVirtualCamera();
00344 }
00345 
00346 void ladybugCameraConfigCallback(const LadybugCameraConfig::ConstPtr& msg) {
00347   ROS_DEBUG("ladybugCameraConfigCallback called");
00348 
00349   // TODO: Lock camera here?
00350   //  camera.lockCapture();
00351   camera.stopCapture();
00352   camera.stopVideoTransmission();
00353 
00354   ladybugCameraConfig = *msg;
00355   camera.setSelectedImages(msg->imagesSelected);
00356 
00357   camera.setupCapture();
00358   camera.startVideoTransmission();
00359   //  camera.unlockCapture();
00360 }
00361 
00362 bool getLadybugCameraConfigService(GetLadybugCameraConfig::Request& request, GetLadybugCameraConfig::Response& response) {
00363   ROS_DEBUG("getLadybugCameraConfigService called");
00364   // There is nothing interesting in the request...
00365   // Fill the response with current values. Prevent returning inconsistent state.
00366   // TODO: Lock camera?
00367 
00368   ladybugCameraConfig.imagesSelected = camera.getSelectedImages();
00369   response.config = ladybugCameraConfig;
00370   return true;
00371 }
00372 
00373 void logDuration(string message, tms t1, long r1) {
00374   struct tms t2;
00375   long r2;
00376   r2 = times(&t2);
00377 
00378   float userTime = ((float) (t2.tms_utime - t1.tms_utime)) / HZ;
00379   float systemTime = ((float) (t2.tms_stime - t1.tms_stime)) / HZ;
00380   float realTime = ((float) (r2 - r1)) / HZ;
00381 
00382   std::string format = "%s: real time: %1.2f, user time: %1.2f, system time: %1.2f";
00383   ROS_DEBUG(format.data(), message.data(), realTime, userTime, systemTime);
00384   //  printf(format.data(), message, realTime, userTime, systemTime);
00385 }
00386 
00387 }
 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