1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2008, Nils Hasler, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 
42 // Author: Nils Hasler <hasler@mpi-inf.mpg.de>
43 //
44 //         Max-Planck-Institut Informatik
45 
46 //
47 // capture video from a sequence of images
48 // the filename when opening can either be a printf pattern such as
49 // video%04d.png or the first frame of the sequence i.e. video0001.png
50 //
51 
52 #include "precomp.hpp"
53 #include <sys/stat.h>
54 
55 #ifdef NDEBUG
56 #define CV_WARN(message)
57 #else
58 #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
59 #endif
60 
61 #ifndef _MAX_PATH
62 #define _MAX_PATH 1024
63 #endif
64 
65 class CvCapture_Images : public CvCapture
66 {
67 public:
CvCapture_Images()68     CvCapture_Images()
69     {
70         filename = 0;
71         currentframe = firstframe = 0;
72         length = 0;
73         frame = 0;
74     }
75 
~CvCapture_Images()76     virtual ~CvCapture_Images()
77     {
78         close();
79     }
80 
81     virtual bool open(const char* _filename);
82     virtual void close();
83     virtual double getProperty(int) const;
84     virtual bool setProperty(int, double);
85     virtual bool grabFrame();
86     virtual IplImage* retrieveFrame(int);
87 
88 protected:
89     char*  filename; // actually a printf-pattern
90     unsigned currentframe;
91     unsigned firstframe; // number of first frame
92     unsigned length; // length of sequence
93 
94     IplImage* frame;
95 };
96 
97 
close()98 void CvCapture_Images::close()
99 {
100     if( filename )
101     {
102         free(filename);
103         filename = 0;
104     }
105     currentframe = firstframe = 0;
106     length = 0;
107     cvReleaseImage( &frame );
108 }
109 
110 
grabFrame()111 bool CvCapture_Images::grabFrame()
112 {
113     char str[_MAX_PATH];
114     sprintf(str, filename, firstframe + currentframe);
115 
116     cvReleaseImage(&frame);
117     frame = cvLoadImage(str, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
118     if( frame )
119         currentframe++;
120 
121     return frame != 0;
122 }
123 
retrieveFrame(int)124 IplImage* CvCapture_Images::retrieveFrame(int)
125 {
126     return frame;
127 }
128 
getProperty(int id) const129 double CvCapture_Images::getProperty(int id) const
130 {
131     switch(id)
132     {
133     case CV_CAP_PROP_POS_MSEC:
134         CV_WARN("collections of images don't have framerates\n");
135         return 0;
136     case CV_CAP_PROP_POS_FRAMES:
137         return currentframe;
138     case CV_CAP_PROP_FRAME_COUNT:
139         return length;
140     case CV_CAP_PROP_POS_AVI_RATIO:
141         return (double)currentframe / (double)(length - 1);
142     case CV_CAP_PROP_FRAME_WIDTH:
143         return frame ? frame->width : 0;
144     case CV_CAP_PROP_FRAME_HEIGHT:
145         return frame ? frame->height : 0;
146     case CV_CAP_PROP_FPS:
147         CV_WARN("collections of images don't have framerates\n");
148         return 1;
149     case CV_CAP_PROP_FOURCC:
150         CV_WARN("collections of images don't have 4-character codes\n");
151         return 0;
152     }
153     return 0;
154 }
155 
setProperty(int id,double value)156 bool CvCapture_Images::setProperty(int id, double value)
157 {
158     switch(id)
159     {
160     case CV_CAP_PROP_POS_MSEC:
161     case CV_CAP_PROP_POS_FRAMES:
162         if(value < 0) {
163             CV_WARN("seeking to negative positions does not work - clamping\n");
164             value = 0;
165         }
166         if(value >= length) {
167             CV_WARN("seeking beyond end of sequence - clamping\n");
168             value = length - 1;
169         }
170         currentframe = cvRound(value);
171         return true;
172     case CV_CAP_PROP_POS_AVI_RATIO:
173         if(value > 1) {
174             CV_WARN("seeking beyond end of sequence - clamping\n");
175             value = 1;
176         } else if(value < 0) {
177             CV_WARN("seeking to negative positions does not work - clamping\n");
178             value = 0;
179         }
180         currentframe = cvRound((length - 1) * value);
181         return true;
182     }
183     CV_WARN("unknown/unhandled property\n");
184     return false;
185 }
186 
icvExtractPattern(const char * filename,unsigned * offset)187 static char* icvExtractPattern(const char *filename, unsigned *offset)
188 {
189     char *name = (char *)filename;
190 
191     if( !filename )
192         return 0;
193 
194     // check whether this is a valid image sequence filename
195     char *at = strchr(name, '%');
196     if(at)
197     {
198         int dummy;
199         if(sscanf(at + 1, "%ud", &dummy) != 1)
200             return 0;
201         name = strdup(filename);
202     }
203     else // no pattern filename was given - extract the pattern
204     {
205         at = name;
206 
207         // ignore directory names
208         char *slash = strrchr(at, '/');
209         if (slash) at = slash + 1;
210 
211 #ifdef _WIN32
212         slash = strrchr(at, '\\');
213         if (slash) at = slash + 1;
214 #endif
215 
216         while (*at && !isdigit(*at)) at++;
217 
218         if(!*at)
219             return 0;
220 
221         sscanf(at, "%u", offset);
222 
223         int size = (int)strlen(filename) + 20;
224         name = (char *)malloc(size);
225         strncpy(name, filename, at - filename);
226         name[at - filename] = 0;
227 
228         strcat(name, "%0");
229 
230         int i;
231         char *extension;
232         for(i = 0, extension = at; isdigit(at[i]); i++, extension++)
233             ;
234         char places[10];
235         sprintf(places, "%dd", i);
236 
237         strcat(name, places);
238         strcat(name, extension);
239     }
240 
241     return name;
242 }
243 
244 
open(const char * _filename)245 bool CvCapture_Images::open(const char * _filename)
246 {
247     unsigned offset = 0;
248     close();
249 
250     filename = icvExtractPattern(_filename, &offset);
251     if(!filename)
252         return false;
253 
254     // determine the length of the sequence
255     length = 0;
256     char str[_MAX_PATH];
257     for(;;)
258     {
259         sprintf(str, filename, offset + length);
260         struct stat s;
261         if(stat(str, &s))
262         {
263             if(length == 0 && offset == 0) // allow starting with 0 or 1
264             {
265                 offset++;
266                 continue;
267             }
268         }
269 
270         if(!cvHaveImageReader(str))
271             break;
272 
273         length++;
274     }
275 
276     if(length == 0)
277     {
278         close();
279         return false;
280     }
281 
282     firstframe = offset;
283     return true;
284 }
285 
286 
cvCreateFileCapture_Images(const char * filename)287 CvCapture* cvCreateFileCapture_Images(const char * filename)
288 {
289     CvCapture_Images* capture = new CvCapture_Images;
290 
291     if( capture->open(filename) )
292         return capture;
293 
294     delete capture;
295     return 0;
296 }
297 
298 //
299 //
300 // image sequence writer
301 //
302 //
303 class CvVideoWriter_Images : public CvVideoWriter
304 {
305 public:
CvVideoWriter_Images()306     CvVideoWriter_Images()
307     {
308         filename = 0;
309         currentframe = 0;
310     }
~CvVideoWriter_Images()311     virtual ~CvVideoWriter_Images() { close(); }
312 
313     virtual bool open( const char* _filename );
314     virtual void close();
315     virtual bool writeFrame( const IplImage* );
316 
317 protected:
318     char* filename;
319     unsigned currentframe;
320 };
321 
writeFrame(const IplImage * image)322 bool CvVideoWriter_Images::writeFrame( const IplImage* image )
323 {
324     char str[_MAX_PATH];
325     sprintf(str, filename, currentframe);
326     int ret = cvSaveImage(str, image);
327 
328     currentframe++;
329 
330     return ret > 0;
331 }
332 
close()333 void CvVideoWriter_Images::close()
334 {
335     if( filename )
336     {
337         free( filename );
338         filename = 0;
339     }
340     currentframe = 0;
341 }
342 
343 
open(const char * _filename)344 bool CvVideoWriter_Images::open( const char* _filename )
345 {
346     unsigned offset = 0;
347 
348     close();
349 
350     filename = icvExtractPattern(_filename, &offset);
351     if(!filename)
352         return false;
353 
354     char str[_MAX_PATH];
355     sprintf(str, filename, 0);
356     if(!cvHaveImageWriter(str))
357     {
358         close();
359         return false;
360     }
361 
362     currentframe = offset;
363     return true;
364 }
365 
366 
cvCreateVideoWriter_Images(const char * filename)367 CvVideoWriter* cvCreateVideoWriter_Images( const char* filename )
368 {
369     CvVideoWriter_Images *writer = new CvVideoWriter_Images;
370 
371     if( writer->open( filename ))
372         return writer;
373 
374     delete writer;
375     return 0;
376 }
377