refactoring and small fixes

#27
by sofmi - opened
Files changed (38) hide show
  1. .gitignore +3 -0
  2. DLC_models/__pycache__/models.cpython-310.pyc +0 -0
  3. DLC_models/download_utils.py +61 -0
  4. DLC_models/models.py +60 -0
  5. DLC_models/pretrained_model_urls.yaml +9 -0
  6. {model β†’ DLC_models}/read.md +0 -0
  7. {example β†’ MD_models}/read.md +0 -0
  8. app.py +99 -276
  9. detection_utils.py +116 -0
  10. {example β†’ examples}/cat.jpg +0 -0
  11. {example β†’ examples}/dog.jpeg +0 -0
  12. examples/monkey_face.jpeg +0 -0
  13. {example β†’ examples}/monkey_full.jpg +0 -0
  14. {font β†’ examples}/read.md +0 -0
  15. {font β†’ fonts}/Amiko-Regular.ttf +0 -0
  16. {font β†’ fonts}/LoveNature.otf +0 -0
  17. {font β†’ fonts}/PainterDecorator.otf +0 -0
  18. {font β†’ fonts}/UncialAnimals.ttf +0 -0
  19. {font β†’ fonts}/ZEN.TTF +0 -0
  20. {megadet_model β†’ fonts}/read.md +0 -0
  21. model/DLC_Cat_resnet_50_iteration-0_shuffle-0/pose_cfg.yaml +0 -106
  22. model/DLC_Cat_resnet_50_iteration-0_shuffle-0/read.md +0 -0
  23. model/DLC_Cat_resnet_50_iteration-0_shuffle-0/snapshot-75000.pb +0 -3
  24. model/DLC_Dog_resnet_50_iteration-0_shuffle-0/pose_cfg.yaml +0 -106
  25. model/DLC_Dog_resnet_50_iteration-0_shuffle-0/read.md +0 -0
  26. model/DLC_Dog_resnet_50_iteration-0_shuffle-0/snapshot-75000.pb +0 -3
  27. model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1/pose_cfg.yaml +0 -154
  28. model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1/read.md +0 -0
  29. model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1/snapshot-1030000.pb +0 -3
  30. model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1/pose_cfg.yaml +0 -72
  31. model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1/read.md +0 -0
  32. model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1/snapshot-103000.pb +0 -3
  33. model/DLC_monkey_resnet_50_iteration-0_shuffle-1/pose_cfg.yaml +0 -96
  34. model/DLC_monkey_resnet_50_iteration-0_shuffle-1/read.md +0 -0
  35. model/DLC_monkey_resnet_50_iteration-0_shuffle-1/snapshot-1030000.pb +0 -3
  36. save_results.py +56 -0
  37. ui_utils.py +81 -0
  38. viz_utils.py +165 -0
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ model/__pycache__/
DLC_models/__pycache__/models.cpython-310.pyc ADDED
Binary file (2.29 kB). View file
 
DLC_models/download_utils.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import urllib.request
2
+ import tarfile
3
+ from tqdm import tqdm
4
+ import os
5
+ import yaml
6
+ from ruamel.yaml import YAML
7
+
8
+ def read_plainconfig(configname):
9
+ if not os.path.exists(configname):
10
+ raise FileNotFoundError(
11
+ f"Config {configname} is not found. Please make sure that the file exists."
12
+ )
13
+ with open(configname) as file:
14
+ return YAML().load(file)
15
+
16
+ def DownloadModel(modelname,
17
+ target_dir):
18
+ """
19
+ Downloads a DeepLabCut Model Zoo Project
20
+ """
21
+
22
+ def show_progress(count, block_size, total_size):
23
+ pbar.update(block_size)
24
+
25
+ def tarfilenamecutting(tarf):
26
+ """' auxfun to extract folder path
27
+ ie. /xyz-trainsetxyshufflez/
28
+ """
29
+ for memberid, member in enumerate(tarf.getmembers()):
30
+ if memberid == 0:
31
+ parent = str(member.path)
32
+ l = len(parent) + 1
33
+ if member.path.startswith(parent):
34
+ member.path = member.path[l:]
35
+ yield member
36
+
37
+ neturls = read_plainconfig("DLC_models/pretrained_model_urls.yaml") #FIXME
38
+
39
+ if modelname in neturls.keys():
40
+ url = neturls[modelname]
41
+ print(url)
42
+ response = urllib.request.urlopen(url)
43
+ print(
44
+ "Downloading the model from the DeepLabCut server @Harvard -> Go Crimson!!! {}....".format(
45
+ url
46
+ )
47
+ )
48
+ total_size = int(response.getheader("Content-Length"))
49
+ pbar = tqdm(unit="B", total=total_size, position=0)
50
+ filename, _ = urllib.request.urlretrieve(url, reporthook=show_progress)
51
+ with tarfile.open(filename, mode="r:gz") as tar:
52
+ tar.extractall(target_dir, members=tarfilenamecutting(tar))
53
+ else:
54
+ models = [
55
+ fn
56
+ for fn in neturls.keys()
57
+ if "resnet_" not in fn and "mobilenet_" not in fn
58
+ ]
59
+ print("Model does not exist: ", modelname)
60
+ print("Pick one of the following: ", models)
61
+ return target_dir
DLC_models/models.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import urllib.request
2
+ import tarfile
3
+ from tqdm import tqdm
4
+ import os
5
+ import yaml
6
+ from ruamel.yaml import YAML
7
+
8
+ def read_plainconfig(configname):
9
+ if not os.path.exists(configname):
10
+ raise FileNotFoundError(
11
+ f"Config {configname} is not found. Please make sure that the file exists."
12
+ )
13
+ with open(configname) as file:
14
+ return YAML().load(file)
15
+
16
+ def DownloadModel(modelname, target_dir):
17
+ """
18
+ Downloads a DeepLabCut Model Zoo Project
19
+ """
20
+
21
+ def show_progress(count, block_size, total_size):
22
+ pbar.update(block_size)
23
+
24
+ def tarfilenamecutting(tarf):
25
+ """' auxfun to extract folder path
26
+ ie. /xyz-trainsetxyshufflez/
27
+ """
28
+ for memberid, member in enumerate(tarf.getmembers()):
29
+ if memberid == 0:
30
+ parent = str(member.path)
31
+ l = len(parent) + 1
32
+ if member.path.startswith(parent):
33
+ member.path = member.path[l:]
34
+ yield member
35
+
36
+ neturls = read_plainconfig("./model/pretrained_model_urls.yaml") #FIXME
37
+
38
+ if modelname in neturls.keys():
39
+ url = neturls[modelname]
40
+ print(url)
41
+ response = urllib.request.urlopen(url)
42
+ print(
43
+ "Downloading the model from the DeepLabCut server @Harvard -> Go Crimson!!! {}....".format(
44
+ url
45
+ )
46
+ )
47
+ total_size = int(response.getheader("Content-Length"))
48
+ pbar = tqdm(unit="B", total=total_size, position=0)
49
+ filename, _ = urllib.request.urlretrieve(url, reporthook=show_progress)
50
+ with tarfile.open(filename, mode="r:gz") as tar:
51
+ tar.extractall(target_dir, members=tarfilenamecutting(tar))
52
+ else:
53
+ models = [
54
+ fn
55
+ for fn in neturls.keys()
56
+ if "resnet_" not in fn and "mobilenet_" not in fn
57
+ ]
58
+ print("Model does not exist: ", modelname)
59
+ print("Pick one of the following: ", models)
60
+ return target_dir
DLC_models/pretrained_model_urls.yaml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #Model Zoo from where the Charles flow(s)
2
+ full_human: http://deeplabcut.rowland.harvard.edu/models/DLC_human_fullbody_resnet_101.tar.gz
3
+ full_dog: http://deeplabcut.rowland.harvard.edu/models/DLC_Dog_resnet_50_iteration-0_shuffle-0.tar.gz
4
+ full_cat: http://deeplabcut.rowland.harvard.edu/models/DLC_Cat_resnet_50_iteration-0_shuffle-0.tar.gz
5
+ primate_face: http://deeplabcut.rowland.harvard.edu/models/DLC_primate_face_resnet_50_iteration-1_shuffle-1.tar.gz
6
+ mouse_pupil_vclose: http://deeplabcut.rowland.harvard.edu/models/DLC_mouse_pupil_vclose_resnet_50_iteration-0_shuffle-1.tar.gz
7
+ horse_sideview: http://deeplabcut.rowland.harvard.edu/models/DLC_Horses_resnet_50_iteration-1_shuffle-1.tar.gz
8
+ full_macaque: http://deeplabcut.rowland.harvard.edu/models/DLC_macaque_full_resnet50.tar.gz
9
+ full_cheetah: http://deeplabcut.rowland.harvard.edu/models/DLC_full_cheetah_resnet_152.tar.
{model β†’ DLC_models}/read.md RENAMED
File without changes
{example β†’ MD_models}/read.md RENAMED
File without changes
app.py CHANGED
@@ -2,171 +2,41 @@
2
  # Built from https://huggingface.co/spaces/sofmi/MegaDetector_DLClive/blob/main/app.py
