BeoMap.C

Go to the documentation of this file.
00001 /*!@file BeoSub/BeoMap.C Class for stitching images */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/BeoMap.C $
00035 // $Id: BeoMap.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 #include "BeoSub/BeoMap.H"
00039 
00040 // ######################################################################
00041 BeoMap::BeoMap(float cut_thresh, int size_thresh, bool toCut)
00042 {
00043   CUT_THRESHOLD = cut_thresh;
00044   SIZE_THRESH = size_thresh;
00045   globalcounter = 0;
00046   pw = 0;
00047   ph = 0;
00048   switchcnt = 0;
00049   cut = toCut;
00050 }
00051 
00052 // ######################################################################
00053 BeoMap::~BeoMap()
00054 {
00055 
00056 }
00057 
00058 // ######################################################################
00059 void BeoMap::makePanorama(const char* nam1, const char* nam2)
00060 {
00061   MYLOGVERB = LOG_INFO;
00062 
00063   // check command-line args:
00064   //if (argc < 4)
00065   //LFATAL("USAGE: app-SIFT-panorama <result.png> "
00066   //       "<image1.png> ... <imageN.png>");
00067 
00068   // loop over the images and get all the SIFTaffines:
00069   ImageSet< PixRGB<byte> > images;
00070 
00071   //const char *nam1 = fm;
00072   Image< PixRGB<byte> > im1 = Raster::ReadRGB(nam1);
00073   images.push_back(im1);
00074   rutz::shared_ptr<VisualObject> vo1(new VisualObject(nam1, "", im1));
00075   LINFO("keypoint extractions completed for input image (%d keypoints)",
00076         vo1->numKeypoints());
00077 
00078 
00079   std::vector<SIFTaffine> affines;
00080   SIFTaffine comboaff; // default constructor is identity
00081   affines.push_back(comboaff);
00082   int minx = 0, miny = 0, maxx = im1.getWidth()-1, maxy = im1.getHeight()-1;
00083   for (int i = 1; i < 2; i ++)
00084   {
00085       Image< PixRGB<byte> > im2 = Raster::ReadRGB(nam2);
00086       images.push_back(im2);
00087       // LINFO("just before initializing im2");
00088       rutz::shared_ptr<VisualObject> vo2;
00089       //  LINFO("asd");
00090       LINFO("Pass #%d\n", globalcounter);
00091       /*
00092       if(!cut){
00093          rutz::shared_ptr<VisualObject>
00094          votemp( new VisualObject(nam2, "", im2));
00095         vo2 = votemp;
00096           }
00097       else{
00098         rutz::shared_ptr<VisualObject>
00099         votemp( new VisualObject(nam2, "", im3));
00100         vo2 = votemp;
00101           }
00102       */
00103 
00104       if(!cut){
00105          rutz::shared_ptr<VisualObject>
00106            votemp( new VisualObject(nam2, "", im2));
00107         vo2 = votemp;
00108       }
00109       else{
00110         rutz::shared_ptr<VisualObject>
00111           votemp( new VisualObject(nam2, "", im3));
00112         vo2 = votemp;
00113       }
00114 
00115 
00116 
00117 
00118 
00119       LINFO("keypoint extractions completed for map (%d keypoints)",
00120             vo2->numKeypoints());
00121 
00122 
00123       /**/ maxx = im2.getWidth()-1, maxy = im2.getHeight()-1;
00124       // compute the matching keypoints:
00125       //Timer tim(1000000);
00126       VisualObjectMatch match(vo1, vo2, VOMA_SIMPLE);
00127       LINFO("%d keypoints matched at pass %d", match.size(), globalcounter);
00128 
00129 
00130       //uint64 t = tim.get();
00131 
00132       //      LINFO("Found %u matches between %s and %s in %.3fms",
00133       //           match.size(), nam1, nam2, float(t) * 0.001F);
00134 
00135       // let's prune the matches:
00136       //uint np =
00137       match.prune();
00138       //LINFO("Pruned %u outlier matches.", np);
00139 
00140       // show our final affine transform:
00141       SIFTaffine aff = match.getSIFTaffine();
00142       std::cerr<<aff;
00143 
00144       // compose with the previous affines and store:
00145       comboaff = comboaff.compose(aff);
00146       affines.push_back(comboaff);
00147 
00148       // update panorama boundaries, using the inverse combo aff to
00149       // find the locations of the four corners of our image in the
00150       // panorama:
00151       if (comboaff.isInversible() == false) LFATAL("Oooops, singular affine!");
00152       SIFTaffine iaff = comboaff.inverse();
00153       const float ww = float(im2.getWidth() - 1);
00154       const float hh = float(im2.getHeight() - 1);
00155       float xx, yy; int x, y;
00156 
00157       iaff.transform(0.0F, 0.0F, xx, yy); x = int(xx); y = int(yy);
00158       if (x < minx) {minx = x; }
00159       if (x > maxx) {maxx = x; }
00160       if (y < miny) {miny = y; }
00161       if (y > maxy) {maxy = y; }
00162 
00163       iaff.transform(ww, 0.0F, xx, yy); x = int(xx); y = int(yy);
00164       if (x < minx) {minx = x; }
00165       if (x > maxx) {maxx = x; }
00166       if (y < miny) {miny = y; }
00167       if (y > maxy) {maxy = y; }
00168 
00169 
00170       iaff.transform(0.0F, hh, xx, yy); x = int(xx); y = int(yy);
00171       if (x < minx) {minx = x; }
00172       if (x > maxx) {maxx = x; }
00173       if (y < miny) {miny = y; }
00174       if (y > maxy) {maxy = y; }
00175 
00176 
00177       iaff.transform(ww, hh, xx, yy); x = int(xx); y = int(yy);
00178       if (x < minx) {minx = x; }
00179       if (x > maxx) {maxx = x; }
00180       if (y < miny) {miny = y; }
00181       if (y > maxy) {maxy = y; }
00182 
00183       //LINFO("modMinX %d, modMaxX %d, modMinY %d, modMaxY %d",
00184       //modMinX, modMaxX, modMinY, modMaxY);
00185       // get ready for next pair:
00186       im1 = im2; vo1 = vo2; nam1 = nam2;
00187     }
00188 
00189   // all right, allocate the panorama:
00190   //LINFO("x = [%d .. %d], y = [%d .. %d]", minx, maxx, miny, maxy);
00191   int w = maxx - minx + 1, h = maxy - miny + 1;
00192 
00193 
00194   if(globalcounter==0){
00195     pw=w;
00196     ph=h;
00197   }
00198 
00199   //
00200   // if the map size is within acceptable range.
00201   //
00202   if(w <= pw && h <= ph)
00203     {
00204 
00205       //LINFO("Allocating %dx%d panorama...", w, h);
00206   if (w < 2 || h < 2) LFATAL("Oooops, panorama too small!");
00207   Image< PixRGB<byte> > pano(w, h, ZEROS);
00208   Image< PixRGB<byte> >::iterator p = pano.beginw();
00209 
00210   int minStitchedX=0, maxStitchedX=0,
00211     minStitchedY=0, maxStitchedY=0,
00212     counterStitching = 0;
00213   int minStitchedX2=0, maxStitchedX2=0,
00214     minStitchedY2=0, maxStitchedY2=0,
00215     counterStitching2 = 0;
00216   // let's stitch the images into the panorama. This code is similar
00217   // to that in VisualObjectMatch::getTransfTestImage() but modified
00218   // for a large panorama and many images:
00219 
00220 
00221   for (int j = 0; j < h; j ++)
00222     for (int i = 0; i < w; i ++)
00223       {
00224         // compute the value that should go into the current panorama
00225         // pixel based on all the images and affines; this is very
00226         // wasteful and may be optimized later:
00227         PixRGB<int> val(0); uint n = 0U;
00228         //LINFO("images.size is %d",images.size());
00229         for (uint k = 0; k < images.size(); k ++)
00230           {
00231             // get transformed coordinates for image k:
00232             float u, v;
00233             affines[k].transform(float(i + minx), float(j + miny), u, v);
00234             //            LINFO("K is %d, i+minx is %d, i+miny is %d, u is %f, v is %f",k,i+minx,i+miny,u,v);
00235             // if we are within bounds of image k, accumulate the pix value:
00236             if (images[k].coordsOk(u, v))
00237               {
00238                 val += PixRGB<int>(images[k].getValInterp(u, v));
00239                 //the if-else statement below gathers the min/max coordinates on the resulting image the input image is.
00240                 if(k == 0 && counterStitching == 0)
00241                   {
00242                     minStitchedX = maxStitchedX = i;
00243                     minStitchedY = maxStitchedY = j;
00244                     counterStitching++;
00245                   }
00246                 else if(k==0)
00247                   {
00248                     if(minStitchedX > i)
00249                       minStitchedX = i;
00250                     if(maxStitchedX < i)
00251                       maxStitchedX = i;
00252                     if(minStitchedY > j)
00253                       minStitchedY = j;
00254                     if(maxStitchedY < j)
00255                       maxStitchedY = j;
00256                     counterStitching++;
00257                   }
00258                 if(counterStitching2 == 0)
00259                   {
00260                     minStitchedX2 = maxStitchedX2 = i;
00261                     minStitchedY2 = maxStitchedY2 = j;
00262                     counterStitching2++;
00263                   }
00264                 else
00265                   {
00266                     if(minStitchedX2 > i)
00267                       minStitchedX2 = i;
00268                     if(maxStitchedX2 < i)
00269                       maxStitchedX2 = i;
00270                     if(minStitchedY2 > j)
00271                       minStitchedY2 = j;
00272                     if(maxStitchedY2 < j)
00273                       maxStitchedY2 = j;
00274                     counterStitching2++;
00275                   }
00276 
00277                 ++ n;
00278               }
00279           }
00280 
00281         if (n > 0) *p = PixRGB<byte>(val / n);
00282 
00283         ++ p;
00284       }
00285 
00286   LINFO("Pixel coordinates of the area Stitched: xmin %d, xmax %d, ymin %d, ymax %d",minStitchedX, maxStitchedX, minStitchedY, maxStitchedY);
00287   LINFO("Pixel coordinates of the area Stitched: xmin2 %d, xmax2 %d, ymin2 %d, ymax2 %d",minStitchedX2, maxStitchedX2, minStitchedY2, maxStitchedY2);
00288 
00289 
00290   //if(maxStitchedX2 + 10 < w &&maxStitchedY2+10 < h){
00291   Image< PixRGB<byte> > pano2((maxStitchedX2+10<w)?maxStitchedX2+10:w, (maxStitchedY2+10<h)?maxStitchedY2+10:h, ZEROS);
00292   for(int i = 0; i < pano2.getWidth(); i++)
00293     for(int j = 0; j<pano2.getHeight(); j++)
00294       {
00295         pano2.setVal(i,j,pano.getVal(i,j));
00296 
00297       }
00298   //  }
00299 
00300     // w = maxStitchedX2+1;
00301     // h = maxStitchedY2+1;
00302   if(  (pano2.getHeight()*pano2.getWidth()/*w*h*/) / (float)((maxStitchedX - minStitchedX+1)*(maxStitchedY - minStitchedY+1)) >= CUT_THRESHOLD )
00303     {
00304       //  LINFO("GO CUT THE MAP!\n");
00305 
00306       //
00307       // Simple map cutting algorithm.
00308       //
00309       // Coded on Feb/8/2006.
00310 
00311 
00312       //LINFO("===================================================\n");
00313 
00314         // calculate cutting position.
00315 
00316         medge.rightedge = maxStitchedX + SIZE_THRESH;
00317         medge.leftedge = minStitchedX - SIZE_THRESH;
00318         medge.upperedge = minStitchedY - SIZE_THRESH;
00319         medge.loweredge = maxStitchedY + SIZE_THRESH;
00320 
00321         if( (pano2.getWidth()/*w*/ - medge.rightedge) < 20){
00322           medge.rightedge = -1; // -1 means dont cut a map.
00323         }
00324 
00325         if(medge.leftedge < 20){
00326           medge.leftedge = -1; // -1 means dont cut a map.
00327         }
00328 
00329         if( (medge.upperedge) <= 20){
00330           medge.upperedge = -1; // -1 means dont cut a map.
00331         }
00332 
00333         if( (pano2.getHeight()/*h*/ - medge.loweredge) < 20){
00334           medge.loweredge = -1; // -1 means dont cut a map.
00335         }
00336 
00337 
00338         LINFO("minX %d , maxX %d, minY %d, maxY %d", minStitchedX, maxStitchedX, minStitchedY, maxStitchedY);
00339 
00340 
00341                 if(medge.upperedge > 0) LINFO("UPPER-SIDE :  %d \n", medge.upperedge);
00342         else LINFO("UPPER-SIDE : No cut");
00343 
00344 
00345                 if(medge.rightedge > 0) LINFO("RIGHT-SIDE :  %d \n", medge.rightedge);
00346                 else LINFO("RIGHT-SIDE : No cut");
00347 
00348                 if(medge.leftedge > 0) LINFO("LEFT-SIDE :  %d \n", medge.leftedge);
00349                 else LINFO("LEFT-SIDE : No cut");
00350 
00351 
00352 
00353                 if(medge.loweredge > 0) LINFO("LOWER-SIDE :  %d \n", medge.loweredge);
00354                 else LINFO("LOWER-SIDE : No cut");
00355 
00356                 LINFO("Map size : (Xsize, Ysize) = (%d, %d)\n", w, h);
00357 
00358         //        LINFO("===================================================\n");
00359 
00360                 int widthtmp(pano2.getWidth()/*w*/); int hswitch(0);
00361 
00362 
00363         ///////////////////////////////////////////////////////////////////////////////
00364         //////// X-Direction cut.
00365 
00366         if((medge.rightedge != -1) && (medge.leftedge != -1)){
00367           im3.resize(widthtmp = (medge.rightedge+1) - medge.leftedge, pano2.getHeight());
00368           //LINFO("size of im3 is %d,%d",im3.getWidth(), im3.getHeight());
00369           for(int i = 0; i<im3.getWidth();i++)
00370             for(int j = 0; j <im3.getHeight();j++)
00371               {
00372                 im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j));
00373               }
00374           cut = true;
00375           hswitch = 1;
00376         }
00377         else if((medge.rightedge != -1) && (medge.leftedge==-1))
00378           {
00379             im3.resize(widthtmp = (medge.rightedge+1), pano2.getHeight());
00380             //  LINFO("size of im3 is %d,%d",im3.getWidth(), im3.getHeight());
00381             for(int i = 0; i<im3.getWidth();i++)
00382               for(int j = 0; j <im3.getHeight();j++)
00383                 {
00384                   im3.setVal(i,j,pano2.getVal(i, j));
00385                 }
00386             cut = true;
00387             hswitch = 2;
00388           }
00389         else if((medge.rightedge == -1) && (medge.leftedge!=-1))
00390           {
00391             im3.resize(widthtmp = (pano2.getWidth()-medge.leftedge-1), pano2.getHeight());
00392             //LINFO("size of im3 is %d,%d",im3.getWidth(), im3.getHeight());
00393             for(int i = 0; i<im3.getWidth();i++)
00394               for(int j = 0; j <im3.getHeight();j++)
00395                 {
00396                   im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j));
00397                 }
00398             cut = true;
00399             hswitch = 3;
00400           }
00401         else{
00402           cut = false;
00403           hswitch = 0;
00404           widthtmp = pano2.getWidth();
00405         }
00406 
00407         ///////////////////////////////////////////////////////////////////////////////
00408         //////// Y-Direction cut.
00409 
00410         if((medge.upperedge != -1) && (medge.loweredge != -1)){// upper lower both cut.
00411           im3.resize(widthtmp, medge.loweredge - medge.upperedge );
00412           //LINFO("size of im3 is %d,%d",im3.getWidth(), im3.getHeight());
00413           for(int i = 0; i<im3.getWidth();i++)
00414             for(int j = 0; j <im3.getHeight();j++)
00415               {
00416                 if(hswitch == 0)// left right no cut
00417                   im3.setVal(i,j,pano2.getVal(i, j+medge.upperedge));
00418                 if(hswitch == 1)// left right both cut
00419                   im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j+medge.upperedge));
00420                 if(hswitch == 2)// left no cut, right cut
00421                   im3.setVal(i,j,pano2.getVal(i, j+medge.upperedge));
00422                 if(hswitch == 3)// left cut right no cut.
00423                   im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j+medge.upperedge));
00424               }
00425           cut = true;
00426         }
00427         else if((medge.upperedge != -1) && (medge.loweredge==-1)){//  upper cut lower no cut
00428             im3.resize(widthtmp, pano2.getHeight() - medge.upperedge);
00429             //LINFO("size of im3 is %d,%d",im3.getWidth(), im3.getHeight());
00430             for(int i = 0; i<im3.getWidth();i++)
00431               for(int j = 0; j <im3.getHeight();j++)
00432                 {
00433                   //  im3.setVal(i,j,pano.getVal(i, j));
00434                   if(hswitch == 0)// left right no cut
00435                     im3.setVal(i,j,pano2.getVal(i, j+medge.upperedge));
00436                   if(hswitch == 1)// left right both cut
00437                     im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j+medge.upperedge));
00438                   if(hswitch == 2)// left no cut, right cut
00439                     im3.setVal(i,j,pano2.getVal(i, j+medge.upperedge));
00440                   if(hswitch == 3)// left cut right no cut.
00441                     im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j+medge.upperedge));
00442                 }
00443             cut = true;
00444           }
00445         else if((medge.upperedge == -1) && (medge.loweredge !=-1)){// upper no cut lower cut
00446             im3.resize(widthtmp, medge.loweredge+1);
00447             //LINFO("size of im3 is %d,%d",im3.getWidth(), im3.getHeight());
00448             for(int i = 0; i<im3.getWidth();i++)
00449               for(int j = 0; j <im3.getHeight();j++)
00450                 {
00451                   //          im3.setVal(i,j,pano.getVal(i+medge.leftedge, j));
00452                                     //  im3.setVal(i,j,pano.getVal(i, j));
00453                   if(hswitch == 0)// left right no cut
00454                     im3.setVal(i,j,pano2.getVal(i, j));
00455                   if(hswitch == 1)// left right both cut
00456                     im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j));
00457                   if(hswitch == 2)// left no cut, right cut
00458                     im3.setVal(i,j,pano2.getVal(i, j));
00459                   if(hswitch == 3)// left cut right no cut.
00460                     im3.setVal(i,j,pano2.getVal(i+medge.leftedge, j));
00461                 }
00462             cut = true;
00463           }
00464         else{
00465           cut = false;
00466         }
00467 
00468 
00469 
00470         ///////////
00471 
00472     }
00473   else
00474     {
00475       cut = false;
00476     }
00477 
00478 
00479   //  pano.resize(maxStitchedX2+1, maxStitchedY2+1,false);
00480   // save final panorama:
00481   //pano = rescale(pano, maxStitchedX2+1, maxStitchedY2+1);
00482 
00483   Raster::WriteRGB(pano2, nam2);
00484   // LINFO("Done.");
00485 
00486   // to avid making a map extremely big.
00487   pw = (int)(pano2.getWidth()*1.5);//w*1.5);
00488   ph = (int)(pano2.getHeight()*1.5);//h*1.5);
00489   globalcounter++;
00490     }
00491 }
Generated on Sun May 8 08:40:19 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3