157 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python
 | 
						|
# Software License Agreement (BSD License)
 | 
						|
#
 | 
						|
# Copyright (c) 2012, Philipp Wagner <bytefish[at]gmx[dot]de>.
 | 
						|
# All rights reserved.
 | 
						|
#
 | 
						|
# Redistribution and use in source and binary forms, with or without
 | 
						|
# modification, are permitted provided that the following conditions
 | 
						|
# are met:
 | 
						|
#
 | 
						|
#  * Redistributions of source code must retain the above copyright
 | 
						|
#    notice, this list of conditions and the following disclaimer.
 | 
						|
#  * Redistributions in binary form must reproduce the above
 | 
						|
#    copyright notice, this list of conditions and the following
 | 
						|
#    disclaimer in the documentation and/or other materials provided
 | 
						|
#    with the distribution.
 | 
						|
#  * Neither the name of the author nor the names of its
 | 
						|
#    contributors may be used to endorse or promote products derived
 | 
						|
#    from this software without specific prior written permission.
 | 
						|
#
 | 
						|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
						|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
						|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
						|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
						|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
						|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
						|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 | 
						|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
						|
# POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import cv2
 | 
						|
import numpy as np
 | 
						|
 | 
						|
def normalize(X, low, high, dtype=None):
 | 
						|
    """Normalizes a given array in X to a value between low and high."""
 | 
						|
    X = np.asarray(X)
 | 
						|
    minX, maxX = np.min(X), np.max(X)
 | 
						|
    # normalize to [0...1].    
 | 
						|
    X = X - float(minX)
 | 
						|
    X = X / float((maxX - minX))
 | 
						|
    # scale to [low...high].
 | 
						|
    X = X * (high-low)
 | 
						|
    X = X + low
 | 
						|
    if dtype is None:
 | 
						|
        return np.asarray(X)
 | 
						|
    return np.asarray(X, dtype=dtype)
 | 
						|
 | 
						|
 | 
						|
def read_images(path, sz=None):
 | 
						|
    """Reads the images in a given folder, resizes images on the fly if size is given.
 | 
						|
    
 | 
						|
    Args:
 | 
						|
        path: Path to a folder with subfolders representing the subjects (persons).
 | 
						|
        sz: A tuple with the size Resizes 
 | 
						|
    
 | 
						|
    Returns:
 | 
						|
        A list [X,y]
 | 
						|
        
 | 
						|
            X: The images, which is a Python list of numpy arrays.
 | 
						|
            y: The corresponding labels (the unique number of the subject, person) in a Python list.
 | 
						|
    """
 | 
						|
    c = 0
 | 
						|
    X,y = [], []
 | 
						|
    for dirname, dirnames, filenames in os.walk(path):
 | 
						|
        for subdirname in dirnames:
 | 
						|
            subject_path = os.path.join(dirname, subdirname)
 | 
						|
            for filename in os.listdir(subject_path):
 | 
						|
                try:
 | 
						|
                    im = cv2.imread(os.path.join(subject_path, filename), cv2.IMREAD_GRAYSCALE)
 | 
						|
                    # resize to given size (if given)
 | 
						|
                    if (sz is not None):
 | 
						|
                        im = cv2.resize(im, sz)
 | 
						|
                    X.append(np.asarray(im, dtype=np.uint8))
 | 
						|
                    y.append(c)
 | 
						|
                except IOError, (errno, strerror):
 | 
						|
                    print "I/O error({0}): {1}".format(errno, strerror)
 | 
						|
                except:
 | 
						|
                    print "Unexpected error:", sys.exc_info()[0]
 | 
						|
                    raise
 | 
						|
            c = c+1
 | 
						|
    return [X,y]
 | 
						|
   
 | 
						|
