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