XCgrab_bayer.C

00001 /*!@file AppPsycho/videograb.C grab frames and save the debayered color
00002   images to disk. Use it like: XCgrab_bayer <name>*/
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Zhicheng Li <zhicheng@usc.edu>
00035 // $$
00036 // $Id: XCgrab_bayer.C 12962 2010-03-06 02:13:53Z irock $
00037 //
00038 
00039 #include "Component/ModelManager.H"
00040 #include "Devices/FrameGrabberConfigurator.H"
00041 #include "Devices/DeviceOpts.H"
00042 #include "Image/DrawOps.H"
00043 #include "Image/Image.H"
00044 #include "Image/ShapeOps.H"
00045 #include "Image/CutPaste.H"
00046 #include "Image/ImageCache.H"
00047 #include "Image/Pixels.H"
00048 #include "GUI/SDLdisplay.H"
00049 #include "GUI/GUIOpts.H"
00050 #include "Raster/Raster.H"
00051 #include "Transport/FrameIstream.H"
00052 #include "Util/Timer.H"
00053 #include "Util/log.H"
00054 #include "Util/sformat.H"
00055 #include "Util/FileUtil.H"
00056 #include "Video/RgbConversion.H" // for toVideoYUV422()
00057 #include "Raster/DeBayer.H" // for debayer()
00058 
00059 #include <pthread.h>
00060 
00061 //! number of frames over which frame rate is computed
00062 #define NAVG 20
00063 
00064 #define MAXSAVETHREAD 4
00065 
00066 //! Enumerate the video preview type
00067 enum PreviewType
00068   {
00069     PrevAll,
00070     PrevTopLeft,
00071     PrevTopRight,
00072     PrevBotLeft,
00073     PrevBotRight,
00074     PrevCenter
00075   };
00076 
00077 //! counter for saved frame number
00078 uint fnb = 0;
00079 pthread_mutex_t qmutex_cache, qmutex_cachesv, qmutex_imgShow;
00080 ImageCache<byte> cache, cachesv;
00081 std::vector<std::string> base;
00082 bool saving = false;
00083 Image<PixRGB<byte> > imgShow;
00084 PreviewType prevType = PrevAll;
00085 Dims showDim;
00086 
00087 
00088 //save the bayer format frames in disk as "ppm" format
00089 static void* saveframes(void *)
00090 {
00091   while(1) {
00092     Image<byte> img; bool havemore = false;
00093     uint cntTmp = 0;
00094 
00095     // do we have images ready to go?
00096     pthread_mutex_lock(&qmutex_cachesv);
00097     if (cachesv.size()){
00098       img = cachesv.pop_front();
00099       fnb++;
00100       cntTmp = fnb;
00101     }
00102     if (cachesv.size()) havemore = true;
00103     pthread_mutex_unlock(&qmutex_cachesv);
00104 
00105     // if we got an image, save it:
00106     if (img.initialized())
00107       {
00108         // we save each frame to a different base in a rolling manner:
00109         const char *b = base[cntTmp % base.size()].c_str();
00110         Raster::WriteGray(img, sformat("%s%06u.pgm", b, cntTmp));
00111       }
00112 
00113     if (havemore == false) usleep(1000);
00114   }
00115   return NULL;
00116 }
00117 
00118 
00119 //debayer the captured image and display a smaller size on the screen
00120 static void* debayerframes(void *)
00121 {
00122   while(1){
00123     Image<byte> img; bool havemore = false;
00124     Image<PixRGB<byte> > imgRGB;
00125 
00126     pthread_mutex_lock(&qmutex_cache);
00127     if(cache.size()) img = cache.pop_front();
00128     if(cache.size()) havemore = true;
00129     pthread_mutex_unlock(&qmutex_cache);
00130 
00131     if( img.initialized())
00132       {
00133         imgRGB = deBayer(img, BAYER_GBRG);
00134         pthread_mutex_lock(&qmutex_imgShow);
00135 
00136         switch(prevType){
00137         case PrevAll:  // scaled size of the whole image
00138           imgShow = rescale(imgRGB, showDim.w(), showDim.h(),
00139                             RESCALE_SIMPLE_NOINTERP);
00140           break;
00141         case PrevTopLeft:  // top left
00142           imgShow = crop(imgRGB, Point2D<int>(0,0), showDim);
00143           break;
00144         case PrevTopRight:  // top right
00145           imgShow = crop(imgRGB, Point2D<int>
00146                          (imgRGB.getWidth()-showDim.w(),0), showDim);
00147           break;
00148         case PrevBotLeft:  // bottom left
00149           imgShow = crop(imgRGB, Point2D<int>
00150                          (0,imgRGB.getHeight()-showDim.h()), showDim);
00151           break;
00152         case PrevBotRight:  // bottom right
00153           imgShow = crop(imgRGB, Point2D<int>
00154                          (imgRGB.getWidth()-showDim.w(),
00155                           imgRGB.getHeight()-showDim.h()), showDim);
00156           break;
00157         case PrevCenter:  // center
00158           imgShow = crop(imgRGB, Point2D<int>
00159                          ((imgRGB.getWidth()-showDim.w())/2,
00160                           (imgRGB.getHeight()-showDim.h())/2),showDim);
00161           break;
00162         default:
00163           LFATAL("the preview type should between 0 and 5");
00164         }
00165 
00166         pthread_mutex_unlock(&qmutex_imgShow);
00167       }
00168 
00169     if(havemore == false) usleep(1000);
00170   }
00171   return NULL;
00172 }
00173 
00174 
00175 /*! This simple executable grabs video frames through the EPIX XC HD
00176   camera link grabber (see XCgrabber.H). Selection of the grabber type
00177   is made via the  --fg-type=XC command-line option. Frames are pushed
00178   into a queue and  a second thread then tries to empty the queue as
00179   quickly as possible by writing the frames to disk. In testing, PPM
00180   format actually gave better frame rates than PNG, so that's what is
00181   used.  Press <SPACE> to start grabbing and <SPACE> again to stop. */
00182 static int submain(const int argc, char** argv)
00183 {
00184   // instantiate a model manager:
00185   ModelManager manager("Frame Grabber");
00186 
00187   // Instantiate our various ModelComponents:
00188   nub::soft_ref<FrameGrabberConfigurator>
00189     gbc(new FrameGrabberConfigurator(manager));
00190   manager.addSubComponent(gbc);
00191 
00192   nub::soft_ref<SDLdisplay> d(new SDLdisplay(manager));
00193   manager.addSubComponent(d);
00194 
00195   manager.setOptionValString(&OPT_SDLdisplayPriority, "0");
00196   manager.setOptionValString(&OPT_FrameGrabberType, "XC");
00197   manager.setOptionValString(&OPT_SDLdisplayFullscreen,"false");
00198   manager.setOptionValString(&OPT_SDLdisplayDims, "960x640");
00199 
00200   // Parse command-line:
00201   if (manager.parseCommandLine(argc, argv, "<basename> ... <basename>",
00202                                1, MAXSAVETHREAD) == false)
00203     return(1);
00204 
00205   // do post-command-line configs:
00206   nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00207   if (gb.isInvalid())
00208     LFATAL("You need to have XC camera and XClibrary");
00209 
00210   // get the basename:
00211   for (uint i = 0; i < manager.numExtraArgs(); i ++)
00212     base.push_back(manager.getExtraArg(i));
00213 
00214   // let's get all our ModelComponent instances started:
00215   manager.start();
00216 
00217   // get ready for main loop:
00218   Timer tim,timer; uint64 t[NAVG]; int frame = 0;
00219   d->clearScreen(PixRGB<byte>(128)); bool doit = true;
00220 
00221   showDim = d->getDims();
00222   int iw = showDim.w(), ih = showDim.h();
00223   int dw = d->getDims().w(), dh = d->getDims().h();
00224 
00225   int ovlyoff = (dw - iw) / 2 + dw * ((dh - ih) / 2);
00226   int ovluvoff = (dw - iw) / 4 + dw * ((dh - ih) / 8);
00227   int ystride = (dw - iw), uvstride = (dw - iw) / 2;
00228 
00229   pthread_t saver[MAXSAVETHREAD];
00230   for(int ii = 0; ii<(int)base.size(); ii++)
00231     pthread_create(saver+ii, NULL, &saveframes, (void *)NULL);
00232 
00233   pthread_t debayer, debayer1;
00234   pthread_create(&debayer, NULL, &debayerframes, (void*) NULL);
00235   pthread_create(&debayer1, NULL, &debayerframes, (void*) NULL);
00236 
00237   // create an overlay:
00238   d->createYUVoverlay(SDL_YV12_OVERLAY);
00239 
00240   // get the frame grabber to start streaming:
00241   gb->startStream();
00242 
00243   // main loop:
00244   // if we type space to record then next space will stop the first record section
00245   // the next section will be begin when the third space typed and so on..
00246 
00247   float frate = 0.0f;
00248 
00249   while(doit) {
00250     tim.reset();
00251 
00252     // grab a frame:
00253     Image<byte> img = gb->readGray();
00254     pthread_mutex_lock(&qmutex_cache);
00255     cache.push_back(img);
00256     pthread_mutex_unlock(&qmutex_cache);
00257 
00258     if(saving)
00259       {
00260         pthread_mutex_lock(&qmutex_cachesv);
00261         cachesv.push_back(img);
00262         pthread_mutex_unlock(&qmutex_cachesv);
00263       }
00264 
00265     // to measure display time:
00266     uint64 t0 = tim.get();
00267 
00268     // if saving, push image into queue:
00269     pthread_mutex_lock(&qmutex_imgShow);
00270     if (saving)
00271       {
00272         const std::string msg =
00273           sformat(" %.1ffps [%04d] ", frate, cachesv.size());
00274         writeText(imgShow, Point2D<int>(0, 0), msg.c_str());
00275       }
00276     else // tell user we are ready to save
00277       {
00278         const std::string msg =
00279           sformat(" [SPC] to save %.1ffp [%04d] ", frate, cache.size());
00280         writeText(imgShow, Point2D<int>(0, 0), msg.c_str());
00281       }
00282 
00283     // show the frame:
00284     SDL_Overlay* ovl = d->lockYUVoverlay();
00285     toVideoYUV422(imgShow, ovl->pixels[0] + ovlyoff,
00286                   ovl->pixels[2] + ovluvoff,
00287                   ovl->pixels[1] + ovluvoff,
00288              ystride, uvstride, uvstride);
00289 
00290     d->unlockYUVoverlay();
00291     d->displayYUVoverlay(-1, SDLdisplay::NO_WAIT);
00292     pthread_mutex_unlock(&qmutex_imgShow);
00293 
00294     // check for space bar pressed; note: will abort us violently if
00295     // ESC is pressed instead:
00296     int ii = (d->checkForKey());
00297     if(ii == ' ')
00298       { saving = ! saving;
00299         prevType = PrevAll;
00300       }
00301     else if(ii == 'q')
00302       prevType = PrevTopLeft;
00303     else if(ii == 'e')
00304       prevType = PrevTopRight;
00305     else if(ii == 'a')
00306       prevType = PrevBotLeft;
00307     else if(ii == 'd')
00308       prevType = PrevBotRight;
00309     else if(ii == 's')
00310       prevType = PrevCenter;
00311     else if(ii == 'w')
00312       prevType = PrevAll;
00313 
00314     t[frame % NAVG] = tim.get();
00315     t0 = t[frame % NAVG] - t0;
00316     if (t0 > 20000ULL) LINFO("Display took %lluus", t0);
00317 
00318     // compute and show framerate over the last NAVG frames:
00319     if (frame % NAVG == 0 && frame > 0)
00320       {
00321         uint64 avg = 0ULL; for (int i = 0; i < NAVG; i ++) avg += t[i];
00322         frate = 1000.0F / float(avg) * float(NAVG);
00323         if(saving)
00324           LINFO("Frame rate %f fps, buf size %u, time %f", frate,
00325                 cachesv.size(), timer.getSecs());
00326         else
00327           LINFO("Frame rate %f fps, buf size %u, time %f", frate,
00328                 cache.size(), timer.getSecs());
00329       }
00330     frame ++;
00331   }
00332 
00333   d->destroyYUVoverlay();
00334   manager.stop();
00335 
00336   // all done!
00337   return 0;
00338 }
00339 
00340 extern "C" int main(const int argc, char** argv)
00341 {
00342   try
00343     {
00344       return submain(argc, argv);
00345     }
00346   catch (...)
00347     {
00348       REPORT_CURRENT_EXCEPTION;
00349     }
00350 
00351   return 1;
00352 }
00353 
00354 // ######################################################################
00355 /* So things look consistent in everyone's emacs... */
00356 /* Local Variables: */
00357 /* indent-tabs-mode: nil */
00358 /* End: */
Generated on Sun May 8 08:40:07 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3