mirror of
https://github.com/jlengrand/Ivolution.git
synced 2026-03-10 08:21:18 +00:00
Creates output generation function
Finds and saves center of faces Uses most probable face as input Video generation to be implemented Picture cropping to be implemented, V0 should be finished ! Signed-off-by: julien Lengrand-Lambert <julien@lengrand.fr>
This commit is contained in:
40
FaceParams.py
Normal file
40
FaceParams.py
Normal 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 "---------"
|
||||
174
Guy.py
174
Guy.py
@@ -10,32 +10,91 @@ import os # needed only for main. Shall be removed
|
||||
class Guy(object):
|
||||
'''
|
||||
Represents the user on the people at a fixed time.
|
||||
All datas found for this time may be found here.
|
||||
All data found for this time may be found here.
|
||||
'''
|
||||
def __init__(self, image, image_id):
|
||||
'''
|
||||
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 ?
|
||||
self.eyes = [] # List of eyes detected for this input
|
||||
self.eyes = [] # List of eyes detected for this input
|
||||
|
||||
# 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
|
||||
# Two variables used to define the new center of interest of the image
|
||||
# they are defined as the middle of input image at first
|
||||
self.x_center = self.in_x / 2
|
||||
self.y_center = self.in_y / 2
|
||||
|
||||
# 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)
|
||||
|
||||
# sorting faces to keep only the most probable one
|
||||
self.sort_faces()
|
||||
self.update_center() # finds centre of face in image
|
||||
|
||||
def sort_faces(self):
|
||||
"""
|
||||
sort faces by probability, most probable one first
|
||||
"""
|
||||
if self.has_face() : # needed ?
|
||||
self.faces.sort(key= lambda prob : prob[1], reverse=True)
|
||||
|
||||
def update_center(self):
|
||||
"""
|
||||
Using sorted faces, defines the new center of interest of the output image
|
||||
"""
|
||||
if self.has_face():
|
||||
((x, y, w, h), n) = self.faces[0]
|
||||
self.x_center = x + w / 2
|
||||
self.y_center = y + h / 2
|
||||
|
||||
|
||||
def in_display(self, time):
|
||||
"""
|
||||
Displays the input image, for time ms.
|
||||
@@ -43,7 +102,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 +115,105 @@ class Guy(object):
|
||||
cv.NamedWindow(win_name)
|
||||
cv.ShowImage(win_name, self.in_image)
|
||||
cv.WaitKey(time)
|
||||
|
||||
cv.DestroyWindow(win_name)
|
||||
|
||||
def save_result(self, face_params, out_folder, ext, debug=False):
|
||||
"""
|
||||
Saves output image to the given format (given in extension)
|
||||
"""
|
||||
# FIXME : face_params to be removed !
|
||||
# TODO : should be refactored into a create_output(debug function)
|
||||
if (debug and self.has_face()):
|
||||
# Adds a rectangle around the output, and a point in the center
|
||||
((x, y, w, h), n) = self.faces[0]
|
||||
# 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(self.out_im,
|
||||
pt1,
|
||||
pt2,
|
||||
cv.RGB(255, 0, 0),
|
||||
3, 8, 0)# surrounds face
|
||||
|
||||
# Adds point in the center
|
||||
pt3 = (int(self.x_center * face_params.image_scale),
|
||||
int(self.y_center * face_params.image_scale))
|
||||
cv.Line(self.out_im,
|
||||
pt3,
|
||||
pt3,
|
||||
cv.RGB(0, 255, 0),
|
||||
3, 8, 0)
|
||||
|
||||
# check that format is a string ? ?
|
||||
file_name = self.name + "." + ext
|
||||
out_name = os.path.join(out_folder, file_name)
|
||||
print "Saving %s" %(out_name)
|
||||
|
||||
cv.SaveImage(out_name, self.out_im)
|
||||
|
||||
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 !
|
||||
"""
|
||||
# Instead of doing it for all, do it only for the biggest one
|
||||
if self.has_face() :
|
||||
|
||||
debug_image = cv.CreateImage((self.in_x, self.in_y),cv.IPL_DEPTH_8U, self.in_channels)
|
||||
cv.Copy(self.in_image, debug_image)
|
||||
|
||||
# some nice drawings
|
||||
((x, y, w, h), n) = self.faces[0]
|
||||
# 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)# surrounds face
|
||||
|
||||
# Adds point in the center
|
||||
pt3 = (int(self.x_center * face_params.image_scale),
|
||||
int(self.y_center * face_params.image_scale))
|
||||
cv.Line(debug_image,
|
||||
pt3,
|
||||
pt3,
|
||||
cv.RGB(0, 255, 0),
|
||||
3, 8, 0)
|
||||
|
||||
win_name = self.name + " - debug"
|
||||
cv.NamedWindow(win_name, cv.CV_WINDOW_NORMAL)
|
||||
cv.ResizeWindow(win_name, 640, 480)
|
||||
cv.ShowImage(win_name, debug_image)
|
||||
cv.WaitKey(time)
|
||||
cv.DestroyWindow(win_name)
|
||||
|
||||
else :
|
||||
print "Warning! No face found for %s" %(self.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"
|
||||
|
||||
60
facemovie.py
60
facemovie.py
@@ -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,14 +49,59 @@ 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, 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"
|
||||
|
||||
def save_faces(self, out_folder, format="png", debug=True):
|
||||
"""
|
||||
Save all faces into out_folder, in the given format
|
||||
Debug is used to draw rectangles around found faces
|
||||
"""
|
||||
for a_guy in self.guys:
|
||||
a_guy.save_result(self.face_params,
|
||||
out_folder,
|
||||
format,
|
||||
debug)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# quick and dirty tests
|
||||
root_fo = "C:\Users\jll\perso\FaceMovie"
|
||||
in_fo = os.path.join(root_fo, "input\Axel")
|
||||
in_fo = os.path.join(root_fo, "input\Axel_tsts")
|
||||
#in_fo = os.path.join(root_fo, "input\Axel")
|
||||
out_fo = os.path.join(root_fo, "output")
|
||||
par_fo = os.path.join(root_fo, "haarcascades")
|
||||
|
||||
my_movie = FaceMovie(in_fo, out_fo, par_fo)
|
||||
my_movie.list_guys()
|
||||
my_movie.search_faces()
|
||||
#my_movie.show_faces(2000, "debug")
|
||||
my_movie.save_faces("output", debug=True)
|
||||
print "Done !"
|
||||
BIN
input/Axel_tsts/2012-03-08-12h09m30DSCN1671.JPG
Normal file
BIN
input/Axel_tsts/2012-03-08-12h09m30DSCN1671.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
BIN
output/2012-03-08-12h09m30DSCN1671.JPG.png
Normal file
BIN
output/2012-03-08-12h09m30DSCN1671.JPG.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 MiB |
Reference in New Issue
Block a user