Created
May 13, 2013 12:41
-
-
Save jo32/5568048 to your computer and use it in GitHub Desktop.
face detection using OpeCV haar detection and save them
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
This program is used for face detection and save the faces it detects. | |
""" | |
import sys | |
import re | |
import cv2 | |
import cv2.cv as cv | |
import numpy | |
from optparse import OptionParser | |
from datetime import datetime | |
""" | |
Parameters for haar detection: | |
min_size: minimum face size is 20 * 20. | |
image_scale: scale factor is 1.2 | |
haar_scale: haar scale is 1.2 | |
haar_flags: Mode of operation. Currently the only flag that may be specified is | |
CV_HAAR_DO_CANNY_PRUNING. | |
""" | |
min_size = (20, 20) | |
image_scale = 2 | |
haar_scale = 1.2 | |
min_neighbors = 2 | |
haar_flags = 0 | |
# get the filename to save | |
def get_file_name(index): | |
time = str(datetime.now()) | |
time = re.sub(r"\D", "", time) | |
prefix = "faces/" + time | |
return prefix + "_" + str(index) + ".jpg" | |
class FaceDetector(object): | |
def __init__(self): | |
super(FaceDetector, self).__init__() | |
# initially setting the number of face as 0 | |
self.no_faces = 0 | |
def save_faces(self, image, faces): | |
# if there is new faces enter the screen, save them. | |
if len(faces) <= self.no_faces: | |
if len(faces) != self.no_faces: | |
self.no_faces = len(faces) | |
return | |
index = 0 | |
print "Saving %d faces ..." % self.no_faces | |
for ((x, y, w, h), n) in faces: | |
# rescaling x, y, w, h parameters to the original size | |
x *= image_scale | |
y *= image_scale | |
w *= image_scale | |
h *= image_scale | |
# getting the detected sub region of the face | |
src_region = cv.GetSubRect(image, (x, y, w, h)) | |
# crop the image | |
cropped = cv.CreateImage((w, h), image.depth, image.nChannels) | |
cv.Copy(src_region, cropped) | |
# save the image to the 'filename' | |
filename = get_file_name(index) | |
array = numpy.asarray(cropped[:, :]) | |
cv2.imwrite(filename, array) | |
index += 1 | |
self.no_faces = len(faces) | |
# the function used to detect and draw the result of a image | |
def detect_and_draw(self, img, cascade): | |
# allocate temporary images | |
# create a image with depth level is 8 and 1 channels. | |
gray = cv.CreateImage((img.width, img.height), 8, 1) | |
# the size of small image | |
size = (cv.Round(img.width / image_scale), | |
cv.Round(img.height / image_scale)) | |
# create a small image | |
small_img = cv.CreateImage(size, 8, 1) | |
# convert color input image to grayscale | |
cv.CvtColor(img, gray, cv.CV_BGR2GRAY) | |
# scale input image for faster processing | |
cv.Resize(gray, small_img, cv.CV_INTER_LINEAR) | |
# Histogram Equalization | |
cv.EqualizeHist(small_img, small_img) | |
# using the cascade input to do haar detection | |
if(cascade): | |
# getting the tick count | |
t = cv.GetTickCount() | |
# doing the haar detection using API HaarDetectObjects | |
faces = cv.HaarDetectObjects( | |
small_img, | |
cascade, | |
cv.CreateMemStorage(0), | |
haar_scale, | |
min_neighbors, | |
haar_flags, | |
min_size | |
) | |
# get and print the time spent to do the haar face detection | |
t = cv.GetTickCount() - t | |
print "detection time = %gms" % \ | |
(t / (cv.GetTickFrequency() * 1000.)) | |
if faces: | |
self.save_faces(img, faces) | |
# drawing each object detected with a rectangle | |
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 * image_scale), | |
int(y * image_scale) | |
) | |
pt2 = ( | |
int((x + w) * image_scale), | |
int((y + h) * image_scale) | |
) | |
cv.Rectangle(img, pt1, pt2, cv.RGB(0, 119, 34), 3, 8, 0) | |
else: | |
self.no_faces = 0 | |
cv.ShowImage("result", img) | |
if __name__ == '__main__': | |
# adding the cascade file option | |
parser = OptionParser( | |
usage="usage: %prog [options] [filename|camera_index]") | |
parser.add_option( | |
"-c", "--cascade", action="store", dest="cascade", type="str", | |
help="Haar cascade file, default %default", | |
default="face.xml") | |
(options, args) = parser.parse_args() | |
cascade = cv.Load(options.cascade) | |
if len(args) != 1: | |
parser.print_help() | |
sys.exit(1) | |
input_name = args[0] | |
if input_name.isdigit(): | |
capture = cv.CreateCameraCapture(int(input_name)) | |
else: | |
capture = None | |
cv.NamedWindow("result", 1) | |
width = 320 # leave None for auto-detection | |
height = 240 # leave None for auto-detection | |
if width is None: | |
width = int(cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH)) | |
else: | |
cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_WIDTH, width) | |
if height is None: | |
height = int(cv.GetCaptureProperty( | |
capture, cv.CV_CAP_PROP_FRAME_HEIGHT)) | |
else: | |
cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_FRAME_HEIGHT, height) | |
face_detector = FaceDetector() | |
if capture: | |
frame_copy = None | |
while True: | |
frame = cv.QueryFrame(capture) | |
if not frame: | |
cv.WaitKey(0) | |
break | |
if not frame_copy: | |
frame_copy = cv.CreateImage((frame.width, frame.height), | |
cv.IPL_DEPTH_8U, frame.nChannels) | |
if frame.origin == cv.IPL_ORIGIN_TL: | |
cv.Copy(frame, frame_copy) | |
else: | |
cv.Flip(frame, frame_copy, 0) | |
face_detector.detect_and_draw(frame_copy, cascade) | |
if cv.WaitKey(10) >= 0: | |
break | |
else: | |
image = cv.LoadImage(input_name, 1) | |
face_detector.detect_and_draw(image, cascade) | |
cv.WaitKey(0) | |
cv.DestroyWindow("result") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment