Subtitles section Play video
[TRAIN WHISTLE]
Hello and welcome to another video tutorial
about working with Runway and running machine learning models
in Runway itself.
Now, before you watch this video tutorial,
if you've never used Runway before,
you might want to go back and look at my Introduction
to Runway, how to download and install it.
But to be honest, you probably can figure that out
if you just go to runwayml.com and click on Download Beta.
You're going to want to download and open the runway software.
You'll go then to Browse Models.
I might go here under Motion, and I'm going to click PoseNet.
And you'll find yourself right here.
So this is where I am.
I've installed Runway.
I've downloaded it.
And I'm on the page in the Runway software for the PoseNet
machine learning model.
Now, what is PoseNet?
PoseNet is a machine learning model
that performs real-time skeletal tracking of one or more people.
And guess what?
I'm a person, and I've got Runway running here
with PoseNet.
So I'm going to run it.
So let's actually first click Add To Workspace.
So I already have a workspace that I've
made in the previous video called Coding Train Live
Stream.
I want to choose an input source, which
I want it to be my webcam.
So, yep, Runway go right ahead, and there I am.
And then I want to choose an output source, which eventually
I want to be processing, because I want
to get the results of running this machine learning model
PoseNet into processing itself.
But for right now, I'm just going to click on Preview.
So I click on Preview.
Oh, and I have to run.
But guess what?
So this is different than what I've showed in previous videos.
I've got an option for Run Locally.
And, in fact, this model can only be run locally.
It would be silly to run this one in the cloud,
because I'd have to spend all this time sending
the data over the network.
And it's very easy for it to run.
This is a very small, fast model.
It can be run on most modern computers.
So I'm going to click Run Locally.
So it requires no GPU credits.
Absolutely, can be used for free.
And we can see there it goes.
It's running right now.
It is making guesses as to where the various key points
of my skeleton are on my body in the output That's. viewable
below.
So one of the nice things about working
with Runway and its models is a lot
of times models have different parameters and values
and things that you can tweak and change to try running it
in different ways.
And these are sort of known as hyper parameters
to a machine learning model.
And so some of them I would actually
have to stop running the model and then
I can start to play with it.
So, for example, this Architecture one
is something I can actually make the models smaller.
It might be less accurate, but it will run faster.
But so, for example, I'm just going
to change this to 0.75 instead.
I'm going to run it again.
But some of these parameters can actually
be tweaked in real time.
So, for example, I can change the width and height
of the image, which is actually changing
the resolution of the image from the webcam itself.
And I can make it more grayscale if I want.
I could do various things to actually tweak
the image before it goes in.
But this is not the important piece
of what I want to do in this video.
What I want to do in this video is
we have a moment here where I've got a model running in Runway.
And I'm able to play with it, tweak it, get it exactly
the way I want it to work.
And I want to take that next step
from having it run here to be able to see the result of it
in my own piece of software.
So let's make that happen.
This software that I'm going to use to attempt this
is something called Processing.
So since this size here in Runway of the output
is 640 by 362, what I'm going to do in my Processing code
is set the size of the canvas to 640 by 362.
void draw.
background 0.
So now, I have a Processing sketch,
which I am running right here.
How do I see the results, the output of the model
in my Processing sketch?
So there are a variety of different network protocols
that Runway supports.
And I can find out about them up here
by clicking this Network tab.
And the one that I want to use for working with Processing
is OSC.
So there's a variety of reasons why you might
pick one protocol over another.
It really depends on what you're doing.
In the case of where I just want to get a single image,
an HTTP request would make the most sense.
And I'll do that in another video
when I show you how to work with style again in Runway.
But right now, I'm going to click
on OSC, which works pretty well with Processing.
And it's telling me a lot of information here.
So it's saying, hey, this is the server address.
So this is the most important thing that I need from Runway.
It's what I'm going to tell Processing is the unique IP
address, which happens to be the local IP
address of this computer and the port number
from which it can get the OSC messages.
I'm going to click here.
And I'm going to create a string called like ip.
I'm pretty sure I'm probably going
to want the port number in a separate variable.
And I'm going to create a port number like this.
Now, I could sit here and write all the code
for this, which is what I usually
do in Coding Train videos.
But this is a fairly different circumstance.
I really just want to get the example up
and running and show you how to do this.
And one of the nice things about working with Runway
is there are a whole bunch of premade examples
for you with different platforms and pieces of software,
one of which is Processing.
So let me show you how you would actually
do this in the real world, how I would be doing this, which
is the way to do it right now.
So if I go to the Runway ML GitHub--
and I actually should go back one level
and go here under Runway ML.
You can see here's the GitHub page for the Runway software.
And there's a lot of information.
There's some sort of like high-level stuff
here about how to port your own machine learning model
to Runway itself.
So if you've trained your own model or you
find a model that's not supported by Runway,
how you could add it.
But that's not what we're really doing here.
What I want to look for is here Processing, Runway
and Processing.
If I click here, this repository has
a whole bunch of examples of using Runway with Processing.
So you can see there's a StreetView one, attnGAN,
face landmarks, im2txt, and, voila, PoseNet.
This is the one that I'm working with.
So I'm going to look at this example.
I should say that this is an open source project.
Processing is an open source project
that I'm involved with that I've talked
about in a lot of other videos.
So maybe this is a place where if you find another model
in Runway that you've made work and you want to contribute
your Processing example here, I would encourage you to do that.
And Chris, one of the founders and creators of Runway,
and I have been talking about making a Processing
library for Runway.
And it just so happens that I made two recent video tutorials
about how to make a Processing Java library.
So I see a project in the future, which is a Processing
library for Runway.
So if you want to get involved with that, with making that,
write in the comments and let me know.
And maybe we'll create a GitHub repo for that.
OK, so I mean to go here under PoseNet.
And I'm just going to click here under posenet.pde.
So I could just copy paste the whole thing,
but I'm going to kind of go piece by piece.
And you can see here already Runway host and Runway port.
So I made a mistake in my code.
So I got a-- oh, I'm missing the 0.1 here,
which I'm sure the Chat is already talking about.
And there's an extra 1 here.
And this should be an integer.
And this would really be Host.
So actually let me use the same variable
names, runwayHost and runwayPort.
OK, so I think I've gotten this right now.
Now, in order for the example to work,
I need to make sure also I have the Processing OSC
library installed.
So if I come over here, I can copy
paste these import statements.
I can copy paste this OSC object that I definitely need.
And we'll see very quickly that I
have an error, which is the class OscP5 does not exist.
This is because I haven't installed the Processing OSC
library.
You might have already have it installed because you use it
with a different project.
But I could go here.
And I could do Sketch, Import Library,
Add Library, OSC to search for it.
This is the library I'm looking for oscP5.
I'm going to click Install.
And now, you'll see that error message goes away.
The next thing that I want to do is create an object
to receive OSC messages.
And I think I can just make this a new OscP5 object.
I need to give it a reference to this particular sketch,
because it's going to need to trigger events in the sketch
when there's data available.
And then just give it the port number.
This is called runwayPort.
So if you look at the runway example,
it's actually using this object called OscProperties, which
is a bit more sophisticated.
It says a remote address, a listening port, a datagram
size, and some other stuff.
I should probably just copy paste this into my example,
but I'm curious if it will work with just the sort of more
simplified default OscP5 object, where I just say
this and the particular port.
But I do need this.
I do need a broadcast location, because I'm
going to have to send messages to Runway as well, saying I'm
connected or I'm disconnected.
So there's two things at play here.
There's the Processing software.
And there's the Runway software.
They're both running locally on my computer.
Now, it's possible that in other scenarios
there could also be a cloud GPU involved
that runway sends messages back and forth between.
And this is something that I'm going
to do in the next example, where I work
with something called StyleGAN.
I'm going to have Runway also talk to a cloud GPU.
But that's not happening here.
PoseNet is actually running inside of--
basically wrapped into Runway itself locally.
So PoseNets running here in Runway locally.
Processing is sending a message like connect.
Like, hey, I want to hear information.
That's a one-time message.
And then Runway will just continuously send data via OSC
to Processing about what pose it's detecting with the PoseNet
model from the webcam input.
So if I wanted, I probably could figure out a way
to get the camera input into Processing,
send the image to Runway, and then have
Runway send the results back.
But Runway can connect to the camera directly,
so I might as well just do that, because that's pretty easy.
So I should also put here that like
if I make a little note here, like webcam--
that webcam is talking to Runway.
I might also have it talk to Processing
if I want to show the results in Processing as well.
So this is what's going on in this particular example.
So I want to create this broadcast location, which
is a net address object.
So I need to put that in here.
And then the first thing that I want to do
is just send the connect message.
So I'm going to copy this in and paste it here and say Connect.
So what I'm doing when Processing starts up
is it calls the function connect, which
creates an OSC message.
Every single OSC message is comprised of two parts.
Those two parts are an address, which
is usually denoted as a string, kind of like a path--
and you can see this is server/connect.
That's the address.
Or you might also think of that almost as like the message
name as the way I sometimes think about it--
and then the data.
Now, in this case, there actually
is no data, because the address itself is the message.
So this is a very simplified thing,
where this connect message is just, hey, I'm connecting.
So the name of the message, the address,
is the only thing needs to be there.
There's no data.
But when Runway sends data back, it's
going to have a message name, like a data or key points
or poses, something like that.
And then that's going to have packaged with it lots of data,
like all the xy's of all the positions of everything.
All right, so let's run this and see what happens.
Yeah, that's pretty good.
No errors.
Now that I've connected, I want to listen for messages.
And the way that that is done is with an event called OSC Event.
So this is much like mouse pressed
or key pressed or serial event or capture event.
This is a function in Processing that has a very special name,
called OSC Event.
And the oscP5 library knows to call that function
when there's data coming in.
So I'm going to just copy paste this.
And I'm going to put it in here.
And what I'm going to-- so let's take a look at this.
So there's an OSC Event that has passed through it
an OSC message.
I'll just change this to message.
And if the message has that data--
so this is like its address.
Remember that?
Its address has data, that's the address we're looking for.
Or if it doesn't, get out of here.
So I want to ignore any other messages coming in.
Then what I want to do is get the data itself.
So the data of the message actually comes in as a string.
But the string is formatted as JSON, which
is JavaScript Object Notation.
If you don't know what JSON is I might refer you
to a different video of mine that explains what JSON is.
JSON works really nicely in JavaScript.
It's a little bit awkward to work with it
in Processing, because Processing is Java.
It doesn't speak JavaScript natively.
But we're going to make it work.
So the first thing in the message
itself is a big string of JSON data, which then is a JSON
object that can be parsed with Processing's parseJSONObject
function.
And then I can just look at it in the console.
So let's see if we actually get the data in.
I'm not getting anything.
And I'm wondering why.
And actually I know why, because I had to figure it out.
So first of all, there's a clue to me here.
It says, could not create datagram socket
port 5100, because it's already in use.
And I forgot there's a weird thing going on here.
If I were using OSC to communicate between two
separate computers, I could use the same port number
on each separate computer because it's just
one port number.
But, here, I need to be able to send data to runway
at a particular port, as well as receive data into processing
at a different port that cannot be the same port,
otherwise it will be in conflict.
So the port that I am broadcasting to is 57100.
That's what's listed in Runway.
But the actual port that I want to receive messages at
is 57200.
And maybe Runway knows just to add 100 to it automatically
behind the scenes.
But this is the default setup that's in Runway.
So I need to have a different port for receiving the data,
as the port that I'm sending to.
And let me show you what I mean by that in the code.
So this is the Runway port right there, 57100.
That's the port that I want to broadcast to.
And it's part of my broadcast location.
That's where I'm broadcasting to.
But where I want to receive messages is actually 57200.
So now, if I run this, I'm actually receiving messages.
But I've got a new error--
ArrayIndexOutOfBoundsException.
So this is a rare case, where the data that Runway
is sending for all of these poses is actually quite large.
And so what it needs is more space.
It needs a bigger packet size.
And so that's why in the Runway example
there was this extra OSC properties
object, which allowed setting a larger datagram size.
And the listening port is 57200.
So just before using OscP5 by default--
you don't need to do this, but I'm
going to copy paste this in.
I'm going to put this back here and then
I am going to change this to properties.
And I think I now have all of the pieces,
and what I should see is-- there we go, a lot of stuff.
And look at this.
Now, I've got exactly coming into processing a confidence
score--
it clearly cannot see my left ankle,
because my left ankle is not viewable to the camera.
So that's why that confidence score is so low.
Let's scroll up and do like right ear.
It's got a very high confidence score and an x and a y
for my right ear.
So now, I'm at the point, where I can actually use this data.
Going back to the Runway example,
you can see here that there's a very elaborate loop
to parse through the JSON and look
at all the different key points and get
all the different positions of everything that it detects.
I'm going to try to do something much simpler right now.
I'm just going to get the right eye and left eye.
So let's see if we can figure that out.
One way we can approach this is we
can make this data variable a global variable.
So I'm going to take this JSON object.
And I'm going to make this a global variable.
I'm going to call it data.
And then, in the draw loop, I'm just
going to say as long as data is not equal to null--
I forget that I'm in Java.
I can just do that--
data will be null until it's received something from Runway.
So as soon as it's received something from Runway,
all I need to do now is parse this JSON.
Something I've done to make this a little bit easier
is I've just taken that JSON that prints it
to the processing console and I've
pasted it into a into a JSON file
that I can look at in Visual Studio Code
just so I have something to reference to for.
So I know that I need to get something called poses.
So the first thing that I want is the poses array.
So one of the thing that's really weird in Processing
with JSON is you have to specify whether the data you're
looking at is a JSON object or JSON array.
And this poses data is an array, as indicated
by this square bracket.
So I'm going to say JSONArray poses equals
data.getJSONArray string poses.
Then, I want to get the key points array.
Oh, because there could be more than one pose.
But I'm going to assume there's just one pose.
So then that's the poses.
So then I'm going to say the key points are also
an array equal poses.get 0.
So that would be the first element of the array.
Now, get a new array called key points.
Get a JSON array key points.
The good news is the Runway example
has all of this in there, so if I get it wrong--
key points.
I have an error here, because I can't just say get element 0.
What is element 0?
It's a JSON object.
There we go.
So now, I have the key points, which
are the JSON array called key points in the first JSON object
index 0.
Then, what do I want to look for?
So now, I'm in the key points array.
This is element 0.
If I knew like left--
oh, this is easy, let's do nose, left eye, and right eye,
0, 1, and 2, perfect.
So I want to get JSONObject nose equals
keypoints.getJSONObject 0.
And we'll do three of these.
Left eye-- I'm doing this a little bit
different than the Runway example.
And then I'll point you runway example after right eye.
Certainly, I could use a loop here--
so nose, left eye, right eye.
And then I need to get the position--
nosePos equals nos.getJSONObject.
I should just do the nose.
I'm just going to do the nose just
to keep things simpler here.
You can extrapolate to figure out
how to do the left eye and the right eye--
nose.getJSONObject position.
And then x equals--
I'm going to call this nose position.
Nose position gets x.
Pretty sure this is right.
And y equals nosePosition.get y.
All right, let's see, what have I gotten wrong here?
getFloat.
Again, I'm in Java.
I've got to specify the type.
So if I've done everything correctly,
I've gotten all the key points of the first pose.
I've gotten the object with all the data for the nose.
Then I can get the nose position out of that object, then the x
and y out of that object.
Phew.
Now, I'm gong to say ellipse x,y 2020.
And let's make it a red nose.
fill 255.0.0.
Let's give this a run.
And there we go.
I am now controlling my nose.
From Runway into Processing with OSC messages.
Amazing.
OK, so this really concludes this particular video tutorial.
Certainly, what you might want to do
is see the entire skeleton.
To use PoseNet effectively, you really
want to have the camera probably around 6 feet from you.
You want to back up and allow it to see your full form.
You can also pass it images and get the pose, the skeleton off
from an image.
There's lots of different things you can do.
And, certainly, I would recommend
that you check the example in the Runway GitHub repo itself,
which has a nice loop to go through all
of the different positions.
And actually it also has this little mapping to map
what all the connections are between them
for the actual skeleton itself.
So as a little exercise, see if you
can expand what I did to have the right eye and the left eye.
But even so, you could just go get the Runway example itself.
But this is a guiding principle for how
any particular model that you might find in Runway itself--
someone in the chat was just asking about dense
pose, for example, that you can communicate from runway via OSC
to Processing.
But in a lot of other cases, you might
want to use web sockets or an HTTP connection
to communicate, particularly if you're working
in the browser with JavaScript.
So what I'm going to do in the next video,
if you want to watch, is run StyleGAN to generate a rainbow
image and then pass that image into P5
and render it in the browser itself.
And breaking news from the chat, Damien
writes SRSP stand for Send and Receive on the Same Port.
By default, OSC packets are not received and sent
by the same port, if you need to send or receive
in the same port.
Oh, so maybe I could have actually done something
with the port numbers.
I have no idea.
I'm sure people will write about it in the comments.
But this code works.
The code in the Runway GitHub repository works.
So how fun.
Use it.
Make something with it.
Please share it with me.
And hope you enjoyed this tutorial about Processing,
Runway, and the PoseNet model running locally
on your computer.
Goodbye.
[TRAIN WHISTLE]
[MUSIC PLAYING]