C-Achard commited on
Commit
ade4ba6
Β·
1 Parent(s): 5cce2c7

Align DLC outputs with filtered detections

Browse files

Carry the filtered MegaDetector bounding boxes through cropping, visualization, and JSON export so pose results stay matched to the correct animal detections. This also removes the obsolete save_results module and hardens DLC inference by handling empty crop lists, converting crop channel order for DLCLive, and masking low-confidence keypoints with NaN.

Files changed (5) hide show
  1. app.py +15 -17
  2. detection_utils.py +4 -2
  3. dlc_utils.py +11 -9
  4. save_results.py +0 -56
  5. viz_utils.py +7 -16
app.py CHANGED
@@ -70,10 +70,10 @@ def predict_pipeline(img_input,
70
  size=640) #Image.fromarray(results.imgs[0])
71
 
72
  ################################################################
73
- # Obtain animal crops for bboxes with confidence above th
74
- list_crops = crop_animal_detections(img_input,
75
- md_results,
76
- bbox_likelihood_th)
77
 
78
  ############################################################
79
 
@@ -135,8 +135,9 @@ def predict_pipeline(img_input,
135
  md_results.ims[0].shape[0]))
136
 
137
  # draw keypoints on each crop and paste to background img
138
- for ic, (np_crop, kpts_crop) in enumerate(zip(list_crops,
139
- list_kpts_per_crop)):
 
140
 
141
  img_crop = Image.fromarray(np_crop)
142
 
@@ -152,20 +153,17 @@ def predict_pipeline(img_input,
152
  marker_size=marker_size)
153
 
154
  # Paste crop in original image
155
- img_background.paste(img_crop,
156
- box = tuple([int(t) for t in md_results.xyxy[0][ic,:2]]))
157
 
158
  # Plot bbox
159
- bb_per_animal = md_results.xyxy[0].tolist()[ic]
160
- pred = md_results.xyxy[0].tolist()[ic][4]
161
- if bbox_likelihood_th < pred:
162
- draw_bbox_w_text(img_background,
163
- bb_per_animal,
164
- font_size=font_size) # TODO: add selectable color for bbox?
165
-
166
-
167
  # Save detection results as json
168
- download_file = save_results_as_json(md_results,list_kpts_per_crop,map_label_id_to_str, bbox_likelihood_th,dlc_model_input_str,mega_model_input)
169
 
170
  return img_background, download_file
171
 
 
70
  size=640) #Image.fromarray(results.imgs[0])
71
 
72
  ################################################################
73
+ # Obtain animal crops (and their bboxes) with confidence above th
74
+ list_crops, list_bboxes = crop_animal_detections(img_input,
75
+ md_results,
76
+ bbox_likelihood_th)
77
 
78
  ############################################################
79
 
 
135
  md_results.ims[0].shape[0]))
136
 
137
  # draw keypoints on each crop and paste to background img
138
+ for np_crop, kpts_crop, bb_per_animal in zip(list_crops,
139
+ list_kpts_per_crop,
140
+ list_bboxes):
141
 
142
  img_crop = Image.fromarray(np_crop)
143
 
 
153
  marker_size=marker_size)
154
 
155
  # Paste crop in original image
156
+ img_background.paste(img_crop,
157
+ box = tuple([int(t) for t in bb_per_animal[:2]]))
158
 
159
  # Plot bbox
160
+ draw_bbox_w_text(img_background,
161
+ bb_per_animal,
162
+ font_size=font_size) # TODO: add selectable color for bbox?
163
+
164
+
 
 
 
165
  # Save detection results as json
166
+ download_file = save_results_as_json(md_results,list_kpts_per_crop,list_bboxes,map_label_id_to_str,dlc_model_input_str,mega_model_input)
167
 
168
  return img_background, download_file
169
 
detection_utils.py CHANGED
@@ -56,8 +56,9 @@ def crop_animal_detections(img_in,
56
  likelihood_th):
57
 
58
  ## Extract animal crops
59
- list_labels_as_str = [i for i in yolo_results.names.values()] # ['animal', 'person', 'vehicle']
60
  list_np_animal_crops = []
 
61
 
62
  # image to crop (scale as input for megadetector)
