PARP Research Group University of Murcia, Spain


src/qvio/qvcameraworker.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <QTimer>
00026 
00027 #include <QVImage>
00028 #include <qvio/qvcameraworker.h>
00029 #include <qvip/qvipp/qvipp.h>
00030 
00031 #define DEFAULT_IMAGE_SIZE 128
00032 
00033 QVCameraWorker::QVCameraWorker(QString name): QVWorker(name)
00034         {
00035         // Input properties:
00036         addProperty<bool>("NoLoop", inputFlag, FALSE,"If the camera should be opened in no loop mode");
00037         addProperty<QString>("URL", inputFlag, QString(""),"URL of the video source to read");
00038         addProperty<int>("Cols", inputFlag, 0, "Suggested number of columns of the video");
00039         addProperty<int>("Rows", inputFlag, 0, "Suggested number of rows of the video");
00040         // RealTime property is also input (and as such can be initialized using the command line), but invisible to the GUI
00041         // (because once the camera has been linked, it cannot be relinked changing its synchronism):
00042         addProperty<bool>("RealTime", inputFlag|guiInvisible, FALSE, "If the camera should be opened in real time mode");
00043 
00044         // Output integer and boolean properties:
00045         addProperty<bool>("Opened", outputFlag, FALSE, "If the camera is correctly opened and working");
00046         addProperty<int>("FPS", outputFlag, 0, "FPS of the video");
00047         addProperty<int>("Frames", outputFlag, 0, "Number of read frames");
00048         addProperty<int>("ColsR", outputFlag, 0, "Actual number of columns of the video");
00049         addProperty<int>("RowsR", outputFlag, 0, "Actual number of rows of the video");
00050 
00051         // Output image properties:
00052         addProperty< QVImage<uChar,3> >("RGB image", outputFlag, QVImage<uChar,3>(), "Last grabbed RGB image");
00053         addProperty< QVImage<uChar,1> >("Y channel image",outputFlag, QVImage<uChar,1>(), "Last grabbed Y channel image");
00054         addProperty< QVImage<uChar,1> >("U channel image",outputFlag, QVImage<uChar,1>(), "Last grabbed U channel image");
00055         addProperty< QVImage<uChar,1> >("V channel image",outputFlag, QVImage<uChar,1>(), "Last grabbed V channel image");
00056 
00057         // Trigger "Reopen":
00058         addTrigger("Reopen");
00059 
00060         // Initial images (only useful if first open fails, for a default set of images to be available...)
00061         imageY = QVImage<uChar>(DEFAULT_IMAGE_SIZE,DEFAULT_IMAGE_SIZE,DEFAULT_IMAGE_SIZE);
00062         imageU = QVImage<uChar>(DEFAULT_IMAGE_SIZE/2,DEFAULT_IMAGE_SIZE/2,DEFAULT_IMAGE_SIZE/2);
00063         imageV = QVImage<uChar>(DEFAULT_IMAGE_SIZE/2,DEFAULT_IMAGE_SIZE/2,DEFAULT_IMAGE_SIZE/2);
00064         Set(128,imageY);
00065         Set(128,imageU);
00066         Set(128,imageV);
00067         setPropertyValue< QVImage<uChar, 1> >("Y channel image", imageY);
00068         setPropertyValue< QVImage<uChar, 1> >("U channel image", imageU);
00069         setPropertyValue< QVImage<uChar, 1> >("V channel image", imageV);
00070         QVImage<uChar, 3> imageRGB(DEFAULT_IMAGE_SIZE,DEFAULT_IMAGE_SIZE);
00071         YUV420ToRGB(imageY, imageU, imageV, imageRGB);
00072         setPropertyValue< QVImage<uChar, 3> >("RGB image", imageRGB);
00073 
00074         }
00075 
00076 QVCameraWorker::~QVCameraWorker()
00077         {
00078         // closeCam() must be called in the destructor of the derived class, because it is virtual, and thus can't be
00079         // called by this base class destructor.
00080         }
00081 
00082 static inline int iRoundUp(int a, int b) {
00083   return (a % b == 0) ? a : b*(a / b + 1) ;
00084 }
00085 
00086 void QVCameraWorker::tryOpeningCam()
00087 {
00088         // We open the camera with the specified input properties, and update output properties accordingly:
00089         int cols, rows, fps;
00090 
00091         // Read current input properties:
00092         realTime = getPropertyValue<bool>("RealTime");
00093         noLoop = getPropertyValue<bool>("NoLoop");
00094         urlName = getPropertyValue<QString>("URL");
00095         cols =  getPropertyValue<int>("Cols");
00096         rows =  getPropertyValue<int>("Rows");
00097 
00098         // Virtual call; urlName is input parameter; cols and rows are input/output; fps is output.
00099         if(this->openCam(urlName,cols,rows,fps)) 
00100                 {
00101                 setPropertyValue<bool>("Opened",TRUE);
00102                 setPropertyValue<int>("ColsR",cols);
00103                 setPropertyValue<int>("RowsR",rows);
00104                 setPropertyValue<int>("FPS",fps);
00105                 setPropertyValue<int>("Frames",0);
00106                 imageY = QVImage<uChar>(cols, rows, iRoundUp(cols,8));
00107                 imageU = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00108                 imageV = QVImage<uChar>(cols/2, rows/2, iRoundUp(cols/2,8));
00109                 setPropertyValue< QVImage<uChar, 1> >("Y channel image", imageY);
00110                 setPropertyValue< QVImage<uChar, 1> >("U channel image", imageU);
00111                 setPropertyValue< QVImage<uChar, 1> >("V channel image", imageV);
00112                 setPropertyValue< QVImage<uChar, 3> >("RGB image", QVImage<uChar,3>(cols, rows, iRoundUp(3*cols,8)));
00113                 newGrabbedFrame = FALSE;
00114 
00115                 // If the camera is in real time mode, a single shot timer will do the grabbing job (this timer will
00116                 // always be relaunched after each grab()). Otherwise, the QVCameraWorker::iterate() will simply call 
00117                 // explicitly the grabFrame slot.
00118                 if (realTime)
00119                         QTimer::singleShot(0, this, SLOT(grabFrame()));  // Schedule first grabFrame()
00120 
00121                 // Once opened, the worker is ready to run (useful when reopening stopped cameras):
00122                 unPause();
00123                 }
00124         else    // If something fails when opening, we reset using resetCameraWorker():
00125                 resetCameraWorker();
00126 }
00127 
00128 void QVCameraWorker::resetCameraWorker()
00129         {
00130 
00131         // Flush any possible timer event pending:
00132         flush_pending_images = TRUE;
00133         while(qApp->hasPendingEvents ()) qApp->processEvents();
00134         flush_pending_images = FALSE;
00135 
00136         // Close camera ...
00137         this->closeCam(); // Virtual call.
00138 
00139         // ... reset output properties (except images and RowsR/ColsR, that are left untouched), ...
00140         setPropertyValue<bool>("Opened",FALSE);
00141         setPropertyValue<int>("FPS",0);
00142         setPropertyValue<int>("Frames",0);
00143 
00144         // ...and stop worker:
00145         stop();
00146         }
00147 
00148 
00149 bool QVCameraWorker::linkUnspecifiedOutputProperty(QVPropertyContainer *destinyContainer, QString destinyPropertyName)
00150         {
00151         // Asynchronous links for real time cameras, synchronous for non real time:
00152         LinkType linkType = getPropertyValue<bool>("RealTime") ? AsynchronousLink : SynchronousLink;
00153 
00154         // Link the destination image property, depending on the number of channels.
00155         if (destinyContainer->isType< QVImage<uChar, 3> >(destinyPropertyName))
00156                 return QVWorker::linkProperty("RGB image", destinyContainer, destinyPropertyName, linkType);
00157         else if (destinyContainer->isType< QVImage<uChar, 1> >(destinyPropertyName))
00158                 return QVWorker::linkProperty("Y channel image", destinyContainer, destinyPropertyName, linkType);
00159         else
00160                 {
00161                 qWarning() << "QVCameraWorker::linkUnspecifiedOutputProperty(): error, can't link property " << qPrintable(destinyPropertyName) << ".";
00162                 return false;
00163                 }
00164         }
00165 
00166 bool QVCameraWorker::linkUnspecifiedOutputProperty(QVPropertyContainer *destinyContainer, QString destinyPropertyName1, QString destinyPropertyName2, QString destinyPropertyName3)
00167         {
00168         // Asynchronous links for real time cameras, synchronous for non real time:
00169         LinkType linkType = getPropertyValue<bool>("RealTime") ? AsynchronousLink : SynchronousLink;
00170 
00171         bool ok = TRUE;
00172 
00173         // Link the destination image properties (must be one channel each)
00174         if (destinyContainer->isType< QVImage<uChar, 1> >(destinyPropertyName1))
00175                 if(not QVWorker::linkProperty("Y channel image", destinyContainer, destinyPropertyName1, linkType))
00176                         {
00177                         ok = FALSE;
00178                         qWarning() << "QVCameraWorker::linkUnspecifiedOutputProperty(): error, can't link Y property " << qPrintable(destinyPropertyName1) ;
00179                         }
00180         if (destinyContainer->isType< QVImage<uChar, 1> >(destinyPropertyName2))
00181                 if(not QVWorker::linkProperty("U channel image", destinyContainer, destinyPropertyName2, linkType))
00182                         {
00183                         ok = FALSE;
00184                         qWarning() << "QVCameraWorker::linkUnspecifiedOutputProperty(): error, can't link U property " << qPrintable(destinyPropertyName2) ;
00185                         }
00186         if (destinyContainer->isType< QVImage<uChar, 1> >(destinyPropertyName3))
00187                 if(not QVWorker::linkProperty("V channel image", destinyContainer, destinyPropertyName3, linkType))
00188                         {
00189                         ok = FALSE;
00190                         qWarning() << "QVCameraWorker::linkUnspecifiedOutputProperty(): error, can't link V property " << qPrintable(destinyPropertyName3) ;
00191                         }
00192 
00193         return ok;
00194         }
00195 
00196 
00197 void QVCameraWorker::grabFrame()
00198         {
00199         // Virtual call; imageY, imageU and imageV are output parameters.
00200         if(this->grab(imageY,imageU,imageV))
00201                 {
00202                 setPropertyValue<int>("Frames",getPropertyValue<int>("Frames")+1);
00203                 newGrabbedFrame = TRUE;
00204 
00205                 // Post following timer event to schedule next grabbing (except if we are flushing images out for closing).
00206                 if(realTime and not flush_pending_images)
00207                         QTimer::singleShot(0, this, SLOT(grabFrame()));
00208                 }
00209         else
00210                 resetCameraWorker();
00211         }
00212 
00213 void QVCameraWorker::iterate()
00214         {
00215         // Try opening camera if first iteration (performed here, instead of the constructor, to assure 
00216         // that openCam() is executed always in this thread.
00217         if(getIteration()==0)
00218                 tryOpeningCam();
00219 
00220         // Needed for not try to grab from closed (stoped) cameras:
00221         if(isStoped()) return; 
00222 
00223         // If the camera is in real time mode, the timer should have called the slot for us, so we do not have to do it
00224         // explicitly. Otherwise, we call grabFrame();
00225         if (not realTime)
00226                 grabFrame();
00227 
00228         setPropertyValue< QVImage<uChar, 1> >("Y channel image", imageY);
00229         setPropertyValue< QVImage<uChar, 1> >("U channel image", imageU);
00230         setPropertyValue< QVImage<uChar, 1> >("V channel image", imageV);
00231         newGrabbedFrame = FALSE;
00232 
00233         if (isLinkedOutput("RGB image"))
00234                 {
00235                 QVImage<uChar, 3> imageRGB(imageY.getCols(),imageY.getRows());
00236                 YUV420ToRGB(imageY, imageU, imageV, imageRGB);
00237                 setPropertyValue< QVImage<uChar, 3> >("RGB image", imageRGB);
00238                 }
00239 
00240         }
00241 
00242 void QVCameraWorker::processTrigger(QString str)
00243         {
00244         if(str=="Reopen")
00245                 {
00246                 // When reopening, we must reset the camera worker ...
00247                 resetCameraWorker();
00248                 // ... and open the camera again using the new input properties.
00249                 readInputProperties();
00250                 tryOpeningCam();
00251                 }
00252         }



QVision framework. PARP research group, copyright 2007, 2008.