[No audio]
Hey, welcome to this new lecture, and
here you will learn how to detect faces.
And we will be using OpenCV with Python
to detect one or more faces from an
image. So basically, how does face
detection works anyway? Well, the idea
is that someone has created some
cascades, which are basically some XML
files, such as this one,
[No audio]
and this XML file contains information about the
features that an image of a face
contains. So we're talking about ratio
of the shadows or the eyes and nose and
lips, and all of these features, this pixel
intensity numbers are stored, are
recorded in this XML file, which has
been created by using some images with
faces as training samples. So basically,
you tell your computers, okay, these are
all of these are faces, and then you use
software like OpenCV to create such XML
files. So these are called haarcascades,
and this is a haarcascade for
frontal face object, and if you want
other objects, you can find them in this
link here. So you've got fullbody and
lefteye and lowerbody and so on.
Alternatively, you can use the resource
section of this lecture, and you can
download on a zip file with all the XML
haarcascades there. But in this
lecture, we will be focusing on the frontalface.
So we'll be using these cascades
to detect faces. And the way it works now is
that we will load the image in Python.
And then we will tell Python that this
is a model that you want to look for in
the image, and you want to find this
model, so the XML model in the image,
and what Python will do with the
help of OpenCV, it will start to
search all the image using a window, and
then it will resize the image, so it will
decrease the image size, and using the
same window, it will detect for
smaller faces, and so on. We will go
through that step by step. So let's
write the script that detects faces.
import cv2 is the first thing you
want to do, and that the next thing is
you want to read the cascade in Python.
So let's call the variable face_cascade
[No audio]
cv2, and we have a methods called
CascadeClassifier. So this will create a
face_cascade object in Python, and all
we have to pass here is the path of the
haarcascade.
[No audio]
That's it.
[No audio]
And that will create a CascadeClassifier object, and
now you can use this CascadeClassifier
object of the face feature to search for
face in your image. So the next thing
you might want to do is to load the
image in Python, the image that you want
to search for a face, let's say image
equals. So you know that we can load
images in Python via the imageread
method of the OpenCV, and you can just
pass the photo.jpg name here. So I'm
passing the file path of this image. So
I'm not passing any second parameter
here, that means I'm reading the image
as a color image. However, a good idea
is to use grayscale images when
searching for a face. So I loaded the
image here, but I'll be using the
grayscale version of the image when
searching for a face in that image. That
is thought to produce higher accuracy
when searching for faces. Because
you know, you may notice that when you
have very busy images with lots of
features, OpenCV will not be 100%
accurate. So you may get faces that,
obviously, will miss out, or you may
get features that will be classified as faces.
Using the grayscale
image though increases the accuracy. I
could go ahead and pass a 0 flag here
so that I could read this image as a greyscale
but I'd like to actually
keep the original image as a color
version, because I want to show the
color version at the end, but use the
gray_image to pass it to the methods
that will be searching for the face.
So I'll create here a gray_image
variable. We're all still a grayscale
version of the image. So cv2 and we
have a method called cvtColor, and
that takes as argument the original
image, of course, and a flag, so one
argument called cv2.COLOR_BGR2GRAY.
So what this means is that this
will convert the BGR image, so blue,
green, red bands. It will convert it to a
grayscale image, that's it. So, if
you want to quickly show this gray_image,
if you like, cv2.imshow gray_image there,
we give a name for the
window Gray and the image you want to
show, and you need to pass the waitKey
parameter here, let's say 0. So we'll
press any key and it will close the
window. cv2.destroyAllWindows.
[No audio]
So you learned these methods in the
previous lectures. Let me execute this.
[No audio]
So this is a grayscale version of the
image. Come and now we will use a method
called detectMultiScale, and what this
method will do, it will search for the
CascadeClassifier. So it will search
for this frontalface xml file in our
image, and it will return the
coordinates of the face in the image. So for instance,
[No audio]
this is the image and what
this method will return is it will find
the face and it will say. So it will
give you the number of the row and the
column of the upper left point of the
face. So it will start here and it will
also give you the height of the face
and the width of the face. So we've get a
rectangle, and then we will draw that
rectangle in the image.
[No audio]
So that's basically but you'll understand it
better, and so we need to create, let's
say a faces object variable, where we'll
store this x, y width and height values.
So let's quickly grab that.
[No audio]
So we need to refer to the CascadeClassifier
object, which is this one here, and what
we want to do this with this object
is detectMultiScale, and we want to
detect the gray_image, and then you
want to pass a scale factor in there.
You know that when you have lots of
parameters, and they are too many to fit
in a line. After the comma, you can
just press Enter and Python will read
your line as it was, you know, single line.
So that be sure to just press Enter after the
comma, and so we have scaleFactor, and
a good value to give for this would be
1.05. Now what does this mean,
anyway? Well, let's consider this image.
What Python will do is that it will
start from the original size of the
image and it will search, it will create
a window that will search for faces in
the image, so search in this area, in this
area, in this area, and so once it does that,
then by giving a scaleFactor of 1.05,
you're telling Python to decrease the
scale by 5% for the next face search.
So what Python will do is it will
downscale the image by 5% and it will
research for bigger faces in the image.
So search again, search again, and then
decrease it by 5% again the image and
search for bigger faces, and so on until
it goes to a final size. So that means a
smaller value means higher accuracy. If
you give for example, .5, Python will
decrease the scale by 50%. So, it
will start from the original size and
then it will go 50% higher and so you
don't get much accuracy with that. The
profit with this normally is that the script
will run quicker. So you'll have
less passes to the image for searching
for face, 0.5 is good. Okay, and then
you have another parameter called
minimumNeighbor and that is usually
set to 5. And What this basically is that
this will tell Python how many neighbors to
search around the window. So you may
want to experiment with this numbers a
little bit, and see which gets the
better results. But these two are well
accepted numbers. So let's do something
now. Let's print out faces and see what
this is about. So what kinds of
object this is? And I could also
print the type of faces, just like that.
[No audio]
So I'll run the script now and what
the script will do, it will
read this xml file and it will load the
image, it will make the grayscale version
of the image, and then it will
detect the coordinates of upper left
corner of the face in the image and the
width and the height of the rectangle
defining the face in the image, and then
it will print out the type of the faces and
it will print the faces, the actual faces object. So
[No audio]
okay, press any key to exit
this. And so faces is a NumPy array, an n
dimensional array object, and it is an
array with four values. So we have
detected our face, and these are the values
basically defining the face in the
image. So basically, what we have here
is, so this is 155, which would be the
155th column, so this is the x. So it's,
the rectangle should start somewhere
here. Now, in the forehead, and this should be 83,
so the row 83, column 155, and then
we have the width, which is 382, and the
height, which is the same, and so we have a
rectangle in the face. Now, let's go
ahead and draw that rectangle in the face,
in the image. So we created the faces
array, and then what we want to do
is access all of these values of this
array. To do that, we can use a for
loop. So for x, y, width, and height in faces.
[No audio]
Well image, so we are updating
the image object that we have read here,
we have loaded here. So we will update
it by drawing a rectangle in the image.
[No audio]
And again, you'll need to pass in each
object in here, and then you need to pass
four more arguments. The first argument
would be the starting point of the
rectangle, so that would be x and y, so
these coordinates of the face array.
Great, and then the next parameter is
another tuple defining the coordinates
of the other corner of the image. So
we've got the top left corner in here, and
we got the lowest right corner in down
here. So what that would be is x+ the width
and y+ the height. That's
it. Yet another parameter and this would
be the color that you want to give to
this rectangle. So and that comes as a BGR
format. So you want to pass value for
the blue color. So let's say 0 for
blue, and let's have a green rectangle,
so 255 for green, so we'll have a full
green there, and then 0 for red, and you
can also pass another parameter, which
would be the width of the rectangle, let's say 3.
[No audio]
Okay, and once you do
that, so once you have updated your
image, you may want to show your image
window on the screen now. So we use the
image.show method, but here we have a
gray_image, so we want to pass the
updated image object, and we should be
good to go. Save the script, go and try
to run it, and my system is not being
able to find the face_detector.py.
Yeah, I've messed up something with a name
here. So let me change this '.py', Enter,
so nothing to do with the script, and
let me try again. Great. So I hope
this is what you were expecting.
So, the rectangle starts here and it
has a width and a height, and it ends up
in here. Sometimes though, I assume I
already know you may have images that
are bigger than your screen resolution.
In that case, your image would not fit
in your screen, on your screen, so what
you could do is resize the image before showing it.
[No audio]
So let me create a resized
variable here, and that would be equal
to cv2.resize
and we want to pass image, so which
contains the rectangle there, and you
want to resize the image to these two
values. So you need to set the
resolution of the image here, and as you
know, you can just put some values here,
let's say 500 by 500. But these values
might stretch out your image, so you,
a better solution would be to access the
shape of the image. So the resolution of
the image, and this should be the width of
your image. So you already know this, I
explain this. So I'm just going through
this quickly, and to make sure you get a
good size, you could divide it by 3,
and then again, image.shape, you get
the height, which is the first value of
the tuple and divided by 3 again.
And you also wants to convert these
to integers, because you might get
float numbers and Python will say that
[No audio]
it cannot resize an image to
float numbers. So that should be okay.
And then you want to show the resized image.
[No audio]
Quickly testing it, and I'm missing a
bracket here, so this should be a
tuple all of these, but here, I'm not
starting with as a tuple. So bracket
here and closes in here.
[No audio]
That should work now.
[No audio]
Yeah, so this was my picture,
but let's try a more challenging
picture now, this one here.
[No audio]
So we've got two faces, which are not very clear,
this is not a real frontal face, and this
guy here he has his eyes closed and his
chin is not visible, and we've also got
these two faces here in the newspapers,
which let me open the original image
from here, which have basically a very
low resolution, and I think Python will
not be able to detect this two faces.
So let's me check this.
[No audio]
Here's our face_detector, and we want to pass the
name of the new image file.
[No audio]
Save the script and go ahead and run it. So
we've got some back to reality here, and
as you see this time, Python and OpenCV
were able to detect this face, even
though it's not in a very frontal
position, and obviously, it was also
able to detect the hand of this guy. So
Python read it as a face, and what you
can do in this case is to tweak this
values here, so the scaleFactor and
the minimumNeighbor. Something you may
also be interested to know is the faces
array here has two lists in this case.
So this is the first face, the
coordinates of the first face, and then
the second face, which in this case
happens to be hand. But anyway, you get the idea.
[No audio]
So probably by maybe using a
1.1 scale, you may be able to get rid of
that hand, so yeah, that's it. You can
also try out to detect the face of this guy
but I don't think you'll be able to do
it. So just that you know that these
techniques have limitations. So its a
computer, its not a human being, so it will
always have some downsides in the accuracy.
I hope you've found this useful though.
and I'll see you in the next lecture.