Hey everyone Caleb here with Deb slopes and in the last video we finally printed out our bounding box
and since we successfully printed it out that means that vision is already doing the work to identify
faces and it's telling us it's giving us a treasure map telling us exactly where that face is on the
image or at least where it thinks it is and we're going to use these coordinates and these width and
height values to actually drop this on the screen so that we can actually see what is going on where
the face is on our image so I'm going to go ahead and remember that bounding box parameter and delete
this for now.
Then what we're going to do is we're going to go ahead and create a quick little function that is going
to allow us to draw up a view on our screen and it's going to be a nice you know outline a yellow outline.
So let's build that function now create a face outline but we're going to need to pass in a rectangle
that's going to need to know for you know what rectangle.
And so we'll pass in a C-g recked just like so.
And now we can go ahead and create the view.
So let yello view.
It's going to be yellow and that's going to be you view of course now we need to set the background
to be clear.
So yellow.
Background color is clear and it'll be transparent at that point yellow view.
We want to set the border color so layer dot border color that's going to be equal to you eye color
dot yellow dot C-g color just a weird requirement of the border color has to be a C.G. color because
I guess the border is drawn using core graphics which is pretty cool.
We're going to set the border with so do yellow.
If you layer that border with and let's set that to something like three and then we want it to actually
be rounded If you think about the the iOS camera when it identifies the face it puts a yellow outline
and there's a bit of a rounded edge on the corners.
So we're going to do the same thing yellow view layer dot corner radius and we'll set that to be five.
Just very small rounding but still nice.
And then we're going to go ahead and set the alpha or the opacity of this layer to be zero.
And then as soon as we're ready to add it we're going to fade it in nicely with an animation.
So yellow of you dot Alpha will be zero point zero at the beginning.
And then we're going to go ahead and set the frame of this to be the rectangle that we pass in that
will actually tell it where it should go and how wide and tall it should be.
So yellow frame we're going to set that to be the rectangle and then we're going to go ahead and add
it to our view.
So self dot view adds subcu and we'll add in the yellow view but at this point it is transparent because
we have set the Alpha to zero.
So let's animate it back in once it's been added.
With you I view it animate with duration and the duration will be zero point three seconds.
And the animations block we can just push enter on and now we can say what things we want to actually
modify at this point if you think back to our app here this label and the you know indicator here they
should they should stop.
They should stop spinning.
It should hide away.
So we're going to go ahead and actually first fade in our yellow view yellow dot Alpha and set it to
be zero point seven five seventy five percent.
Should be good.
We will then go ahead and call self dot spinner dot Alpha and that will be equal to zero point zero.
We want that to be completely hidden.
And same with our message label will set that to be zero point zero so that it'll fade away nicely.
But remember we called that spinner to actually hide when it is when it's stopped.
And so I'm going to go ahead and once that's done once that animation is done I mean we're going to
go ahead and actually stop it from animating.
So we now can create a face outline.
OK.
And we're going to go ahead and actually call that here create face outline for CEG recked And now we
need to actually generate our rectangle using these values.
So let's go ahead and let's create a face rectangle so type let's face rectangle equals C-g rect and
of course we need one with x y width and height.
And for now let's just say 0 0 0 and let's just give it a width of one hundred and a height of 100 and
we'll pass in that that face rectangle into our function.
This is just kind of to test to see how everything works and making sure it's all good.
So you know what.
Actually I think after this I'm going to go ahead and just tell the spinner to stop spinning.
There we go.
OK so now it should hopefully fade in a nice view at 0 0 and then the rectangle should be 100 and 100
0 0 0.
I needa call self here.
There we go because we're in a closure.
And now if I build this we should get a little rectangle that pops up on the screen up in the top right
corner.
So here we go and look at that.
That's exactly right.
One hundred one hundred It's sort of transparent you can kind of see the hair through there.
Very very cool stuff.
So it is successfully adding the image.
But did you notice that when we actually run the app the screen stays white for quite a long time and
we don't actually get to see the interface until the work has already finished.
So the boom done that is a problem.
And the reason that this is happening is because we're doing everything on the same thread.
So we're going to actually do some work here to ensure that this this you know continues to work the
way we want and in order to actually do that we're going to go ahead and put this out on the main thread
the UI related stuff.
So we're going to go ahead and say dispatch.
Q Like so dot main dot async we're going to do this asynchronously and I'm going to go ahead and paste
that in there.
And now we build and run this we should see that the UI appears and that changes
OK.
Let's see.
Interesting so I saw a flash of the label and I saw a flash of the spinner right before they went away.
But I want to make sure that everything is I want to make sure that everything is visible the time it
should be.
So you know what I think that this vision request I think I can pull this back on a background thread
so that it happens in the background and all of the related stuff happens in the foreground.
So go ahead and type dispatch.
Q dots global.
And are we going to use q OS which is quality of service and background is one of those.
Q OS classes and it's something I want to happen in the background.
So this of course will be asynchronous and I'm going to pass in that vision or quest but it's going
to yell at me that since I am now in a closure I need to make a reference to self.
And so now if we build and run this we should see the interface first.
All of the vision or quest stuff happens in the background and the UI is actually happening in the foreground
so as you can see there it is.
And as soon as the rectangle is done we will see that actually pop up right on the screen like so.
Very cool stuff.
So what we couldn't see before we now can thanks to threading.
Nice.
So that is now in place.
And so we need to basically get this rectangle showing up in the right spot.
We have a face observation.
We have a bounding box.
But now we need to actually set up the parameters to get these in their rightful places.
So we're going to need a height a with an X and a Y value.
So let's go ahead let's start with the width that's going to be a pretty simple calculation.
So we're going to go ahead and type it with and that's going to be equal to self-comfort view framed
with we're going to take the the width of the screen and what we're going to do is we're going to actually
multiply it by face observation bounding box width.
Now if you remember it said that the dimensions were normalized or sorry the coordinates or normalized
to the dimensions of the process damage.
And so what that means is we need to basically scale it up so that it matches the width what we're going
to use the width of the view.
And we're going to scale it to match the width of the image.
And so if I pass that in let's pass in with if we build and run this you'll see that the width will
change.
It won't necessarily be 100 but if you think about it and if you were to move it over you should see
that the width of the frame should fit the face perfectly.
Let's see how we do.
OK so it's a little skinnier that should fit right on her face which is awesome.
So now we're going to go ahead and set up the height and height actually it's simpler than you'd think
but we can't use the height of the view because that doesn't reflect the height of the image.
And if you remember we set a property earlier called scaled height and that scaled high value basically
ensured that the UI image view was the same size as the image.
But if I tried to access scaled height right here I don't have access to it because we created it up
here in our set up image view function.
But what I can do is I can add a parameter to perform vision or Quest and I can pass that in right there.
So for image with scaled height and that's going to be a CEG float value.
That's what the height comes in as.
So now we have access to scaled height but I need to actually pass that in here.
And so if I pass in scaled height we should be able to access that down below if I build that it sees
a good where is that function yet looks good.
Very cool.
And I can take my scaled height and then in order to scale it properly I can access face observation
bounding box and pull out the height of the parameters we get from the bounding box.
If I don't build it yet getting ahead of myself if I pass in the height value here and build and run
this we should see that our face in the simulator the box matches the face much better.
So it's going to do its thing its thinking and finding faces.
Here we go.
And it appears to still be 100 by 100 which is a little confusing.
Let's think about what we're doing here.
We are taking the wits we're taking the height we're passing it into our rectangle and we're creating
a face outline for that rectangle.
OK so that's good.
Looks like looks like we're doing everything right which is which is awesome.
Let's go ahead and let's modify the X and the y parameters here.
So let's go ahead and create a variable for X and set it to equal to self.
View of frame width.
And what we're going to do is we're going to multiply that by the the origin point of the bounding box.
So let's go ahead and type face observation bounding box origin dot X and that's basically going to
you know use the width and it's going to take this normalized x variable and it's going to actually
fit it so that it is in reference to this screen size.
So if I pass in X here we should see that the box moves on the screen.
It'll You know think a little bit and then it will put it in a better place should be lined up with
the actual person's face in this image.
Let's see how we did.
OK.
Beautiful.
So as you can see it is perfectly aligned.
Now we need to figure out the Y parameter.
So let's go ahead and let's add the Y parameter let y and for y remember y is going to be going up and
down and that has to do with the height.
So we're going to use that scaled height parameter once more scaled height.
And what do you think we're going to do you might think scale it by face observation bounding box that
origin dot Y.
And that's a good thought.
Let's see what happens when we do that.
Let's go ahead and build and run.
OK.
It is building.
It's running.
And let's see where that box ends up.
OK so it is way too low.
Now you might be wondering well why.
Why wouldn't it be in the right place that doesn't make sense.
Remember the bounding box it says that the origin is the images.
Lower left corner right.
So what that means.
Think about where this box is.
If you were to flip the image upside down or I guess if this clear layer with the yellow box if you
flip that around it would be right over her face.
If you think about the distance from here to here and you were to focus here to here that brings it
to exactly where her face is on the bounding box is actually upside down.
So what we're going to do to fix that is we're going to take one hundred OK or one because these values
are all on a percentage basis we're going to take one and we're going to subtract one from this so one
minus whatever this is.
And that's going to get the remainder of where it should be.
So let's go ahead let's build and run that one more time.
That should help invert it up to the top.
We will get the.
The other side of those values.
It's loading.
Doing its thing.
Let's see.
OK so we are super super close to where we need to be it's still too low though.
And you know it sounded like we were on the right track but what we actually need to do is the bounding
box its origin point is zero zero.
Right.
And zero zero point is here or at least the origin point is the top left corner but our bounding box
the origin point is down at the bottom so we need to actually delete or subtract the height of the box
itself.
So we'll use the height parameter to do so.
And once we subtract the height we should be able to see that our height should be perfect on the y
axis and it should go right over our subjects face finding faces here we go
and boom the labels hide the spinner hides the box is perfectly over our persons face here.
That is seriously so so cool.
I love it.
But I want to make sure that this works with more than just one face we pass in a request.
But how many faces can handle.
If you remember we have a Faces image here and so I'm going to change the character to s that will switch
out the image and we'll see if we get a similar result with multiple faces in the same image.
Let's check it out.
OK.
There's our image it's finding faces.
And what do we get.
It's taking a bit longer I guess because there are multiple faces but look at that.
We get all four faces perfectly identified and they drop in at the exact right coordinate.
Guys this is so so cool.
We have now successfully identified faces and put a bounding box over them in an image in a future section
we're going to actually draw the lines for the facial features that you see in a photo.
And beyond that we're going to use a live view to actually track and identify user's faces on the camera.
So pat yourself on the back.
Fantastic work.
We have now successfully built an app that can analyze and recognize faces in photos using the vision
framework from Apple.
Let's head over to the next section and let's keep learning.