Spaces:
Runtime error
Runtime error
sfmig
commited on
Commit
·
fcf3dc1
1
Parent(s):
07d3c1e
pushing all but dlc models
Browse files- .gitignore +2 -0
- README.md +2 -1
- app.py +221 -0
- model_weights/md_v5a.0.0.pt +3 -0
- requirements.txt +7 -0
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
notebook_megadetector_crop.py
|
2 |
+
flagged/*
|
README.md
CHANGED
@@ -9,4 +9,5 @@ app_file: app.py
|
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
-
|
|
|
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
+
Combining MegaDetector implementation from https://huggingface.co/spaces/hlydecker/MegaDetector_v5 with DLClive
|
13 |
+
# Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import gradio as gr
|
3 |
+
import torch
|
4 |
+
import torchvision
|
5 |
+
import numpy as np
|
6 |
+
from PIL import Image
|
7 |
+
import PIL.ImageDraw as ImageDraw
|
8 |
+
import math
|
9 |
+
import pdb
|
10 |
+
|
11 |
+
from dlclive import DLCLive, Processor
|
12 |
+
|
13 |
+
import matplotlib.pyplot as plt
|
14 |
+
|
15 |
+
#########################################
|
16 |
+
# https://www.programcreek.com/python/?code=fjchange%2Fobject_centric_VAD%2Fobject_centric_VAD-master%2Fobject_detection%2Futils%2Fvisualization_utils.py
|
17 |
+
def draw_keypoints_on_image(image,
|
18 |
+
keypoints,
|
19 |
+
color='red',
|
20 |
+
radius=2,
|
21 |
+
use_normalized_coordinates=True):
|
22 |
+
"""Draws keypoints on an image.
|
23 |
+
|
24 |
+
Args:
|
25 |
+
image: a PIL.Image object.
|
26 |
+
keypoints: a numpy array with shape [num_keypoints, 2].
|
27 |
+
color: color to draw the keypoints with. Default is red.
|
28 |
+
radius: keypoint radius. Default value is 2.
|
29 |
+
use_normalized_coordinates: if True (default), treat keypoint values as
|
30 |
+
relative to the image. Otherwise treat them as absolute.
|
31 |
+
"""
|
32 |
+
# get a drawing context
|
33 |
+
draw = ImageDraw.Draw(image)
|
34 |
+
|
35 |
+
im_width, im_height = image.size
|
36 |
+
keypoints_x = [k[1] for k in keypoints]
|
37 |
+
keypoints_y = [k[0] for k in keypoints]
|
38 |
+
|
39 |
+
# adjust keypoints coords if required
|
40 |
+
if use_normalized_coordinates:
|
41 |
+
keypoints_x = tuple([im_width * x for x in keypoints_x])
|
42 |
+
keypoints_y = tuple([im_height * y for y in keypoints_y])
|
43 |
+
|
44 |
+
# draw ellipses around keypoints
|
45 |
+
for keypoint_x, keypoint_y in zip(keypoints_x, keypoints_y):
|
46 |
+
draw.ellipse([(keypoint_x - radius, keypoint_y - radius),
|
47 |
+
(keypoint_x + radius, keypoint_y + radius)],
|
48 |
+
outline=color, fill=color)
|
49 |
+
############################################
|
50 |
+
|
51 |
+
# Predict detections with MegaDetector v5a model
|
52 |
+
def predict_md(im, size=640):
|
53 |
+
# resize image
|
54 |
+
g = (size / max(im.size)) # gain
|
55 |
+
im = im.resize((int(x * g) for x in im.size), Image.ANTIALIAS) # resize
|
56 |
+
|
57 |
+
## detect objects
|
58 |
+
results = MD_model(im) # inference # vars(results).keys()= dict_keys(['imgs', 'pred', 'names', 'files', 'times', 'xyxy', 'xywh', 'xyxyn', 'xywhn', 'n', 't', 's'])
|
59 |
+
results.render() # updates results.imgs with boxes and labels
|
60 |
+
|
61 |
+
return results #Image.fromarray(results.imgs[0]) ---return animals only?
|
62 |
+
|
63 |
+
def crop_animal_detections(yolo_results, likelihood_th):
|
64 |
+
## crop if animal and return list of crops
|
65 |
+
|
66 |
+
list_labels_as_str = yolo_results.names #['animal', 'person', 'vehicle']
|
67 |
+
list_np_animal_crops = []
|
68 |
+
|
69 |
+
# for every image
|
70 |
+
for img, det_array in zip(yolo_results.imgs,
|
71 |
+
yolo_results.xyxy):
|
72 |
+
|
73 |
+
# for every detection
|
74 |
+
for j in range(det_array.shape[0]):
|
75 |
+
|
76 |
+
# compute coords around bbox rounded to the nearest integer (for pasting later)
|
77 |
+
xmin_rd = int(math.floor(det_array[j,0])) # int() should suffice?
|
78 |
+
ymin_rd = int(math.floor(det_array[j,1]))
|
79 |
+
|
80 |
+
xmax_rd = int(math.ceil(det_array[j,2]))
|
81 |
+
ymax_rd = int(math.ceil(det_array[j,3]))
|
82 |
+
|
83 |
+
pred_llk = det_array[j,4] #-----TODO: filter based on likelihood?
|
84 |
+
pred_label = det_array[j,5]
|
85 |
+
|
86 |
+
if (pred_label == list_labels_as_str.index('animal')) and \
|
87 |
+
(pred_llk >= likelihood_th):
|
88 |
+
area = (xmin_rd, ymin_rd, xmax_rd, ymax_rd)
|
89 |
+
|
90 |
+
crop = Image.fromarray(img).crop(area)
|
91 |
+
crop_np = np.asarray(crop)
|
92 |
+
|
93 |
+
# add to list
|
94 |
+
list_np_animal_crops.append(crop_np)
|
95 |
+
|
96 |
+
# for detections_dict in img_data["detections"]:
|
97 |
+
# index = img_data["detections"].index(detections_dict)
|
98 |
+
# if detections_dict["conf"] > 0.8:
|
99 |
+
# x1, y1,w_box, h_box = detections_dict["bbox"]
|
100 |
+
# ymin,xmin,ymax, xmax = y1, x1, y1 + h_box, x1 + w_box
|
101 |
+
|
102 |
+
# imageWidth=img.size[0]
|
103 |
+
# imageHeight= img.size[1]
|
104 |
+
# area = (xmin * imageWidth, ymin * imageHeight, xmax * imageWidth,
|
105 |
+
# ymax * imageHeight)
|
106 |
+
# crop = img.crop(area)
|
107 |
+
# crop_np = np.asarray(crop)
|
108 |
+
#
|
109 |
+
# if detections_dict["category"] == "1":
|
110 |
+
return list_np_animal_crops
|
111 |
+
|
112 |
+
def predict_dlc(list_np_crops,DLCmodel,dlc_proc):
|
113 |
+
# run dlc thru list of crops
|
114 |
+
dlc_live = DLCLive(DLCmodel, processor=dlc_proc)
|
115 |
+
dlc_live.init_inference(list_np_crops[0])
|
116 |
+
|
117 |
+
list_kpts_per_crop = []
|
118 |
+
for crop in list_np_crops:
|
119 |
+
keypts = dlc_live.get_pose(crop) # third column is llk!
|
120 |
+
list_kpts_per_crop.append(keypts)
|
121 |
+
|
122 |
+
return list_kpts_per_crop
|
123 |
+
|
124 |
+
|
125 |
+
|
126 |
+
def predict_pipeline(img_input):
|
127 |
+
|
128 |
+
# these eventually user inputs....
|
129 |
+
path_to_DLCmodel = "DLC_models/DLC_Cat_resnet_50_iteration-0_shuffle-0"
|
130 |
+
likelihood_th = 0.8
|
131 |
+
|
132 |
+
# Run Megadetector
|
133 |
+
md_results = predict_md(img_input) #Image.fromarray(results.imgs[0])
|
134 |
+
|
135 |
+
# Obtain animal crops with confidence above th
|
136 |
+
list_crops = crop_animal_detections(md_results,
|
137 |
+
likelihood_th)
|
138 |
+
|
139 |
+
# Run DLC
|
140 |
+
# TODO: add llk threshold for kpts too?
|
141 |
+
dlc_proc = Processor()
|
142 |
+
list_kpts_per_crop = predict_dlc(list_crops,
|
143 |
+
path_to_DLCmodel,
|
144 |
+
dlc_proc)
|
145 |
+
|
146 |
+
|
147 |
+
# # Produce final image
|
148 |
+
fig = plt.Figure(md_results.imgs[0].shape[:2]) #figsize=(10,10)) #md_results.imgs[0].shape)
|
149 |
+
for ic, (np_crop, kpts_crop) in enumerate(zip(list_crops,
|
150 |
+
list_kpts_per_crop)):
|
151 |
+
|
152 |
+
# Draw keypts on crop
|
153 |
+
img_crop = Image.fromarray(np_crop)
|
154 |
+
draw_keypoints_on_image(img_crop,
|
155 |
+
kpts_crop, # a numpy array with shape [num_keypoints, 2].
|
156 |
+
color='red',
|
157 |
+
radius=2,
|
158 |
+
use_normalized_coordinates=False) # if True, then I should use md_results.xyxyn
|
159 |
+
|
160 |
+
# Paste crop in original image
|
161 |
+
# https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.paste
|
162 |
+
|
163 |
+
img_input.paste(img_crop,
|
164 |
+
box = tuple([int(math.floor(t)) for t in md_results.xyxy[0][ic,:2]]))
|
165 |
+
|
166 |
+
# plt.imshow(np_crop)
|
167 |
+
# plt.scatter(kpts_crop[:,0], kpts_crop[:,1], 40,
|
168 |
+
# color='r')
|
169 |
+
# img_overlay = Image.frombytes('RGB',
|
170 |
+
# fig.canvas.get_width_height(),
|
171 |
+
# fig.canvas.tostring_rgb())
|
172 |
+
return img_input #Image.fromarray(list_crops[0]) #Image.fromarray(md_results.imgs[0]) #
|
173 |
+
|
174 |
+
|
175 |
+
##########################################################
|
176 |
+
# Get MegaDetector model
|
177 |
+
# TODO: Allow user selectable model?
|
178 |
+
# models = ["model_weights/md_v5a.0.0.pt","model_weights/md_v5b.0.0.pt"]
|
179 |
+
MD_model = torch.hub.load('ultralytics/yolov5', 'custom', "model_weights/md_v5a.0.0.pt")
|
180 |
+
|
181 |
+
|
182 |
+
|
183 |
+
####################################################
|
184 |
+
# Create user interface and launch
|
185 |
+
#inputs = [image, chosen_model, size]
|
186 |
+
inputs = gr.inputs.Image(type="pil", label="Input Image")
|
187 |
+
outputs = gr.outputs.Image(type="pil", label="Output Image")
|
188 |
+
#image = gr.inputs.Image(type="pil", label="Input Image")
|
189 |
+
#chosen_model = gr.inputs.Dropdown(choices = models, value = "model_weights/md_v5a.0.0.pt",type = "value", label="Model Weight")
|
190 |
+
#size = 640
|
191 |
+
|
192 |
+
title = "MegaDetector v5 + DLC live"
|
193 |
+
description = "Detect and estimate pose of animals camera trap images using MegaDetector v5a + DLClive"
|
194 |
+
# 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>"
|
195 |
+
# examples = [['data/Macropod.jpg'], ['data/koala2.jpg'],['data/cat.jpg'],['data/BrushtailPossum.jpg']]
|
196 |
+
|
197 |
+
gr.Interface(predict_pipeline,
|
198 |
+
inputs,
|
199 |
+
outputs,
|
200 |
+
title=title,
|
201 |
+
description=description,
|
202 |
+
theme="huggingface").launch(enable_queue=True)
|
203 |
+
|
204 |
+
|
205 |
+
# def dlclive_pose(model, crop_np, crop, fname, index,dlc_proc):
|
206 |
+
# dlc_live = DLCLive(model, processor=dlc_proc)
|
207 |
+
# dlc_live.init_inference(crop_np)
|
208 |
+
# keypts = dlc_live.get_pose(crop_np)
|
209 |
+
# savetxt(str(fname)+ '_' + str(index) + '.csv' , keypts, delimiter=',')
|
210 |
+
# xpose = []
|
211 |
+
# ypose = []
|
212 |
+
# for key in keypts[:,2]:
|
213 |
+
# # if key > 0.05: # which value do we need here?
|
214 |
+
# i = np.where(keypts[:,2]==key)
|
215 |
+
# xpose.append(keypts[i,0])
|
216 |
+
# ypose.append(keypts[i,1])
|
217 |
+
# plt.imshow(crop)
|
218 |
+
# plt.scatter(xpose[:], ypose[:], 40, color='cyan')
|
219 |
+
# plt.savefig(str(fname)+ '_' + str(index) + '.png')
|
220 |
+
# plt.show()
|
221 |
+
# plt.clf()
|
model_weights/md_v5a.0.0.pt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:94e88fe97c8050f2e3d0cc4cb4f64729d639d74312dcbe2f74f8eecd3b01b276
|
3 |
+
size 280766885
|
requirements.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
torch
|
3 |
+
torchvision
|
4 |
+
numpy
|
5 |
+
opencv-python
|
6 |
+
seaborn
|
7 |
+
dlclive
|