1
+ {
2
+ "cells" : [
3
+ {
4
+ "cell_type" : " markdown" ,
5
+ "id" : " stupid-court" ,
6
+ "metadata" : {},
7
+ "source" : [
8
+ " # Video MAL"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type" : " markdown" ,
13
+ "id" : " intellectual-idaho" ,
14
+ "metadata" : {},
15
+ "source" : [
16
+ " * Upload model inferences for video tasks\n " ,
17
+ " * Support types\n " ,
18
+ " * bounding box"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type" : " code" ,
23
+ "execution_count" : 1 ,
24
+ "id" : " voluntary-minister" ,
25
+ "metadata" : {},
26
+ "outputs" : [],
27
+ "source" : [
28
+ " !pip install -q labelbox"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type" : " code" ,
33
+ "execution_count" : 2 ,
34
+ "id" : " committed-richards" ,
35
+ "metadata" : {},
36
+ "outputs" : [],
37
+ "source" : [
38
+ " import os\n " ,
39
+ " import uuid\n " ,
40
+ " from io import BytesIO\n " ,
41
+ " from typing import Dict, Any, Tuple\n " ,
42
+ " \n " ,
43
+ " from labelbox import Client, LabelingFrontend\n " ,
44
+ " from labelbox.schema.ontology import OntologyBuilder, Tool, Classification, Option"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type" : " code" ,
49
+ "execution_count" : 4 ,
50
+ "id" : " thirty-grocery" ,
51
+ "metadata" : {},
52
+ "outputs" : [],
53
+ "source" : [
54
+ " API_KEY = os.environ.get(\" LABELBOX_API_KEY\" )\n " ,
55
+ " if not API_KEY:\n " ,
56
+ " raise EnvironmentError(\" Missing API Key\" )"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type" : " code" ,
61
+ "execution_count" : 5 ,
62
+ "id" : " conservative-marsh" ,
63
+ "metadata" : {},
64
+ "outputs" : [],
65
+ "source" : [
66
+ " # Only update this if you have an on-prem deployment\n " ,
67
+ " ENDPOINT = \" https://api.labelbox.com/graphql\" "
68
+ ]
69
+ },
70
+ {
71
+ "cell_type" : " code" ,
72
+ "execution_count" : 6 ,
73
+ "id" : " affecting-myanmar" ,
74
+ "metadata" : {},
75
+ "outputs" : [],
76
+ "source" : [
77
+ " client = Client(\n " ,
78
+ " api_key=API_KEY,\n " ,
79
+ " endpoint=ENDPOINT\n " ,
80
+ " )"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type" : " markdown" ,
85
+ "id" : " blessed-venture" ,
86
+ "metadata" : {},
87
+ "source" : [
88
+ " ### Project Setup"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type" : " code" ,
93
+ "execution_count" : 7 ,
94
+ "id" : " suburban-crowd" ,
95
+ "metadata" : {},
96
+ "outputs" : [],
97
+ "source" : [
98
+ " # We want to try out a few different tools here.\n " ,
99
+ " ontology_builder = OntologyBuilder(\n " ,
100
+ " tools=[\n " ,
101
+ " Tool(tool=Tool.Type.BBOX, name=\" jellyfish\" )\n " ,
102
+ " ]\n " ,
103
+ " )"
104
+ ]
105
+ },
106
+ {
107
+ "cell_type" : " code" ,
108
+ "execution_count" : 8 ,
109
+ "id" : " modern-program" ,
110
+ "metadata" : {},
111
+ "outputs" : [],
112
+ "source" : [
113
+ " # Lets setup a project to label\n " ,
114
+ " # Note see Ontology, Project, and Project_setup notebooks for more information on this section.\n " ,
115
+ " project = client.create_project(name=\" video_mal_project\" )\n " ,
116
+ " dataset = client.create_dataset(name=\" video_mal_dataset\" )\n " ,
117
+ " dataset.create_data_row(\n " ,
118
+ " row_data=\" https://storage.labelbox.com/cjhfn5y6s0pk507024nz1ocys%2Fb8837f3b-b071-98d9-645e-2e2c0302393b-jellyfish2-100-110.mp4\" )\n " ,
119
+ " editor = next(\n " ,
120
+ " client.get_labeling_frontends(where=LabelingFrontend.name == \" Editor\" )\n " ,
121
+ " )\n " ,
122
+ " project.setup(editor, ontology_builder.asdict())\n " ,
123
+ " project.datasets.connect(dataset)"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type" : " markdown" ,
128
+ "id" : " portable-grenada" ,
129
+ "metadata" : {},
130
+ "source" : [
131
+ " #### Grab featureSchemaIds"
132
+ ]
133
+ },
134
+ {
135
+ "cell_type" : " code" ,
136
+ "execution_count" : 10 ,
137
+ "id" : " abstract-fifteen" ,
138
+ "metadata" : {},
139
+ "outputs" : [
140
+ {
141
+ "name" : " stdout" ,
142
+ "output_type" : " stream" ,
143
+ "text" : [
144
+ " {'jellyfish': 'cky3dt2lja37d0z9t26wf3qo5'}\n "
145
+ ]
146
+ }
147
+ ],
148
+ "source" : [
149
+ " # When we created a project with the ontology defined above, all of the ids were assigned.\n " ,
150
+ " # So lets reconstruct the ontology builder with all of the ids.\n " ,
151
+ " ontology = ontology_builder.from_project(project)\n " ,
152
+ " # We want all of the feature schemas to be easily accessible by name.\n " ,
153
+ " schema_lookup = {tool.name: tool.feature_schema_id for tool in ontology.tools}\n " ,
154
+ " print(schema_lookup)"
155
+ ]
156
+ },
157
+ {
158
+ "cell_type" : " markdown" ,
159
+ "id" : " portuguese-arthur" ,
160
+ "metadata" : {},
161
+ "source" : [
162
+ " ## Import Format\n " ,
163
+ " \n " ,
164
+ " * [Documentation](https://docs.labelbox.com/docs/bounding-box-json)\n " ,
165
+ " \n " ,
166
+ " \n " ,
167
+ " ```\n " ,
168
+ " Each row of the import is a unique instance\n " ,
169
+ " \n " ,
170
+ " schemaId: <featureSchemaId>\n " ,
171
+ " dataRow:\n " ,
172
+ " id: <dataRowId>\n " ,
173
+ " Instance:\n " ,
174
+ " [Segments]:\n " ,
175
+ " [KeyFrames]:\n " ,
176
+ " frame:\n " ,
177
+ " bbox:\n " ,
178
+ " top:\n " ,
179
+ " bottom:\n " ,
180
+ " height:\n " ,
181
+ " width:\n " ,
182
+ " ```\n " ,
183
+ " \n " ,
184
+ " **segments**: A segment represents a continuous section where an object is visible. If an instance disappears then the segment ends. If it re-appears, a new segment is created.\n " ,
185
+ " \n " ,
186
+ " **keyframes**: Key frames identify the location of an instance. Between keyframes, the location of the instance is interpolated.\n " ,
187
+ " \n " ,
188
+ " **bbox**: The coordinates of the bounding box"
189
+ ]
190
+ },
191
+ {
192
+ "cell_type" : " code" ,
193
+ "execution_count" : 11 ,
194
+ "id" : " 5fc417c5" ,
195
+ "metadata" : {},
196
+ "outputs" : [],
197
+ "source" : [
198
+ " segments = [\n " ,
199
+ " {\n " ,
200
+ " \" keyframes\" : [\n " ,
201
+ " {\n " ,
202
+ " \" frame\" : 1,\n " ,
203
+ " \" bbox\" : {\n " ,
204
+ " \" top\" : 80,\n " ,
205
+ " \" left\" : 80,\n " ,
206
+ " \" height\" : 80,\n " ,
207
+ " \" width\" : 80\n " ,
208
+ " }\n " ,
209
+ " },\n " ,
210
+ " {\n " ,
211
+ " \" frame\" : 20,\n " ,
212
+ " \" bbox\" : {\n " ,
213
+ " \" top\" : 125,\n " ,
214
+ " \" left\" : 125,\n " ,
215
+ " \" height\" : 200,\n " ,
216
+ " \" width\" : 300\n " ,
217
+ " }\n " ,
218
+ " }\n " ,
219
+ " ]\n " ,
220
+ " },\n " ,
221
+ " {\n " ,
222
+ " \" keyframes\" : [\n " ,
223
+ " {\n " ,
224
+ " \" frame\" : 27,\n " ,
225
+ " \" bbox\" : {\n " ,
226
+ " \" top\" : 80,\n " ,
227
+ " \" left\" : 50,\n " ,
228
+ " \" height\" : 80,\n " ,
229
+ " \" width\" : 50\n " ,
230
+ " }\n " ,
231
+ " }\n " ,
232
+ " ]\n " ,
233
+ " }\n " ,
234
+ " ]"
235
+ ]
236
+ },
237
+ {
238
+ "cell_type" : " markdown" ,
239
+ "id" : " convertible-entry" ,
240
+ "metadata" : {},
241
+ "source" : [
242
+ " ##### Create helper functions to make this much easier"
243
+ ]
244
+ },
245
+ {
246
+ "cell_type" : " code" ,
247
+ "execution_count" : 12 ,
248
+ "id" : " developing-beauty" ,
249
+ "metadata" : {},
250
+ "outputs" : [],
251
+ "source" : [
252
+ " def create_video_bbox_ndjson(datarow_id: str, schema_id: str, segments: Dict[str, Any]) -> Dict[str, Any]:\n " ,
253
+ " return {\n " ,
254
+ " \" uuid\" : str(uuid.uuid4()),\n " ,
255
+ " \" schemaId\" : schema_id,\n " ,
256
+ " \" dataRow\" : {\" id\" : datarow_id},\n " ,
257
+ " \" segments\" : segments\n " ,
258
+ " }"
259
+ ]
260
+ },
261
+ {
262
+ "cell_type" : " code" ,
263
+ "execution_count" : 13 ,
264
+ "id" : " asian-savings" ,
265
+ "metadata" : {},
266
+ "outputs" : [],
267
+ "source" : [
268
+ " uploads = []\n " ,
269
+ " \n " ,
270
+ " for data_row in dataset.data_rows():\n " ,
271
+ " uploads.append(create_video_bbox_ndjson(data_row.uid, schema_lookup['jellyfish'], segments))"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type" : " markdown" ,
276
+ "id" : " perfect-seafood" ,
277
+ "metadata" : {},
278
+ "source" : [
279
+ " ### Upload the annotations"
280
+ ]
281
+ },
282
+ {
283
+ "cell_type" : " code" ,
284
+ "execution_count" : 14 ,
285
+ "id" : " entire-community" ,
286
+ "metadata" : {},
287
+ "outputs" : [],
288
+ "source" : [
289
+ " # Let's upload!\n " ,
290
+ " # Validate must be set to false for video bounding boxes\n " ,
291
+ " upload_task = project.upload_annotations(name=f\" upload-job-{uuid.uuid4()}\" ,\n " ,
292
+ " annotations=uploads,\n " ,
293
+ " validate=False)"
294
+ ]
295
+ },
296
+ {
297
+ "cell_type" : " code" ,
298
+ "execution_count" : 15 ,
299
+ "id" : " hollywood-faculty" ,
300
+ "metadata" : {},
301
+ "outputs" : [
302
+ {
303
+ "name" : " stdout" ,
304
+ "output_type" : " stream" ,
305
+ "text" : [
306
+ " []\n "
307
+ ]
308
+ }
309
+ ],
310
+ "source" : [
311
+ " # Wait for upload to finish (Will take up to five minutes)\n " ,
312
+ " upload_task.wait_until_done()\n " ,
313
+ " # Review the upload status\n " ,
314
+ " print(upload_task.errors)"
315
+ ]
316
+ }
317
+ ],
318
+ "metadata" : {
319
+ "kernelspec" : {
320
+ "display_name" : " Python 3 (ipykernel)" ,
321
+ "language" : " python" ,
322
+ "name" : " python3"
323
+ },
324
+ "language_info" : {
325
+ "codemirror_mode" : {
326
+ "name" : " ipython" ,
327
+ "version" : 3
328
+ },
329
+ "file_extension" : " .py" ,
330
+ "mimetype" : " text/x-python" ,
331
+ "name" : " python" ,
332
+ "nbconvert_exporter" : " python" ,
333
+ "pygments_lexer" : " ipython3" ,
334
+ "version" : " 3.8.2"
335
+ }
336
+ },
337
+ "nbformat" : 4 ,
338
+ "nbformat_minor" : 5
339
+ }
0 commit comments