Starts implementing image processing functions.

Adds debug display.
Adds separate class to store processing parameters.


Signed-off-by: julien Lengrand-Lambert <julien@lengrand.fr>
This commit is contained in:
julien Lengrand-Lambert
2012-04-02 13:47:20 +02:00
parent 8a1366c3e9
commit 106c783c0e
3 changed files with 157 additions and 17 deletions

40
FaceParams.py Normal file
View File

@@ -0,0 +1,40 @@
'''
Created on 30 mars 2012
@author: jll
'''
import cv
import os
class FaceParams(object):
'''
Simple class used to store parameters used for Face detection
'''
def __init__(self, xml_folder, i_scale=2, h_scale=1.2, h_flags=0, mn=2):
'''
Constructor
'''
# Setting up some default parameters for Face Detection
self.face_cascade = cv.Load(os.path.join(xml_folder, "haarcascade_frontalface_alt.xml"))
self.eye_cascade = cv.Load(os.path.join(xml_folder, "haarcascade_eye.xml"))
# To be defined more precisely
self.min_size = (20,20)
self.image_scale = i_scale
self.haar_scale = h_scale
self.min_neighbors = mn
self.haar_flags = h_flags
def __str__(self):
"""
More convenient print method
"""
print "---------"
print "Selected parameters for Face Detection:"
print "Selected cascade for Face detection : %s" % ("haarcascade_frontalface_alt")
print "Minimum Size (x, y): %d" % (self.min_size[0], self.min_size[1])
print "Image scaling: %d, %d)" % (self.image_scale)
print "Haar scaling: %f" % (self.haar_scale)
print "Number of Haar flags: %d" % (self.haar_flags)
print "Minimum number of neighbors: %d" % (self.min_neighbors)
print "---------"

89
Guy.py
View File

@@ -16,12 +16,13 @@ class Guy(object):
'''
Constructor
'''
self.in_image = image # input image
self.in_x = None
self.in_y = None
self.in_channels = self.in_image.nChannels
self.in_channels = image.nChannels
self.name = image_id # Name of the picture used as input
self.out_im = None
self.in_image = None # input image
self.faces = [] # List of faces detected for this input
# TODO: should eyes be tied to a precise face ?
@@ -29,12 +30,44 @@ class Guy(object):
# Some operations on variables
(self.in_x, self.in_y) = cv.GetSize(self.in_image) # image size in x, y
(self.in_x, self.in_y) = cv.GetSize(image) # image size in x, y
# Creation of the output image
# Creation of the images
self.in_image = cv.CreateImage((self.in_x, self.in_y),cv.IPL_DEPTH_8U, self.in_channels)
cv.Copy(image, self.in_image)
self.out_im = cv.CreateImage((self.in_x, self.in_y),cv.IPL_DEPTH_8U, self.in_channels)
cv.Zero(self.out_im) # put everything to 0
def search_face(self, face_params):
"""
Search on the picture for a face.
Populates faces
"""
# Allocate the temporary images
gray = cv.CreateImage((self.in_x, self.in_y),
cv.IPL_DEPTH_8U,
1)
smallImage = cv.CreateImage((cv.Round(self.in_x / face_params.image_scale),
cv.Round (self.in_y / face_params.image_scale)),
cv.IPL_DEPTH_8U ,
1)
# Converts color input image to grayscale
cv.CvtColor(self.in_image, gray, cv.CV_BGR2GRAY)
# Scales input image for faster processing
cv.Resize(gray, smallImage, cv.CV_INTER_LINEAR)
# Equalizes the histogram
cv.EqualizeHist(smallImage, smallImage)
# Detect the faces
self.faces = cv.HaarDetectObjects(smallImage,
face_params.face_cascade,
cv.CreateMemStorage(0),
face_params.haar_scale,
face_params.min_neighbors,
face_params.haar_flags,
face_params.min_size)
def in_display(self, time):
"""
@@ -43,7 +76,8 @@ class Guy(object):
"""
cv.NamedWindow(self.name)
cv.ShowImage(self.name, self.in_image)
cv.WaitKey(time)
cv.WaitKey(time)
cv.DestroyWindow(self.name)
def out_display(self, time):
"""
@@ -55,7 +89,50 @@ class Guy(object):
cv.NamedWindow(win_name)
cv.ShowImage(win_name, self.in_image)
cv.WaitKey(time)
cv.DestroyWindow(win_name)
def show_debug(self, face_params, time):
"""
Function that may be used after having populated faces.
Displays each guy, with a red square around detected face,
for time ms.
TODO: green square around most probable face?
See the doc !
"""
debug_image = cv.CreateImage((self.in_x, self.in_y),cv.IPL_DEPTH_8U, self.in_channels)
cv.Copy(self.in_image, debug_image)
if self.has_face() :
for ((x, y, w, h), n) in faces:
# the input to cv.HaarDetectObjects was resized, so scale the
# bounding box of each face and convert it to two CvPoints
pt1 = (int(x * face_params.image_scale), int(y * face_params.image_scale))
pt2 = (int((x + w) * face_params.image_scale), int((y + h) * face_params.image_scale))
cv.Rectangle(debug_image,
pt1,
pt2,
cv.RGB(255, 0, 0),
3, 8, 0)# If faces are found
win_name = self.name + " - debug"
cv.NamedWindow(win_name)
cv.ShowImage(win_name, debug_image)
cv.WaitKey(time)
cv.DestroyWindow(win_name)
def num_faces(self):
"""
Returns the number of faces found for this guy
"""
return len(self.faces)
def has_face(self):
"""
Returns True if at least one face has been found
"""
return (len(self.faces) > 0)
if __name__ == "__main__":
# quick and dirty tests
name = "input/search.jpg"

View File

@@ -6,6 +6,7 @@ Created on 27 mars 2012
import cv
import os
import Guy
from FaceParams import FaceParams
class FaceMovie(object):
'''
@@ -13,8 +14,6 @@ class FaceMovie(object):
Contains the core image processing functions.
Supports the communication layer with the end user interface.
'''
def __init__(self, in_folder, out_folder, param_folder):
'''
Constructor
@@ -26,15 +25,7 @@ class FaceMovie(object):
self.guys = [] # List of pictures in source folder
# Setting up some default parameters for Face Detection
self.face_cascade = cv.Load(os.path.join(param_folder, "haarcascade_frontalface_alt.xml"))
self.eye_cascade = cv.Load(os.path.join(param_folder, "haarcascade_eye.xml"))
# To be defined more precisely
self.min_size = (20,20)
self.image_scale = 2
self.haar_scale = 1.2
self.min_neighbors = 2
self.haar_flags = 0
self.face_params = FaceParams(self.params_source)
def list_guys(self):
"""
@@ -58,7 +49,37 @@ class FaceMovie(object):
# populating guys
self.guys.append(a_guy)
def search_faces(self):
"""
Searches for all faces in the guys we have
Results to be stored directly in guys
"""
for a_guy in self.guys:
a_guy.search_face(self.face_params)
if a_guy.has_face(): # face(s) have been found
print "%d faces found for %s" % (a_guy.num_faces(), a_guy.name)
# Informative functions
def number_guys(self):
"""
Simply returns the number of guys in the current to-be movie
"""
return len(self.guys)
def show_faces(self, face_params, time=1000, mode="debug"):
"""
Show all faces that have been found for the guys.
The time for which each image will be diplayed can be chosen.
Several modes can be chosen to adapt the result.
"""
# TODO: Where can I find the lower function?
if mode == "debug" :
for a_guy in self.guys:
a_guy.show_debug(self.face_params, time)
else:
print "Warning : only supported mode is debug"
if __name__ == "__main__":
# quick and dirty tests
root_fo = "C:\Users\jll\perso\FaceMovie"
@@ -68,4 +89,6 @@ if __name__ == "__main__":
my_movie = FaceMovie(in_fo, out_fo, par_fo)
my_movie.list_guys()
my_movie.search_faces()
my_movie.show_faces(1000, "debug")
print "Done !"