]> git.defcon.no Git - qopencamwidget/blobdiff - qopencamwidget.cpp
Updated structure of documentation. No need to include GDB includes and Qt Core/GUI...
[qopencamwidget] / qopencamwidget.cpp
index cd5d1b2ac24693956dd2d7443193ff03beba7b53..9b9146165ac9d230619a9332de1b5ef7b0bba4c3 100644 (file)
@@ -1,7 +1,6 @@
 /*
- This file is one part of two, that together make
- QOpenCamWidget, a Qt 4 widget that displays video input 
- from a webcam, along with an optional snapshot button.
+ This file is one part of two, that together make QOpenCamWidget, 
+ a Qt 4 widget that displays video input from a webcam.
 
  Copyright (C) 2009 Jon Langseth
 
  * This class solves the complexity of adding a webcam view,
  * by using the cross-platform available OpenCV library.
  *
- * Limitations, i.e. reasons to read this code and reimplement,
- * are: saving or streaming video is not really available (unless
- * you do repeated timer-triggered connections to the startSnap slot),
- * the widget size is identical to the video source dimensions (it
- * resizes the wodget using setMinimuSize to the video dimensions,
- * and does not handle resizing to sizes above this dimension.
+ * Limitations, i.e. reasons to read this code and reimplement, are: 
+ *
+ * \li saving or streaming video is not really available (unless you do 
+ *     repeated timer-triggered connections to the startSnap slot).
+ * \li this is a crude and simple implementation, created to solve
+ *     the problem of creating a "view-and-shoot" camera app.
+ *     If your needs are more complex than that, read the code,
+ *     and reimplement.
+ *
+ * Note that even tough the main file here totals some ~250 lines,
+ * only about 90 of those are actual code lines, and and even those
+ * contain a lot of "air"...
  *
  * A brief summary of how to use this class:
  * \code
  * QOpenCamWidget *cw = new QOpenCamWidget(this);
  * if ( cw->grabCapture(-1) ) {
- *   cw->setSnapshotVisible(true);
  *   cw->startCapture();
  * }
  * connect( cw, SIGNAL(imageReady(QImage)), this, SLOT(saveImage(QImage)));
+ * 
+ * QPushButton *trigger = new QPushButton(this);
+ * trigger->setText("Take picture");
+ * connect( trigger, SIGNAL(clicked()), cw, SLOT(startSnap()));
+ *
+ * \endcode
+ *
+ * Setting sizes is done during construction, and are not modifiable
+ * after the fact:
+ * \code
+ * QOpenCamWidget *cw = new QOpenCamWidget(this,
+ *                      new QSize(320, 240),
+ *                      new QSize(960, 720));
  * \endcode
  *
  * \param *parent The parent widget containing this widget, defaults to NULL.
+ * \param *viewSize The size of the image displayed, thus the size of the widget,
+ *          defaults to 640x480
+ * \param *resolution The actual resolution captured, and size of the snapshot
+ *          created, defaults t0 960x720, should be larger than viewSize
  *
  **/   