if __name__ == "__main__":
 | 
						|
    # This is where we write the images, if an output_dir is given
 | 
						|
    # in command line:
 | 
						|
    out_dir = None
 | 
						|
    # You'll need at least a path to your image data, please see
 | 
						|
    # the tutorial coming with this source code on how to prepare
 | 
						|
    # your image data:
 | 
						|
    if len(sys.argv) < 2:
 | 
						|
        print "USAGE: facerec_demo.py </path/to/images> [</path/to/store/images/at>]"
 | 
						|
        sys.exit()
 | 
						|
    # Now read in the image data. This must be a valid path!
 | 
						|
    [X,y] = read_images(sys.argv[1])
 | 
						|
    if len(sys.argv) == 3:
 | 
						|
        out_dir = sys.argv[2]
 | 
						|
    # Create the Eigenfaces model. We are going to use the default
 | 
						|
    # parameters for this simple example, please read the documentation
 | 
						|
    # for thresholding:
 | 
						|
    model = cv2.createEigenFaceRecognizer()
 | 
						|
    # Read
 | 
						|
    # Learn the model. Remember our function returns Python lists,
 | 
						|
    # so we use np.asarray to turn them into NumPy lists to make
 | 
						|
    # the OpenCV wrapper happy:
 | 
						|
    model.train(np.asarray(X), np.asarray(y))
 | 
						|
    # We now get a prediction from the model! In reality you 
 | 
						|
    # should always use unseen images for testing your model. 
 | 
						|
    # But so many people were confused, when I sliced an image 
 | 
						|
    # off in the C++ version, so I am just using an image we 
 | 
						|
    # have trained with.
 | 
						|
    #
 | 
						|
    # model.predict is going to return the predicted label and
 | 
						|
    # the associated confidence:
 | 
						|
    [p_label, p_confidence] = model.predict(np.asarray(X[0]))
 | 
						|
    # Print it:
 | 
						|
    print "Predicted label = %d (confidence=%.2f)" % (p_label, p_confidence)
 | 
						|
    # Cool! Finally we'll plot the Eigenfaces, because that's 
 | 
						|
    # what most people read in the papers are keen to see.
 | 
						|
    #
 | 
						|
    # Just like in C++ you have access to all model internal
 | 
						|
    # data, because the cv::FaceRecognizer is a cv::Algorithm.
 | 
						|
    #
 | 
						|
    # You can see the available parameters with getParams():
 | 
						|
    print model.getParams()
 | 
						|
    # Now let's get some data:
 | 
						|
    mean = model.getMat("mean")
 | 
						|
    eigenvectors = model.getMat("eigenvectors")
 | 
						|
    cv2.imwrite("test.png", X[0])
 | 
						|
    # We'll save the mean, by first normalizing it:
 | 
						|
    mean_norm = normalize(mean, 0, 255, dtype=np.uint8)
 | 
						|
    mean_resized = mean_norm.reshape(X[0].shape)
 | 
						|
    if out_dir is None:
 | 
						|
        cv2.imshow("mean", mean_resized)
 | 
						|
    else:
 | 
						|
        cv2.imwrite("%s/mean.png" % (out_dir), mean_resized)
 | 
						|
    # Turn the first (at most) 16 eigenvectors into grayscale 
 | 
						|
    # images. You could also use cv::normalize here, but sticking
 | 
						|
    # to NumPy is much easier for now. 
 | 
						|
    # Note: eigenvectors are stored by column:
 | 
						|
    for i in xrange(min(len(X), 16)):
 | 
						|
        eigenvector_i = eigenvectors[:,i].reshape(X[0].shape)
 | 
						|
        eigenvector_i_norm = normalize(eigenvector_i, 0, 255, dtype=np.uint8)
 | 
						|
        # Show or save the images:
 | 
						|
        if out_dir is None:
 | 
						|
            cv2.imshow("%s/eigenface_%d" % (out_dir,i), eigenvector_i_norm)
 | 
						|
        else:
 | 
						|
            cv2.imwrite("%s/eigenface_%d.png" % (out_dir,i), eigenvector_i_norm)
 | 
						|
    # Show the images:
 | 
						|
    if out_dir is None:
 | 
						|
        cv2.waitKey(0)
 |