]> git.defcon.no Git - qopencamwidget/blob - qopencamwidget.cpp
Cleared out a load of uneeded stuff.
[qopencamwidget] / qopencamwidget.cpp
1 /*
2 This file is one part of two, that together make QOpenCamWidget,
3 a Qt 4 widget that displays video input from a webcam.
4
5 Copyright (C) 2009 Jon Langseth
6
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
10 of the License.
11
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.
16
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.
20 */
21
22 #include "qopencamwidget.h"
23
24 // ------------------------------------------------------------- //
25 // Constructor and Destructor
26 // ------------------------------------------------------------- //
27
28 /*!
29 * \brief Consctructs a QWidget based widget for displaying video
30 * coming from an OpenCV capture source
31 *
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.
35 *
36 * This class solves the complexity of adding a webcam view,
37 * by using the cross-platform available OpenCV library.
38 *
39 * Limitations, i.e. reasons to read this code and reimplement,
40 * are: saving or streaming video is not really available (unless
41 * you do repeated timer-triggered connections to the startSnap slot),
42 * the widget size is identical to the video source dimensions (it
43 * resizes the wodget using setMinimuSize to the video dimensions,
44 * and does not handle resizing to sizes above this dimension.
45 *
46 * A brief summary of how to use this class:
47 * \code
48 * QOpenCamWidget *cw = new QOpenCamWidget(this);
49 * if ( cw->grabCapture(-1) ) {
50 * cw->startCapture();
51 * }
52 * connect( cw, SIGNAL(imageReady(QImage)), this, SLOT(saveImage(QImage)));
53 *
54 * QPushButton *trigger = new QPushButton(this);
55 * trigger->setText("Take picture");
56 * connect( trigger, SIGNAL(clicked()), cw, SLOT(startSnap()));
57 *
58 * \endcode
59 *
60 * \param *parent The parent widget containing this widget, defaults to NULL.
61 *
62 **/
63 QOpenCamWidget::QOpenCamWidget(QWidget *parent)
64 : QWidget(parent)
65 {
66 // Setting sane default values (i.e. NULL) for
67 // private CvCapture *nextFrame and
68 // private QTimer *frametimer from class definition
69 nextFrame = NULL;
70 frametimer = NULL;
71 }
72
73 QOpenCamWidget::~QOpenCamWidget(void)
74 {
75 cvReleaseCapture( &capture );
76 }
77 // ------------------------------------------------------------- //
78 // Public methods (not signals/slots)
79 // ------------------------------------------------------------- //
80
81 /*!
82 * \brief A paint event is a request to repaint all or part of a widget.
83 *
84 * It can happen for one of the following reasons:
85 *
86 * \li repaint() or update() was invoked,
87 * \li the widget was obscured and has now been uncovered, or
88 * \li many other reasons.
89 *
90 * QOpenCamWidget uses the paintEvent to draw each frame onto the screen.
91 * The paintEvent itself is regularily triggered by explicit update()
92 * calls in QOpenCamWidget::grabFrame().
93 *
94 **/
95 void
96 QOpenCamWidget::paintEvent ( QPaintEvent * event )
97 {
98 QPainter * paint = new QPainter;
99 paint->begin(this);
100
101 if ( nextFrame )
102 {
103 // To make the widget as blazingly fast as possible
104 // we output the last captured frame direclty onto
105 // the widget area.
106 paint->drawImage(event->rect(), *nextFrame);
107 }
108 else
109 {
110 paint->drawText(event->rect(),"No data, check/test camera");
111 }
112 paint->end();
113 // Clean up..
114 delete(paint);
115 }
116
117
118 /*!
119 * \brief Grabs an OpenCV video capture source
120 *
121 * By grabbing a source, it is meant to open the capture source,
122 * and have it ready to start streaming/capturing frames.
123 * Returns true on success, false on error. The grabCapture
124 * is separated from the constructor and/or frame-grabbing, so that you
125 * may do the error-checking you really should do before proceeding.
126 *
127 * \param source The OpenCV capture source enumeration index to open
128 *
129 **/
130 bool
131 QOpenCamWidget::grabCapture(int source)
132 {
133 capture = cvCaptureFromCAM(0);
134 if (!capture)
135 {
136 qDebug() << "QOpenCamWidget::grabCapture(" << source << ") failed";
137 return false;
138 }
139 cvGrabFrame(capture); // Grab a single frame, do resizing based on it.
140 IplImage *image = cvRetrieveFrame(capture);
141 QSize t_size = QSize(image->width,image->height);
142
143 this->setMinimumSize(t_size);
144 this->setMaximumSize(t_size);
145
146 return true;
147 }
148
149 /*!
150 * \brief Starts up grabbing of video frames
151 *
152 * The actual grabbing and displaying of video frames is performed by
153 * a QTimer triggering the SLOT QOpenCamWidget::grabFrame().
154 * startCapture() sets up the timer running this captureFrame loop.
155 *
156 * The SLOT QOpenCamWidget::startSnap() is used to get image frames
157 * out from the widget for other uses, like saving or processing.
158 * This function relies on the timer created and configured by
159 * startCapture(), and as such, this function is the only permitted
160 * way to start the actual capture/streaming of video from the source.
161 *
162 **/
163 void
164 QOpenCamWidget::startCapture(void)
165 {
166 frametimer = new QTimer(this);
167 frametimer->start(50);
168 connect(frametimer,SIGNAL(timeout()), this,SLOT(grabFrame()));
169 }
170
171 /*!
172 * \brief Converts from the OpenCV IplImage data structure to a QImage
173 *
174 * OpenCV uses a data strcuture calles IplImage, optimized for
175 * computer vision image processing tasks. This code was adapted
176 * from kcamwidget.cpp, part of the KDE SVN at
177 * playground/multimedia/kcam/kcamwidget.cpp
178 *
179 * In regard that the IplImage can be forced into a format
180 * that aligns well with a RBG888-format, the conversion
181 * becomes one of the shortes, simples IplImage->QImage I've seen.
182 *
183 * \param *img The IplImage to be converted to a QImage.
184 *
185 **/
186 QImage*
187 QOpenCamWidget::Ipl2QImage(IplImage *img)
188 {
189 cvConvertImage(img,img, CV_CVTIMG_SWAP_RB);
190 QImage * qimage = new QImage(
191 reinterpret_cast<uchar*>(img->imageData),
192 img->width, img->height,
193 3* img->width, QImage::Format_RGB888);
194 return qimage;
195
196 }
197 // ------------------------------------------------------------- //
198 // Public SLOTS
199 // ------------------------------------------------------------- //
200
201 /*!
202 * \brief Grabs a frame and causes an update() when triggered.
203 *
204 * This is the SLOT that actually reads the video source and
205 * causes the widget to display live video. Preferably this
206 * slot will never be called my any other signal that a timeout()
207 * on the frametimer, which is controlled by QOpenCamWidget::startCapture()
208 *
209 **/
210 void QOpenCamWidget::grabFrame(void)
211 {
212 if ( !capture ) { qDebug() << "Capture device not ready!"; return; }
213
214 cvGrabFrame(capture);
215
216 IplImage *iplimage = cvRetrieveFrame(capture);
217 if (iplimage)
218 {
219 nextFrame = Ipl2QImage(iplimage);
220 }
221 else
222 {
223 nextFrame = NULL;
224 }
225
226 update();
227 }
228
229 /*!
230 * \brief Trigger this slot to save a frame from the widget.
231 *
232 * When this slot is triggered, the widgets capture loop is temporarily
233 * stopped, and the last displayed frame is "captured", and made
234 * available through the emitting of the class imageReady SIGNAL.
235 *
236 * It is possible, though I would not recommend, to use repeated
237 * triggering of this slot to do repeated frame-capture, and thus
238 * make a form of "Animation" or "Video" capture.
239 *
240 **/
241 void QOpenCamWidget::startSnap(void)
242 {
243 if ( frametimer ) {
244 if (frametimer->isActive())
245 {
246 frametimer->stop();
247 emit imageReady(QImage(*nextFrame));
248 frametimer->start();
249 }
250 }
251 }
252