]>
git.defcon.no Git - qopencamwidget/blob - qopencamwidget.cpp
2 This file is one part of two, that together make QOpenCamWidget,
3 a Qt 4 widget that displays video input from a webcam.
5 Copyright (C) 2009 Jon Langseth
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation in its version 2
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "qopencamwidget.h"
24 // ------------------------------------------------------------- //
25 // Constructor and Destructor
26 // ------------------------------------------------------------- //
29 * \brief Consctructs a QWidget based widget for displaying video
30 * coming from an OpenCV capture source
32 * Including webcam data in a Qt application can be problematic,
33 * at least as long as Phonon does not support webcams, and the
34 * Phonon GStreamer backend only supports simple pipelines.
36 * This class solves the complexity of adding a webcam view,
37 * by using the cross-platform available OpenCV library.
39 * Limitations, i.e. reasons to read this code and reimplement, are:
41 * \li saving or streaming video is not really available (unless you do
42 * repeated timer-triggered connections to the startSnap slot).
43 * \li this is a crude and simple implementation, created to solve
44 * the problem of creating a "view-and-shoot" camera app.
45 * If your needs are more complex than that, read the code,
48 * Note that even tough the main file here totals some ~250 lines,
49 * only about 90 of those are actual code lines, and and even those
50 * contain a lot of "air"...
52 * A brief summary of how to use this class:
54 * QOpenCamWidget *cw = new QOpenCamWidget(this);
55 * if ( cw->grabCapture(-1) ) {
58 * connect( cw, SIGNAL(imageReady(QImage)), this, SLOT(saveImage(QImage)));
60 * QPushButton *trigger = new QPushButton(this);
61 * trigger->setText("Take picture");
62 * connect( trigger, SIGNAL(clicked()), cw, SLOT(startSnap()));
66 * \param *parent The parent widget containing this widget, defaults to NULL.
69 QOpenCamWidget::QOpenCamWidget(QWidget
*parent
)
72 // Setting sane default values (i.e. NULL) for
73 // private CvCapture *nextFrame and
74 // private QTimer *frametimer from class definition
79 QOpenCamWidget::~QOpenCamWidget(void)
81 cvReleaseCapture( &capture
);
83 // ------------------------------------------------------------- //
84 // Public methods (not signals/slots)
85 // ------------------------------------------------------------- //
88 * \brief A paint event is a request to repaint all or part of a widget.
90 * It can happen for one of the following reasons:
92 * \li repaint() or update() was invoked,
93 * \li the widget was obscured and has now been uncovered, or
94 * \li many other reasons.
96 * QOpenCamWidget uses the paintEvent to draw each frame onto the screen.
97 * The paintEvent itself is regularily triggered by explicit update()
98 * calls in QOpenCamWidget::grabFrame().
102 QOpenCamWidget::paintEvent ( QPaintEvent
* event
)
104 QPainter
* paint
= new QPainter
;
109 // To make the widget as blazingly fast as possible
110 // we output the last captured frame direclty onto
112 paint
->drawImage(event
->rect(), *nextFrame
);
116 paint
->drawText(event
->rect(),"No data, check/test camera");
125 * \brief Grabs an OpenCV video capture source
127 * By grabbing a source, it is meant to open the capture source,
128 * and have it ready to start streaming/capturing frames.
129 * Returns true on success, false on error. The grabCapture
130 * is separated from the constructor and/or frame-grabbing, so that you
131 * may do the error-checking you really should do before proceeding.
133 * \param source The OpenCV capture source enumeration index to open
137 QOpenCamWidget::grabCapture(int source
)
139 capture
= cvCreateCameraCapture(0);
142 qDebug() << "QOpenCamWidget::grabCapture(" << source
<< ") failed";
145 cvSetCaptureProperty( capture
, CV_CAP_PROP_FRAME_WIDTH
, 960 );
146 cvSetCaptureProperty( capture
, CV_CAP_PROP_FRAME_HEIGHT
, 720 );
148 cvGrabFrame(capture
); // Grab a single frame, do resizing based on it.
149 IplImage
*image
= cvRetrieveFrame(capture
);
150 QSize t_size
= QSize(image
->width
,image
->height
);
152 this->setMinimumSize(t_size
);
153 this->setMaximumSize(t_size
);
159 * \brief Starts up grabbing of video frames
161 * The actual grabbing and displaying of video frames is performed by
162 * a QTimer triggering the SLOT QOpenCamWidget::grabFrame().
163 * startCapture() sets up the timer running this captureFrame loop.
165 * The SLOT QOpenCamWidget::startSnap() is used to get image frames
166 * out from the widget for other uses, like saving or processing.
167 * This function relies on the timer created and configured by
168 * startCapture(), and as such, this function is the only permitted
169 * way to start the actual capture/streaming of video from the source.
173 QOpenCamWidget::startCapture(void)
175 frametimer
= new QTimer(this);
176 frametimer
->start(50);
177 connect(frametimer
,SIGNAL(timeout()), this,SLOT(grabFrame()));
181 * \brief Converts from the OpenCV IplImage data structure to a QImage
183 * OpenCV uses a data strcuture calles IplImage, optimized for
184 * computer vision image processing tasks. This code was adapted
185 * from kcamwidget.cpp, part of the KDE SVN at
186 * playground/multimedia/kcam/kcamwidget.cpp
188 * In regard that the IplImage can be forced into a format
189 * that aligns well with a RBG888-format, the conversion
190 * becomes one of the shortes, simples IplImage->QImage I've seen.
192 * \param *img The IplImage to be converted to a QImage.
196 QOpenCamWidget::Ipl2QImage(IplImage
*img
)
198 cvConvertImage(img
,img
, CV_CVTIMG_SWAP_RB
);
199 QImage
* qimage
= new QImage(
200 reinterpret_cast<uchar
*>(img
->imageData
),
201 img
->width
, img
->height
,
202 3* img
->width
, QImage::Format_RGB888
);
206 // ------------------------------------------------------------- //
208 // ------------------------------------------------------------- //
211 * \brief Grabs a frame and causes an update() when triggered.
213 * This is the SLOT that actually reads the video source and
214 * causes the widget to display live video. Preferably this
215 * slot will never be called my any other signal that a timeout()
216 * on the frametimer, which is controlled by QOpenCamWidget::startCapture()
219 void QOpenCamWidget::grabFrame(void)
221 if ( !capture
) { qDebug() << "Capture device not ready!"; return; }
223 cvGrabFrame(capture
);
225 IplImage
*iplimage
= cvRetrieveFrame(capture
);
228 nextFrame
= Ipl2QImage(iplimage
);
239 * \brief Trigger this slot to save a frame from the widget.
241 * When this slot is triggered, the widgets capture loop is temporarily
242 * stopped, and the last displayed frame is "captured", and made
243 * available through the emitting of the class imageReady SIGNAL.
245 * It is possible, though I would not recommend, to use repeated
246 * triggering of this slot to do repeated frame-capture, and thus
247 * make a form of "Animation" or "Video" capture.
250 void QOpenCamWidget::startSnap(void)
253 if (frametimer
->isActive())
256 emit
imageReady(QImage(*nextFrame
));