Add OpenCV source code
[platform/upstream/opencv.git] / modules / highgui / src / cap_images.cpp
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:
68     CvCapture_Images()
69     {
70         filename = 0;
71         currentframe = firstframe = 0;
72         length = 0;
73         frame = 0;
74     }
75
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);
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
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
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
124 IplImage* CvCapture_Images::retrieveFrame(int)
125 {
126     return frame;
127 }
128
129 double CvCapture_Images::getProperty(int id)
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_POS_AVI_RATIO:
139         return (double)currentframe / (double)(length - 1);
140     case CV_CAP_PROP_FRAME_WIDTH:
141         return frame ? frame->width : 0;
142     case CV_CAP_PROP_FRAME_HEIGHT:
143         return frame ? frame->height : 0;
144     case CV_CAP_PROP_FPS:
145         CV_WARN("collections of images don't have framerates\n");
146         return 1;
147     case CV_CAP_PROP_FOURCC:
148         CV_WARN("collections of images don't have 4-character codes\n");
149         return 0;
150     }
151     return 0;
152 }
153
154 bool CvCapture_Images::setProperty(int id, double value)
155 {
156     switch(id)
157     {
158     case CV_CAP_PROP_POS_MSEC:
159     case CV_CAP_PROP_POS_FRAMES:
160         if(value < 0) {
161             CV_WARN("seeking to negative positions does not work - clamping\n");
162             value = 0;
163         }
164         if(value >= length) {
165             CV_WARN("seeking beyond end of sequence - clamping\n");
166             value = length - 1;
167         }
168         currentframe = cvRound(value);
169         return true;
170     case CV_CAP_PROP_POS_AVI_RATIO:
171         if(value > 1) {
172             CV_WARN("seeking beyond end of sequence - clamping\n");
173             value = 1;
174         } else if(value < 0) {
175             CV_WARN("seeking to negative positions does not work - clamping\n");
176             value = 0;
177         }
178         currentframe = cvRound((length - 1) * value);
179         return true;
180     }
181     CV_WARN("unknown/unhandled property\n");
182     return false;
183 }
184
185 static char* icvExtractPattern(const char *filename, unsigned *offset)
186 {
187     char *name = (char *)filename;
188
189     if( !filename )
190         return 0;
191
192     // check whether this is a valid image sequence filename
193     char *at = strchr(name, '%');
194     if(at)
195     {
196         int dummy;
197         if(sscanf(at + 1, "%ud", &dummy) != 1)
198             return 0;
199         name = strdup(filename);
200     }
201     else // no pattern filename was given - extract the pattern
202     {
203         at = name;
204
205         // ignore directory names
206         char *slash = strrchr(at, '/');
207         if (slash) at = slash + 1;
208
209 #ifdef _WIN32
210         slash = strrchr(at, '\\');
211         if (slash) at = slash + 1;
212 #endif
213
214         while (*at && !isdigit(*at)) at++;
215
216         if(!*at)
217             return 0;
218
219         sscanf(at, "%u", offset);
220
221         int size = (int)strlen(filename) + 20;
222         name = (char *)malloc(size);
223         strncpy(name, filename, at - filename);
224         name[at - filename] = 0;
225
226         strcat(name, "%0");
227
228         int i;
229         char *extension;
230         for(i = 0, extension = at; isdigit(at[i]); i++, extension++)
231             ;
232         char places[10];
233         sprintf(places, "%dd", i);
234
235         strcat(name, places);
236         strcat(name, extension);
237     }
238
239     return name;
240 }
241
242
243 bool CvCapture_Images::open(const char * _filename)
244 {
245     unsigned offset = 0;
246     close();
247
248     filename = icvExtractPattern(_filename, &offset);
249     if(!filename)
250         return false;
251
252     // determine the length of the sequence
253     length = 0;
254     char str[_MAX_PATH];
255     for(;;)
256     {
257         sprintf(str, filename, offset + length);
258         struct stat s;
259         if(stat(str, &s))
260         {
261             if(length == 0 && offset == 0) // allow starting with 0 or 1
262             {
263                 offset++;
264                 continue;
265             }
266         }
267
268         if(!cvHaveImageReader(str))
269             break;
270
271         length++;
272     }
273
274     if(length == 0)
275     {
276         close();
277         return false;
278     }
279
280     firstframe = offset;
281     return true;
282 }
283
284
285 CvCapture* cvCreateFileCapture_Images(const char * filename)
286 {
287     CvCapture_Images* capture = new CvCapture_Images;
288
289     if( capture->open(filename) )
290         return capture;
291
292     delete capture;
293     return 0;
294 }
295
296 //
297 //
298 // image sequence writer
299 //
300 //
301 class CvVideoWriter_Images : public CvVideoWriter
302 {
303 public:
304     CvVideoWriter_Images()
305     {
306         filename = 0;
307         currentframe = 0;
308     }
309     virtual ~CvVideoWriter_Images() { close(); }
310
311     virtual bool open( const char* _filename );
312     virtual void close();
313     virtual bool writeFrame( const IplImage* );
314
315 protected:
316     char* filename;
317     unsigned currentframe;
318 };
319
320 bool CvVideoWriter_Images::writeFrame( const IplImage* image )
321 {
322     char str[_MAX_PATH];
323     sprintf(str, filename, currentframe);
324     int ret = cvSaveImage(str, image);
325
326     currentframe++;
327
328     return ret > 0;
329 }
330
331 void CvVideoWriter_Images::close()
332 {
333     if( filename )
334     {
335         free( filename );
336         filename = 0;
337     }
338     currentframe = 0;
339 }
340
341
342 bool CvVideoWriter_Images::open( const char* _filename )
343 {
344     unsigned offset = 0;
345
346     close();
347
348     filename = icvExtractPattern(_filename, &offset);
349     if(!filename)
350         return false;
351
352     char str[_MAX_PATH];
353     sprintf(str, filename, 0);
354     if(!cvHaveImageWriter(str))
355     {
356         close();
357         return false;
358     }
359
360     currentframe = offset;
361     return true;
362 }
363
364
365 CvVideoWriter* cvCreateVideoWriter_Images( const char* filename )
366 {
367     CvVideoWriter_Images *writer = new CvVideoWriter_Images;
368
369     if( writer->open( filename ))
370         return writer;
371
372     delete writer;
373     return 0;
374 }