Merge pull request #2887 from ilya-lavrenov:ipp_morph_fix
[platform/upstream/opencv.git] / samples / python2 / facerec_demo.py
1 #!/usr/bin/env python
2 # Software License Agreement (BSD License)
3 #
4 # Copyright (c) 2012, Philipp Wagner <bytefish[at]gmx[dot]de>.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 #  * Redistributions of source code must retain the above copyright
12 #    notice, this list of conditions and the following disclaimer.
13 #  * Redistributions in binary form must reproduce the above
14 #    copyright notice, this list of conditions and the following
15 #    disclaimer in the documentation and/or other materials provided
16 #    with the distribution.
17 #  * Neither the name of the author nor the names of its
18 #    contributors may be used to endorse or promote products derived
19 #    from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33
34 # ------------------------------------------------------------------------------------------------
35 # Note:
36 # When using the FaceRecognizer interface in combination with Python, please stick to Python 2.
37 # Some underlying scripts like create_csv will not work in other versions, like Python 3.
38 # ------------------------------------------------------------------------------------------------
39
40 import os
41 import sys
42 import cv2
43 import numpy as np
44
45 def normalize(X, low, high, dtype=None):
46     """Normalizes a given array in X to a value between low and high."""
47     X = np.asarray(X)
48     minX, maxX = np.min(X), np.max(X)
49     # normalize to [0...1].
50     X = X - float(minX)
51     X = X / float((maxX - minX))
52     # scale to [low...high].
53     X = X * (high-low)
54     X = X + low
55     if dtype is None:
56         return np.asarray(X)
57     return np.asarray(X, dtype=dtype)
58
59
60 def read_images(path, sz=None):
61     """Reads the images in a given folder, resizes images on the fly if size is given.
62
63     Args:
64         path: Path to a folder with subfolders representing the subjects (persons).
65         sz: A tuple with the size Resizes
66
67     Returns:
68         A list [X,y]
69
70             X: The images, which is a Python list of numpy arrays.
71             y: The corresponding labels (the unique number of the subject, person) in a Python list.
72     """
73     c = 0
74     X,y = [], []
75     for dirname, dirnames, filenames in os.walk(path):
76         for subdirname in dirnames:
77             subject_path = os.path.join(dirname, subdirname)
78             for filename in os.listdir(subject_path):
79                 try:
80                     im = cv2.imread(os.path.join(subject_path, filename), cv2.IMREAD_GRAYSCALE)
81                     # resize to given size (if given)
82                     if (sz is not None):
83                         im = cv2.resize(im, sz)
84                     X.append(np.asarray(im, dtype=np.uint8))
85                     y.append(c)
86                 except IOError, (errno, strerror):
87                     print "I/O error({0}): {1}".format(errno, strerror)
88                 except:
89                     print "Unexpected error:", sys.exc_info()[0]
90                     raise
91             c = c+1
92     return [X,y]
93
94 if __name__ == "__main__":
95     # This is where we write the images, if an output_dir is given
96     # in command line:
97     out_dir = None
98     # You'll need at least a path to your image data, please see
99     # the tutorial coming with this source code on how to prepare
100     # your image data:
101     if len(sys.argv) < 2:
102         print "USAGE: facerec_demo.py </path/to/images> [</path/to/store/images/at>]"
103         sys.exit()
104     # Now read in the image data. This must be a valid path!
105     [X,y] = read_images(sys.argv[1])
106     # Convert labels to 32bit integers. This is a workaround for 64bit machines,
107     # because the labels will truncated else. This will be fixed in code as
108     # soon as possible, so Python users don't need to know about this.
109     # Thanks to Leo Dirac for reporting:
110     y = np.asarray(y, dtype=np.int32)
111     # If a out_dir is given, set it:
112     if len(sys.argv) == 3:
113         out_dir = sys.argv[2]
114     # Create the Eigenfaces model. We are going to use the default
115     # parameters for this simple example, please read the documentation
116     # for thresholding:
117     model = cv2.createEigenFaceRecognizer()
118     # Read
119     # Learn the model. Remember our function returns Python lists,
120     # so we use np.asarray to turn them into NumPy lists to make
121     # the OpenCV wrapper happy:
122     model.train(np.asarray(X), np.asarray(y))
123     # We now get a prediction from the model! In reality you
124     # should always use unseen images for testing your model.
125     # But so many people were confused, when I sliced an image
126     # off in the C++ version, so I am just using an image we
127     # have trained with.
128     #
129     # model.predict is going to return the predicted label and
130     # the associated confidence:
131     [p_label, p_confidence] = model.predict(np.asarray(X[0]))
132     # Print it:
133     print "Predicted label = %d (confidence=%.2f)" % (p_label, p_confidence)
134     # Cool! Finally we'll plot the Eigenfaces, because that's
135     # what most people read in the papers are keen to see.
136     #
137     # Just like in C++ you have access to all model internal
138     # data, because the cv::FaceRecognizer is a cv::Algorithm.
139     #
140     # You can see the available parameters with getParams():
141     print model.getParams()
142     # Now let's get some data:
143     mean = model.getMat("mean")
144     eigenvectors = model.getMat("eigenvectors")
145     # We'll save the mean, by first normalizing it:
146     mean_norm = normalize(mean, 0, 255, dtype=np.uint8)
147     mean_resized = mean_norm.reshape(X[0].shape)
148     if out_dir is None:
149         cv2.imshow("mean", mean_resized)
150     else:
151         cv2.imwrite("%s/mean.png" % (out_dir), mean_resized)
152     # Turn the first (at most) 16 eigenvectors into grayscale
153     # images. You could also use cv::normalize here, but sticking
154     # to NumPy is much easier for now.
155     # Note: eigenvectors are stored by column:
156     for i in xrange(min(len(X), 16)):
157         eigenvector_i = eigenvectors[:,i].reshape(X[0].shape)
158         eigenvector_i_norm = normalize(eigenvector_i, 0, 255, dtype=np.uint8)
159         # Show or save the images:
160         if out_dir is None:
161             cv2.imshow("%s/eigenface_%d" % (out_dir,i), eigenvector_i_norm)
162         else:
163             cv2.imwrite("%s/eigenface_%d.png" % (out_dir,i), eigenvector_i_norm)
164     # Show the images:
165     if out_dir is None:
166         cv2.waitKey(0)