Spaces:
Build error
Build error
download models and colors kypts (#25)
Browse files- add download and kypts color (15928d774b7b425b3f655591043b4a12ea2bcd44)
- add save results and modelDownload (e9625b30d389a5aa99b4f989f4310bc58d96ce8b)
- app.py +113 -75
- save_results.py +56 -0
app.py
CHANGED
@@ -3,21 +3,23 @@
|
|
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 |
#########################################
|
@@ -31,14 +33,13 @@ FONTS = {'amiko': "font/Amiko-Regular.ttf",
|
|
31 |
Megadet_Models = {'md_v5a': "megadet_model/md_v5a.0.0.pt",
|
32 |
'md_v5b': "megadet_model/md_v5b.0.0.pt"}
|
33 |
|
34 |
-
|
35 |
-
'full_dog': "model/
|
36 |
-
'primate_face': "model/
|
37 |
-
'full_human': "model/
|
38 |
-
'full_macaque': 'model/
|
39 |
-
|
40 |
-
DLC_models_list = ['full_cat', 'full_dog','
|
41 |
-
|
42 |
#########################################
|
43 |
# Draw keypoints on image
|
44 |
def draw_keypoints_on_image(image,
|
@@ -49,7 +50,8 @@ def draw_keypoints_on_image(image,
|
|
49 |
font_style='amiko',
|
50 |
font_size=8,
|
51 |
keypt_color="#ff0000",
|
52 |
-
marker_size=
|
|
|
53 |
"""Draws keypoints on an image.
|
54 |
Modified from:
|
55 |
https://www.programcreek.com/python/?code=fjchange%2Fobject_centric_VAD%2Fobject_centric_VAD-master%2Fobject_detection%2Futils%2Fvisualization_utils.py
|
@@ -62,25 +64,38 @@ def draw_keypoints_on_image(image,
|
|
62 |
radius: keypoint radius. Default value is 2.
|
63 |
use_normalized_coordinates: if True (default), treat keypoint values as
|
64 |
relative to the image. Otherwise treat them as absolute.
|
|
|
|
|
65 |
"""
|
66 |
# get a drawing context
|
67 |
-
draw = ImageDraw.Draw(image)
|
68 |
|
69 |
im_width, im_height = image.size
|
70 |
keypoints_x = [k[0] for k in keypoints]
|
71 |
keypoints_y = [k[1] for k in keypoints]
|
|
|
|
|
|
|
|
|
|
|
72 |
|
73 |
# adjust keypoints coords if required
|
74 |
if use_normalized_coordinates:
|
75 |
keypoints_x = tuple([im_width * x for x in keypoints_x])
|
76 |
keypoints_y = tuple([im_height * y for y in keypoints_y])
|
77 |
-
|
78 |
-
#
|
|
|
|
|
79 |
for i, (keypoint_x, keypoint_y) in enumerate(zip(keypoints_x, keypoints_y)):
|
|
|
|
|
|
|
|
|
|
|
80 |
draw.ellipse([(keypoint_x - marker_size, keypoint_y - marker_size),
|
81 |
(keypoint_x + marker_size, keypoint_y + marker_size)],
|
82 |
-
outline=
|
83 |
-
fill=keypt_color)
|
84 |
|
85 |
# add string labels around keypoints
|
86 |
if flag_show_str_labels:
|
@@ -88,7 +103,7 @@ def draw_keypoints_on_image(image,
|
|
88 |
font_size)
|
89 |
draw.text((keypoint_x + marker_size, keypoint_y + marker_size),#(0.5*im_width, 0.5*im_height), #-------
|
90 |
map_label_id_to_str[i],
|
91 |
-
ImageColor.getcolor(keypt_color, "RGB"), # rgb
|
92 |
font=font)
|
93 |
|
94 |
############################################
|
@@ -101,29 +116,27 @@ def predict_md(im,
|
|
101 |
g = (size / max(im.size)) # multipl factor to make max size of the image equal to input size
|
102 |
im = im.resize((int(x * g) for x in im.size),
|
103 |
Image.ANTIALIAS) # resize
|
104 |
-
|
105 |
-
MD_model = torch.hub.load('ultralytics/yolov5',
|
106 |
-
'custom',
|
107 |
-
path = Megadet_Models[mega_model_input],
|
108 |
-
force_reload = True,
|
109 |
-
source='github')
|
110 |
|
111 |
## detect objects
|
112 |
results = MD_model(im) # inference # vars(results).keys()= dict_keys(['imgs', 'pred', 'names', 'files', 'times', 'xyxy', 'xywh', 'xyxyn', 'xywhn', 'n', 't', 's'])
|
113 |
-
|
114 |
-
|
115 |
return results
|
116 |
|
117 |
##########################################
|
118 |
-
def crop_animal_detections(
|
|
|
119 |
likelihood_th):
|
120 |
|
121 |
## Extract animal crops
|
122 |
-
list_labels_as_str = [i for i in yolo_results.names.values()] # ['animal', 'person', 'vehicle']
|
123 |
list_np_animal_crops = []
|
124 |
-
|
125 |
-
|
126 |
-
|
|
|
|
|
|
|
127 |
|
128 |
# for every detection
|
129 |
for j in range(det_array.shape[0]):
|
@@ -137,14 +150,13 @@ def crop_animal_detections(yolo_results,
|
|
137 |
|
138 |
pred_llk = det_array[j,4]
|
139 |
pred_label = det_array[j,5]
|
140 |
-
|
141 |
# keep animal crops above threshold
|
142 |
-
# pdb.set_trace()
|
143 |
if (pred_label == list_labels_as_str.index('animal')) and \
|
144 |
(pred_llk >= likelihood_th):
|
145 |
area = (xmin_rd, ymin_rd, xmax_rd, ymax_rd)
|
146 |
|
147 |
-
|
|
|
148 |
crop_np = np.asarray(crop)
|
149 |
|
150 |
# add to list
|
@@ -152,26 +164,50 @@ def crop_animal_detections(yolo_results,
|
|
152 |
|
153 |
return list_np_animal_crops
|
154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
##########################################
|
156 |
def predict_dlc(list_np_crops,
|
157 |
kpts_likelihood_th,
|
158 |
DLCmodel,
|
159 |
dlc_proc):
|
160 |
-
|
161 |
# run dlc thru list of crops
|
162 |
dlc_live = DLCLive(DLCmodel, processor=dlc_proc)
|
163 |
dlc_live.init_inference(list_np_crops[0])
|
164 |
|
165 |
list_kpts_per_crop = []
|
|
|
166 |
np_aux = np.empty((1,3)) # can I avoid hardcoding here?
|
167 |
for crop in list_np_crops:
|
168 |
# scale crop here?
|
169 |
keypts_xyp = dlc_live.get_pose(crop) # third column is llk!
|
170 |
# set kpts below threhsold to nan
|
|
|
|
|
171 |
keypts_xyp[keypts_xyp[:,-1] < kpts_likelihood_th,:] = np_aux.fill(np.nan)
|
172 |
# add kpts of this crop to list
|
173 |
list_kpts_per_crop.append(keypts_xyp)
|
174 |
-
|
|
|
175 |
return list_kpts_per_crop
|
176 |
|
177 |
|
@@ -193,14 +229,14 @@ def predict_pipeline(img_input,
|
|
193 |
## Get DLC model and labels as strings
|
194 |
# TODO: make a dict as for megadetector
|
195 |
# pdb.set_trace()
|
196 |
-
path_to_DLCmodel =
|
197 |
-
pose_cfg_path =
|
198 |
-
#
|
199 |
-
#pose_cfg_path = './model/pose_cfg.yaml'
|
200 |
# extract map label ids to strings
|
201 |
# pose_cfg_dict['all_joints'] is a list of one-element lists,
|
202 |
with open(pose_cfg_path, "r") as stream:
|
203 |
pose_cfg_dict = yaml.safe_load(stream)
|
|
|
204 |
map_label_id_to_str = dict([(k,v) for k,v in zip([el[0] for el in pose_cfg_dict['all_joints']],
|
205 |
pose_cfg_dict['all_joints_names'])])
|
206 |
|
@@ -209,10 +245,12 @@ def predict_pipeline(img_input,
|
|
209 |
md_results = predict_md(img_input,
|
210 |
mega_model_input,
|
211 |
size=640) #Image.fromarray(results.imgs[0])
|
212 |
-
|
213 |
################################################################
|
214 |
# Obtain animal crops for bboxes with confidence above th
|
215 |
-
|
|
|
|
|
216 |
bbox_likelihood_th)
|
217 |
|
218 |
##############################################################
|
@@ -226,7 +264,7 @@ def predict_pipeline(img_input,
|
|
226 |
kpts_likelihood_th,
|
227 |
path_to_DLCmodel,
|
228 |
dlc_proc)
|
229 |
-
# draw kpts on input img
|
230 |
draw_keypoints_on_image(img_input,
|
231 |
list_kpts_per_crop[0], # a numpy array with shape [num_keypoints, 2].
|
232 |
map_label_id_to_str,
|
@@ -236,7 +274,8 @@ def predict_pipeline(img_input,
|
|
236 |
font_size=font_size,
|
237 |
keypt_color=keypt_color,
|
238 |
marker_size=marker_size)
|
239 |
-
|
|
|
240 |
|
241 |
else:
|
242 |
# Compute kpts for each crop
|
@@ -244,18 +283,10 @@ def predict_pipeline(img_input,
|
|
244 |
kpts_likelihood_th,
|
245 |
path_to_DLCmodel,
|
246 |
dlc_proc)
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
# # img_input.size ---> (259, 194)
|
252 |
-
|
253 |
-
|
254 |
-
# resize image to match megadetector output
|
255 |
-
# img_background = img_input
|
256 |
-
# g = (640 / max(img_background.size)) # gain
|
257 |
-
# img_background = img_background.resize((int(x * g) for x in img_background.size),
|
258 |
-
# Image.ANTIALIAS) # resize
|
259 |
for ic, (np_crop, kpts_crop) in enumerate(zip(list_crops,
|
260 |
list_kpts_per_crop)):
|
261 |
|
@@ -271,17 +302,24 @@ def predict_pipeline(img_input,
|
|
271 |
keypt_color=keypt_color,
|
272 |
marker_size=marker_size)
|
273 |
|
274 |
-
## Paste crop in original image
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
|
281 |
#############################################
|
282 |
-
# %%
|
283 |
# User interface: inputs
|
284 |
-
|
285 |
# Input image
|
286 |
gr_image_input = gr.inputs.Image(type="pil", label="Input Image")
|
287 |
|
@@ -301,13 +339,13 @@ gr_dlc_only_checkbox = gr.inputs.Checkbox(False,
|
|
301 |
gr_str_labels_checkbox = gr.inputs.Checkbox(True,
|
302 |
label='Show bodypart labels?')
|
303 |
|
304 |
-
gr_slider_conf_bboxes = gr.inputs.Slider(0,1,.
|
305 |
label='Set confidence threshold for animal detections')
|
306 |
-
gr_slider_conf_keypoints = gr.inputs.Slider(0,1,.05,0
|
307 |
label='Set confidence threshold for keypoints')
|
308 |
|
309 |
# Data viz
|
310 |
-
gr_keypt_color = gr.ColorPicker(
|
311 |
|
312 |
gr_labels_font_style = gr.inputs.Dropdown(choices=['amiko', 'nature', 'painter', 'animals', 'zen'],
|
313 |
default='amiko',
|
@@ -315,7 +353,7 @@ gr_labels_font_style = gr.inputs.Dropdown(choices=['amiko', 'nature', 'painter',
|
|
315 |
label='Select keypoint label font')
|
316 |
gr_slider_font_size = gr.inputs.Slider(5,30,1,8,
|
317 |
label='Set font size')
|
318 |
-
gr_slider_marker_size = gr.inputs.Slider(
|
319 |
label='Set marker size')
|
320 |
|
321 |
# list of inputs
|
@@ -335,12 +373,13 @@ inputs = [gr_image_input,
|
|
335 |
# %%
|
336 |
# User interface: outputs
|
337 |
gr_image_output = gr.outputs.Image(type="pil", label="Output Image")
|
338 |
-
|
|
|
339 |
|
340 |
##############################################
|
341 |
# User interace: description
|
342 |
gr_title = "MegaDetector v5 + DeepLabCut-Live!"
|
343 |
-
gr_description = "Contributed by Sofia Minano, Neslihan Wittek, Nirel Kadzo, VicShaoChih Chiang -- DLC AI Residents 2022..\
|
344 |
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>. \
|
345 |
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> \
|
346 |
<a href='https://huggingface.co/spaces/sofmi/MegaDetector_DLClive'>sofmi/MegaDetector_DLClive</a> \
|
@@ -348,10 +387,9 @@ gr_description = "Contributed by Sofia Minano, Neslihan Wittek, Nirel Kadzo, Vic
|
|
348 |
|
349 |
# 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>"
|
350 |
|
351 |
-
examples = [['example/monkey_full.jpg', 'md_v5a','full_macaque', False, True, 0.5, 0.3, 'amiko',
|
352 |
-
['example/dog.jpeg', 'md_v5a', 'full_dog', False, True, 0.5, 0.
|
353 |
-
['example/cat.jpg', 'md_v5a', 'full_cat', False, True, 0.5, 0.05, 'amiko',
|
354 |
-
['example/monkey_face.jpeg', 'md_v5a', 'primate_face', False, True, 0.5, 0.05, 'amiko', 5, 'orange', 3]]
|
355 |
|
356 |
################################################
|
357 |
# %% Define and launch gradio interface
|
|
|
3 |
# Built from https://huggingface.co/spaces/Neslihan/megadetector_dlcmodels/blob/main/app.py
|
4 |
|
5 |
|
6 |
+
from tkinter import W
|
7 |
import gradio as gr
|
8 |
+
from matplotlib import cm
|
9 |
import torch
|
10 |
import torchvision
|
11 |
from dlclive import DLCLive, Processor
|
12 |
+
import matplotlib
|
13 |
from PIL import Image, ImageColor, ImageFont, ImageDraw
|
14 |
+
# check git lfs pull!!
|
15 |
import numpy as np
|
16 |
import math
|
17 |
|
18 |
# import json
|
19 |
import os
|
20 |
import yaml
|
21 |
+
from model.models import DownloadModel
|
22 |
+
from save_results import save_results
|
23 |
import pdb
|
24 |
|
25 |
#########################################
|
|
|
33 |
Megadet_Models = {'md_v5a': "megadet_model/md_v5a.0.0.pt",
|
34 |
'md_v5b': "megadet_model/md_v5b.0.0.pt"}
|
35 |
|
36 |
+
DLC_folders = {'full_cat': "model/DLC_Cat/",
|
37 |
+
'full_dog': "model/DLC_Dog/",
|
38 |
+
'primate_face': "model/DLC_FacialLandmarks/",
|
39 |
+
'full_human': "model/DLC_human_dancing/",
|
40 |
+
'full_macaque': 'model/DLC_monkey/'}
|
41 |
+
|
42 |
+
DLC_models_list = ['full_cat', 'full_dog','primate_face', 'full_human', 'full_macaque']
|
|
|
43 |
#########################################
|
44 |
# Draw keypoints on image
|
45 |
def draw_keypoints_on_image(image,
|
|
|
50 |
font_style='amiko',
|
51 |
font_size=8,
|
52 |
keypt_color="#ff0000",
|
53 |
+
marker_size=2,
|
54 |
+
):
|
55 |
"""Draws keypoints on an image.
|
56 |
Modified from:
|
57 |
https://www.programcreek.com/python/?code=fjchange%2Fobject_centric_VAD%2Fobject_centric_VAD-master%2Fobject_detection%2Futils%2Fvisualization_utils.py
|
|
|
64 |
radius: keypoint radius. Default value is 2.
|
65 |
use_normalized_coordinates: if True (default), treat keypoint values as
|
66 |
relative to the image. Otherwise treat them as absolute.
|
67 |
+
|
68 |
+
|
69 |
"""
|
70 |
# get a drawing context
|
71 |
+
draw = ImageDraw.Draw(image,"RGBA")
|
72 |
|
73 |
im_width, im_height = image.size
|
74 |
keypoints_x = [k[0] for k in keypoints]
|
75 |
keypoints_y = [k[1] for k in keypoints]
|
76 |
+
alpha = [k[2] for k in keypoints]
|
77 |
+
norm = matplotlib.colors.Normalize(vmin=0, vmax=255)
|
78 |
+
|
79 |
+
names_for_color = [i for i in map_label_id_to_str.keys()]
|
80 |
+
colores = np.linspace(0, 255, num=len(names_for_color),dtype= int)
|
81 |
|
82 |
# adjust keypoints coords if required
|
83 |
if use_normalized_coordinates:
|
84 |
keypoints_x = tuple([im_width * x for x in keypoints_x])
|
85 |
keypoints_y = tuple([im_height * y for y in keypoints_y])
|
86 |
+
|
87 |
+
#cmap = matplotlib.cm.get_cmap('hsv')
|
88 |
+
cmap2 = matplotlib.cm.get_cmap('Greys')
|
89 |
+
# draw ellipses around keypoints
|
90 |
for i, (keypoint_x, keypoint_y) in enumerate(zip(keypoints_x, keypoints_y)):
|
91 |
+
round_fill = list(cm.viridis(norm(colores[i]),bytes=True))#[round(num*255) for num in list(cmap(i))[:3]] #check!
|
92 |
+
if np.isnan(alpha[i]) == False :
|
93 |
+
round_fill[3] = round(alpha[i] *255)
|
94 |
+
#print(round_fill)
|
95 |
+
#round_outline = [round(num*255) for num in list(cmap2(alpha[i]))[:3]]
|
96 |
draw.ellipse([(keypoint_x - marker_size, keypoint_y - marker_size),
|
97 |
(keypoint_x + marker_size, keypoint_y + marker_size)],
|
98 |
+
fill=tuple(round_fill), outline= 'black', width=1) #fill and outline: [0,255]
|
|
|
99 |
|
100 |
# add string labels around keypoints
|
101 |
if flag_show_str_labels:
|
|
|
103 |
font_size)
|
104 |
draw.text((keypoint_x + marker_size, keypoint_y + marker_size),#(0.5*im_width, 0.5*im_height), #-------
|
105 |
map_label_id_to_str[i],
|
106 |
+
ImageColor.getcolor(keypt_color, "RGB"), # rgb #
|
107 |
font=font)
|
108 |
|
109 |
############################################
|
|
|
116 |
g = (size / max(im.size)) # multipl factor to make max size of the image equal to input size
|
117 |
im = im.resize((int(x * g) for x in im.size),
|
118 |
Image.ANTIALIAS) # resize
|
119 |
+
MD_model = torch.hub.load('ultralytics/yolov5', 'custom', Megadet_Models[mega_model_input])
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
## detect objects
|
122 |
results = MD_model(im) # inference # vars(results).keys()= dict_keys(['imgs', 'pred', 'names', 'files', 'times', 'xyxy', 'xywh', 'xyxyn', 'xywhn', 'n', 't', 's'])
|
123 |
+
|
|
|
124 |
return results
|
125 |
|
126 |
##########################################
|
127 |
+
def crop_animal_detections(img_in,
|
128 |
+
yolo_results,
|
129 |
likelihood_th):
|
130 |
|
131 |
## Extract animal crops
|
132 |
+
list_labels_as_str = [i for i in yolo_results.names.values()] # ['animal', 'person', 'vehicle']
|
133 |
list_np_animal_crops = []
|
134 |
+
|
135 |
+
# image to crop (scale as input for megadetector)
|
136 |
+
img_in = img_in.resize((yolo_results.ims[0].shape[1],
|
137 |
+
yolo_results.ims[0].shape[0]))
|
138 |
+
# for every detection in the img
|
139 |
+
for det_array in yolo_results.xyxy:
|
140 |
|
141 |
# for every detection
|
142 |
for j in range(det_array.shape[0]):
|
|
|
150 |
|
151 |
pred_llk = det_array[j,4]
|
152 |
pred_label = det_array[j,5]
|
|
|
153 |
# keep animal crops above threshold
|
|
|
154 |
if (pred_label == list_labels_as_str.index('animal')) and \
|
155 |
(pred_llk >= likelihood_th):
|
156 |
area = (xmin_rd, ymin_rd, xmax_rd, ymax_rd)
|
157 |
|
158 |
+
#pdb.set_trace()
|
159 |
+
crop = img_in.crop(area) #Image.fromarray(img_in).crop(area)
|
160 |
crop_np = np.asarray(crop)
|
161 |
|
162 |
# add to list
|
|
|
164 |
|
165 |
return list_np_animal_crops
|
166 |
|
167 |
+
def draw_rectangle_text(img,results,font_style='amiko',font_size=8, keypt_color="white",):
|
168 |
+
#pdb.set_trace()
|
169 |
+
bbxyxy = results
|
170 |
+
w, h = bbxyxy[2], bbxyxy[3]
|
171 |
+
shape = [(bbxyxy[0], bbxyxy[1]), (w , h)]
|
172 |
+
imgR = ImageDraw.Draw(img)
|
173 |
+
imgR.rectangle(shape, outline ="red",width=5) ##bb for animal
|
174 |
+
|
175 |
+
confidence = bbxyxy[4]
|
176 |
+
string_bb = 'animal ' + str(round(confidence, 2))
|
177 |
+
font = ImageFont.truetype(FONTS[font_style], font_size)
|
178 |
+
|
179 |
+
text_size = font.getsize(string_bb) # (h,w)
|
180 |
+
position = (bbxyxy[0],bbxyxy[1] - text_size[1] -2 )
|
181 |
+
left, top, right, bottom = imgR.textbbox(position, string_bb, font=font)
|
182 |
+
imgR.rectangle((left, top-5, right+5, bottom+5), fill="red")
|
183 |
+
imgR.text((bbxyxy[0] + 3 ,bbxyxy[1] - text_size[1] -2 ), string_bb, font=font, fill="black")
|
184 |
+
|
185 |
+
return imgR
|
186 |
+
|
187 |
##########################################
|
188 |
def predict_dlc(list_np_crops,
|
189 |
kpts_likelihood_th,
|
190 |
DLCmodel,
|
191 |
dlc_proc):
|
192 |
+
|
193 |
# run dlc thru list of crops
|
194 |
dlc_live = DLCLive(DLCmodel, processor=dlc_proc)
|
195 |
dlc_live.init_inference(list_np_crops[0])
|
196 |
|
197 |
list_kpts_per_crop = []
|
198 |
+
all_kypts = []
|
199 |
np_aux = np.empty((1,3)) # can I avoid hardcoding here?
|
200 |
for crop in list_np_crops:
|
201 |
# scale crop here?
|
202 |
keypts_xyp = dlc_live.get_pose(crop) # third column is llk!
|
203 |
# set kpts below threhsold to nan
|
204 |
+
|
205 |
+
#pdb.set_trace()
|
206 |
keypts_xyp[keypts_xyp[:,-1] < kpts_likelihood_th,:] = np_aux.fill(np.nan)
|
207 |
# add kpts of this crop to list
|
208 |
list_kpts_per_crop.append(keypts_xyp)
|
209 |
+
all_kypts.append(keypts_xyp)
|
210 |
+
|
211 |
return list_kpts_per_crop
|
212 |
|
213 |
|
|
|
229 |
## Get DLC model and labels as strings
|
230 |
# TODO: make a dict as for megadetector
|
231 |
# pdb.set_trace()
|
232 |
+
path_to_DLCmodel = DownloadModel(dlc_model_input_str, str(DLC_folders[dlc_model_input_str]) )
|
233 |
+
pose_cfg_path = str(DLC_folders[dlc_model_input_str]) +'pose_cfg.yaml'
|
234 |
+
#pdb.set_trece()
|
|
|
235 |
# extract map label ids to strings
|
236 |
# pose_cfg_dict['all_joints'] is a list of one-element lists,
|
237 |
with open(pose_cfg_path, "r") as stream:
|
238 |
pose_cfg_dict = yaml.safe_load(stream)
|
239 |
+
|
240 |
map_label_id_to_str = dict([(k,v) for k,v in zip([el[0] for el in pose_cfg_dict['all_joints']],
|
241 |
pose_cfg_dict['all_joints_names'])])
|
242 |
|
|
|
245 |
md_results = predict_md(img_input,
|
246 |
mega_model_input,
|
247 |
size=640) #Image.fromarray(results.imgs[0])
|
248 |
+
#pdb.set_trace()
|
249 |
################################################################
|
250 |
# Obtain animal crops for bboxes with confidence above th
|
251 |
+
|
252 |
+
list_crops = crop_animal_detections(img_input,
|
253 |
+
md_results,
|
254 |
bbox_likelihood_th)
|
255 |
|
256 |
##############################################################
|
|
|
264 |
kpts_likelihood_th,
|
265 |
path_to_DLCmodel,
|
266 |
dlc_proc)
|
267 |
+
# draw kpts on input img #fix!
|
268 |
draw_keypoints_on_image(img_input,
|
269 |
list_kpts_per_crop[0], # a numpy array with shape [num_keypoints, 2].
|
270 |
map_label_id_to_str,
|
|
|
274 |
font_size=font_size,
|
275 |
keypt_color=keypt_color,
|
276 |
marker_size=marker_size)
|
277 |
+
|
278 |
+
return img_input, []
|
279 |
|
280 |
else:
|
281 |
# Compute kpts for each crop
|
|
|
283 |
kpts_likelihood_th,
|
284 |
path_to_DLCmodel,
|
285 |
dlc_proc)
|
286 |
+
|
287 |
+
img_background = img_input.resize((md_results.ims[0].shape[1],md_results.ims[0].shape[0]))
|
288 |
+
print('I have ' + str(len(list_crops)) + ' bounding box')
|
289 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
290 |
for ic, (np_crop, kpts_crop) in enumerate(zip(list_crops,
|
291 |
list_kpts_per_crop)):
|
292 |
|
|
|
302 |
keypt_color=keypt_color,
|
303 |
marker_size=marker_size)
|
304 |
|
305 |
+
## Paste crop in original image https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.paste
|
306 |
+
img_background.paste(img_crop, box = tuple([int(t) for t in md_results.xyxy[0][ic,:2]]))
|
307 |
+
|
308 |
+
|
309 |
+
|
310 |
+
bb_per_animal = md_results.xyxy[0].tolist()[ic]
|
311 |
+
pred = md_results.xyxy[0].tolist()[ic][4]
|
312 |
+
if bbox_likelihood_th < pred:
|
313 |
+
draw_rectangle_text(img_background, bb_per_animal ,font_style=font_style,font_size=font_size, keypt_color=keypt_color)
|
314 |
+
|
315 |
+
|
316 |
+
|
317 |
+
download_file = save_results(md_results,list_kpts_per_crop,map_label_id_to_str,bbox_likelihood_th)
|
318 |
+
|
319 |
+
return img_background, download_file
|
320 |
|
321 |
#############################################
|
|
|
322 |
# User interface: inputs
|
|
|
323 |
# Input image
|
324 |
gr_image_input = gr.inputs.Image(type="pil", label="Input Image")
|
325 |
|
|
|
339 |
gr_str_labels_checkbox = gr.inputs.Checkbox(True,
|
340 |
label='Show bodypart labels?')
|
341 |
|
342 |
+
gr_slider_conf_bboxes = gr.inputs.Slider(0,1,.02,0.8,
|
343 |
label='Set confidence threshold for animal detections')
|
344 |
+
gr_slider_conf_keypoints = gr.inputs.Slider(0,1,.05,0,
|
345 |
label='Set confidence threshold for keypoints')
|
346 |
|
347 |
# Data viz
|
348 |
+
gr_keypt_color = gr.ColorPicker(label="choose color for keypoint label")
|
349 |
|
350 |
gr_labels_font_style = gr.inputs.Dropdown(choices=['amiko', 'nature', 'painter', 'animals', 'zen'],
|
351 |
default='amiko',
|
|
|
353 |
label='Select keypoint label font')
|
354 |
gr_slider_font_size = gr.inputs.Slider(5,30,1,8,
|
355 |
label='Set font size')
|
356 |
+
gr_slider_marker_size = gr.inputs.Slider(1,20,1,5,
|
357 |
label='Set marker size')
|
358 |
|
359 |
# list of inputs
|
|
|
373 |
# %%
|
374 |
# User interface: outputs
|
375 |
gr_image_output = gr.outputs.Image(type="pil", label="Output Image")
|
376 |
+
out_smpl_npy_download = gr.File(label="Download JSON file")
|
377 |
+
outputs = [gr_image_output,out_smpl_npy_download]
|
378 |
|
379 |
##############################################
|
380 |
# User interace: description
|
381 |
gr_title = "MegaDetector v5 + DeepLabCut-Live!"
|
382 |
+
gr_description = "Contributed by Sofia Minano, Neslihan Wittek, Nirel Kadzo, VicShaoChih Chiang, Sabrina Benas -- DLC AI Residents 2022..\
|
383 |
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>. \
|
384 |
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> \
|
385 |
<a href='https://huggingface.co/spaces/sofmi/MegaDetector_DLClive'>sofmi/MegaDetector_DLClive</a> \
|
|
|
387 |
|
388 |
# 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>"
|
389 |
|
390 |
+
examples = [['example/monkey_full.jpg', 'md_v5a','full_macaque', False, True, 0.5, 0.3, 'amiko', 9, 'blue', 3],
|
391 |
+
['example/dog.jpeg', 'md_v5a', 'full_dog', False, True, 0.5, 0.00, 'amiko',9, 'yellow', 3],
|
392 |
+
['example/cat.jpg', 'md_v5a', 'full_cat', False, True, 0.5, 0.05, 'amiko', 9, 'purple', 3]]
|
|
|
393 |
|
394 |
################################################
|
395 |
# %% Define and launch gradio interface
|
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 |
+
|