3
  # Built from https://huggingface.co/spaces/Neslihan/megadetector_dlcmodels/blob/main/app.py
4
 
5
-
6
- import gradio as gr
7
-
8
- import torch
9
- import torchvision
10
- from dlclive import DLCLive, Processor
11
-
12
- from PIL import Image, ImageColor, ImageFont, ImageDraw
13
-
14
- import numpy as np
15
- import math
16
-
17
- # import json
18
  import os
19
  import yaml
 
 
 
20
 
21
- import pdb
22
-
23
- #########################################
24
- # Input params
25
- FONTS = {'amiko': "font/Amiko-Regular.ttf",
26
- 'nature': "font/LoveNature.otf",
27
- 'painter':"font/PainterDecorator.otf",
28
- 'animals': "font/UncialAnimals.ttf",
29
- 'zen': "font/ZEN.TTF"}
30
 
31
- Megadet_Models = {'md_v5a': "megadet_model/md_v5a.0.0.pt",
32
- 'md_v5b': "megadet_model/md_v5b.0.0.pt"}
 
33
 
34
- DLC_models = {'full_cat': "model/DLC_Cat_resnet_50_iteration-0_shuffle-0",
35
- 'full_dog': "model/DLC_Dog_resnet_50_iteration-0_shuffle-0",
36
- 'primate_face': "model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1",
37
- 'full_human': "model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1",
38
- 'full_macaque': 'model/DLC_monkey_resnet_50_iteration-0_shuffle-1'}
39
-
40
  #########################################
41
- # Draw keypoints on image
42
- def draw_keypoints_on_image(image,
43
- keypoints,
44
- map_label_id_to_str,
45
- flag_show_str_labels,
46
- use_normalized_coordinates=True,
47
- font_style='amiko',
48
- font_size=8,
49
- keypt_color="#ff0000",
50
- marker_size='2'):
51
- """Draws keypoints on an image.
52
- Modified from:
53
- https://www.programcreek.com/python/?code=fjchange%2Fobject_centric_VAD%2Fobject_centric_VAD-master%2Fobject_detection%2Futils%2Fvisualization_utils.py
54
- Args:
55
- image: a PIL.Image object.
56
- keypoints: a numpy array with shape [num_keypoints, 2].
57
- map_label_id_to_str: dict with keys=label number and values= label string
58
- flag_show_str_labels: boolean to select whether or not to show string labels
59
- color: color to draw the keypoints with. Default is red.
60
- radius: keypoint radius. Default value is 2.
61
- use_normalized_coordinates: if True (default), treat keypoint values as
62
- relative to the image. Otherwise treat them as absolute.
63
- """
64
- # get a drawing context
65
- draw = ImageDraw.Draw(image)
66
-
67
- im_width, im_height = image.size
68
- keypoints_x = [k[0] for k in keypoints]
69
- keypoints_y = [k[1] for k in keypoints]
70
-
71
- # adjust keypoints coords if required
72
- if use_normalized_coordinates:
73
- keypoints_x = tuple([im_width * x for x in keypoints_x])
74
- keypoints_y = tuple([im_height * y for y in keypoints_y])
75
-
76
- # draw ellipses around keypoints and add string labels
77
- for i, (keypoint_x, keypoint_y) in enumerate(zip(keypoints_x, keypoints_y)):
78
- draw.ellipse([(keypoint_x - marker_size, keypoint_y - marker_size),
79
- (keypoint_x + marker_size, keypoint_y + marker_size)],
80
- outline=keypt_color,
81
- fill=keypt_color)
82
-
83
- # add string labels around keypoints
84
- if flag_show_str_labels:
85
- font = ImageFont.truetype(FONTS[font_style],
86
- font_size)
87
- draw.text((keypoint_x + marker_size, keypoint_y + marker_size),#(0.5*im_width, 0.5*im_height), #-------
88
- map_label_id_to_str[i],
89
- ImageColor.getcolor(keypt_color, "RGB"), # rgb
90
- font=font)
91
-
92
- ############################################
93
- # Predict detections with MegaDetector v5a model
94
- def predict_md(im,
95
- mega_model_input,
96
- size=640):
97
-
98
- # resize image
99
- g = (size / max(im.size)) # multipl factor to make max size of the image equal to input size
100
- im = im.resize((int(x * g) for x in im.size),
101
- Image.ANTIALIAS) # resize
102
- MD_model = torch.hub.load('ultralytics/yolov5', 'custom', Megadet_Models[mega_model_input])
103
-
104
- ## detect objects
105
- results = MD_model(im) # inference # vars(results).keys()= dict_keys(['imgs', 'pred', 'names', 'files', 'times', 'xyxy', 'xywh', 'xyxyn', 'xywhn', 'n', 't', 's'])
106
- results.render() # updates results.imgs with boxes and labels
107
-
108
- return results
109
-
110
- ##########################################
111
- def crop_animal_detections(yolo_results,
112
- likelihood_th):
113
-
114
- ## Extract animal crops
115
- list_labels_as_str = yolo_results.names # ['animal', 'person', 'vehicle']
116
- list_np_animal_crops = []
117
- # for every image
118
- for img, det_array in zip(yolo_results.imgs,
119
- yolo_results.xyxy):
120
-
121
- # for every detection
122
- for j in range(det_array.shape[0]):
123
-
124
- # compute coords around bbox rounded to the nearest integer (for pasting later)
125
- xmin_rd = int(math.floor(det_array[j,0])) # int() should suffice?
126
- ymin_rd = int(math.floor(det_array[j,1]))
127
-
128
- xmax_rd = int(math.ceil(det_array[j,2]))
129
- ymax_rd = int(math.ceil(det_array[j,3]))
130
-
131
- pred_llk = det_array[j,4]
132
- pred_label = det_array[j,5]
133
-
134
- # keep animal crops above threshold
135
- if (pred_label == list_labels_as_str.index('animal')) and \
136
- (pred_llk >= likelihood_th):
137
- area = (xmin_rd, ymin_rd, xmax_rd, ymax_rd)
138
-
139
- crop = Image.fromarray(img).crop(area)
140
- crop_np = np.asarray(crop)
141
-
142
- # add to list
143
- list_np_animal_crops.append(crop_np)
144
-
145
- return list_np_animal_crops
146
-
147
- ##########################################
148
- def predict_dlc(list_np_crops,
149
- kpts_likelihood_th,
150
- DLCmodel,
151
- dlc_proc):
152
-
153
- # run dlc thru list of crops
154
- dlc_live = DLCLive(DLCmodel, processor=dlc_proc)
155
- dlc_live.init_inference(list_np_crops[0])
156
-
157
- list_kpts_per_crop = []
158
- np_aux = np.empty((1,3)) # can I avoid hardcoding here?
159
- for crop in list_np_crops:
160
- # scale crop here?
161
- keypts_xyp = dlc_live.get_pose(crop) # third column is llk!
162
- # set kpts below threhsold to nan
163
- keypts_xyp[keypts_xyp[:,-1] < kpts_likelihood_th,:] = np_aux.fill(np.nan)
164
- # add kpts of this crop to list
165
- list_kpts_per_crop.append(keypts_xyp)
166
-
167
- return list_kpts_per_crop
168
-
169
-
170
  #####################################################
