[MUSIC]
>> So we have a sponsored stream today,
where we're going to be making a Christmas Face Generator.
So basically, we're going to use
Microsoft Azure's Face API to turn
our faces into Santa Claus
and Rudolph and then I don't know what else we can make it.
Let's just go with it. Festive Selfies. I like it.
Node, MIT License. Here we go.
It's going to be an open-source project as usual.
We're going to use webwebweb and everything.
Once it's done, then you guys will be able to use it too.
ChristmasElfies. Okay, I'm going to rename it.
ChristmaSelfies. I like it.
Open in desktop.
So we created this repository.
We're going to clone it to My Computer.
ChristmaSelfies, I love the name.
You guys are so creative.
Open in the Command Prompt and
then I also need to open it in Atom.
That is the IDE, Integrated Development Environment.
I think that's what it stands for. Here it goes.
This is the program where you can write and type code in.
It's like Word Processor, but for coders.
Now that we have this,
I need to initialize project,
npm init, ChristmaSelfies? Yes. Version 1?
Yes. What was that a description?
Here, entry point, index.js?
Yes. Test command. It doesn't need a case test command.
Keywords, instafluff, Azure, face, Christmas, festive, holiday,
selfie, image, generator, fun, photo, and save.
There we go. MIT License, command.
I really should have Nano installed on here.
I'll use my fancy IDE.
I need to install webwebweb.
Install webwebweb.
Const Web equals requires "webwebweb".
Then we're going to run this.
What part will we run it on?
Christmas? Christmas is December 25th, why not?
1225.
Index.js.
All we have to do now is to run it and,
web not running. Capitalized. All right.
Voila. We're never going to have to touch this error again.
We just need to figure out how to code the API.
I guess I should actually login to the portal.
I'll show you guys how this works.
We log in to the portal here.
What I need to do is just add a resource.
I can find it here, face.
It should be in "Cognitive Services". Here we go.
What I need to do is go into
"AI" page and search Microsoft Face. Here we go.
Detect, identify, analyze, organize, and tag faces.
Yeah, I think this is all we need.
[MUSIC]
>> We're going to
call this ChristmaSelfies.
Yes, we're going to locate this in West US.
Pricing tier, free, F0.
Resource group, we'll say instafluff. Yeah, great.
It's going to work. Oh dang,
free for two months?
Holy crap, two months of
support. Thank you so much for the support.
I'm going to add it directly into the web page.
So what I needed to do was to get a,
I'm going to start with Bootstrap.
Bootstrap, get started, introduction. You know what?
We're going to add it, why not?
We have a dot n file.
The way we define it is we're going to say "Azure Face API Key.
Then in here, copy the "key" and edit in there.
You're only going to get to see the first part anyway.
So then you just save it as ".env",
like that, and you close it.
Then in here at the very top,
you say require "dotenv", then config.
Then I have to do, is web.APIs.
We say apikey is going to return.
So we can get a query string and we'll return
key equals process
.env .Azure Face API Key, something like that.
There we go. Then we can test it.
It's running on one, two.
So http:1225/apikey.
It's working. That's how I'm going to get the key, dynamically.
So that always a file that contains all the environment variables.
Exactly. You got it, super simple.
Now all we're going to need to do is start a template.
We're going to save this as index.html.
So that should mean,
if I go into local hosts 1225.
Where's the top padding? It's fine.
Inside the script, we need to actually get
the apikey loaded directly from what we just made.
What we need to do is do fetch
http:localhosts:1225/apikey.
We do a get like that and we need to read it as a JSON object.
Then, let apikey equals nothing.
Then apikey equals r.apikey.
This should theoretically work.
I'm going to print it out.
I have to test this off the screen to make sure that it's working,
let me see if this worked.
Hiya, undefined.
Why didn't it work? Local host wanted to find apikey.
It's just key. Let's try this again.
It's working. But how do you get your api dynamically?
I just did this, then in my index.js,
I use webweweb and then made an API.
I can make an API like this.
We left the apikey on the code.
Hard-coded? Nope, I load it from the dot m, like that.
So I can get it by just call this.
Then I loaded it here. Easy, right?
Now that we have that,
we have to use the API console.
Supposedly, we can try this API console.
This is how we're going to do it.
Here, it says I have to do Face Detect.
So when I do detect, no image will be stored.
Only the extracted face features will be stored on a server.
Super easy, and then it gets deleted after 24 hours.
That's perfect. This is what we need.
The allowed images file size is
anywhere between one kilobyte to six megabytes.
You can get attributes like,
predicted age, gender, headPose.
Wow, dang it, it gets you a lot of stuff.
Oh man, it gives you stuff
like whether or not you're wearing glasses,
what emotion, the hair and the makeup and occlusion, accessories.
You could have earrings or nose rings or who
knows what and whether or not you have make
up on, what kind of hair.
Dang, we got to make sure we don't save all this stuff.
That's cool though that there's emotion.
It uses the Microsoft emotion engine, I think.
Detectable face size is 36 by 36.
How do you detect the size in 36 by 36 pixel?
That's impressive. Testing console
where you created your resource, West US.
So we have to do this and then query parameters,
return, detection model.
Oh, this is where we put in the key again.
I got to be very,
very secretive about this.
Give me a second, 1225 apikey,
putting the key. Check this out.
It's hidden. If I click this,
you can see it, but I'm not going to click it.
So then you get this URL and assume example.
Then you get the request URL like this.
I'm not sure how this is supposed to work.
So then you do a post request to this URL.
I'm going to make sure that it doesn't have the key again that.
Okay, it hides it for you.
So you're supposed to do a post requests to hear with
the content type with the JSON and then
the URL of the actual image.
This is pretty neat.
So we could just find images of faces and
selfies online and then see if it works.
Wow, I'm really excited for this.
So when we get the apikey,
for now we'll just do a set timeout. Why not?
Oh, we already have an idea.
What does it return? Does it return an image back?
Oh no, it wouldn't return an image back,
it would return the data and
then we would have to put it on top of the image.
Got it, I understand.
We're just going to do it in code here for now.
We'll make a function for this called detectFace,
and we're going to have apikey, image URL,
we need to do like an async function and then we're
going to do let result equal await,
fetch, this is the URL that it wants.
We need the headers and stuff,
r.json. We need to add an header.
It said what we have to do is to set
the header with Content-Type application JSON.
I have to do headers, and then we'll say
Content-Type applications like JSON,
and we have to put in
the Ocp-Apim-Subscription-Key, I guess that's what it's called.
In here, we give it the apikey like that.
I guess we'll just return the result.
We have to send in the URL.
The URL is going to be image URL like that.
I think we have to do JSON.stringify, like that.
So now we need to find an image,
we need to find apikey,
and then we need to find
an image URL of a face. Let's find something.
Oh, that's a good selfie right there.
Let's find the image address and then ka-bam.
So now supposedly, oh, wait,
I need this to be in async function and then
attributes equal awaits detectFace
and then we're going to console.log attributes.
Let's see if this worked.
Come in, you have to fetch on Window.
Request cannot have body.
Oh, okay, so that's not how you do it.
Javascript fetch host body.
I need to figure out how to post sample with
[inaudible] JSON. This is right.
Oh, maybe it's because it's not
a post method that would probably help, post.
Let's just try this. Oh, you got something back.
You got faceId.
It knows that the face is rectangle, height 161.
That sounds right. Didn't get anything else back.
Where are all of the other attributes?
Optional parameters include faceId, landmarks, and attributes.
Oh, you're supposed to set it, return faceLandmarks, true.
So return face ID, faceLandmarks, true.
I was supposed to set that to true.
So if I do landmarks true.
Oh, here we go.
So we can do faceLandmarks.
I left bottom, I left inner.
Wow, holy cow, I got a lot.
It figured out where the top,
right, eyebrow, mouth left,
mouth right, nose root left,
and face rectangle and wow, would you look at that.
This is very specific.
They use the x and y of where everything is.
All we have to do is to just put the faces on top,
put overlay elements right on top of the image, wherever it says.
This is apparently exactly where the faces and landmarks are,
so the eyes and eyebrows and all that stuff, everything.
This is very, very specific.
I wonder if there's an easier way to get like nose tip,
that's probably what we're
looking for for like if we want to make Rudolph.
I guess we could start off with Rudolph.
You just need to like draw a red circle on top of an image,
we'll just work with images. We'll try this one.
We'll make it transparent,
I guess this doesn't really matter at the moment.
So we're going to put Rudolph's nose
where the nose is supposedly at.
We need to put the nose on top of the image.
So I guess we need to show the images first.
How are we going to overlay images?
It would make sense to do it on a canvas.
What would be the easiest way to draw on a canvas?
Javascript canvas, draw image.
I think it makes the most sense. Oh, here we go.
Onload and then you draw and then draw image,
but what's the image?
So you can get the image element by ID.
Draw image from URL. Let me see.
Oh, I've figured it out.
We're going to do draw image.
Well, x, y ToCanvas.
So now we get the url, x, y.
Okay. My Canvas ID,
so this is going to be the canvas.
We're going to put a canvas on here.
We're going to call this, ChristmaSelfies,
I forgot to make a canvas.
So we need to make a canvas named canvas,
imagine that, a canvas named canvas.
Then we need to draw the image at x and y,
and the url is going to be the I url.
Okay, there we go. I think this is all we need.
Let faceImage equal, and then we put the url in
there, faceImage zero, zero.
I want to make sure that the face image is actually showing up.
Oh, it's not good.
We should make this canvas much bigger.
So we'll put it, width is 640,
height is going to be 640, why not?
Okay. If we do it that way, here we go.
Here's the plan, we're going to find
out if the nose is actually working.
Where's the attributes? Here we go.
We're going to put the nose attribute on
the faceLandmarks, that's where it is.
So it needs to be attributes.faceLandmarks.noseTip.x.
This is where we need to put in the nose tip, and noseTip.y.
The nose image, it's going to be at localhost:1225/web/rednose.
[MUSIC] Oh, reds. Thank you so much.
Oh, my goodness. Let's just try it.
We might get a giant red nose right next to her.
What happened now? It didn't draw it, noseTip of undefined.
Oh, it needs to be the first face, attributes, first face.
Let's try this again. Oh, shoot, yeah.
So its found her nose, it's just too big.
Let's resize this image.
I guess we should relieve resize it in code.
Figure out how big the nose is in the first place.
I'm going to do a scale.
I'll make it 32 by 32 or something.
When we do that draw image, we're going to do,
width equals 0, height equals 0.
The drawImage function, does it have a size, oh it does.
So if width and height,
then otherwise we're going to draw this,
then we're going to give it the width and height.
So 32 by 32.
So then I need to do minus 16,
so that I can center this image, minus 16,
and then supposedly, it should work.
That's where her nose is.
Oh, damn, look at that.
Maybe we can figure out how big
the nose is, noseRootLeft, RootRight.
That gives you the width,
the distance between those RootLeft
and Right. I'm going to try it.
Let noseSize equals noseRootRight.x minus left.x.
This is the noseSize,
we do divided by 2,
and this one divided by 2,
and then noseSize, noseSize.
Holy, what?
It's so small.
Oh, no. Maybe we need to do two times that.
Oh, look at those nostril.
Okay. So then we will do double, perfect.
Got to check the docs.
These docs, Great Scott,
why do we need a doc right and left,
noseRootLeft and RootRight, alar. What is alar?
So what we need is a noseLeftAlarOutTip.
So we need the left part and then we need the
right one. I think I got it.
It's too big, perfect.
Would you look at that. We got the nose on there, at least.
You have a reference image that tells you what each thing is.
Oh, we have one of those,
don't we? Oh yeah.
AlarTop is tip is there,
and then the other tip is there.
Okay. So maybe we do need to do 1.25 times that, perfect.
Antlers. Maybe we should edit this though.
We need to have each antler be separate.
So bring out our artistic skills in Paint.NET.
I'm going to save this out as antlers,
so in this part, left antlers.
I'm going to save this out as left antler,
and then we need antler right, antlerRight.
We need antlers in here, antlerLeft.
We need to put it probably above a little bit and to
the left of the eyebrow, left eyebrow, EyebrowLeftInner.
If we take the eyebrow outer,
its height from the EyeLeftOuter height,
then we can place it above that.
We need eyeLeftInner, wait, inner or outer?
Outer eye left.
Okay. This is what we needed.
EyeLeftOuter is where we need it, is there,
and then time y.
So antlerLeft.y position.
Oh wait, that needs to be on
this side because we need the negative anyway.
Then the other thing is
the EyebrowLeftOuter.y minus this
will give us a negative number.
So then we add that to the EyebrowLeftOuter.y.
Perfect, plus antlerLeft.y.
Then if we place it wherever the LeftOuter.x is,
and the size needs to be,
I don't know about the size.
Let's try it and see where it ends up.
Oh boy. Maybe we need to actually set the size.
Let's say that the size is 100 by 100.
Do minus 100, I guess I need to do,
let antlerSize equals 100 minus antlerSize,
and then minus that,
and that, and that.
Okay, let's see, oh, it is too tiny.
It worked though, that's the most important thing.
There is a Face API connector.
Oh, that's cool, you can get a person's face,
get a person group, and face list.
So what I found out is that you can actually
have more than one face in an image,
and it'll detect all of them up to 100 faces in an image.
I need to make the antler bigger though like
200, and sub-antler size,
we need to do times 0.75,
let's try that. Maybe that's 0.9.
Yeah, maybe not.
Maybe we'll just keep that there.
Oh, perfect, we got antlers guys.
Maybe this should have been 0.8.
Yeah, I think that's pretty good.
So we got the left side.
We should make this a separate function, what was I thinking?
Okay, function drawRudolph is
what this function needs to be, and then face.
We're supposed to put this in here.
So then that way all we have to do is be like,
we drawRudolph for each face,
drawRudlph with a face.
That's what we need it to be doing.
Then we have face, instead of attributes we do faceLandmarks.
Right side is going to be RightOuter.y,
and this one is going to be,
I think this is right. What happened?
I broke it, forEach is not, oh no.
Attributes.forEach.
Okay. The right side needs to be fixed,
but it's almost there.
The Outer.y is good, RightOuter,
and then it needs to be minus, something like that.
Oh great, look at that.
We made Rudolph all day.
I can't believe we've made a ChristmaSelfie.
This is where you can do with Azure, guys.
This is what Microsoft Azure was built for.