XCgrabber.C

Go to the documentation of this file.
00001 /*!@file Devices/XCgrabber.C Interface with a Silicon imaging digital camera */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // 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: Zhicheng Li <zhicheng@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Devices/XCgrabber.C $
00035 // $Id: XCgrabber.C 14376 2011-01-11 02:44:34Z pez $
00036 //
00037 
00038 #include <cstddef>
00039 #include <string>
00040 
00041 #include "Component/OptionManager.H" // for option alias requests
00042 #include "Devices/DeviceOpts.H"
00043 #include "Image/Image.H"
00044 #include "Image/Pixels.H"
00045 #include "Image/MathOps.H"
00046 #include "Raster/GenericFrame.H"
00047 #include "Raster/Raster.H"
00048 #include "Util/Assert.H"
00049 #include "Util/SimTime.H"
00050 #include "Util/sformat.H"
00051 #include "Video/VideoFrame.H"
00052 
00053 #include "Devices/XCgrabber.H"
00054 
00055 // wait when polling for a frame (in us):
00056 #define XCWAIT 50
00057 
00058 // ######################################################################
00059 XCgrabber::XCgrabber(OptionManager& mgr, const std::string& descrName,
00060                      const std::string& tagName, const ParamFlag flags) :
00061   FrameIstream(mgr, descrName, tagName),
00062   itsChannel(&OPT_FrameGrabberChannel, this, 0, USE_MY_VAL),
00063   itsDims(&OPT_FrameGrabberDims, this, Dims(1920, 1080), USE_MY_VAL),
00064   itsOffset(&OPT_FrameGrabberOffset, this, Dims(0, 0), USE_MY_VAL),
00065   itsNbuf(&OPT_FrameGrabberNbuf, this, 4, USE_MY_VAL),
00066   itsGrabMode(&OPT_FrameGrabberMode, this, VIDFMT_BAYER_GB, USE_MY_VAL),
00067   itsByteSwap(&OPT_FrameGrabberByteSwap, this, false, USE_MY_VAL),
00068   itsWhiteBalTarR(&OPT_FrameGrabberWhiteBalTargetR, this, false, USE_MY_VAL),
00069   itsWhiteBalTarG(&OPT_FrameGrabberWhiteBalTargetG, this, false, USE_MY_VAL),
00070   itsWhiteBalTarB(&OPT_FrameGrabberWhiteBalTargetB, this, false, USE_MY_VAL),
00071   itsWhiteBalRefR(&OPT_FrameGrabberWhiteBalReferenceR, this, false, USE_MY_VAL),
00072   itsWhiteBalRefG(&OPT_FrameGrabberWhiteBalReferenceG, this, false, USE_MY_VAL),
00073   itsWhiteBalRefB(&OPT_FrameGrabberWhiteBalReferenceB, this, false, USE_MY_VAL),
00074   itsGamma(&OPT_XCFrameGrabberGamma, this, 1.0, USE_MY_VAL | ALLOW_ONLINE_CHANGES),
00075   itsFPS(&OPT_FrameGrabberFPS, this, 30.0, USE_MY_VAL)
00076 #ifdef HAVE_XCLIB
00077   , itsFormatFile(&OPT_XCFormatFileName, this),
00078   itsCameraOk(false), itsLastBuf(0), itsImgBuf(NULL),
00079   itsStateid(PXMODE_DIGI), itsUnitMap(0), itsPximg(NULL)
00080 #endif
00081 {
00082 #ifdef HAVE_XCLIB
00083   memset(&itsXclib, 0, sizeof(itsXclib));
00084   itsXclib.ddch.len = sizeof(itsXclib);
00085   itsXclib.ddch.mos = XCMOS_LIBS;
00086 #endif
00087 }
00088 
00089 // ######################################################################
00090 void XCgrabber::start1()
00091 {
00092 #ifndef HAVE_XCLIB
00093   LFATAL("you must have XC support and the xclib library in order to use XCgrabber");
00094 #else
00095 
00096   // define the unit map: here we only support one unit, given by itsChannel:
00097   itsUnitMap = (1 << itsChannel.getVal());
00098   const int nbuf = itsNbuf.getVal(); // shortcut
00099   itsStateid = PXMODE_DIGI + itsChannel.getVal(); // black magic
00100   struct xclib::pxvidstate *statep;
00101 
00102   // open the XC cameralink imaging board
00103   if (itsFormatFile.getVal().empty()) {
00104     LINFO("Using default setup configure format");
00105     char* format = (char*)("default");
00106     if (int ret = xclib::xclib_open(&itsXclib, NULL, NULL, format, NULL))
00107       LFATAL("Cannot open XC library [%s]", err(ret));
00108   } else {
00109     LINFO("Using input format file '%s' as configure file", itsFormatFile.getVal().c_str());
00110     char* formatFile = (char*)(itsFormatFile.getVal().c_str());
00111     if (int ret = xclib::xclib_open(&itsXclib, NULL, NULL, NULL, formatFile))
00112       LFATAL("Cannot open XC library [%s]", err(ret));
00113 
00114     // now also actually load the mode defined in the config file (which should correspond to itsStateid) into the
00115     // board's hardware:
00116     if (int ret = itsXclib.xcdev.setVideoConfig(&itsXclib.xcdev, itsUnitMap, 0, itsStateid, NULL, NULL))
00117       LERROR("Set video configure error [%s]", err(ret));
00118     if (int ret = itsXclib.xcdev.setCameraConfig(&itsXclib.xcdev, itsUnitMap, 1, itsStateid, NULL, NULL))
00119       LERROR("Set camera config error [%s]", err(ret));
00120   }
00121 
00122   // shortcuts:
00123   struct xclib::pxlibservice *pxlib = &(itsXclib.pxlib);
00124   struct xclib::xcdevservice *xcdev = &(itsXclib.xcdev);
00125 
00126   // mask of which components in the pixies to grab (0x1 for the first component (gray/bayer), 0x7 for the first 3
00127   // components (rgb):
00128   int pixiemask = 0x1; // keep compiler happy
00129 
00130   // define bit depth, number of components, and pixiemask based on grab mode:
00131   switch(itsGrabMode.getVal()) {
00132   case VIDFMT_BAYER_GB12:  itsBitDepth = 12;  itsNumComp = 1; pixiemask = 0x1; break;
00133   case VIDFMT_BAYER_GR12:  itsBitDepth = 12;  itsNumComp = 1; pixiemask = 0x1; break;
00134   case VIDFMT_BAYER_RG12:  itsBitDepth = 12;  itsNumComp = 1; pixiemask = 0x1; break;
00135   case VIDFMT_BAYER_BG12:  itsBitDepth = 12;  itsNumComp = 1; pixiemask = 0x1; break;
00136   case VIDFMT_BAYER_GB:    itsBitDepth = 8;   itsNumComp = 1; pixiemask = 0x1; break;
00137   case VIDFMT_BAYER_GR:    itsBitDepth = 8;   itsNumComp = 1; pixiemask = 0x1; break;
00138   case VIDFMT_BAYER_RG:    itsBitDepth = 8;   itsNumComp = 1; pixiemask = 0x1; break;
00139   case VIDFMT_BAYER_BG:    itsBitDepth = 8;   itsNumComp = 1; pixiemask = 0x1; break;
00140   case VIDFMT_GREY:        itsBitDepth = 8;   itsNumComp = 1; pixiemask = 0x1; break;
00141   case VIDFMT_RGB24:       itsBitDepth = 8;   itsNumComp = 3; pixiemask = 0x7; break;
00142   default:                 LFATAL("ERROR unsupported video format for the XC grabber");
00143   }
00144 
00145   // list basic camera info:
00146   struct xclib::pxdevinfo pxinfo;
00147   memset(&pxinfo, 0, sizeof(pxinfo)); pxinfo.ddch.len = sizeof(pxinfo); pxinfo.ddch.mos = PXMOS_DEVINFO;
00148   if (int ret = itsXclib.pxdev.getDevInfo(&itsXclib.pxdev, itsUnitMap, 0, &pxinfo) != 0)
00149     LERROR("Error trying to get pxdev info [%s]", err(ret));
00150 
00151   LINFO("Framegrabber board family %d, model %d, submodel %d", pxinfo.family, pxinfo.model, pxinfo.submodel);
00152   LINFO("Found %d units, frame buffer memory = %.4f Kbytes", pxinfo.nunits, float(pxinfo.memsize) / 1024);
00153   LINFO("Driver ID: %s", pxinfo.driverid);
00154   LINFO("Library ID: %s", pxinfo.libraryid);
00155 
00156   // get some info about the xcdev:
00157   struct xclib::xcdevinfo xcinfo;
00158   memset(&xcinfo, 0, sizeof(xcinfo)); xcinfo.ddch.len = sizeof(xcinfo); xcinfo.ddch.mos = XCMOS_DEVINFO;
00159   if (int ret = itsXclib.xcdev.getDevInfo(&itsXclib.xcdev, itsUnitMap, 0, &xcinfo) != 0)
00160     LERROR("Error trying to get xcdev info [%s]", err(ret));
00161   LINFO("PCI Bus %d, virq %d", xcinfo.pcibus, xcinfo.virq);
00162 
00163   // initialize pxvidstate
00164   statep = NULL; // needs to be NULL, will be allocated by allocStateCopy
00165   if (int ret = pxlib->allocStateCopy(pxlib, 0, 0, &statep))
00166     LFATAL("Allocate state copy (video state) error [%s]", err(ret));
00167 
00168   if (itsFormatFile.getVal().empty() == false) {
00169     if (int ret = pxlib->importStateCopy(pxlib, 0, 0, statep, 0, (char *)(itsFormatFile.getVal().c_str()), NULL))
00170       LFATAL("Import state copy (video state) from '%s' error [%s]", itsFormatFile.getVal().c_str(), err(ret));
00171   } else {
00172     if (int ret = pxlib->initStateCopy(pxlib, 0, 0, statep, &pxinfo, (char*)("default"), PXMODE_DIGI))
00173       LFATAL("Init state copy (video state) error [%s]", err(ret));
00174   }
00175 
00176   //! show some info of pxvidstate structure
00177   LINFO("pxvidimage bayerpattern: %d, %d, %d, %d, %d, %d",
00178         statep->vidimage->bp.order,
00179         statep->vidimage->bp.mode,
00180         statep->vidimage->bp.arg[0],
00181         statep->vidimage->bp.arg[1],
00182         statep->vidimage->bp.arg[2],
00183         statep->vidimage->bp.arg[3]);
00184 
00185   LINFO("pxvidimage colorspace: %d, %d, %d",
00186         statep->vidimage->cs.order,
00187         statep->vidimage->cs.mode,
00188         int(statep->vidimage->cs.scale));
00189 
00190   LINFO("pxvidimage whitebalance: %d, %d, %d",
00191         statep->vidimage->wb.order,
00192         statep->vidimage->wb.mode,
00193         int(statep->vidimage->wb.gamma[0][0]));
00194 
00195   LINFO("pxvidimage sharp: %d, %d, %d, %d, %d",
00196         statep->vidimage->sh.order,
00197         statep->vidimage->sh.mode,
00198         statep->vidimage->sh.scale,
00199         statep->vidimage->sh.into[0],
00200         statep->vidimage->sh.from[0]);
00201 
00202   // mess around with capture parameters -- I think this actually has no effect on the board!!
00203   /*
00204   for (int ii = 0; ii < 6; ++ii)
00205     for (int jj = 0; jj < 4; ++jj)
00206       {
00207         statep->vidimage->wb.gamma[ii][jj] = 100;
00208         statep->vidimage->wb.darkreference[ii][jj] = 30;
00209         statep->vidimage->wb.darktarget[ii][jj] = 30;
00210         statep->vidimage->wb.brightreference[ii][jj] = 120;
00211         statep->vidimage->wb.brighttarget[ii][jj] = 200;
00212       }
00213   LINFO("Gamma is %d", (int)statep->vidimage->wb.gamma[0][0]);
00214 
00215   statep->vidimage->wb.mode = 3;
00216   statep->vidimage->wb.order = 1;
00217 
00218   statep->vidimage->sh.order = 1;
00219   statep->vidimage->sh.mode = 3;
00220   statep->vidimage->sh.into[0] = 120;
00221   statep->vidimage->sh.into[1] = 120;
00222   statep->vidimage->sh.into[2] = 120;
00223   statep->vidimage->sh.from[0] = 200;
00224   statep->vidimage->sh.from[1] = 200;
00225   statep->vidimage->sh.from[2] = 200;
00226   statep->vidimage->sh.scale = 2;
00227   statep->vidimage->sh.arg[0] = 1;
00228   statep->vidimage->sh.arg[1] = 1;
00229 
00230   // re-define a "state" (with our itsStateid number) that captures the current modified settings;
00231   // will be needed later:
00232   pxlib->defineState(pxlib, 0, itsStateid, statep);
00233 
00234   // update the hardware config using our stateid:
00235   if (int ret = xcdev->setCameraConfig(xcdev, itsUnitMap, 0, itsStateid, NULL, NULL))
00236     LERROR("Set camera config error [%s]", err(ret));
00237   if (int ret = xcdev->setVideoConfig(xcdev, itsUnitMap, 0, itsStateid, NULL, NULL))
00238     LERROR("Set video configure error [%s]", err(ret));
00239 
00240   // export our state (debug):
00241   pxlib->exportStateCopy(pxlib, 0, itsStateid, NULL, 0, (char*)"trash_xc_format.txt", NULL, NULL, NULL);
00242   */
00243 
00244   // setup the camera for live capture of sequences of buffers:
00245   if (int ret = xcdev->setLiveSeqBuf(xcdev, itsUnitMap, 0, itsStateid, NULL, NULL, 1, nbuf, 1, 0, 1, 0) != 0)
00246     LFATAL("start capture error [%s]; the imaging board cannot work in live mode", err(ret));
00247   LINFO("Live capture starting with %d buffers...", nbuf);
00248 
00249   // Define grab region of interest (sub-window):
00250   xclib::pxywindow pxywin;
00251   pxywin.nw.x = itsOffset.getVal().w();
00252   pxywin.nw.y = itsOffset.getVal().h();
00253   pxywin.se.x = itsDims.getVal().w() + itsOffset.getVal().w();
00254   pxywin.se.y = itsDims.getVal().h() + itsOffset.getVal().h();
00255 
00256   // is the captured image base on byte or uint16 type
00257   const int dataMode = (itsBitDepth == 8 ? PXDATUINT8 : PXDATUINT16);
00258 
00259   // define a bunch of pximage buffers; these will allow us to transfer data from the device memory into main memory:
00260   LINFO("Allocating %d pximage structs for fast I/O transfers", nbuf);
00261   itsPximg = new struct xclib::pximage*[nbuf];
00262   for (int i = 0; i < nbuf; ++i) {
00263     // allocate and initialize each pximage:
00264     itsPximg[i] = new (struct xclib::pximage);
00265     if (int ret = pxlib->initPximage(pxlib, itsUnitMap, itsPximg[i], 1, PXHINTFRAME, 0, itsStateid, i+1, 0) < 1)
00266       LFATAL("Cannot allocate pximage %d/%d [%s]", i, nbuf, err(ret));
00267 
00268     // set the ROI window:
00269     (void)itsPximg[i]->xwind(itsPximg[i], &pxywin, int('s'));
00270 
00271     // setup buffer I/O access:
00272     if (int ret = itsPximg[i]->ioset(itsPximg[i], PXRXSCAN | PXIWRAP, dataMode, pixiemask) < 0)
00273       LFATAL("Cannot setup I/O access for pximage buffer %d/%d [%s]", i, nbuf, err(ret));
00274   }
00275 
00276   // show frame and window dims:
00277   xclib::pxywindow *pxyw = itsPximg[0]->xwind(itsPximg[0], NULL, 'i');
00278   LINFO("Native frame:   [%d .. %d] x [%d .. %d]", pxyw->nw.x, pxyw->se.x, pxyw->nw.y, pxyw->se.y);
00279   pxyw = itsPximg[0]->xwind(itsPximg[0], NULL, 'w');
00280   LINFO("Capture window: [%d .. %d] x [%d .. %d]", pxyw->nw.x, pxyw->se.x, pxyw->nw.y, pxyw->se.y);
00281 
00282   // make sure the camera starts to work for capture. Get the captured buffer ID:
00283   itsLastBuf = (xclib::pxbuffer_t)xcdev->getLiveStatus(xcdev, itsUnitMap, 0, PXVIST_DONE | PXVIST_BUFFER);
00284   LINFO("Waiting for grabber to start streaming...");
00285   while (itsLastBuf == 0) {
00286     usleep(XCWAIT);
00287     itsLastBuf = (xclib::pxbuffer_t)xcdev->getLiveStatus(xcdev, itsUnitMap, 0, PXVIST_DONE | PXVIST_BUFFER);
00288   }
00289   LINFO("Grabber streaming ok.");
00290 
00291   const unsigned int bufSz = itsDims.getVal().sz() * int(ceil(itsBitDepth / 8) * itsNumComp);
00292   itsImgBuf = (byte*)malloc(bufSz);
00293 
00294   itsCameraOk = true;
00295 
00296 #endif // HAVE_XCLIB
00297 }
00298 
00299 // ######################################################################
00300 void XCgrabber::stop2()
00301 {
00302 #ifndef HAVE_XCLIB
00303   // don't LFATAL() in stop() since it may be called in a destructor chain
00304   LERROR("you must have XC  support and the xclib library in order to use XCgrabber");
00305 #else
00306 
00307   if (itsCameraOk) { xclib::xclib_close(&itsXclib); itsCameraOk = false; }
00308   if (itsImgBuf) { free(itsImgBuf); itsImgBuf = NULL; }
00309   if (itsPximg) {
00310     for (int i = 0; i < itsNbuf.getVal(); ++i) delete itsPximg[i];
00311     delete [] itsPximg;
00312     itsPximg = NULL;
00313   }
00314 
00315 #endif // HAVE_XCLIB
00316 }
00317 
00318 // ######################################################################
00319 XCgrabber::~XCgrabber()
00320 { }
00321 
00322 // ######################################################################
00323 GenericFrameSpec XCgrabber::peekFrameSpec()
00324 {
00325   GenericFrameSpec result;
00326   result.nativeType = GenericFrame::VIDEO;
00327   result.videoFormat = itsGrabMode.getVal();
00328   result.videoByteSwap = itsByteSwap.getVal();
00329   result.dims = itsDims.getVal();
00330   result.floatFlags = 0;
00331   return result;
00332 }
00333 
00334 // ######################################################################
00335 SimTime XCgrabber::getNaturalFrameTime() const
00336 {
00337   return SimTime::HERTZ(itsFPS.getVal());
00338 }
00339 
00340 // ######################################################################
00341 GenericFrame XCgrabber::readFrame()
00342 {
00343   return GenericFrame(this->grabRaw());
00344 }
00345 
00346 // ######################################################################
00347 VideoFrame XCgrabber::grabRaw()
00348 {
00349 #ifndef HAVE_XCLIB
00350   LFATAL("you must have XC support and the xclib library in order to use XCgrabber");
00351   return VideoFrame();  /* can't happen */
00352 #else
00353   ASSERT(itsCameraOk);
00354 
00355   // shortcuts:
00356   struct xclib::xcdevservice *xcdev = &(itsXclib.xcdev);
00357 
00358   // get the captured buffer ID
00359   xclib::pxbuffer_t bufferID =
00360     (xclib::pxbuffer_t)xcdev->getLiveStatus(xcdev, itsUnitMap, 0, PXVIST_DONE | PXVIST_BUFFER);
00361   while (bufferID == itsLastBuf) {
00362     bufferID = (xclib::pxbuffer_t)xcdev->getLiveStatus(xcdev, itsUnitMap, 0, PXVIST_DONE | PXVIST_BUFFER);
00363     usleep(XCWAIT);
00364   }
00365 
00366   if (bufferID != (itsLastBuf % itsNbuf.getVal()) + 1)
00367     LERROR("Buffer mis-order (dropped frame)! last buf = %d, curr buf = %d", (int)itsLastBuf, (int)bufferID);
00368 
00369   pthread_mutex_lock(&qmutex_buf);
00370   itsLastBuf = bufferID;
00371   pthread_mutex_unlock(&qmutex_buf);
00372 
00373   const unsigned int bufSz = itsDims.getVal().sz() * int(ceil(itsBitDepth / 8)) * itsNumComp;
00374   const unsigned int imgSz = itsDims.getVal().sz();
00375 
00376   unsigned int readsz = itsPximg[bufferID-1]->ioread(itsPximg[bufferID-1], PXRXSCAN | PXIWRAP, itsImgBuf, bufSz, 0, 0);
00377   if (readsz != imgSz) {
00378     LFATAL("Error in reading frame buffer (size error), got %d, expected size = %d", readsz, imgSz);
00379     return VideoFrame();  // keep compiler happy
00380   }
00381 
00382   return VideoFrame(itsImgBuf, bufSz, itsDims.getVal(), itsGrabMode.getVal(), itsByteSwap.getVal(), false);
00383 
00384 #endif // HAVE_XCLIB
00385 }
00386 
00387 // ######################################################################
00388 void XCgrabber::paramChanged(ModelParamBase* const param,
00389                                    const bool valueChanged,
00390                                    ParamClient::ChangeStatus* status)
00391 {
00392 #ifndef HAVE_XCLIB
00393   LFATAL("you must have XC support and the xclib library in order to use XCgrabber");
00394 #else
00395   FrameIstream::paramChanged(param, valueChanged, status);
00396 #endif // HAVE_XCLIB
00397 }
00398 
00399 // ######################################################################
00400 #ifdef HAVE_XCLIB
00401 xclib::pxbuffer_t XCgrabber::getCurrBufID()
00402 {
00403   xclib::pxbuffer_t tmp;
00404   pthread_mutex_lock(&qmutex_buf);
00405   tmp = itsLastBuf;
00406   pthread_mutex_unlock(&qmutex_buf);
00407   return tmp;
00408 }
00409 #endif
00410 
00411 // ######################################################################
00412 const char* XCgrabber::err(const int errcode)
00413 {
00414 #ifdef HAVE_XCLIB
00415   return itsXclib.pxaux.errorCodeString(&itsXclib.pxaux, errcode);
00416 #else
00417   return NULL;
00418 #endif
00419 }
00420 
00421 // ######################################################################
00422 /* So things look consistent in everyone's emacs... */
00423 /* Local Variables: */
00424 /* indent-tabs-mode: nil */
00425 /* End: */
00426 
Generated on Sun May 8 08:40:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3