63
  img_in = img_in.resize((yolo_results.ims[0].shape[1],
@@ -88,5 +89,6 @@ def crop_animal_detections(img_in,
88
 
89
  # add to list
90
  list_np_animal_crops.append(crop_np)
 
91
 
92
- return list_np_animal_crops
 
56
  likelihood_th):
57
 
58
  ## Extract animal crops
59
+ list_labels_as_str = [i for i in yolo_results.names.values()] # ['animal', 'person', 'vehicle']
60
  list_np_animal_crops = []
61
+ list_animal_bboxes = [] # detection rows [x1,y1,x2,y2,conf,label] matching each crop
62
 
63
  # image to crop (scale as input for megadetector)
64
  img_in = img_in.resize((yolo_results.ims[0].shape[1],
 
89
 
90
  # add to list
91
  list_np_animal_crops.append(crop_np)
92
+ list_animal_bboxes.append(det_array[j,:].tolist())
93
 
94
+ return list_np_animal_crops, list_animal_bboxes
dlc_utils.py CHANGED
@@ -11,22 +11,24 @@ def predict_dlc(list_np_crops,
11
  dlc_model_folder,
12
  dlc_proc):
13
 
 
 
 
 
 
 
 
 
14
  # run dlc thru list of crops
15
  dlc_live = DLCLive(dlc_model_folder, processor=dlc_proc)
16
  dlc_live.init_inference(list_np_crops[0])
17
 
18
  list_kpts_per_crop = []
19
- all_kypts = []
20
- np_aux = np.empty((1,3)) # can I avoid hardcoding here?
21
  for crop in list_np_crops:
22
- # scale crop here?
23
  keypts_xyp = dlc_live.get_pose(crop) # third column is llk!
24
  # set kpts below threhsold to nan
25
-
26
- #pdb.set_trace()
27
- keypts_xyp[keypts_xyp[:,-1] < kpts_likelihood_th,:] = np_aux.fill(np.nan)
28
- # add kpts of this crop to list
29
  list_kpts_per_crop.append(keypts_xyp)
30
- all_kypts.append(keypts_xyp)
31
-
32
  return list_kpts_per_crop
 
11
  dlc_model_folder,
12
  dlc_proc):
13
 
14
+ # no animal detected: nothing to run
15
+ if len(list_np_crops) == 0:
16
+ return []
17
+
18
+ # DLCLive always converts 3-channel frames BGR->RGB, but our crops are
19
+ # already RGB (PIL), so pass them as BGR for the model to see RGB
20
+ list_np_crops = [np.ascontiguousarray(crop[..., ::-1]) for crop in list_np_crops]
21
+
22
  # run dlc thru list of crops
23
  dlc_live = DLCLive(dlc_model_folder, processor=dlc_proc)
24
  dlc_live.init_inference(list_np_crops[0])
25
 
26
  list_kpts_per_crop = []
 
 
27
  for crop in list_np_crops:
 
28
  keypts_xyp = dlc_live.get_pose(crop) # third column is llk!
29
  # set kpts below threhsold to nan
30
+ keypts_xyp[keypts_xyp[:,-1] < kpts_likelihood_th,:] = np.nan
31
+ # add kpts of this crop to list
 
 
32
  list_kpts_per_crop.append(keypts_xyp)
33
+
 
34
  return list_kpts_per_crop
save_results.py DELETED
@@ -1,56 +0,0 @@
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
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
viz_utils.py CHANGED
@@ -62,7 +62,6 @@ def draw_keypoints_on_image(image,
62
  keypoints_y = tuple([im_height * y for y in keypoints_y])
63
 
64
  #cmap = matplotlib.cm.get_cmap('hsv')
65
- cmap2 = matplotlib.cm.get_cmap('Greys')
66
  # draw ellipses around keypoints
67
  for i, (keypoint_x, keypoint_y) in enumerate(zip(keypoints_x, keypoints_y)):
68
  round_fill = list(cm.viridis(norm(colores[i]),bytes=True))#[round(num*255) for num in list(cmap(i))[:3]] #check!
@@ -113,11 +112,12 @@ def draw_bbox_w_text(img,
113
  return imgR
114
 
115
  ###########################################
116
- def save_results_as_json(md_results, dlc_outputs, map_dlc_label_id_to_str, thr,model,mega_model_input, path_to_output_file = 'download_predictions.json'):
117
 
118
  """
119
  Output detections as json file
120
 
 
121
  """
122
  # initialise dict to save to json
123
  info = {}
@@ -128,29 +128,20 @@ def save_results_as_json(md_results, dlc_outputs, map_dlc_label_id_to_str, thr,m
128
  number_bb = len(md_results.xyxy[0].tolist())
129
  info['number_of_bb'] = number_bb
130
  # info from DLC
131
- number_bb_thr = len(dlc_outputs)
132
  labels = [n for n in map_dlc_label_id_to_str.values()]
133
-
134
- # create list of bboxes above th
135
- new_index = []
136
- for i in range(number_bb):
137
- corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = md_results.xyxy[0].tolist()[i]
138
-
139
- if confidence > thr:
140
- new_index.append(i)
141
 
142
- # define aux dict for every bounding box above threshold
143
- for i in range(number_bb_thr):
144
  aux={}
145
  # MD output
146
- corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = md_results.xyxy[0].tolist()[new_index[i]]
147
  aux['corner_1'] = (corner_x1,corner_y1)
148
  aux['corner_2'] = (corner_x2,corner_y2)
149
  aux['predict MD'] = md_results.names[0]
150
  aux['confidence MD'] = confidence
151
 
152
  # DLC output
153
- info['dlc_model'] = model
154
  kypts = []
155
  for s in dlc_outputs[i]:
156
  aux1 = []
@@ -159,7 +150,7 @@ def save_results_as_json(md_results, dlc_outputs, map_dlc_label_id_to_str, thr,m
159
 
160
  kypts.append(aux1)
161
  aux['dlc_pred'] = dict(zip(labels,kypts))
162
- info['bb_' + str(new_index[i]) ]=aux
163
 
164
  # save dict as json
165
  with open(path_to_output_file, 'w') as f:
 
62
  keypoints_y = tuple([im_height * y for y in keypoints_y])
63
 
64
  #cmap = matplotlib.cm.get_cmap('hsv')
 
65
  # draw ellipses around keypoints
66
  for i, (keypoint_x, keypoint_y) in enumerate(zip(keypoints_x, keypoints_y)):
67
  round_fill = list(cm.viridis(norm(colores[i]),bytes=True))#[round(num*255) for num in list(cmap(i))[:3]] #check!
 
112
  return imgR
113
 
114
  ###########################################
115
+ def save_results_as_json(md_results, dlc_outputs, animal_bboxes, map_dlc_label_id_to_str, model,mega_model_input, path_to_output_file = 'download_predictions.json'):
116
 
117
  """
118
  Output detections as json file
119
 
120
+ animal_bboxes: detection rows [x1,y1,x2,y2,conf,label], one per entry of dlc_outputs
121
  """
122
  # initialise dict to save to json
123
  info = {}
 
128
  number_bb = len(md_results.xyxy[0].tolist())
129
  info['number_of_bb'] = number_bb
130
  # info from DLC
131
+ info['dlc_model'] = model
132
  labels = [n for n in map_dlc_label_id_to_str.values()]
 
 
 
 
 
 
 
 
133
 
134
+ # define aux dict for every animal bounding box above threshold
135
+ for i in range(len(dlc_outputs)):
136
  aux={}
137
  # MD output
138
+ corner_x1,corner_y1,corner_x2,corner_y2,confidence, _ = animal_bboxes[i]
139
  aux['corner_1'] = (corner_x1,corner_y1)
140
  aux['corner_2'] = (corner_x2,corner_y2)
141
  aux['predict MD'] = md_results.names[0]
142
  aux['confidence MD'] = confidence
143
 
144
  # DLC output
 
145
  kypts = []
146
  for s in dlc_outputs[i]:
147
  aux1 = []
 
150
 
151
  kypts.append(aux1)
152
  aux['dlc_pred'] = dict(zip(labels,kypts))
153
+ info['bb_' + str(i) ]=aux
154
 
155
  # save dict as json
156
  with open(path_to_output_file, 'w') as f: