Subversion Repositories OpenCV2-Cookbook

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 PointedEar 1
/*------------------------------------------------------------------------------------------*\
2
   This file contains material supporting chapter 10 of the cookbook:  
3
   Computer Vision Programming using the OpenCV Library.
4
   by Robert Laganiere, Packt Publishing, 2011.
5
 
6
   This program is free software; permission is hereby granted to use, copy, modify,
7
   and distribute this source code, or portions thereof, for any purpose, without fee,
8
   subject to the restriction that the copyright notice may not be removed
9
   or altered from any source or altered source distribution.
10
   The software is released on an as-is basis and without any warranties of any kind.
11
   In particular, the software is not guaranteed to be fault-tolerant or free from failure.
12
   The author disclaims all warranties with regard to this software, any use,
13
   and any consequent failure, is purely the responsibility of the user.
14
 
15
   Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
16
\*------------------------------------------------------------------------------------------*/
17
 
18
#if !defined VPROCESSOR
19
#define VPROCESSOR
20
 
21
#include <iostream>
22
#include <iomanip>
23
#include <sstream>
24
#include <string>
25
#include <vector>
26
#include <opencv2/core/core.hpp>
27
#include <opencv2/highgui/highgui.hpp>
28
 
29
// The frame processor interface
30
class FrameProcessor {
31
 
32
  public:
33
        // processing method
34
        virtual void process(cv:: Mat &input, cv:: Mat &output)= 0;
35
};
36
 
37
class VideoProcessor {
38
 
39
  private:
40
 
41
          // the OpenCV video capture object
42
          cv::VideoCapture capture;
43
          // the callback function to be called 
44
          // for the processing of each frame
45
          void (*process)(cv::Mat&, cv::Mat&);
46
          // the pointer to the class implementing 
47
          // the FrameProcessor interface
48
          FrameProcessor *frameProcessor;
49
          // a bool to determine if the 
50
          // process callback will be called
51
          bool callIt;
52
          // Input display window name
53
          std::string windowNameInput;
54
          // Output display window name
55
          std::string windowNameOutput;
56
          // delay between each frame processing
57
          int delay;
58
          // number of processed frames 
59
          long fnumber;
60
          // stop at this frame number
61
          long frameToStop;
62
          // to stop the processing
63
          bool stop;
64
 
65
          // vector of image filename to be used as input
66
          std::vector<std::string> images;
67
          // image vector iterator
68
          std::vector<std::string>::const_iterator itImg;
69
 
70
          // the OpenCV video writer object
71
          cv::VideoWriter writer;
72
          // output filename
73
          std::string outputFile;
74
 
75
          // current index for output images
76
          int currentIndex;
77
          // number of digits in output image filename
78
          int digits;
79
          // extension of output images
80
          std::string extension;
81
 
82
          // to get the next frame 
83
          // could be: video file; camera; vector of images
84
          bool readNextFrame(cv::Mat& frame) {
85
 
86
                  if (images.size()==0)
87
                          return capture.read(frame);
88
                  else {
89
 
90
                          if (itImg != images.end()) {
91
 
92
                                  frame= cv::imread(*itImg);
93
                                  itImg++;
94
                                  return frame.data != 0;
95
                          }
96
                  }
97
          }
98
 
99
          // to write the output frame 
100
          // could be: video file or images
101
          void writeNextFrame(cv::Mat& frame) {
102
 
103
                  if (extension.length()) { // then we write images
104
 
105
                          std::stringstream ss;
106
                      ss << outputFile << std::setfill('0') << std::setw(digits) << currentIndex++ << extension;
107
                          cv::imwrite(ss.str(),frame);
108
 
109
                  } else { // then write video file
110
 
111
                          writer.write(frame);
112
                  }
113
          }
114
 
115
  public:
116
 
117
          // Constructor setting the default values
118
          VideoProcessor() : callIt(false), delay(-1),
119
                  fnumber(0), stop(false), digits(0), frameToStop(-1),
120
              process(0), frameProcessor(0) {}
121
 
122
          // set the name of the video file
123
          bool setInput(std::string filename) {
124
 
125
                fnumber= 0;
126
                // In case a resource was already 
127
                // associated with the VideoCapture instance
128
                capture.release();
129
                images.clear();
130
 
131
                // Open the video file
132
                return capture.open(filename);
133
          }
134
 
135
          // set the camera ID
136
          bool setInput(int id) {
137
 
138
                fnumber= 0;
139
                // In case a resource was already 
140
                // associated with the VideoCapture instance
141
                capture.release();
142
                images.clear();
143
 
144
                // Open the video file
145
                return capture.open(id);
146
          }
147
 
148
          // set the vector of input images
149
          bool setInput(const std::vector<std::string>& imgs) {
150
 
151
                fnumber= 0;
152
                // In case a resource was already 
153
                // associated with the VideoCapture instance
154
                capture.release();
155
 
156
                // the input will be this vector of images
157
                images= imgs;
158
                itImg= images.begin();
159
 
160
                return true;
161
          }
162
 
163
          // set the output video file
164
          // by default the same parameters than input video will be used
165
          bool setOutput(const std::string &filename, int codec=0, double framerate=0.0, bool isColor=true) {
166
 
167
                  outputFile= filename;
168
                  extension.clear();
169
 
170
                  if (framerate==0.0)
171
                          framerate= getFrameRate(); // same as input
172
 
173
                  char c[4];
174
                  // use same codec as input
175
                  if (codec==0) {
176
                          codec= getCodec(c);
177
                  }
178
 
179
                  // Open output video
180
                  return writer.open(outputFile, // filename
181
                          codec, // codec to be used 
182
                          framerate,      // frame rate of the video
183
                          getFrameSize(), // frame size
184
                          isColor);       // color video?
185
          }
186
 
187
          // set the output as a series of image files
188
          // extension must be ".jpg", ".bmp" ...
189
          bool setOutput(const std::string &filename, // filename prefix
190
                  const std::string &ext, // image file extension 
191
                  int numberOfDigits=3,   // number of digits
192
                  int startIndex=0) {     // start index
193
 
194
                  // number of digits must be positive
195
                  if (numberOfDigits<0)
196
                          return false;
197
 
198
                  // filenames and their common extension
199
                  outputFile= filename;
200
                  extension= ext;
201
 
202
                  // number of digits in the file numbering scheme
203
                  digits= numberOfDigits;
204
                  // start numbering at this index
205
                  currentIndex= startIndex;
206
 
207
                  return true;
208
          }
209
 
210
          // set the callback function that will be called for each frame
211
          void setFrameProcessor(void (*frameProcessingCallback)(cv::Mat&, cv::Mat&)) {
212
 
213
                  // invalidate frame processor class instance
214
                  frameProcessor= 0;
215
                  // this is the frame processor function that will be called
216
                  process= frameProcessingCallback;
217
                  callProcess();
218
          }
219
 
220
          // set the instance of the class that implements the FrameProcessor interface
221
          void setFrameProcessor(FrameProcessor* frameProcessorPtr) {
222
 
223
                  // invalidate callback function
224
                  process= 0;
225
                  // this is the frame processor instance that will be called
226
                  frameProcessor= frameProcessorPtr;
227
                  callProcess();
228
          }
229
 
230
          // stop streaming at this frame number
231
          void stopAtFrameNo(long frame) {
232
 
233
                  frameToStop= frame;
234
          }
235
 
236
          // process callback to be called
237
          void callProcess() {
238
 
239
                  callIt= true;
240
          }
241
 
242
          // do not call process callback
243
          void dontCallProcess() {
244
 
245
                  callIt= false;
246
          }
247
 
248
          // to display the processed frames
249
          void displayInput(std::string wn) {
250
 
251
                  windowNameInput= wn;
252
                  cv::namedWindow(windowNameInput);
253
          }
254
 
255
          // to display the processed frames
256
          void displayOutput(std::string wn) {
257
 
258
                  windowNameOutput= wn;
259
                  cv::namedWindow(windowNameOutput);
260
          }
261
 
262
          // do not display the processed frames
263
          void dontDisplay() {
264
 
265
                  cv::destroyWindow(windowNameInput);
266
                  cv::destroyWindow(windowNameOutput);
267
                  windowNameInput.clear();
268
                  windowNameOutput.clear();
269
          }
270
 
271
          // set a delay between each frame
272
          // 0 means wait at each frame
273
          // negative means no delay
274
          void setDelay(int d) {
275
 
276
                  delay= d;
277
          }
278
 
279
          // a count is kept of the processed frames
280
          long getNumberOfProcessedFrames() {
281
 
282
                  return fnumber;
283
          }
284
 
285
          // return the size of the video frame
286
          cv::Size getFrameSize() {
287
 
288
                if (images.size()==0) {
289
 
290
                        // get size of from the capture device
291
                        int w= static_cast<int>(capture.get(CV_CAP_PROP_FRAME_WIDTH));
292
                        int h= static_cast<int>(capture.get(CV_CAP_PROP_FRAME_HEIGHT));
293
 
294
                        return cv::Size(w,h);
295
 
296
                } else { // if input is vector of images
297
 
298
                        cv::Mat tmp= cv::imread(images[0]);
299
                        if (!tmp.data) return cv::Size(0,0);
300
                        else return tmp.size();
301
                }
302
          }
303
 
304
          // return the frame number of the next frame
305
          long getFrameNumber() {
306
 
307
                if (images.size()==0) {
308
 
309
                        // get info of from the capture device
310
                    long f= static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));
311
                    return f;
312
 
313
                } else { // if input is vector of images
314
 
315
                        return static_cast<long>(itImg-images.begin());
316
                }
317
          }
318
 
319
          // return the position in ms
320
          double getPositionMS() {
321
 
322
                  // undefined for vector of images
323
                  if (images.size()!=0) return 0.0;
324
 
325
                  double t= capture.get(CV_CAP_PROP_POS_MSEC);
326
                  return t;
327
          }
328
 
329
          // return the frame rate
330
          double getFrameRate() {
331
 
332
                  // undefined for vector of images
333
                  if (images.size()!=0) return 0;
334
 
335
                  double r= capture.get(CV_CAP_PROP_FPS);
336
                  return r;
337
          }
338
 
339
          // return the number of frames in video
340
          long getTotalFrameCount() {
341
 
342
                  // for vector of images
343
                  if (images.size()!=0) return images.size();
344
 
345
                  long t= capture.get(CV_CAP_PROP_FRAME_COUNT);
346
                  return t;
347
          }
348
 
349
          // get the codec of input video
350
          int getCodec(char codec[4]) {
351
 
352
                  // undefined for vector of images
353
                  if (images.size()!=0) return -1;
354
 
355
                  union {
356
                          int value;
357
                          char code[4]; } returned;
358
 
359
                  returned.value= static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
360
 
361
                  codec[0]= returned.code[0];
362
                  codec[1]= returned.code[1];
363
                  codec[2]= returned.code[2];
364
                  codec[3]= returned.code[3];
365
 
366
                  return returned.value;
367
          }
368
 
369
          // go to this frame number
370
          bool setFrameNumber(long pos) {
371
 
372
                  // for vector of images
373
                  if (images.size()!=0) {
374
 
375
                          // move to position in vector
376
                          itImg= images.begin() + pos;
377
                          // is it a valid position?
378
                          if (pos < images.size())
379
                                  return true;
380
                          else
381
                                  return false;
382
 
383
                  } else { // if input is a capture device
384
 
385
                        return capture.set(CV_CAP_PROP_POS_FRAMES, pos);
386
                  }
387
          }
388
 
389
          // go to this position
390
          bool setPositionMS(double pos) {
391
 
392
                  // not defined in vector of images
393
                  if (images.size()!=0)
394
                          return false;
395
                  else
396
                      return capture.set(CV_CAP_PROP_POS_MSEC, pos);
397
          }
398
 
399
          // go to this position expressed in fraction of total film length
400
          bool setRelativePosition(double pos) {
401
 
402
                  // for vector of images
403
                  if (images.size()!=0) {
404
 
405
                          // move to position in vector
406
                          long posI= static_cast<long>(pos*images.size()+0.5);
407
                          itImg= images.begin() + posI;
408
                          // is it a valid position?
409
                          if (posI < images.size())
410
                                  return true;
411
                          else
412
                                  return false;
413
 
414
                  } else { // if input is a capture device
415
 
416
                          return capture.set(CV_CAP_PROP_POS_AVI_RATIO, pos);
417
                  }
418
          }
419
 
420
          // Stop the processing
421
          void stopIt() {
422
 
423
                  stop= true;
424
          }
425
 
426
          // Is the process stopped?
427
          bool isStopped() {
428
 
429
                  return stop;
430
          }
431
 
432
          // Is a capture device opened?
433
          bool isOpened() {
434
 
435
                  return capture.isOpened() || !images.empty();
436
          }
437
 
438
          // to grab (and process) the frames of the sequence
439
          void run() {
440
 
441
                  // current frame
442
                  cv::Mat frame;
443
                  // output frame
444
                  cv::Mat output;
445
 
446
                  // if no capture device has been set
447
                  if (!isOpened())
448
                          return;
449
 
450
                  stop= false;
451
 
452
                  while (!isStopped()) {
453
 
454
                          // read next frame if any
455
                          if (!readNextFrame(frame))
456
                                  break;
457
 
458
                          // display input frame
459
                          if (windowNameInput.length()!=0)
460
                                  cv::imshow(windowNameInput,frame);
461
 
462
                      // calling the process function or method
463
                          if (callIt) {
464
 
465
                                // process the frame
466
                                if (process)
467
                                    process(frame, output);
468
                                else if (frameProcessor)
469
                                        frameProcessor->process(frame,output);
470
                                // increment frame number
471
                            fnumber++;
472
 
473
                          } else {
474
 
475
                                output= frame;
476
                          }
477
 
478
                          // write output sequence
479
                          if (outputFile.length()!=0)
480
                                  writeNextFrame(output);
481
 
482
                          // display output frame
483
                          if (windowNameOutput.length()!=0)
484
                                  cv::imshow(windowNameOutput,output);
485
 
486
                          // introduce a delay
487
                          if (delay>=0 && cv::waitKey(delay)>=0)
488
                                stopIt();
489
 
490
                          // check if we should stop
491
                          if (frameToStop>=0 && getFrameNumber()==frameToStop)
492
                                  stopIt();
493
                  }
494
          }
495
};
496
 
497
#endif