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