171
  def predict_pipeline(img_input,
172
  mega_model_input,
@@ -181,33 +51,41 @@ def predict_pipeline(img_input,
181
  marker_size,
182
  ):
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  ############################################################
185
- ## Get DLC model and labels as strings
186
- # TODO: make a dict as for megadetector
187
- # pdb.set_trace()
188
- path_to_DLCmodel = DLC_models[dlc_model_input_str]
189
- pose_cfg_path = os.path.join(path_to_DLCmodel,'pose_cfg.yaml')
190
-
 
 
 
 
 
191
  # extract map label ids to strings
192
- # pose_cfg_dict['all_joints'] is a list of one-element lists,
 
193
  with open(pose_cfg_path, "r") as stream:
194
  pose_cfg_dict = yaml.safe_load(stream)
195
- map_label_id_to_str = dict([(k,v) for k,v in zip([el[0] for el in pose_cfg_dict['all_joints']],
196
  pose_cfg_dict['all_joints_names'])])
197
 
198
- ############################################################
199
- # ### Run Megadetector
200
- md_results = predict_md(img_input,
201
- mega_model_input,
202
- size=640) #Image.fromarray(results.imgs[0])
203
-
204
- ################################################################
205
- # Obtain animal crops for bboxes with confidence above th
206
- list_crops = crop_animal_detections(md_results,
207
- bbox_likelihood_th)
208
-
209
  ##############################################################
210
- # Run DLC
211
  dlc_proc = Processor()
212
 
213
  # if required: ignore MD crops and run DLC on full image [mostly for testing]
@@ -217,7 +95,7 @@ def predict_pipeline(img_input,
217
  kpts_likelihood_th,
218
  path_to_DLCmodel,
219
  dlc_proc)
220
- # draw kpts on input img
221
  draw_keypoints_on_image(img_input,
222
  list_kpts_per_crop[0], # a numpy array with shape [num_keypoints, 2].
223
  map_label_id_to_str,
@@ -227,7 +105,8 @@ def predict_pipeline(img_input,
227
  font_size=font_size,
228
  keypt_color=keypt_color,
229
  marker_size=marker_size)
230
- return img_input
 
231
 
232
  else:
233
  # Compute kpts for each crop
@@ -235,21 +114,18 @@ def predict_pipeline(img_input,
235
  kpts_likelihood_th,
236
  path_to_DLCmodel,
237
  dlc_proc)
238
-
239
- # Produce final image
240
- img_background = Image.fromarray(md_results.imgs[0]) # img_input or Image.fromarray(md_results.imgs[0])?
241
- # Image.fromarray(md_results.imgs[0]) --> (640, 479)
242
- # img_input.size ---> (259, 194)
243
- # pdb.set_trace()
244
-
245
- # resize image to match megadetector output
246
- # g = (640 / max(img_background.size)) # gain
247
- # img_background = img_background.resize((int(x * g) for x in img_background.size), Image.ANTIALIAS) # resize
248
  for ic, (np_crop, kpts_crop) in enumerate(zip(list_crops,
249
  list_kpts_per_crop)):
250
 
251
- ## Draw keypts on crop
252
  img_crop = Image.fromarray(np_crop)
 
 
253
  draw_keypoints_on_image(img_crop,
254
  kpts_crop, # a numpy array with shape [num_keypoints, 2].
255
  map_label_id_to_str,
@@ -260,98 +136,45 @@ def predict_pipeline(img_input,
260
  keypt_color=keypt_color,
261
  marker_size=marker_size)
262
 
263
- ## Paste crop in original image
264
- # https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.paste
265
- img_background.paste(img_crop,
266
  box = tuple([int(t) for t in md_results.xyxy[0][ic,:2]]))
267
-
268
- return img_background
269
-
270
- #############################################
271
- # %%
272
- # User interface: inputs
273
-
274
- # Input image
275
- gr_image_input = gr.inputs.Image(type="pil", label="Input Image")
276
-
277
-
278
- # Models
279
- gr_dlc_model_input = gr.inputs.Dropdown(choices=list(DLC_models.keys()), # choices
280
- default='full_cat', # default option
281
- type='value', # Type of value to be returned by component. "value" returns the string of the choice selected, "index" returns the index of the choice selected.
282
- label='Select DeepLabCut model')
283
- gr_mega_model_input = gr.inputs.Dropdown(choices=list(Megadet_Models.keys()),
284
- default='md_v5a', # default option
285
- type='value', # Type of value to be returned by component. "value" returns the string of the choice selected, "index" returns the index of the choice selected.
286
- label='Select MegaDetector model')
287
- # Other inputs
288
- gr_dlc_only_checkbox = gr.inputs.Checkbox(False,
289
- label='Run DLClive only, directly on input image?')
290
- gr_str_labels_checkbox = gr.inputs.Checkbox(True,
291
- label='Show bodypart labels?')
292
-
293
- gr_slider_conf_bboxes = gr.inputs.Slider(0,1,.05,0.8,
294
- label='Set confidence threshold for animal detections')
295
- gr_slider_conf_keypoints = gr.inputs.Slider(0,1,.05,0,
296
- label='Set confidence threshold for keypoints')
297
 
298
- # Data viz
299
- gr_keypt_color = gr.ColorPicker(label="choose color for keypoint label")
300
-
301
- gr_labels_font_style = gr.inputs.Dropdown(choices=['amiko', 'nature', 'painter', 'animals', 'zen'],
302
- default='amiko',
303
- type='value',
304
- label='Select keypoint label font')
305
- gr_slider_font_size = gr.inputs.Slider(5,30,1,8,
306
- label='Set font size')
307
- gr_slider_marker_size = gr.inputs.Slider(0.5,5,0.2,2,
308
- label='Set marker size')
309
-
310
- # list of inputs
311
- inputs = [gr_image_input,
312
- gr_mega_model_input,
313
- gr_dlc_model_input,
314
- gr_dlc_only_checkbox,
315
- gr_str_labels_checkbox,
316
- gr_slider_conf_bboxes,
317
- gr_slider_conf_keypoints,
318
- gr_labels_font_style,
319
- gr_slider_font_size,
320
- gr_keypt_color,
321
- gr_slider_marker_size,
322
- ]
323
- ####################################################
324
- # %%
325
- # User interface: outputs
326
- gr_image_output = gr.outputs.Image(type="pil", label="Output Image")
327
- outputs = [gr_image_output]
328
-
329
- ##############################################
330
- # User interace: description
331
- gr_title = "MegaDetector v5 + DeepLabCut-Live!"
332
- gr_description = "Contributed by Sofia Minano, Neslihan Wittek, Nirel Kadzo, VicShaoChih Chiang -- DLC AI Residents 2022..\
333
- This App detects and estimate the pose of animals in camera trap images using <a href='https://github.com/microsoft/CameraTraps'>MegaDetector v5a</a> + <a href='https://github.com/DeepLabCut/DeepLabCut-live'>DeepLabCut-live</a>. \
334
- We host models from the <a href='http://www.mackenziemathislab.org/dlc-modelzoo'>DeepLabCut ModelZoo Project</a>\, and two <a href='https://github.com/microsoft/CameraTraps/blob/main/megadetector.md'>MegaDetector Models</a>. Please carefully check their licensing information if you use this project. The App additionally builds upon on work from <a href='https://huggingface.co/spaces/hlydecker/MegaDetector_v5'>hlydecker/MegaDetector_v5</a> \
335
- <a href='https://huggingface.co/spaces/sofmi/MegaDetector_DLClive'>sofmi/MegaDetector_DLClive</a> \
336
- <a href='https://huggingface.co/spaces/Neslihan/megadetector_dlcmodels'>Neslihan/megadetector_dlcmodels</a>\."
337
-
338
- # article = "<p style='text-align: center'>This app makes predictions using a YOLOv5x6 model that was trained to detect animals, humans, and vehicles in camera trap images; find out more about the project on <a href='https://github.com/microsoft/CameraTraps'>GitHub</a>. This app was built by Henry Lydecker but really depends on code and models developed by <a href='http://ecologize.org/'>Ecologize</a> and <a href='http://aka.ms/aiforearth'>Microsoft AI for Earth</a>. Find out more about the YOLO model from the original creator, <a href='https://pjreddie.com/darknet/yolo/'>Joseph Redmon</a>. YOLOv5 is a family of compound-scaled object detection models trained on the COCO dataset and developed by Ultralytics, and includes simple functionality for Test Time Augmentation (TTA), model ensembling, hyperparameter evolution, and export to ONNX, CoreML and TFLite. <a href='https://github.com/ultralytics/yolov5'>Source code</a> | <a href='https://pytorch.org/hub/ultralytics_yolov5'>PyTorch Hub</a></p>"
339
-
340
- examples = [['example/monkey_full.jpg', 'md_v5a','full_macaque', False, True, 0.5, 0.3, 'amiko', 5, 'blue', 3],
341
- ['example/dog.jpeg', 'md_v5a', 'full_dog', False, True, 0.5, 0.05, 'amiko', 5, 'yellow', 3],
342
- ['example/cat.jpg', 'md_v5a', 'full_cat', False, True, 0.5, 0.05, 'amiko', 5, 'purple', 3]]
343
-
344
- ################################################
345
- # %% Define and launch gradio interface
346
  demo = gr.Interface(predict_pipeline,
347
  inputs=inputs,
348
  outputs=outputs,
349
  title=gr_title,
350
  description=gr_description,
351
  examples=examples,
352
- theme="huggingface",
353
- #live=True
354
- )
355
 
356
  demo.launch(enable_queue=True, share=True)
357
 
 
2
  # Built from https://huggingface.co/spaces/sofmi/MegaDetector_DLClive/blob/main/app.py
3
  # Built from https://huggingface.co/spaces/Neslihan/megadetector_dlcmodels/blob/main/app.py
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import os
6
  import yaml
7
+ import numpy as np
8
+ from matplotlib import cm
9
+ import gradio as gr
10
 
11
+ from PIL import Image, ImageColor, ImageFont, ImageDraw
12
+ # check git lfs pull!!
13
+ from DLC_models.download_utils import DownloadModel
14
+ from dlclive import DLCLive, Processor
 
 
 
 
 
15
 
16
+ from viz_utils import save_results_as_json, draw_keypoints_on_image, draw_bbox_w_text
17
+ from detection_utils import predict_md, crop_animal_detections, predict_dlc
18
+ from ui_utils import gradio_inputs_for_MD_DLC, gradio_outputs_for_MD_DLC, gradio_description_and_examples
19
 
20
+ # import pdb
 
 
 
 
 
21
  #########################################
22
+ # Input params - Global vars
23
+
24
+ MD_models_dict = {'md_v5a': "MD_models/md_v5a.0.0.pt", #
25
+ 'md_v5b': "MD_models/md_v5b.0.0.pt"}
26
+
27
+ # DLC models target dirs
28
+ DLC_models_dict = {'full_cat': "DLC_models/DLC_Cat/",
29
+ 'full_dog': "DLC_models/DLC_Dog/",
30
+ 'primate_face': "DLC_models/DLC_FacialLandmarks/",
31
+ 'full_human': "DLC_models/DLC_human_dancing/",
32
+ 'full_macaque': 'DLC_models/DLC_monkey/'}
33
+
34
+
35
+ # FONTS = {'amiko': "fonts/Amiko-Regular.ttf",
36
+ # 'nature': "fonts/LoveNature.otf",
37
+ # 'painter':"fonts/PainterDecorator.otf",
38
+ # 'animals': "fonts/UncialAnimals.ttf",
39
+ # 'zen': "fonts/ZEN.TTF"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  #####################################################
41
  def predict_pipeline(img_input,
42
  mega_model_input,
 
51
  marker_size,
52
  ):
53
 
54
+ if not flag_dlc_only:
55
+ ############################################################
56
+ # ### Run Megadetector
57
+ md_results = predict_md(img_input,
58
+ MD_models_dict[mega_model_input], #mega_model_input,
59
+ size=640) #Image.fromarray(results.imgs[0])
60
+
61
+ ################################################################
62
+ # Obtain animal crops for bboxes with confidence above th
63
+ list_crops = crop_animal_detections(img_input,
64
+ md_results,
65
+ bbox_likelihood_th)
66
+
67
  ############################################################
68
+ ## Get DLC model and label map
69
+
70
+ # If model is found: do not download (previous execution is likely within same day)
71
+ # TODO: can we ask the user whether to reload dlc model if a directory is found?
72
+ if os.path.isdir(DLC_models_dict[dlc_model_input_str]) and \
73
+ len(os.listdir(DLC_models_dict[dlc_model_input_str])) > 0:
74
+ path_to_DLCmodel = DLC_models_dict[dlc_model_input_str]
75
+ else:
76
+ path_to_DLCmodel = DownloadModel(dlc_model_input_str,
77
+ DLC_models_dict[dlc_model_input_str])
78
+
79
  # extract map label ids to strings
80
+ pose_cfg_path = os.path.join(DLC_models_dict[dlc_model_input_str],
81
+ 'pose_cfg.yaml')
82
  with open(pose_cfg_path, "r") as stream:
83
  pose_cfg_dict = yaml.safe_load(stream)
84
+ map_label_id_to_str = dict([(k,v) for k,v in zip([el[0] for el in pose_cfg_dict['all_joints']], # pose_cfg_dict['all_joints'] is a list of one-element lists,
85
  pose_cfg_dict['all_joints_names'])])
86
 
 
 
 
 
 
 
 
 
 
 
 
87
  ##############################################################
88
+ # Run DLC and visualise results
89
  dlc_proc = Processor()
90
 
91
  # if required: ignore MD crops and run DLC on full image [mostly for testing]
 
95
  kpts_likelihood_th,
96
  path_to_DLCmodel,
97
  dlc_proc)
98
+ # draw kpts on input img #fix!
99
  draw_keypoints_on_image(img_input,
100
  list_kpts_per_crop[0], # a numpy array with shape [num_keypoints, 2].
101
  map_label_id_to_str,
 
105
  font_size=font_size,
106
  keypt_color=keypt_color,
107
  marker_size=marker_size)
108
+
109
+ return img_input, []
110
 
111
  else:
112
  # Compute kpts for each crop
 
114
  kpts_likelihood_th,
115
  path_to_DLCmodel,
116
  dlc_proc)
117
+
118
+ # resize input image to match megadetector output
119
+ img_background = img_input.resize((md_results.ims[0].shape[1],
120
+ md_results.ims[0].shape[0]))
121
+
122
+ # draw keypoints on each crop and paste to background img
 
 
 
 
123
  for ic, (np_crop, kpts_crop) in enumerate(zip(list_crops,
124
  list_kpts_per_crop)):
125
 
 
126
  img_crop = Image.fromarray(np_crop)
127
+
128
+ # Draw keypts on crop
129
  draw_keypoints_on_image(img_crop,
130
  kpts_crop, # a numpy array with shape [num_keypoints, 2].
131
  map_label_id_to_str,
 
136
  keypt_color=keypt_color,
137
  marker_size=marker_size)
138
 
139
+ # Paste crop in original image
140
+ img_background.paste(img_crop,
 
141
  box = tuple([int(t) for t in md_results.xyxy[0][ic,:2]]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
+ # Plot bbox
144
+ bb_per_animal = md_results.xyxy[0].tolist()[ic]
145
+ pred = md_results.xyxy[0].tolist()[ic][4]
146
+ if bbox_likelihood_th < pred:
147
+ draw_bbox_w_text(img_background,
148
+ bb_per_animal,
149
+ font_style=font_style,
150
+ font_size=font_size) # TODO: add selectable color for bbox?
151
+
152
+
153
+ # Save detection results as json
154
+ download_file = save_results_as_json(md_results,
155
+ list_kpts_per_crop,
156
+ map_label_id_to_str,
157
+ bbox_likelihood_th)
158
+
159
+ return img_background, download_file
160
+
161
+ #########################################################
162
+ # Define user interface and launch
163
+ inputs = gradio_inputs_for_MD_DLC(list(MD_models_dict.keys()),
164
+ list(DLC_models_dict.keys()))
165
+ outputs = gradio_outputs_for_MD_DLC()
166
+ [gr_title,
167
+ gr_description,
168
+ examples] = gradio_description_and_examples()
169
+
170
+ # launch
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  demo = gr.Interface(predict_pipeline,
172
  inputs=inputs,
173
  outputs=outputs,
174
  title=gr_title,
175
  description=gr_description,
176
  examples=examples,
177
+ theme="huggingface")
 
 
178
 
179
  demo.launch(enable_queue=True, share=True)
180
 
detection_utils.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from tkinter import W
3
+ import gradio as gr
4
+ from matplotlib import cm
5
+ import torch
6
+ import torchvision
7
+ from dlclive import DLCLive, Processor
8
+ import matplotlib
9
+ from PIL import Image, ImageColor, ImageFont, ImageDraw
10
+ import numpy as np
11
+ import math
12
+
13
+
14
+ import yaml
15
+ import pdb
16
+
17
+ ############################################
18
+ # Predict detections with MegaDetector v5a model
19
+ def predict_md(im,
20
+ megadetector_model, #Megadet_Models[mega_model_input]
21
+ size=640):
22
+
23
+ # resize image
24
+ g = (size / max(im.size)) # multipl factor to make max size of the image equal to input size
25
+ im = im.resize((int(x * g) for x in im.size),
26
+ Image.ANTIALIAS) # resize
27
+ # device
28
+ if torch.cuda.is_available():
29
+ md_device = torch.device('cuda')
30
+ else:
31
+ md_device = torch.device('cpu')
32
+
33
+ # megadetector
34
+ MD_model = torch.hub.load('ultralytics/yolov5', # repo_or_dir
35
+ 'custom', #model
36
+ megadetector_model, # args for callable model
37
+ force_reload=True,
38
+ device=md_device)
39
+
40
+ # send model to gpu if possible
41
+ if (md_device == torch.device('cuda')):
42
+ print('Sending model to GPU')
43
+ MD_model.to(md_device)
44
+
45
+ ## detect objects
46
+ results = MD_model(im) # inference # vars(results).keys()= dict_keys(['imgs', 'pred', 'names', 'files', 'times', 'xyxy', 'xywh', 'xyxyn', 'xywhn', 'n', 't', 's'])
47
+
48
+ return results
49
+
50
+
51
+ ##########################################
52
+ def crop_animal_detections(img_in,
53
+ yolo_results,
54
+ likelihood_th):
55
+
56
+ ## Extract animal crops
57
+ list_labels_as_str = [i for i in yolo_results.names.values()] # ['animal', 'person', 'vehicle']
58
+ list_np_animal_crops = []
59
+
60
+ # image to crop (scale as input for megadetector)
61
+ img_in = img_in.resize((yolo_results.ims[0].shape[1],
62
+ yolo_results.ims[0].shape[0]))
63
+ # for every detection in the img
64
+ for det_array in yolo_results.xyxy:
65
+
66
+ # for every detection
67
+ for j in range(det_array.shape[0]):
68
+
69
+ # compute coords around bbox rounded to the nearest integer (for pasting later)
70
+ xmin_rd = int(math.floor(det_array[j,0])) # int() should suffice?
71
+ ymin_rd = int(math.floor(det_array[j,1]))
72
+
73
+ xmax_rd = int(math.ceil(det_array[j,2]))
74
+ ymax_rd = int(math.ceil(det_array[j,3]))
75
+
76
+ pred_llk = det_array[j,4]
77
+ pred_label = det_array[j,5]
78
+ # keep animal crops above threshold
79
+ if (pred_label == list_labels_as_str.index('animal')) and \
80
+ (pred_llk >= likelihood_th):
81
+ area = (xmin_rd, ymin_rd, xmax_rd, ymax_rd)
82
+
83
+ #pdb.set_trace()
84
+ crop = img_in.crop(area) #Image.fromarray(img_in).crop(area)
85
+ crop_np = np.asarray(crop)
86
+
87
+ # add to list
88
+ list_np_animal_crops.append(crop_np)
89
+
90
+ return list_np_animal_crops
91
+
92
+ ##########################################
93
+ def predict_dlc(list_np_crops,
94
+ kpts_likelihood_th,
95
+ DLCmodel,
96
+ dlc_proc):
97
+
98
+ # run dlc thru list of crops
99
+ dlc_live = DLCLive(DLCmodel, processor=dlc_proc)
100
+ dlc_live.init_inference(list_np_crops[0])
101
+
102
+ list_kpts_per_crop = []
103
+ all_kypts = []
104
+ np_aux = np.empty((1,3)) # can I avoid hardcoding here?
105
+ for crop in list_np_crops:
106
+ # scale crop here?
107
+ keypts_xyp = dlc_live.get_pose(crop) # third column is llk!
108
+ # set kpts below threhsold to nan
109
+
110
+ #pdb.set_trace()
111
+ keypts_xyp[keypts_xyp[:,-1] < kpts_likelihood_th,:] = np_aux.fill(np.nan)
112
+ # add kpts of this crop to list
113
+ list_kpts_per_crop.append(keypts_xyp)
114
+ all_kypts.append(keypts_xyp)
115
+
116
+ return list_kpts_per_crop
{example β†’ examples}/cat.jpg RENAMED
File without changes
{example β†’ examples}/dog.jpeg RENAMED
File without changes
examples/monkey_face.jpeg ADDED
{example β†’ examples}/monkey_full.jpg RENAMED
File without changes
{font β†’ examples}/read.md RENAMED
File without changes
{font β†’ fonts}/Amiko-Regular.ttf RENAMED
File without changes
{font β†’ fonts}/LoveNature.otf RENAMED
File without changes
{font β†’ fonts}/PainterDecorator.otf RENAMED
File without changes
{font β†’ fonts}/UncialAnimals.ttf RENAMED
File without changes
{font β†’ fonts}/ZEN.TTF RENAMED
File without changes
{megadet_model β†’ fonts}/read.md RENAMED
File without changes
model/DLC_Cat_resnet_50_iteration-0_shuffle-0/pose_cfg.yaml DELETED
@@ -1,106 +0,0 @@
1
- all_joints:
2
- - - 0
3
- - - 1
4
- - - 2
5
- - - 3
6
- - - 4
7
- - - 5
8
- - - 6
9
- - - 7
10
- - - 8
11
- - - 9
12
- - - 10
13
- - - 11
14
- - - 12
15
- - - 13
16
- - - 14
17
- - - 15
18
- - - 16
19
- - - 17
20
- - - 18
21
- - - 19
22
- all_joints_names:
23
- - Nose
24
- - L_Eye
25
- - R_Eye
26
- - L_Ear
27
- - R_Ear
28
- - Throat
29
- - Withers
30
- - TailSet
31
- - L_F_Paw
32
- - R_F_Paw
33
- - L_F_Wrist
34
- - R_F_Wrist
35
- - L_F_Elbow
36
- - R_F_Elbow
37
- - L_B_Paw
38
- - R_B_Paw
39
- - L_B_Hock
40
- - R_B_Hock
41
- - L_B_Stiffle
42
- - R_B_Stiffle
43
- augmentationprobability: 0.5
44
- batch_size:
45
- bottomheight: 400
46
- covering: true
47
- crop: true
48
- crop_pad: 0
49
- cropratio: 0.4
50
- dataset: training-datasets/iteration-0/UnaugmentedDataSet_CatMay11/Cat_TeamDLC99shuffle0.mat
51
- dataset_type: imgaug
52
- deterministic: false
53
- display_iters: 1000
54
- elastic_transform: true
55
- fg_fraction: 0.25
56
- global_scale: 0.8
57
- init_weights: TBA
58
- intermediate_supervision: false
59
- intermediate_supervision_layer: 12
60
- leftwidth: 400
61
- location_refinement: true
62
- locref_huber_loss: true
63
- locref_loss_weight: 0.05
64
- locref_stdev: 7.2801
65
- log_dir: log
66
- max_input_size: 1500
67
- mean_pixel:
68
- - 123.68
69
- - 116.779
70
- - 103.939
71
- metadataset: training-datasets/iteration-0/UnaugmentedDataSet_CatMay11/Documentation_data-Cat_99shuffle0.pickle
72
- min_input_size: 64
73
- minsize: 100
74
- mirror: false
75
- motion_blur: true
76
- multi_step:
77
- - - 0.0001
78
- - 7500
79
- - - 5e-05
80
- - 12000
81
- - - 1e-05
82
- - 75000
83
- net_type: resnet_50
84
- num_joints: 20
85
- num_outputs: 1
86
- optimizer: adam
87
- pairwise_huber_loss: true
88
- pairwise_predict: false
89
- partaffinityfield_predict: false
90
- pos_dist_thresh: 17
91
- project_path: TBA
92
- regularize: false
93
- rightwidth: 400
94
- rotation: 180
95
- save_iters: 50000
96
- scale_jitter_lo: 0.5
97
- scale_jitter_up: 1.5
98
- scoremap_dir: test
99
- shuffle: true
100
- snapshot_prefix: TBA
101
- stride: 8.0
102
- topheight: 400
103
- weigh_negatives: false
104
- weigh_only_present_joints: false
105
- weigh_part_predictions: false
106
- weight_decay: 0.0001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/DLC_Cat_resnet_50_iteration-0_shuffle-0/read.md DELETED
File without changes
model/DLC_Cat_resnet_50_iteration-0_shuffle-0/snapshot-75000.pb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d44893d1d7a0a07afd37b28c8c00cd8178ae69a0ff49152f16c08c53b8efa4da
3
- size 98887790
 
 
 
 
model/DLC_Dog_resnet_50_iteration-0_shuffle-0/pose_cfg.yaml DELETED
@@ -1,106 +0,0 @@
1
- all_joints:
2
- - - 0
3
- - - 1
4
- - - 2
5
- - - 3
6
- - - 4
7
- - - 5
8
- - - 6
9
- - - 7
10
- - - 8
11
- - - 9
12
- - - 10
13
- - - 11
14
- - - 12
15
- - - 13
16
- - - 14
17
- - - 15
18
- - - 16
19
- - - 17
20
- - - 18
21
- - - 19
22
- all_joints_names:
23
- - Nose
24
- - L_Eye
25
- - R_Eye
26
- - L_Ear
27
- - R_Ear
28
- - Throat
29
- - Withers
30
- - TailSet
31
- - L_F_Paw
32
- - R_F_Paw
33
- - L_F_Wrist
34
- - R_F_Wrist
35
- - L_F_Elbow
36
- - R_F_Elbow
37
- - L_B_Paw
38
- - R_B_Paw
39
- - L_B_Hock
40
- - R_B_Hock
41
- - L_B_Stiffle
42
- - R_B_Stiffle
43
- augmentationprobability: 0.5
44
- batch_size:
45
- bottomheight: 400
46
- covering: true
47
- crop: true
48
- crop_pad: 0
49
- cropratio: 0.4
50
- dataset: training-datasets/iteration-0/UnaugmentedDataSet_DogMay11/Dog_TeamDLC99shuffle0.mat
51
- dataset_type: imgaug
52
- deterministic: false
53
- display_iters: 1000
54
- elastic_transform: true
55
- fg_fraction: 0.25
56
- global_scale: 0.8
57
- init_weights: TBA
58
- intermediate_supervision: false
59
- intermediate_supervision_layer: 12
60
- leftwidth: 400
61
- location_refinement: true
62
- locref_huber_loss: true
63
- locref_loss_weight: 0.05
64
- locref_stdev: 7.2801
65
- log_dir: log
66
- max_input_size: 1500
67
- mean_pixel:
68
- - 123.68
69
- - 116.779
70
- - 103.939
71
- metadataset: training-datasets/iteration-0/UnaugmentedDataSet_DogMay11/Documentation_data-Dog_99shuffle0.pickle
72
- min_input_size: 64
73
- minsize: 100
74
- mirror: false
75
- motion_blur: true
76
- multi_step:
77
- - - 0.0001
78
- - 7500
79
- - - 5e-05
80
- - 12000
81
- - - 1e-05
82
- - 75000
83
- net_type: resnet_50
84
- num_joints: 20
85
- num_outputs: 1
86
- optimizer: adam
87
- pairwise_huber_loss: true
88
- pairwise_predict: false
89
- partaffinityfield_predict: false
90
- pos_dist_thresh: 17
91
- project_path: TBA
92
- regularize: false
93
- rightwidth: 400
94
- rotation: 180
95
- save_iters: 50000
96
- scale_jitter_lo: 0.5
97
- scale_jitter_up: 1.5
98
- scoremap_dir: test
99
- shuffle: true
100
- snapshot_prefix: TBA
101
- stride: 8.0
102
- topheight: 400
103
- weigh_negatives: false
104
- weigh_only_present_joints: false
105
- weigh_part_predictions: false
106
- weight_decay: 0.0001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/DLC_Dog_resnet_50_iteration-0_shuffle-0/read.md DELETED
File without changes
model/DLC_Dog_resnet_50_iteration-0_shuffle-0/snapshot-75000.pb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:f126991a0a312e0acf61313244107a476ffa68355bd4e34337dddb35784f5c5f
3
- size 98887790
 
 
 
 
model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1/pose_cfg.yaml DELETED
@@ -1,154 +0,0 @@
1
- all_joints:
2
- - - 0
3
- - - 1
4
- - - 2
5
- - - 3
6
- - - 4
7
- - - 5
8
- - - 6
9
- - - 7
10
- - - 8
11
- - - 9
12
- - - 10
13
- - - 11
14
- - - 12
15
- - - 13
16
- - - 14
17
- - - 15
18
- - - 16
19
- - - 17
20
- - - 18
21
- - - 19
22
- - - 20
23
- - - 21
24
- - - 22
25
- - - 23
26
- - - 24
27
- - - 25
28
- - - 26
29
- - - 27
30
- - - 28
31
- - - 29
32
- - - 30
33
- - - 31
34
- - - 32
35
- - - 33
36
- - - 34
37
- - - 35
38
- - - 36
39
- - - 37
40
- - - 38
41
- - - 39
42
- - - 40
43
- - - 41
44
- - - 42
45
- - - 43
46
- - - 44
47
- - - 45
48
- - - 46
49
- - - 47
50
- - - 48
51
- - - 49
52
- - - 50
53
- - - 51
54
- - - 52
55
- - - 53
56
- - - 54
57
- all_joints_names:
58
- - HeadTop_Mid
59
- - RightEarTop_Join
60
- - RightEarTop_High
61
- - RightEar_Outer
62
- - RightEarBottom_Low
63
- - RightEarBottom_Join
64
- - RightEar_Tragus
65
- - OutlineTop_Mid
66
- - OutlineTop_Right
67
- - OutlineRight_Brow
68
- - OutlineRight_Indent
69
- - OutlineRight_Cheek
70
- - OutlineRight_Mouth
71
- - OutlineChin_Mid
72
- - OutlineLeft_Mouth
73
- - OutlineLeft_Cheek
74
- - OutlineLeft_Indent
75
- - OutlineLeft_Brow
76
- - OutlineTop_Left
77
- - LeftEarTop_Join
78
- - LeftEarTop_High
79
- - LeftEar_Outer
80
- - LeftEarBottom_Low
81
- - LeftEarBottom_Join
82
- - LeftEar_Tragus
83
- - Eyes_MidPoint
84
- - RightEye_Inner
85
- - RightEye_Top
86
- - RightEye_Outer
87
- - RightEye_Bottom
88
- - RightEye_Pupil
89
- - RightEye_Highlight
90
- - LeftEye_Inner
91
- - LeftEye_Top
92
- - LeftEye_Outer
93
- - LeftEye_Bottom
94
- - LeftEye_Pupil
95
- - LeftEye_Highlight
96
- - RightBrow_Outer
97
- - RightBrow_Top
98
- - RightBrow_Inner
99
- - Brow_MidPoint
100
- - LeftBrow_Inner
101
- - LeftBrow_Top
102
- - LeftBrow_Outer
103
- - RightNostrils_Top
104
- - RightNostrils_Bottom
105
- - LeftNostrils_Bottom
106
- - LeftNostrils_Top
107
- - NostrilsTop_Centre
108
- - UpperLip_Centre
109
- - LipsMeet_Centre
110
- - LowerLip_Centre
111
- - MidPoint_Nostrils_Mouth
112
- - Neck_Nape
113
- batch_size:
114
- bottomheight: 400
115
- crop: false
116
- crop_pad: 0
117
- cropratio: 0.25
118
- dataset: training-datasets\iteration-1\UnaugmentedDataSet_FacialLandmarksNov19\FacialLandmarks_Witham95shuffle1.mat
119
- dataset_type: default
120
- deconvolutionstride: 2
121
- deterministic: false
122
- fg_fraction: 0.25
123
- global_scale: 0.8
124
- init_weights: C:\Data\Python\examples\FacialLandmarks-Witham-2019-11-09\dlc-models\iteration-1\FacialLandmarksNov19-trainset95shuffle1\train\snapshot-1030000
125
- intermediate_supervision: false
126
- intermediate_supervision_layer: 12
127
- leftwidth: 400
128
- location_refinement: true
129
- locref_huber_loss: true
130
- locref_loss_weight: 1.0
131
- locref_stdev: 7.2801
132
- log_dir: log
133
- mean_pixel:
134
- - 123.68
135
- - 116.779
136
- - 103.939
137
- minsize: 100
138
- mirror: false
139
- net_type: resnet_50
140
- num_joints: 55
141
- num_outputs: 1
142
- optimizer: sgd
143
- output_stride: 16
144
- regularize: false
145
- rightwidth: 400
146
- scoremap_dir: test
147
- shuffle: true
148
- snapshot_prefix: C:\Data\Python\examples\FacialLandmarks-Witham-2019-11-09\dlc-models\iteration-1\FacialLandmarksNov19-trainset95shuffle1\test\snapshot
149
- stride: 8.0
150
- topheight: 400
151
- weigh_negatives: false
152
- weigh_only_present_joints: false
153
- weigh_part_predictions: false
154
- weight_decay: 0.0001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1/read.md DELETED
File without changes
model/DLC_FacialLandmarks_resnet_50_iteration-1_shuffle-1/snapshot-1030000.pb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:f195f6c51827fe2e69493ca93947177f2ef80b1dcdb6e49637d2ffd45ccb4d4c
3
- size 106628915
 
 
 
 
model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1/pose_cfg.yaml DELETED
@@ -1,72 +0,0 @@
1
- all_joints:
2
- - - 0
3
- - - 1
4
- - - 2
5
- - - 3
6
- - - 4
7
- - - 5
8
- - - 6
9
- - - 7
10
- - - 8
11
- - - 9
12
- - - 10
13
- - - 11
14
- - - 12
15
- - - 13
16
- all_joints_names:
17
- - ankle1
18
- - knee1
19
- - hip1
20
- - hip2
21
- - knee2
22
- - ankle2
23
- - wrist1
24
- - elbow1
25
- - shoulder1
26
- - shoulder2
27
- - elbow2
28
- - wrist2
29
- - chin
30
- - forehead
31
- batch_size:
32
- bottomheight: 400
33
- crop: false
34
- crop_pad: 0
35
- cropratio: 0.25
36
- dataset: dataset-test.mat
37
- dataset_type: default
38
- deconvolutionstride: 2
39
- deterministic: false
40
- fg_fraction: 0.25
41
- global_scale: 1.0
42
- init_weights: /content/human_dancing-teamDLC-2020-04-26/dlc-models/iteration-0/human_dancingApr26-trainset95shuffle1/train/snapshot-103000
43
- intermediate_supervision: false
44
- intermediate_supervision_layer: 12
45
- leftwidth: 400
46
- location_refinement: true
47
- locref_huber_loss: true
48
- locref_loss_weight: 1.0
49
- locref_stdev: 7.2801
50
- log_dir: log
51
- mean_pixel:
52
- - 123.68
53
- - 116.779
54
- - 103.939
55
- minsize: 100
56
- mirror: false
57
- net_type: resnet_101
58
- num_joints: 14
59
- num_outputs: 1
60
- optimizer: sgd
61
- output_stride: 16
62
- regularize: false
63
- rightwidth: 400
64
- scoremap_dir: test
65
- shuffle: true
66
- snapshot_prefix: /content/human_dancing-teamDLC-2020-04-26/dlc-models/iteration-0/human_dancingApr26-trainset95shuffle1/test/snapshot
67
- stride: 8.0
68
- topheight: 400
69
- weigh_negatives: false
70
- weigh_only_present_joints: false
71
- weigh_part_predictions: false
72
- weight_decay: 0.0001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1/read.md DELETED
File without changes
model/DLC_human_dancing_resnet_101_iteration-0_shuffle-1/snapshot-103000.pb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:dbcef35a3734d76909f08d51b938ec84c985b9597f75db028861678c0fa2f4a0
3
- size 173890143
 
 
 
 
model/DLC_monkey_resnet_50_iteration-0_shuffle-1/pose_cfg.yaml DELETED
@@ -1,96 +0,0 @@
1
- all_joints:
2
- - - 0
3
- - - 1
4
- - - 2
5
- - - 3
6
- - - 4
7
- - - 5
8
- - - 6
9
- - - 7
10
- - - 8
11
- - - 9
12
- - - 10
13
- - - 11
14
- - - 12
15
- - - 13
16
- - - 14
17
- - - 15
18
- - - 16
19
- all_joints_names:
20
- - nose
21
- - left_eye
22
- - right_eye
23
- - left_ear
24
- - right_ear
25
- - left_shoulder
26
- - right_shoulder
27
- - left_elbow
28
- - right_elbow
29
- - left_wrist
30
- - right_wrist
31
- - left_hip
32
- - right_hip
33
- - left_knee
34
- - right_knee
35
- - left_ankle
36
- - right_ankle
37
- batch_size:
38
- bottomheight: 400
39
- crop: true
40
- crop_pad: 0
41
- cropratio: 0.4
42
- dataset: training-datasets/iteration-0/UnaugmentedDataSet_monkeyOct30/monkey_Toyama95shuffle1.mat
43
- dataset_type: default
44
- deconvolutionstride: 2
45
- deterministic: false
46
- display_iters: 1000
47
- fg_fraction: 0.25
48
- global_scale: 0.8
49
- init_weights: /media/deepstation/843cad10-f308-49f6-b896-b1ac1470af80/dlcmodel_to_pri_20200616/monkey-afterfix-Toyama-v2-2018-10-30/dlc-models/iteration-0/monkeyOct30-trainset95shuffle1/train/snapshot-1030000
50
- intermediate_supervision: false
51
- intermediate_supervision_layer: 12
52
- leftwidth: 400
53
- location_refinement: true
54
- locref_huber_loss: true
55
- locref_loss_weight: 0.05
56
- locref_stdev: 7.2801
57
- log_dir: log
58
- max_input_size: 1500
59
- mean_pixel:
60
- - 123.68
61
- - 116.779
62
- - 103.939
63
- metadataset: training-datasets/iteration-0/UnaugmentedDataSet_monkeyOct30/Documentation_data-monkey_95shuffle1.pickle
64
- min_input_size: 64
65
- minsize: 100
66
- mirror: false
67
- multi_step:
68
- - - 0.005
69
- - 10000
70
- - - 0.02
71
- - 430000
72
- - - 0.002
73
- - 730000
74
- - - 0.001
75
- - 1030000
76
- net_type: resnet_50
77
- num_joints: 17
78
- num_outputs: 1
79
- optimizer: sgd
80
- output_stride: 16
81
- pos_dist_thresh: 17
82
- project_path: /home/chava/Kyutech/DeepLabCut214/examples/monkey-afterfix-Toyama-v2-2018-10-30
83
- regularize: false
84
- rightwidth: 400
85
- save_iters: 50000
86
- scale_jitter_lo: 0.5
87
- scale_jitter_up: 1.25
88
- scoremap_dir: test
89
- shuffle: true
90
- snapshot_prefix: /media/deepstation/843cad10-f308-49f6-b896-b1ac1470af80/dlcmodel_to_pri_20200616/monkey-afterfix-Toyama-v2-2018-10-30/dlc-models/iteration-0/monkeyOct30-trainset95shuffle1/train/snapshot
91
- stride: 8.0
92
- topheight: 400
93
- weigh_negatives: false
94
- weigh_only_present_joints: false
95
- weigh_part_predictions: false
96
- weight_decay: 0.0001
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model/DLC_monkey_resnet_50_iteration-0_shuffle-1/read.md DELETED
File without changes
model/DLC_monkey_resnet_50_iteration-0_shuffle-1/snapshot-1030000.pb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:3d11182f326f35f9eb66772ee820a08820822ac9a5a89b026e0b2b61eaa0b06c
3
- size 98224202
 
 
 
 
save_results.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import numpy as np
3
+ import pdb
4
+
5
+ dict_pred = {0: 'animal', 1: 'person', 2: 'vehicle'}
6
+
7
+
8
+ def save_results(md_results, dlc_outputs,map_label_id_to_str,thr,output_file = 'dowload_predictions.json'):
9
+
10
+ """
11
+
12
+ write json
13
+
14
+ """
15
+ info = {}
16
+ ## info megaDetector
17
+ info['file']= md_results.files[0]
18
+ number_bb = len(md_results.xyxy[0].tolist())
19
+ info['number_of_bb'] = number_bb
20
+ number_bb_thr = len(dlc_outputs)
21
+ labels = [n for n in map_label_id_to_str.values()]
22
+ #pdb.set_trace()
23
+ new_index = []
24
+ for i in range(number_bb):
25
+ corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = md_results.xyxy[0].tolist()[i]
26
+
27
+ if confidence > thr:
28
+ new_index.append(i)
29
+
30
+
31
+ for i in range(number_bb_thr):
32
+ aux={}
33
+ corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = md_results.xyxy[0].tolist()[new_index[i]]
34
+ aux['corner_1'] = (corner_x1,corner_y1)
35
+ aux['corner_2'] = (corner_x2,corner_y2)
36
+ aux['predict MD'] = md_results.names[0]
37
+ aux['confidence MD'] = confidence
38
+
39
+ ## info dlc
40
+ kypts = []
41
+ for s in dlc_outputs[i]:
42
+ aux1 = []
43
+ for j in s:
44
+ aux1.append(float(j))
45
+
46
+ kypts.append(aux1)
47
+ aux['dlc_pred'] = dict(zip(labels,kypts))
48
+ info['bb_' + str(new_index[i]) ]=aux
49
+
50
+
51
+ with open(output_file, 'w') as f:
52
+ json.dump(info, f, indent=1)
53
+ print('Output file saved at {}'.format(output_file))
54
+
55
+ return output_file
56
+
ui_utils.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ ##############################
4
+ def gradio_inputs_for_MD_DLC(md_models_list, # list(MD_models_dict.keys())
5
+ dlc_models_list, # list(DLC_models_dict.keys())
6
+ ):
7
+ # Input image
8
+ gr_image_input = gr.inputs.Image(type="pil", label="Input Image")
9
+
10
+
11
+ # Models
12
+ gr_mega_model_input = gr.inputs.Dropdown(choices=md_models_list,
13
+ default='md_v5a', # default option
14
+ type='value', # Type of value to be returned by component. "value" returns the string of the choice selected, "index" returns the index of the choice selected.
15
+ label='Select MegaDetector model')
16
+ gr_dlc_model_input = gr.inputs.Dropdown(choices=dlc_models_list, # choices
17
+ default='full_cat', # default option
18
+ type='value', # Type of value to be returned by component. "value" returns the string of the choice selected, "index" returns the index of the choice selected.
19
+ label='Select DeepLabCut model')
20
+
21
+ # Other inputs
22
+ gr_dlc_only_checkbox = gr.inputs.Checkbox(False,
23
+ label='Run DLClive only, directly on input image?')
24
+ gr_str_labels_checkbox = gr.inputs.Checkbox(True,
25
+ label='Show bodypart labels?')
26
+
27
+ gr_slider_conf_bboxes = gr.inputs.Slider(0,1,.02,0.8,
28
+ label='Set confidence threshold for animal detections')
29
+ gr_slider_conf_keypoints = gr.inputs.Slider(0,1,.05,0,
30
+ label='Set confidence threshold for keypoints')
31
+
32
+ # Data viz
33
+ gr_keypt_color = gr.ColorPicker(label="choose color for keypoint label")
34
+
35
+ gr_labels_font_style = gr.inputs.Dropdown(choices=['amiko', 'nature', 'painter', 'animals', 'zen'],
36
+ default='amiko',
37
+ type='value',
38
+ label='Select keypoint label font')
39
+ gr_slider_font_size = gr.inputs.Slider(5,30,1,8,
40
+ label='Set font size')
41
+ gr_slider_marker_size = gr.inputs.Slider(1,20,1,5,
42
+ label='Set marker size')
43
+
44
+ # list of inputs
45
+ return [gr_image_input,
46
+ gr_mega_model_input,
47
+ gr_dlc_model_input,
48
+ gr_dlc_only_checkbox,
49
+ gr_str_labels_checkbox,
50
+ gr_slider_conf_bboxes,
51
+ gr_slider_conf_keypoints,
52
+ gr_labels_font_style,
53
+ gr_slider_font_size,
54
+ gr_keypt_color,
55
+ gr_slider_marker_size]
56
+
57
+ ####################################################
58
+ def gradio_outputs_for_MD_DLC():
59
+ # User interface: outputs
60
+ gr_image_output = gr.outputs.Image(type="pil", label="Output Image")
61
+ gr_file_download = gr.File(label="Download JSON file")
62
+ return [gr_image_output,
63
+ gr_file_download]
64
+
65
+ ##############################################
66
+ # User interace: description
67
+ def gradio_description_and_examples():
68
+ title = "MegaDetector v5 + DeepLabCut-Live!"
69
+ description = "Contributed by Sofia Minano, Neslihan Wittek, Nirel Kadzo, VicShaoChih Chiang, Sabrina Benas -- DLC AI Residents 2022..\
70
+ This App detects and estimate the pose of animals in camera trap images using <a href='https://github.com/microsoft/CameraTraps'>MegaDetector v5a</a> + <a href='https://github.com/DeepLabCut/DeepLabCut-live'>DeepLabCut-live</a>. \
71
+ We host models from the <a href='http://www.mackenziemathislab.org/dlc-modelzoo'>DeepLabCut ModelZoo Project</a>\, and two <a href='https://github.com/microsoft/CameraTraps/blob/main/megadetector.md'>MegaDetector Models</a>. Please carefully check their licensing information if you use this project. The App additionally builds upon on work from <a href='https://huggingface.co/spaces/hlydecker/MegaDetector_v5'>hlydecker/MegaDetector_v5</a> \
72
+ <a href='https://huggingface.co/spaces/sofmi/MegaDetector_DLClive'>sofmi/MegaDetector_DLClive</a> \
73
+ <a href='https://huggingface.co/spaces/Neslihan/megadetector_dlcmodels'>Neslihan/megadetector_dlcmodels</a>\."
74
+
75
+ # article = "<p style='text-align: center'>This app makes predictions using a YOLOv5x6 model that was trained to detect animals, humans, and vehicles in camera trap images; find out more about the project on <a href='https://github.com/microsoft/CameraTraps'>GitHub</a>. This app was built by Henry Lydecker but really depends on code and models developed by <a href='http://ecologize.org/'>Ecologize</a> and <a href='http://aka.ms/aiforearth'>Microsoft AI for Earth</a>. Find out more about the YOLO model from the original creator, <a href='https://pjreddie.com/darknet/yolo/'>Joseph Redmon</a>. YOLOv5 is a family of compound-scaled object detection models trained on the COCO dataset and developed by Ultralytics, and includes simple functionality for Test Time Augmentation (TTA), model ensembling, hyperparameter evolution, and export to ONNX, CoreML and TFLite. <a href='https://github.com/ultralytics/yolov5'>Source code</a> | <a href='https://pytorch.org/hub/ultralytics_yolov5'>PyTorch Hub</a></p>"
76
+
77
+ examples = [['examples/monkey_full.jpg', 'md_v5a','full_macaque', False, True, 0.5, 0.3, 'amiko', 9, 'blue', 3],
78
+ ['examples/dog.jpeg', 'md_v5a', 'full_dog', False, True, 0.5, 0.00, 'amiko',9, 'yellow', 3],
79
+ ['examples/cat.jpg', 'md_v5a', 'full_cat', False, True, 0.5, 0.05, 'amiko', 9, 'purple', 3]]
80
+
81
+ return [title,description,examples]
viz_utils.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import numpy as np
3
+
4
+ from matplotlib import cm
5
+ import matplotlib
6
+ from PIL import Image, ImageColor, ImageFont, ImageDraw
7
+ import numpy as np
8
+
9
+ FONTS = {'amiko': "fonts/Amiko-Regular.ttf",
10
+ 'nature': "fonts/LoveNature.otf",
11
+ 'painter':"fonts/PainterDecorator.otf",
12
+ 'animals': "fonts/UncialAnimals.ttf",
13
+ 'zen': "fonts/ZEN.TTF"}
14
+
15
+ #########################################
16
+ # Draw keypoints on image
17
+ def draw_keypoints_on_image(image,
18
+ keypoints,
19
+ map_label_id_to_str,
20
+ flag_show_str_labels,
21
+ use_normalized_coordinates=True,
22
+ font_style='amiko',
23
+ font_size=8,
24
+ keypt_color="#ff0000",
25
+ marker_size=2,
26
+ ):
27
+ """Draws keypoints on an image.
28
+ Modified from:
29
+ https://www.programcreek.com/python/?code=fjchange%2Fobject_centric_VAD%2Fobject_centric_VAD-master%2Fobject_detection%2Futils%2Fvisualization_utils.py
30
+ Args:
31
+ image: a PIL.Image object.
32
+ keypoints: a numpy array with shape [num_keypoints, 2].
33
+ map_label_id_to_str: dict with keys=label number and values= label string
34
+ flag_show_str_labels: boolean to select whether or not to show string labels
35
+ color: color to draw the keypoints with. Default is red.
36
+ radius: keypoint radius. Default value is 2.
37
+ use_normalized_coordinates: if True (default), treat keypoint values as
38
+ relative to the image. Otherwise treat them as absolute.
39
+
40
+
41
+ """
42
+ # get a drawing context
43
+ draw = ImageDraw.Draw(image,"RGBA")
44
+
45
+ im_width, im_height = image.size
46
+ keypoints_x = [k[0] for k in keypoints]
47
+ keypoints_y = [k[1] for k in keypoints]
48
+ alpha = [k[2] for k in keypoints]
49
+ norm = matplotlib.colors.Normalize(vmin=0, vmax=255)
50
+
51
+ names_for_color = [i for i in map_label_id_to_str.keys()]
52
+ colores = np.linspace(0, 255, num=len(names_for_color),dtype= int)
53
+
54
+ # adjust keypoints coords if required
55
+ if use_normalized_coordinates:
56
+ keypoints_x = tuple([im_width * x for x in keypoints_x])
57
+ keypoints_y = tuple([im_height * y for y in keypoints_y])
58
+
59
+ #cmap = matplotlib.cm.get_cmap('hsv')
60
+ cmap2 = matplotlib.cm.get_cmap('Greys')
61
+ # draw ellipses around keypoints
62
+ for i, (keypoint_x, keypoint_y) in enumerate(zip(keypoints_x, keypoints_y)):
63
+ round_fill = list(cm.viridis(norm(colores[i]),bytes=True))#[round(num*255) for num in list(cmap(i))[:3]] #check!
64
+ if np.isnan(alpha[i]) == False :
65
+ round_fill[3] = round(alpha[i] *255)
66
+ #print(round_fill)
67
+ #round_outline = [round(num*255) for num in list(cmap2(alpha[i]))[:3]]
68
+ draw.ellipse([(keypoint_x - marker_size, keypoint_y - marker_size),
69
+ (keypoint_x + marker_size, keypoint_y + marker_size)],
70
+ fill=tuple(round_fill), outline= 'black', width=1) #fill and outline: [0,255]
71
+
72
+ # add string labels around keypoints
73
+ if flag_show_str_labels:
74
+ font = ImageFont.truetype(FONTS[font_style],
75
+ font_size)
76
+ draw.text((keypoint_x + marker_size, keypoint_y + marker_size),#(0.5*im_width, 0.5*im_height), #-------
77
+ map_label_id_to_str[i],
78
+ ImageColor.getcolor(keypt_color, "RGB"), # rgb #
79
+ font=font)
80
+
81
+ #########################################
82
+ # Draw bboxes on image
83
+ def draw_bbox_w_text(img,
84
+ results,
85
+ font_style='amiko',
86
+ font_size=8): #TODO: select color too?
87
+ #pdb.set_trace()
88
+ bbxyxy = results
89
+ w, h = bbxyxy[2], bbxyxy[3]
90
+ shape = [(bbxyxy[0], bbxyxy[1]), (w , h)]
91
+ imgR = ImageDraw.Draw(img)
92
+ imgR.rectangle(shape, outline ="red",width=5) ##bb for animal
93
+
94
+ confidence = bbxyxy[4]
95
+ string_bb = 'animal ' + str(round(confidence, 2))
96
+ font = ImageFont.truetype(FONTS[font_style], font_size)
97
+
98
+ text_size = font.getsize(string_bb) # (h,w)
99
+ position = (bbxyxy[0],bbxyxy[1] - text_size[1] -2 )
100
+ left, top, right, bottom = imgR.textbbox(position, string_bb, font=font)
101
+ imgR.rectangle((left, top-5, right+5, bottom+5), fill="red")
102
+ imgR.text((bbxyxy[0] + 3 ,bbxyxy[1] - text_size[1] -2 ), string_bb, font=font, fill="black")
103
+
104
+ return imgR
105
+
106
+ ###########################################
107
+ def save_results_as_json(md_results,
108
+ dlc_outputs,
109
+ map_dlc_label_id_to_str,
110
+ thr,
111
+ path_to_output_file = 'download_predictions.json'):
112
+
113
+ """
114
+ Output detections as json file
115
+
116
+ """
117
+ # initialise dict to save to json
118
+ info = {}
119
+ # info from megaDetector
120
+ info['file']= md_results.files[0]
121
+ number_bb = len(md_results.xyxy[0].tolist())
122
+ info['number_of_bb'] = number_bb
123
+ # info from DLC
124
+ number_bb_thr = len(dlc_outputs)
125
+ labels = [n for n in map_dlc_label_id_to_str.values()]
126
+
127
+ # create list of bboxes above th
128
+ new_index = []
129
+ for i in range(number_bb):
130
+ corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = md_results.xyxy[0].tolist()[i]
131
+
132
+ if confidence > thr:
133
+ new_index.append(i)
134
+
135
+ # define aux dict for every bounding box above threshold
136
+ for i in range(number_bb_thr):
137
+ aux={}
138
+ # MD output
139
+ corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = md_results.xyxy[0].tolist()[new_index[i]]
140
+ aux['corner_1'] = (corner_x1,corner_y1)
141
+ aux['corner_2'] = (corner_x2,corner_y2)
142
+ aux['predict MD'] = md_results.names[0]
143
+ aux['confidence MD'] = confidence
144
+
145
+ # DLC output
146
+ kypts = []
147
+ for s in dlc_outputs[i]:
148
+ aux1 = []
149
+ for j in s:
150
+ aux1.append(float(j))
151
+
152
+ kypts.append(aux1)
153
+ aux['dlc_pred'] = dict(zip(labels,kypts))
154
+ info['bb_' + str(new_index[i]) ]=aux
155
+
156
+ # save dict as json
157
+ with open(path_to_output_file, 'w') as f:
158
+ json.dump(info, f, indent=1)
159
+ print('Output file saved at {}'.format(path_to_output_file))
160
+
161
+ return path_to_output_file
162
+
163
+
164
+
165
+ ###########################################