img2pano_lut.cpp
Go to the documentation of this file.
00001 /*
00002  * IMG2PANO_LUT - stitching of incoming IMAGES to PANORAMIC view using pre-computed LOOK-UP TABLES
00003  * by M. Reinstein, 2011
00004  *
00005  * -m  ... mode of operation (1-6 single cam output, 7 panorama using LUT)
00006  * -t  ... input topic name (default: "/camera/image")
00007  * -o  ... output topic name (default: "/viz/image_out")
00008  * -ph ... output panorama height (default: PANO_HEIGHT 375)
00009  * -pw ... output panorama width (default: IMAGE_WIDTH 808)
00010  * -ih ... input image height (default: IMAGE_HEIGHT 616)
00011  * -iw ... input image width (default: IMAGE_WIDTH 808)
00012  * -r  ... sphere radius [m] (default: PANO_RADIUS 20)
00013  *
00014  * LUTs generated for the following parameters:
00015  * 1. image 808x616, panorama 750x375, radius 20 (default for mode 7, i.e. -m 7)
00016  *
00017  * To RUN the node:
00018  * use img2pano.launch
00019  * OR
00020  * rosrun omnicamera img2pano_lut -m 7 -ih 616 -iw 808 -ph 375 -pw 750 -r 20 -path $(find omnicamera)/res/lut
00021  *
00022  * To VIEW the panorama using default output:
00023  * rosrun image_view image_view image:=viz/image_out
00024  *
00025 */
00026 
00027 //#include <opencv/highgui.h>
00028 #include <opencv/cv.h>
00029 #include <iostream>
00030 #include <sstream>
00031 #include <fstream>
00032 #include <string>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <cv_bridge/cv_bridge.h>
00036 #include <opencv/cvwimage.h>
00037 #include <image_transport/image_transport.h>// ROS
00038 #include <ros/ros.h>                                            // ROS
00039 #include <vision_msgs/Rect.h>                           // ROS
00040 
00041 #define NCAMS 6 // not to be changed! For single cam output use: -m 1 to -m 6
00042 #define IMAGE_HEIGHT 616
00043 #define IMAGE_WIDTH 808
00044 #define PANO_HEIGHT 375
00045 #define PANO_WIDTH 750
00046 #define PANO_RADIUS 20
00047 using namespace std;
00048 
00049 // IMAGE TEMPLATE:
00050 template<class T> class Image
00051 {
00052 private:
00053   IplImage* imgp;
00054 public:
00055   Image(IplImage* img=0) {imgp=img;}
00056   ~Image(){imgp=0;}
00057   void operator=(IplImage* img) {imgp=img;}
00058   inline T* operator[](const int rowIndx) {
00059     return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
00060 };
00061 typedef struct{
00062   unsigned char b,g,r;
00063 } RgbPixel;
00064 typedef struct{
00065   float b,g,r;
00066 } RgbPixelFloat;
00067 
00068 typedef Image<RgbPixel>       RgbImage;
00069 typedef Image<RgbPixelFloat>  RgbImageFloat;
00070 typedef Image<unsigned char>  BwImage;
00071 typedef Image<float>          BwImageFloat;
00072 
00073 // LOOK-UP TABLE:
00074 class CLut
00075 {
00076 public:
00077         CLut(int nRows, int nCols, int nCams);
00078         ~CLut();
00079         int getValue(int iRow, int iCol, int iCam);                             // read LUT value
00080         void setValue(int iRow, int iCol, int iCam, int iVal);  // set LUT value
00081         int fillArray(string cFileName[]);                                              // fill LUT using txt file of given name
00082 private:
00083         void initArray();
00084         int *m_array;
00085         int m_Rows;// = HEIGHT
00086         int m_Cols;// = WIDTH
00087         int m_Cams;// = 6
00088 };
00089 CLut::CLut(int nRows, int nCols, int nCams)
00090 {
00091 m_Rows = nRows;
00092 m_Cols = nCols;
00093 m_Cams = nCams;
00094 initArray();
00095 }
00096 CLut::~CLut(){
00097         delete m_array;
00098 }
00099 void CLut::initArray()
00100 {
00101         m_array = new int [m_Rows*m_Cols*NCAMS];
00102 }
00103 inline int CLut::getValue(int iRow, int iCol, int iCam)
00104 {
00105 if (iRow<m_Rows && iCol<m_Cols && iCam <m_Cams)
00106         return m_array[iCol+iRow*m_Cols+iCam*m_Cols*m_Rows];
00107 else
00108         return 0;
00109 }
00110 inline void CLut::setValue(int iRow, int iCol, int iCam, int iVal)
00111 {
00112 if (iRow<m_Rows && iCol<m_Cols && iCam <m_Cams)
00113         m_array[iCol+iRow*m_Cols+iCam*m_Cols*m_Rows] = iVal;
00114 }
00115 int CLut::fillArray(string cFileName[])
00116 {
00117         const char * pFileName;
00118         int indCam = 0;
00119         int value = 0;
00120         int linenum = 0;
00121         int itemnum = 0;
00122         string line, item;
00123 
00124 
00125         for(indCam = 0; indCam<6; indCam++)
00126         {
00127                 linenum = 0;
00128                 pFileName = cFileName[indCam].c_str();
00129                 ifstream inFile(pFileName);
00130                 if (inFile.is_open())
00131                   {
00132                         while (getline (inFile, line))
00133                         {
00134                                 if (linenum <m_Rows)
00135                                 {
00136                                         istringstream linestream(line);
00137                                         while (getline (linestream, item, ',') && (itemnum<m_Cols))
00138                                         {
00139                                                 istringstream is(item);
00140                                                 is >> value;
00141                                                 m_array[itemnum+linenum*m_Cols+indCam*m_Cols*m_Rows] = value-1;
00142                                                 itemnum++;
00143                                         }
00144                                 }
00145                         linenum++;
00146                         itemnum = 0; // set itemnum to zero at the beginning of the new line
00147                         }
00148                         inFile.close();
00149                         cout << "LUT uploaded: " << pFileName << endl;
00150                   }
00151                 else
00152                 {
00153                         ROS_ERROR("Unable to open following LUT file: '%s'\n", pFileName);
00154                         //cout << "HINT: If the LUT file does not exist, use ladybug_lut/main_pano_mesh.m and ladybug_lut/lut2txt.m to generate it." << endl;
00155                         exit (1);
00156                 }
00157         }
00158         return 0;
00159 
00160 }
00161 void setlabels(string (&labelset)[NCAMS], char path[], int pheight, int pwidth, int iheight, int iwidth, int prange, char xory)
00162 {
00163         char label[200];
00164         for(int i = 1; i <= NCAMS; i++) {
00165                 sprintf(label, "%s/LUT_img_%ix%i_pano_%ix%ir%i_%c%i.txt", path, iwidth, iheight, pwidth, pheight, prange, xory, i);
00166                 labelset[i-1] = label;
00167         }
00168 }
00169 
00170 // IMAGE HANDLING:
00171 int mode = 1;                           // default mode of operation
00172 int imgh = IMAGE_HEIGHT;        // default expected input image height
00173 int imgw = IMAGE_WIDTH;         // default expected input image height
00174 int panoh = PANO_HEIGHT;        // default desired panorama height
00175 int panow = PANO_WIDTH;         // default desired panorama width
00176 int panor = PANO_RADIUS;        // default sphere radius used for stitching
00177 
00178 CLut *pLUTX;
00179 CLut *pLUTY;
00180 CLut *pLUTA;
00181 IplImage *frame;
00182 IplImage *out;
00183 image_transport::Publisher pub;
00184 ros::Publisher camera_info_pub;
00185 sensor_msgs::CameraInfo msg_cam;
00186 
00187 void imageCallback(const sensor_msgs::ImageConstPtr& msg)
00188 {
00189   sensor_msgs::CvBridge bridge;
00190   try  {
00191         frame = bridge.imgMsgToCv(msg, "bgr8");
00192         int w,h;
00193         w = frame->height/6;
00194         h = frame->width;
00195         if ((mode>=1)&&(mode<=6)){              // single camera output 1-6
00196           out = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 3);
00197           RgbImage  imgA(frame);
00198           RgbImage  imgB(out);
00199           int i = mode;                                 // image number
00200           for (int u=0; u<w; u++){
00201             for (int v=0; v<h; v++){
00202               imgB[v][w-u-1].b = imgA[u+(i-1)*w][v].b;
00203               imgB[v][w-u-1].r = imgA[u+(i-1)*w][v].r;
00204               imgB[v][w-u-1].g = imgA[u+(i-1)*w][v].g;
00205                 }
00206           }
00207         }
00208         if (mode == 7) {                                        // mode for panorama stitching
00209           out = cvCreateImage(cvSize(panow, panoh), IPL_DEPTH_8U, 3);
00210           RgbImage imgA(frame);
00211           RgbImage imgB(out);
00212           if ((frame->height/6 == imgh) && (frame->width == imgw)) {
00213             int x = 0;
00214             int y = 0;
00215             unsigned int avgb, avgr, avgg, count;
00216             for (int u = 0; u < panoh; u++) {
00217               for (int v = 0; v < panow; v++) {
00218                 count = avgb = avgr = avgg =0;
00219                 // TODO: TP: Alpha using the look-up tables.
00220                 for(int c=0; c<NCAMS; c++){
00221                   x = pLUTX->getValue(u, v, c);
00222                   y = pLUTY->getValue(u, v, c);
00223                   //&& x<imgw-1 && y!=imgh && y!=imgh*2 && y!=imgh*3 && y!=imgh*4 && y!=imgh*5 && y!=imgh*6
00224                   if (x >= 0 && y >= 0){
00225                     unsigned int a = pLUTA->getValue(u, v, c);
00226                     avgb = avgb + (unsigned int) imgA[y][x].b * a;
00227                     avgr = avgr + (unsigned int) imgA[y][x].r * a;
00228                     avgg = avgg + (unsigned int) imgA[y][x].g * a;
00229                     count++;
00230                   }
00231                 }
00232                 if (count > 0) {
00233                   imgB[u][v].b = (unsigned char) (avgb / 255);
00234                   imgB[u][v].r = (unsigned char) (avgr / 255);
00235                   imgB[u][v].g = (unsigned char) (avgg / 255);
00236                 }
00237               }
00238             }
00239           }
00240           else {
00241             ROS_ERROR("Input image size '%ix%i' does not match the expected '%ix%i'\n",frame->width, frame->height, imgw, imgh );
00242             ros::shutdown();
00243 
00244           }
00245         }
00246     cv::WImageBuffer3_b image( out );
00247     sensor_msgs::ImagePtr msg_out = sensor_msgs::CvBridge::cvToImgMsg(image.Ipl(), "bgr8");  
00248     msg_out->header = msg->header;    // Use appropriate frame_id for separate images (mode 1..6).
00249     if (mode >= 1 && mode <= 6) {
00250       char buffer[100];
00251       sprintf(buffer  ,"tflbcamera%d", mode - 1);
00252       msg_out->header.frame_id = string(buffer);
00253         }
00254     pub.publish(msg_out);
00255     //msg_cam.header.frame_id = msg_out->header.frame_id;
00256     msg_cam.header = msg_out->header;
00257     msg_cam.height = out->height;
00258     msg_cam.width = out->width;
00259     camera_info_pub.publish(msg_cam);
00260   }
00261   catch (sensor_msgs::CvBridgeException& e)  {
00262       ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
00263   }
00264 }
00265 
00266 int main(int argc, char ** argv)
00267 {  
00268   // NODE INTERFACE
00269   char topic_name[200]; 
00270   char topic_name_out[200];
00271   char lutpath[500];
00272   strcpy( topic_name,  "/camera/image");
00273   strcpy( topic_name_out,  "/viz/image_out");
00274   for(int i = 0; i < argc; ++i) {   
00275     if(strcmp(argv[i], "-t") == 0) {
00276       if(i == argc - 1) {                
00277           fprintf(stderr, "Missing input topic name after -t, default topic %s is used.\n", topic_name);
00278       }
00279       else {
00280           ++i;
00281           strcpy( topic_name, argv[i] );
00282       }
00283     }
00284     if(strcmp(argv[i], "-o") == 0) {
00285       if(i == argc - 1) {               
00286           fprintf(stderr, "Missing output topic name after -o, default topic %s is used.\n", topic_name_out);
00287       }
00288       else {
00289           ++i;
00290           strcpy( topic_name_out, argv[i] );
00291       }
00292     }
00293     if(strcmp(argv[i], "-m") == 0) {
00294       if(i == argc - 1) {               
00295           fprintf(stderr, "Missing mode number after -m, default topic %d is used.\n", mode);
00296       }
00297       else {
00298           ++i;
00299           mode = atoi(argv[i]);
00300       }
00301     }
00302     if(strcmp(argv[i], "-ph") == 0) {
00303         if(i == argc - 1) {
00304                 fprintf(stderr, "Missing pano_height after -ph, default pano_height %d is used.\n", panoh);
00305         }
00306         else {
00307                 ++i;
00308                 panoh = atoi(argv[i]);
00309         }
00310     }
00311     if(strcmp(argv[i], "-pw") == 0) {
00312                 if(i == argc - 1) {
00313                         fprintf(stderr, "Missing pano_width after -pw, default pano_width %d is used.\n", panow);
00314                 }
00315                 else {
00316                         ++i;
00317                         panow = atoi(argv[i]);
00318                 }
00319         }
00320     if(strcmp(argv[i], "-ih") == 0) {
00321         if(i == argc - 1) {
00322                 fprintf(stderr, "Missing image_height after -ih, default image_height %d is used.\n", panoh);
00323         }
00324         else {
00325                 ++i;
00326                 imgh = atoi(argv[i]);
00327         }
00328     }
00329     if(strcmp(argv[i], "-iw") == 0) {
00330                 if(i == argc - 1) {
00331                         fprintf(stderr, "Missing image_width after -iw, default image_width %d is used.\n", imgw);
00332                 }
00333                 else {
00334                         ++i;
00335                         imgw = atoi(argv[i]);
00336                 }
00337         }
00338     if(strcmp(argv[i], "-r") == 0) {
00339                 if(i == argc - 1) {
00340                         fprintf(stderr, "Missing camera range  after -r, default camera range %d is used.\n", imgh);
00341                 }
00342                 else {
00343                         ++i;
00344                         panor = atoi(argv[i]);
00345                 }
00346         }
00347     if(strcmp(argv[i], "-path") == 0) {
00348                 if(i == argc - 1) {
00349                         fprintf(stderr, "Missing path to LUT files after -path");
00350                 }
00351                 else {
00352                         ++i;
00353                         strcpy( lutpath, argv[i] );
00354                 }
00355         }
00356   }
00357 
00358   // LUT CREATION
00359   // Construct file names of look-up tables for x and y coordinates, and alpha.
00360   string LABELSLUTX[NCAMS], LABELSLUTY[NCAMS], LABELSLUTA[NCAMS];
00361   setlabels(LABELSLUTX, lutpath, panoh, panow, imgh, imgw, panor, 'x');
00362   setlabels(LABELSLUTY, lutpath, panoh, panow, imgh, imgw, panor, 'y');
00363   setlabels(LABELSLUTA, lutpath, panoh, panow, imgh, imgw, panor, 'a');
00364   CLut LUTX(panoh, panow, NCAMS);                                                               // create LUT instance for X coordinates
00365   CLut LUTY(panoh, panow, NCAMS);                                                               // create LUT instance for Y coordinates
00366   CLut LUTA(panoh, panow, NCAMS);               // create LUT instance for alpha channel
00367   // fill the created LUTs with data according to the labels of the source files
00368   LUTX.fillArray(LABELSLUTX);
00369   LUTY.fillArray(LABELSLUTY);
00370   LUTA.fillArray(LABELSLUTA);
00371   // enabling access of the imageCallback function to the LUTX, LUTY
00372   pLUTX = &LUTX;
00373   pLUTY = &LUTY;
00374   pLUTA = &LUTA;
00375   
00376   // ROS DATA EXCHANGE
00377   ros::init(argc, argv, "image_listener");      // ROS initialization
00378   ros::NodeHandle nh;                                           // NODE handle assignment
00379   image_transport::ImageTransport it(nh);
00380   image_transport::Subscriber sub = it.subscribe(topic_name, 1, imageCallback);
00381   image_transport::ImageTransport it2(nh);
00382   pub = it2.advertise(topic_name_out, 1);
00383   camera_info_pub = nh.advertise<sensor_msgs::CameraInfo>("/viz/camera_info", 100);
00384   sensor_msgs::CameraInfo msg_cam;
00385 
00386   ros::spin();
00387 
00388   return 0;
00389 }
00390 
 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