Update to 2.0.0 tree from current Fremantle build
[opencv] / samples / c / adaptiveskindetector.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////\r
2 //\r
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.\r
4 //\r
5 //  By downloading, copying, installing or using the software you agree to this license.\r
6 //  If you do not agree to this license, do not download, install, copy or use the software.\r
7 //\r
8 // Copyright (C) 2009, Farhad Dadgostar\r
9 // Intel Corporation and third party copyrights are property of their respective owners.\r
10 //\r
11 // Redistribution and use in source and binary forms, with or without modification,\r
12 // are permitted provided that the following conditions are met:\r
13 //\r
14 //   * Redistribution's of source code must retain the above copyright notice,\r
15 //     this list of conditions and the following disclaimer.\r
16 //\r
17 //   * Redistribution's in binary form must reproduce the above copyright notice,\r
18 //     this list of conditions and the following disclaimer in the documentation\r
19 //     and/or other materials provided with the distribution.\r
20 //\r
21 //   * The name of Intel Corporation may not be used to endorse or promote products\r
22 //     derived from this software without specific prior written permission.\r
23 //\r
24 // This software is provided by the copyright holders and contributors "as is" and\r
25 // any express or implied warranties, including, but not limited to, the implied\r
26 // warranties of merchantability and fitness for a particular purpose are disclaimed.\r
27 // In no event shall the Intel Corporation or contributors be liable for any direct,\r
28 // indirect, incidental, special, exemplary, or consequential damages\r
29 // (including, but not limited to, procurement of substitute goods or services;\r
30 // loss of use, data, or profits; or business interruption) however caused\r
31 // and on any theory of liability, whether in contract, strict liability,\r
32 // or tort (including negligence or otherwise) arising in any way out of\r
33 // the use of this software, even if advised of the possibility of such damage.\r
34 //\r
35 //M*/\r
36 \r
37 \r
38 #include <iostream>\r
39 #include <cstdio>\r
40 #include <cstring>\r
41 #include <ctime>\r
42 #include <cvaux.h>\r
43 #include <highgui.h>\r
44 \r
45 class ASDFrameHolder\r
46 {\r
47 private:\r
48         IplImage *image;\r
49         double timeStamp;\r
50 \r
51 public:\r
52         ASDFrameHolder();\r
53         virtual ~ASDFrameHolder();\r
54         virtual void assignFrame(IplImage *sourceImage, double frameTime);\r
55         inline IplImage *getImage();\r
56         inline double getTimeStamp();\r
57         virtual void setImage(IplImage *sourceImage);\r
58 };\r
59 \r
60 class ASDFrameSequencer\r
61 {\r
62 public:\r
63         virtual ~ASDFrameSequencer();\r
64         virtual IplImage *getNextImage();\r
65         virtual void close();\r
66         virtual bool isOpen();\r
67         virtual void getFrameCaption(char *caption);\r
68 };\r
69 \r
70 class ASDCVFrameSequencer : public ASDFrameSequencer\r
71 {\r
72 protected:\r
73         CvCapture *capture;\r
74 \r
75 public:\r
76         virtual IplImage *getNextImage();\r
77         virtual void close();\r
78         virtual bool isOpen();\r
79 };\r
80 \r
81 class ASDFrameSequencerWebCam : public ASDCVFrameSequencer\r
82 {\r
83 public:\r
84         virtual bool open(int cameraIndex);\r
85 };\r
86 \r
87 class ASDFrameSequencerVideoFile : public ASDCVFrameSequencer\r
88 {\r
89 public:\r
90         virtual bool open(const char *fileName);\r
91 };\r
92 \r
93 class ASDFrameSequencerImageFile : public ASDFrameSequencer {\r
94 private:\r
95         char sFileNameMask[2048];\r
96         int nCurrentIndex, nStartIndex, nEndIndex;\r
97 \r
98 public:\r
99         virtual void open(const char *fileNameMask, int startIndex, int endIndex);\r
100         virtual void getFrameCaption(char *caption);\r
101         virtual IplImage *getNextImage();\r
102         virtual void close();\r
103         virtual bool isOpen();\r
104 };\r
105 \r
106 //-------------------- ASDFrameHolder -----------------------//\r
107 ASDFrameHolder::ASDFrameHolder( )\r
108 {\r
109         image = NULL;\r
110         timeStamp = 0;\r
111 };\r
112 \r
113 ASDFrameHolder::~ASDFrameHolder( )\r
114 {\r
115         cvReleaseImage(&image);\r
116 };\r
117 \r
118 void ASDFrameHolder::assignFrame(IplImage *sourceImage, double frameTime)\r
119 {\r
120         if (image != NULL)\r
121         {\r
122                 cvReleaseImage(&image);\r
123                 image = NULL;\r
124         }\r
125 \r
126         image = cvCloneImage(sourceImage);\r
127         timeStamp = frameTime;\r
128 };\r
129 \r
130 IplImage *ASDFrameHolder::getImage()\r
131 {\r
132         return image;\r
133 };\r
134 \r
135 double ASDFrameHolder::getTimeStamp()\r
136 {\r
137         return timeStamp;\r
138 };\r
139 \r
140 void ASDFrameHolder::setImage(IplImage *sourceImage)\r
141 {\r
142         image = sourceImage;\r
143 };\r
144 \r
145 \r
146 //-------------------- ASDFrameSequencer -----------------------//\r
147 \r
148 ASDFrameSequencer::~ASDFrameSequencer()\r
149 {\r
150         close();\r
151 };\r
152 \r
153 IplImage *ASDFrameSequencer::getNextImage()\r
154 {\r
155         return NULL;\r
156 };\r
157 \r
158 void ASDFrameSequencer::close()\r
159 {\r
160 \r
161 };\r
162 \r
163 bool ASDFrameSequencer::isOpen()\r
164 {\r
165         return false;\r
166 };\r
167 \r
168 void ASDFrameSequencer::getFrameCaption(char *caption) {\r
169         return;\r
170 };\r
171 \r
172 IplImage* ASDCVFrameSequencer::getNextImage()\r
173 {\r
174         IplImage *image;\r
175 \r
176         image = cvQueryFrame(capture);\r
177 \r
178         if (image != NULL)\r
179         {\r
180                 return cvCloneImage(image);\r
181         }\r
182         else\r
183         {\r
184                 return NULL;\r
185         }\r
186 };\r
187 \r
188 void ASDCVFrameSequencer::close()\r
189 {\r
190         if (capture != NULL)\r
191         {\r
192                 cvReleaseCapture(&capture);\r
193         }\r
194 };\r
195 \r
196 bool ASDCVFrameSequencer::isOpen()\r
197 {\r
198         return (capture != NULL);\r
199 };\r
200 \r
201 \r
202 //-------------------- ASDFrameSequencerWebCam -----------------------//\r
203 \r
204 bool ASDFrameSequencerWebCam::open(int cameraIndex)\r
205 {\r
206         close();\r
207 \r
208         capture = cvCaptureFromCAM(cameraIndex);\r
209 \r
210         if (!capture)\r
211         {\r
212                 return false;\r
213         }\r
214         else\r
215         {\r
216                 return true;\r
217         }\r
218 };\r
219 \r
220 \r
221 //-------------------- ASDFrameSequencerVideoFile -----------------------//\r
222 \r
223 bool ASDFrameSequencerVideoFile::open(const char *fileName)\r
224 {\r
225         close();\r
226 \r
227         capture = cvCaptureFromFile(fileName);\r
228         if (!capture)\r
229         {\r
230                 return false;\r
231         }\r
232         else\r
233         {\r
234                 return true;\r
235         }\r
236 };\r
237 \r
238 \r
239 //-------------------- ASDFrameSequencerImageFile -----------------------//\r
240 \r
241 void ASDFrameSequencerImageFile::open(const char *fileNameMask, int startIndex, int endIndex)\r
242 {\r
243         nCurrentIndex = startIndex-1;\r
244         nStartIndex = startIndex;\r
245         nEndIndex = endIndex;\r
246 \r
247         std::sprintf(sFileNameMask, "%s", fileNameMask);\r
248 };\r
249 \r
250 void ASDFrameSequencerImageFile::getFrameCaption(char *caption) {\r
251         std::sprintf(caption, sFileNameMask, nCurrentIndex);\r
252 };\r
253 \r
254 IplImage* ASDFrameSequencerImageFile::getNextImage()\r
255 {\r
256         char fileName[2048];\r
257 \r
258         nCurrentIndex++;\r
259 \r
260         if (nCurrentIndex > nEndIndex)\r
261                 return NULL;\r
262 \r
263         std::sprintf(fileName, sFileNameMask, nCurrentIndex);\r
264 \r
265         IplImage* img = cvLoadImage(fileName);\r
266 \r
267         return img;\r
268 };\r
269 \r
270 void ASDFrameSequencerImageFile::close()\r
271 {\r
272         nCurrentIndex = nEndIndex+1;\r
273 };\r
274 \r
275 bool ASDFrameSequencerImageFile::isOpen()\r
276 {\r
277         return (nCurrentIndex <= nEndIndex);\r
278 };\r
279 \r
280 void putTextWithShadow(IplImage *img, const char *str, CvPoint point, CvFont *font, CvScalar color = CV_RGB(255, 255, 128))\r
281 {\r
282         cvPutText(img, str, cvPoint(point.x-1,point.y-1), font, CV_RGB(0, 0, 0));\r
283         cvPutText(img, str, point, font, color);\r
284 };\r
285 \r
286 #define ASD_RGB_SET_PIXEL(pointer, r, g, b)     { (*pointer) = (unsigned char)b; (*(pointer+1)) = (unsigned char)g;     (*(pointer+2)) = (unsigned char)r; }\r
287 \r
288 #define ASD_RGB_GET_PIXEL(pointer, r, g, b) {b = (unsigned char)(*(pointer)); g = (unsigned char)(*(pointer+1)); r = (unsigned char)(*(pointer+2));}\r
289 \r
290 void displayBuffer(IplImage *rgbDestImage, IplImage *buffer, int rValue, int gValue, int bValue)\r
291 {\r
292         int x, y, nWidth, nHeight;\r
293         double destX, destY, dx, dy;\r
294         uchar c;\r
295         unsigned char *pSrc;\r
296 \r
297         nWidth = buffer->width;\r
298         nHeight = buffer->height;\r
299 \r
300         dx = double(rgbDestImage->width)/double(nWidth);\r
301         dy = double(rgbDestImage->height)/double(nHeight);\r
302 \r
303         destX = 0;\r
304         for (x = 0; x < nWidth; x++)\r
305         {\r
306                 destY = 0;\r
307                 for (y = 0; y < nHeight; y++)\r
308                 {\r
309                         c = ((uchar*)(buffer->imageData + buffer->widthStep*y))[x];\r
310 \r
311                         if (c)\r
312                         {\r
313                                 pSrc = (unsigned char *)rgbDestImage->imageData + rgbDestImage->widthStep*int(destY) + (int(destX)*rgbDestImage->nChannels);\r
314                                 ASD_RGB_SET_PIXEL(pSrc, rValue, gValue, bValue);\r
315                         }\r
316                         destY += dy;\r
317                 }\r
318                 destY = 0;\r
319                 destX += dx;\r
320         }\r
321 };\r
322 \r
323 int main(int argc, char** argv )\r
324 {\r
325         IplImage *img, *filterMask = NULL;\r
326         CvAdaptiveSkinDetector filter(1, CvAdaptiveSkinDetector::MORPHING_METHOD_ERODE_DILATE);\r
327         ASDFrameSequencer *sequencer;\r
328         CvFont base_font;\r
329         char caption[2048], s[256], windowName[256];\r
330         long int clockTotal = 0, numFrames = 0;\r
331         std::clock_t clock;\r
332 \r
333         if (argc < 4)\r
334         {\r
335                 std::cout << "Usage: " << std::endl <<\r
336                         argv[0] << " fileMask firstFrame lastFrame" << std::endl << std::endl <<\r
337                         "Example: " << std::endl <<\r
338                         argv[0] << " C:\\VideoSequences\\sample1\\right_view\\temp_%05d.jpg  0  1000" << std::endl <<\r
339                         "       iterates through temp_00000.jpg  to  temp_01000.jpg" << std::endl << std::endl <<\r
340                         "If no parameter specified, this application will try to capture from the default Webcam." << std::endl <<\r
341                         "Please note: Background should not contain large surfaces with skin tone." <<\r
342                         std::endl;\r
343 \r
344                 sequencer = new ASDFrameSequencerWebCam();\r
345                 (dynamic_cast<ASDFrameSequencerWebCam*>(sequencer))->open(-1);\r
346 \r
347                 if (! sequencer->isOpen())\r
348                 {\r
349                         std::cout << std::endl << "Error: Cannot initialize the default Webcam" << std::endl << std::endl;\r
350                 }\r
351         }\r
352         else\r
353         {\r
354                 sequencer = new ASDFrameSequencerImageFile();\r
355                 (dynamic_cast<ASDFrameSequencerImageFile*>(sequencer))->open(argv[1], std::atoi(argv[2]), std::atoi(argv[3]) ); // A sequence of images captured from video source, is stored here\r
356 \r
357         }\r
358         std::sprintf(windowName, "%s", "Adaptive Skin Detection Algorithm for Video Sequences");\r
359 \r
360         cvNamedWindow(windowName, CV_WINDOW_AUTOSIZE);\r
361         cvInitFont( &base_font, CV_FONT_VECTOR0, 0.5, 0.5);\r
362 \r
363         // Usage:\r
364         //              c:\>CvASDSample "C:\VideoSequences\sample1\right_view\temp_%05d.jpg" 0 1000\r
365 \r
366         std::cout << "Press ESC to stop." << std::endl << std::endl;\r
367         while ((img = sequencer->getNextImage()) != 0)\r
368         {\r
369                 numFrames++;\r
370 \r
371                 if (filterMask == NULL)\r
372                 {\r
373                         filterMask = cvCreateImage( cvSize(img->width, img->height), IPL_DEPTH_8U, 1);\r
374                 }\r
375                 clock = std::clock();\r
376                 filter.process(img, filterMask);        // process the frame\r
377                 clockTotal += (std::clock() - clock);\r
378 \r
379                 displayBuffer(img, filterMask, 0, 255, 0);\r
380 \r
381                 sequencer->getFrameCaption(caption);\r
382                 std::sprintf(s, "%s - %d x %d", caption, img->width, img->height);\r
383                 putTextWithShadow(img, s, cvPoint(10, img->height-35), &base_font);\r
384 \r
385                 std::sprintf(s, "Average processing time per frame: %5.2fms", (double(clockTotal*1000/CLOCKS_PER_SEC))/numFrames);\r
386                 putTextWithShadow(img, s, cvPoint(10, img->height-15), &base_font);\r
387 \r
388                 cvShowImage (windowName, img);\r
389                 cvReleaseImage(&img);\r
390 \r
391                 if (cvWaitKey(1) == 27)\r
392                         break;\r
393         }\r
394 \r
395         sequencer->close();\r
396         delete sequencer;\r
397 \r
398         cvReleaseImage(&filterMask);\r
399 \r
400         cvDestroyWindow(windowName);\r
401 \r
402         std::cout << "Finished, " << numFrames << " frames processed." << std::endl;\r
403 \r
404         return 0;\r
405 }\r
406 \r