generated from processing/processing-library-template
/
PoseNetWebcam.pde
147 lines (132 loc) · 4.81 KB
/
PoseNetWebcam.pde
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (C) 2020 Runway AI Examples
//
// This file is part of Runway AI Examples.
//
// Runway-Examples is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Runway-Examples is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RunwayML. If not, see <http://www.gnu.org/licenses/>.
//
// ===========================================================================
// RUNWAY
// www.runwayapp.ai
// PoseNet Demo:
// Receive OSC messages from Runway
// Running PoseNet model
// original example by Anastasis Germanidis, adapted by George Profenza
import oscP5.*;
// import video library
import processing.video.*;
// import Runway library
import com.runwayml.*;
// reference to runway instance
RunwayOSC runway;
// This array will hold all the humans detected
JSONObject data;
// This are the pair of body connections we want to form.
// Try creating new ones!
int[][] connections = {
{ModelUtils.POSE_NOSE_INDEX, ModelUtils.POSE_LEFT_EYE_INDEX},
{ModelUtils.POSE_LEFT_EYE_INDEX, ModelUtils.POSE_LEFT_EAR_INDEX},
{ModelUtils.POSE_NOSE_INDEX,ModelUtils.POSE_RIGHT_EYE_INDEX},
{ModelUtils.POSE_RIGHT_EYE_INDEX,ModelUtils.POSE_RIGHT_EAR_INDEX},
{ModelUtils.POSE_RIGHT_SHOULDER_INDEX,ModelUtils.POSE_RIGHT_ELBOW_INDEX},
{ModelUtils.POSE_RIGHT_ELBOW_INDEX,ModelUtils.POSE_RIGHT_WRIST_INDEX},
{ModelUtils.POSE_LEFT_SHOULDER_INDEX,ModelUtils.POSE_LEFT_ELBOW_INDEX},
{ModelUtils.POSE_LEFT_ELBOW_INDEX,ModelUtils.POSE_LEFT_WRIST_INDEX},
{ModelUtils.POSE_RIGHT_HIP_INDEX,ModelUtils.POSE_RIGHT_KNEE_INDEX},
{ModelUtils.POSE_RIGHT_KNEE_INDEX,ModelUtils.POSE_RIGHT_ANKLE_INDEX},
{ModelUtils.POSE_LEFT_HIP_INDEX,ModelUtils.POSE_LEFT_KNEE_INDEX},
{ModelUtils.POSE_LEFT_KNEE_INDEX,ModelUtils.POSE_LEFT_ANKLE_INDEX}
};
// reference to the camera
Capture camera;
// periocally to be updated using millis()
int lastMillis;
// how often should the above be updated and a time action take place ?
// takes about 100-200ms for Runway to process a 600x400 PoseNet frame
int waitTime = 210;
void setup(){
// match sketch size to default model camera setup
size(600,400);
// change default black stroke
stroke(9,130,250);
strokeWeight(3);
// setup Runway
runway = new RunwayOSC(this);
// setup camera
camera = new Capture(this,640,480);
camera.start();
// setup timer
lastMillis = millis();
}
void draw(){
// update timer
int currentMillis = millis();
// if the difference between current millis and last time we checked past the wait time
if(currentMillis - lastMillis >= waitTime){
// call the timed function
sendFrameToRunway();
// update lastMillis, preparing for another wait
lastMillis = currentMillis;
}
background(0);
// draw webcam image
image(camera,0,0);
// manually draw PoseNet parts
drawPoseNetParts(data);
}
void sendFrameToRunway(){
// nothing to send if there's no new camera data available
if(camera.available() == false){
return;
}
// read a new frame
camera.read();
// crop image to Runway input format (600x400)
PImage image = camera.get(0,0,600,400);
// query Runway with webcam image
runway.query(image);
}
void drawPoseNetParts(JSONObject data){
// Only if there are any humans detected
if (data != null) {
JSONArray humans = data.getJSONArray("poses");
for(int h = 0; h < humans.size(); h++) {
JSONArray keypoints = humans.getJSONArray(h);
// Now that we have one human, let's draw its body parts
for(int i = 0 ; i < connections.length; i++){
JSONArray startPart = keypoints.getJSONArray(connections[i][0]);
JSONArray endPart = keypoints.getJSONArray(connections[i][1]);
// extract floats fron JSON array and scale normalized value to sketch size
float startX = startPart.getFloat(0) * width;
float startY = startPart.getFloat(1) * height;
float endX = endPart.getFloat(0) * width;
float endY = endPart.getFloat(1) * height;
line(startX,startY,endX,endY);
}
}
}
}
// this is called when new Runway data is available
void runwayDataEvent(JSONObject runwayData){
// point the sketch data to the Runway incoming data
data = runwayData;
}
// this is called each time Processing connects to Runway
// Runway sends information about the current model
public void runwayInfoEvent(JSONObject info){
println(info);
}
// if anything goes wrong
public void runwayErrorEvent(String message){
println(message);
}