-QOpenCamWidget::QOpenCamWidget(QWidget *parent
+QOpenCamWidget::QOpenCamWidget(QWidget *parent, QSize *viewSize, QSize *resolution)
        : QWidget(parent) 
 {
-       // private CvCapture *nextFrame from class definition
+       // Setting sane default values (i.e. NULL) for 
+       // private CvCapture *nextFrame  and
+       // private QTimer    *frametimer from class definition
        nextFrame = NULL;
-       // private QTimer *frametimer from class definition
        frametimer = NULL;
-       // private QVBoxLayout *layout from class definition
-       layout = new QVBoxLayout(this);
-       
-       // private QLabel *canvas from class definition
-       canvas = new QLabel(this);
-       canvas->setMinimumSize(200, 100);
-       canvas->setAlignment(Qt::AlignCenter);
+        if ( viewSize == NULL )
+        {
+            vSize = new QSize(640, 480);
+        }
+        else vSize = viewSize;
+        if ( resolution == NULL )
+        {
+            res = new QSize(960, 720);
+        }
+        else res = resolution;
 
-       // private QPushButton *trigger from class definition
-       trigger = new QPushButton(this);
-       trigger->setText("Take picture");
-       trigger->setEnabled(false);
-       trigger->hide();
+        this->setMinimumSize(*vSize);
+        this->setMaximumSize(*vSize);
 
-       // private bool trigger_active from class definition
-       trigger_active = false;
-
-       layout->addWidget(canvas);
-       this->setLayout(layout);
 }
 
 QOpenCamWidget::~QOpenCamWidget(void)
 {
        cvReleaseCapture( &capture );
-       delete canvas;
-       delete trigger;
 }
 // ------------------------------------------------------------- //
 // Public methods (not signals/slots)
 // ------------------------------------------------------------- //
 
-/*! 
- * \brief Changes the visibility of the optional built-in "Take snapshot" button.
- *
- * The widget contains a push-button that optionally can be displayed. When
- * visible, this button is located at the bottom of the widget, and causes
- * the SLOT QOpenCamWidget::startSnap to be triggered when clicked.
- *
- * \param visible True makes the button display, and trigger, 
- *                false turns the feature off. False, i.e. no button, is default.
- * 
- **/
-void 
-QOpenCamWidget::setSnapshotVisible(bool visible)
-{
-       // Checking both parameter and private "sanity" variable,
-       // as a sanity- and error-control
-       if ( visible && !trigger_active )
-       {
-               connect( trigger, SIGNAL(clicked()), this, SLOT(startSnap()));
-               layout->addWidget(trigger);
-               trigger->show();
-               trigger_active = true;
-       }
-       if ( !visible && trigger_active )
-       {
-               layout->removeWidget(trigger);
-               disconnect( trigger, SIGNAL(clicked()), 0, 0 );
-               trigger->hide();
-               trigger_active = false;
-       }
-}
 /*!
  * \brief A paint event is a request to repaint all or part of a widget. 
  *
@@ -148,22 +132,19 @@ QOpenCamWidget::paintEvent ( QPaintEvent * event )
                
        if ( nextFrame )
        {
-               // Using this objects painter to draw the image
-               // causes a cute, but not desired effect..
-               //paint->drawImage(event->rect(), *nextFrame);
-
-               // Until I find a better solution on how to do the
-               // redraw of the image, setPixmap on the canvas
-               // does do the job. This may cause a performance
-               // penalty though, and is considered a FIXME
-               // Another drawback is that the widget does not resize..
-               canvas->setPixmap( QPixmap::fromImage(*nextFrame) );
+               // To make the widget as blazingly fast as possible
+               // we output the last captured frame direclty onto
+               // the widget area.
+                // It has been slowed down a bit by doing a resize tho...
+                paint->drawImage(event->rect(), nextFrame->scaled( vSize->width(), vSize->height() ));
        }
        else
        {
-               canvas->setText("No data, check/test camera");
+               paint->drawText(event->rect(),"No data, check/test camera");
        }
        paint->end();
+       // Clean up..
+       delete(paint);
 }
 
 
@@ -182,19 +163,17 @@ QOpenCamWidget::paintEvent ( QPaintEvent * event )
 bool 
 QOpenCamWidget::grabCapture(int source)
 {
-       capture = cvCaptureFromCAM(0);
+        capture = cvCreateCameraCapture(0);
        if (!capture)
        {
                qDebug() << "QOpenCamWidget::grabCapture(" << source << ") failed";
                return false;
        }
+        cvSetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH, res->width() );
+        cvSetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT, res->height() );
+
         cvGrabFrame(capture); // Grab a single frame, do resizing based on it.
         IplImage *image = cvRetrieveFrame(capture);
-        QSize t_size = QSize(image->width,image->height);
-
-        qDebug() << "Device image format: " << image->width << "x" << image->height;
-       canvas->setMinimumSize(t_size);
-       canvas->setMaximumSize(t_size);
 
        return true;
 }
@@ -217,9 +196,8 @@ void
 QOpenCamWidget::startCapture(void)
 {
        frametimer = new QTimer(this);
-        frametimer->start(70);
+        frametimer->start(50);
         connect(frametimer,SIGNAL(timeout()), this,SLOT(grabFrame()));
-       trigger->setEnabled(true);
 }
 
 /*!
@@ -238,15 +216,13 @@ QOpenCamWidget::startCapture(void)
  *
  **/
 QImage* 
-QOpenCamWidget::Ipl2QImage(const IplImage *img)
+QOpenCamWidget::Ipl2QImage(IplImage *img)
 {
-       IplImage *tmp=cvCloneImage(img);
-       cvConvertImage(img,tmp, CV_CVTIMG_SWAP_RB  );
-       QImage * qimage = new QImage(reinterpret_cast<uchar*>(tmp->imageData),
-                       tmp->width,
-                       tmp->height,
-                       3* tmp->width,
-                       QImage::Format_RGB888);
+       cvConvertImage(img,img, CV_CVTIMG_SWAP_RB);
+       QImage * qimage = new QImage(
+               reinterpret_cast<uchar*>(img->imageData),
+               img->width, img->height,
+               3* img->width, QImage::Format_RGB888);
        return qimage;
 
 }
@@ -265,16 +241,11 @@ QOpenCamWidget::Ipl2QImage(const IplImage *img)
  **/
 void QOpenCamWidget::grabFrame(void)
 {
-       if ( !capture )
-       {
-               qDebug() << "Capture device not ready!";
-               return;
-       }
+       if ( !capture ) { qDebug() << "Capture device not ready!"; return; }
 
        cvGrabFrame(capture);
 
        IplImage *iplimage = cvRetrieveFrame(capture);
-
        if (iplimage)
        {
                nextFrame = Ipl2QImage(iplimage);
@@ -283,6 +254,7 @@ void QOpenCamWidget::grabFrame(void)
        {
                nextFrame =  NULL;
        }
+
        update();
 }
 
@@ -293,11 +265,6 @@ void QOpenCamWidget::grabFrame(void)
  * stopped, and the last displayed frame is "captured", and made
  * available through the emitting of the class imageReady SIGNAL.
  *
- * With the "Take snapshot" button visible (setSnapshotVisible(true)),
- * this SLOT is triggered when the user clicks on the trigger button.
- * If you do not wish to use the internal trigger button, you
- * will have to add a different mechanism to trigger this SLOT.
- *
  * It is possible, though I would not recommend, to use repeated
  * triggering of this slot to do repeated frame-capture, and thus
  * make a form of "Animation" or "Video" capture.
@@ -309,8 +276,6 @@ void QOpenCamWidget::startSnap(void)
                if (frametimer->isActive())
                {
                        frametimer->stop();
-                       qDebug() << "SNAP!";
-
                        emit imageReady(QImage(*nextFrame));
                        frametimer->start();
                }