19 Authors: Giacomo Colosio, Sebastiano Colosio, Patrizio Acquadro, Tito Nicola Drugman
25 import tensorflow
as tf
26 import matplotlib.pyplot
as plt
27 from typing
import Optional
29 from src.postprocessing
import heatmaps_spe_postprocess
32 def _oks_matrix(kpt0:tf.Tensor, kpt1:tf.Tensor, area:tf.Tensor, stddev:tf.Tensor, eps:Optional[float] = 1e-7):
34 Calculate OKS (object keypoint similarities) matrix
37 kpt0 (tf.Tensor): shape (batch, N, nb_kpts, 3) FLOAT32 representing ground truth keypoints.
38 kpt1 (tf.Tensor): shape (batch, M, nb_kpts, 3) FLOAT32 representing predicted keypoints.
39 area (tf.Tensor): shape (batch, N) FLOAT32 representing areas of the poses of the gt kpts.
40 stddev (tf.Tensor): shape (nb_kpts, ) FLOAT32 representing the normalized keypoints standard deviation
41 eps Optional[float]: shape (1,) FLOAT32 value used to avoid division by zero
44 oks (tf.Tensor): shape (batch, N, M) representing the object keypoint similarities.
49 X_2 = tf.square(kpt0[:, :,
None, :, 0] - kpt1[:,
None, :, :, 0])
50 Y_2 = tf.square(kpt0[:, :,
None, :, 1] - kpt1[:,
None, :, :, 1])
54 distances_2 = X_2 + Y_2
56 z = -distances_2 / (tf.square(2*stddev[
None,
None,
None, :]) * (area[:, :,
None,
None] + eps) * 2)
58 oks = tf.math.reduce_sum(tf.math.exp(z) * mask[:, :,
None, :], axis=-1) / (tf.math.reduce_sum(mask, axis=-1)[:, :,
None] + eps)
64 Calculate the area of a pose
67 tensor (tf.Tensor): shape (batch, N, 2) FLOAT32 bounding box [w h] values
70 area (tf.Tensor): shape (batch, N) FLOAT32 W*H area of the poses
73 area = tensor[...,0] * tensor[...,1]
79 Matching of the predictions with the ground truths
82 tensor (tf.Tensor): shape (batch, N, M) FLOAT32 representing the object keypoint similarities.
83 thres (tf.Tensor): shape (thres, ) FLOAT32 thresholds for the OKS
86 matching (tf.Tensor): shape (batch, M, thres) FLOAT32 0 and 1's representing the matching of the preds with a gt for every thresholds.
89 batch,N,M = tf.shape(tensor)
91 rtensor = tf.reshape(tensor,[-1,N*M])
94 stensor = tf.argsort(rtensor)[:,::-1]
97 z = tf.zeros(tf.shape(stensor),tf.int32)
99 range_t = tf.tile(tf.range(batch)[:,
None],[1,N*M])
100 range_t = tf.reshape(range_t,-1)
102 fstensor = tf.reshape(stensor,-1)
103 fstensor = tf.stack([range_t,fstensor],-1)
105 updates = tf.range(batch*N*M)
108 stensor = tf.tensor_scatter_nd_update(tensor=z,
111 stensor -= tf.range(batch)[:,
None]*N*M
113 nm = tf.cast(N*M,tf.float32)
116 stensor = (nm-1.) - tf.cast(stensor,tf.float32)
117 rstensor = tf.reshape(stensor,[-1,N,M])
120 arstensor = tf.argmax(rstensor,axis=1)
121 oarst = tf.one_hot(arstensor,N,axis=1)
125 rstensor = rstensor*oarst - (1-oarst)
127 eqzz = tf.reduce_sum(oarst,axis=-1)
128 eqzz = tf.cast(eqzz!=0,tf.float32)
130 brstensor = tf.argmax(rstensor,axis=-1)
131 obrst = tf.one_hot(brstensor,M,axis=-1)
132 obrst *= eqzz[:,:,
None]
136 oks_v = tf.reduce_max(tensor * matching,axis=1)
138 t_matching = oks_v > thres[:,
None,
None]
139 t_matching = tf.cast(t_matching,tf.float32)
140 t_matching = tf.transpose(t_matching,[1,2,0])
146 Compute the OKS (object keypoint similarities) metric for single pose estimation
149 y_true (tf.Tensor): shape (batch, 1, 5+nb_kpts*3) FLOAT32 representing ground truth keypoints.
150 y_pred (tf.Tensor): shape (batch, 1, nb_kpts*3) FLOAT32 representing predicted keypoints.
153 spe_oks (tf.Tensor): shape (batch,) representing the object keypoint similarities.
156 shg = tf.shape(y_true)
157 shp = tf.shape(y_pred)
163 def f1():
return tf.constant([0.026,0.025,0.025,0.035,0.035,0.079,0.079,0.072,0.072,0.062,0.062,0.107,0.107,0.087,0.087,0.089,0.089],tf.float32)
164 def f2():
return tf.constant([0.035,0.079,0.079,0.072,0.072,0.062,0.062,0.107,0.107,0.087,0.087,0.089,0.089],tf.float32)
165 def f3():
return tf.zeros(nb_kpts,tf.float32)
167 stddev = tf.case([(nb_kpts == 17, f1), (nb_kpts == 13, f2)], default=f3, exclusive=
True)
170 gt = tf.reshape(gt, [shg[0],shg[1],nb_kpts,3])
171 pred = tf.reshape(y_pred,[shp[0],shp[1],nb_kpts,3])
179 Compute the OKS (object keypoint similarities) metric for single pose estimation heatmaps
182 y_true (tf.Tensor): shape (batch, 1, 5+nb_kpts*3) FLOAT32 representing ground truth keypoints.
183 y_pred (tf.Tensor): shape (batch, res, res, keypoints) FLOAT32 representing predicted heatmaps.
186 spe_oks (tf.Tensor): shape (batch,) representing the object keypoint similarities.
193 Compute the OKS mAP (object keypoint similarities - mean Average Precision) metric for multi pose estimation
196 y_true (tf.Tensor): shape (batch, N, 5+nb_kpts*3) FLOAT32 representing ground truth keypoints.
197 y_pred (tf.Tensor): shape (batch, M, 5+nb_kpts*3) FLOAT32 representing predicted keypoints.
200 tp (tf.Tensor): shape (batch*M,thresh) FLOAT32 0's and 1's representing the true positives
201 conf (tf.Tensor): shape (batch*M,) FLOAT32 box confidences of the detections
202 nb_gt (tf.Tensor): shape (1,) FLOAT32 number ground truths
203 maskpad (tf.Tensor): shape (batch*M,) FLOAT32 mask for the padding of predictions
206 sh = tf.shape(y_pred[:,:,5:])
211 gtT = tf.reduce_sum(y_true[:,:,5:],-1)
212 preT = tf.reduce_sum(y_pred,-1)
213 maskpad = tf.cast(preT>0,tf.float32)
214 maskpad = tf.reshape(maskpad,[-1])
216 stddev = tf.constant([0.026,0.025,0.025,0.035,0.035,0.079,0.079,0.072,0.072,0.062,0.062,0.107,0.107,0.087,0.087,0.089,0.089],tf.float32)
217 thres = tf.constant([0.5 , 0.55, 0.6 , 0.65, 0.7 , 0.75, 0.8 , 0.85, 0.9, 0.95],tf.float32)
220 pred = y_pred[:,:,5:]
221 gt = tf.reshape(gt, [sh[0],-1,nb_kpts,3])
222 pred = tf.reshape(pred,[sh[0],-1,nb_kpts,3])
225 conf = tf.reshape(conf,[-1])
231 tp = tf.reshape(mtp,[sh[0]*sh[1],-1])
233 nb_gt = tf.math.count_nonzero(gtT)
234 nb_gt = tf.reduce_sum(nb_gt)
235 nb_gt = tf.cast(nb_gt, tf.float32)
237 return tp, conf, nb_gt, maskpad
239 def _precision_recall(tp:tf.Tensor, conf:tf.Tensor, nb_gt:tf.Tensor, maskpad:tf.Tensor, eps:Optional[float] = 1e-7):
241 Compute precision and recall for all thresholds
244 tp (tf.Tensor): shape (batch*M,thresh) FLOAT32 0's and 1's representing the true positives
245 conf (tf.Tensor): shape (batch*M,) FLOAT32 box confidences of the detections
246 nb_gt (tf.Tensor): shape (1,) FLOAT32 number ground truths
247 maskpad (tf.Tensor): shape (batch*M,) FLOAT32 mask for the padding of predictions
248 eps Optional[float]: shape (1,) FLOAT32 value used to avoid division by zero
251 precision (tf.Tensor): shape (thres, ) FLOAT32 precision values for all the thresholds
252 recall (tf.Tensor): shape (thres, ) FLOAT32 recall values for all the thresholds
255 conf_sort = tf.argsort(conf)[::-1]
257 ntp = tf.gather(tp,conf_sort)
259 nmaskpad = tf.gather(maskpad,conf_sort)
262 FP = tf.cumsum((1-ntp)*nmaskpad[:,
None])
264 precision = TP / (TP + FP + eps)
265 recall = TP / (nb_gt + eps)
267 return precision, recall
269 def _auc(precision:tf.Tensor, recall:tf.Tensor):
271 Compute the Area Under the Curve (AUC) that gives the mAP value
274 precision (tf.Tensor): shape (thres, ) FLOAT32 precision values for all the thresholds
275 recall (tf.Tensor): shape (thres, ) FLOAT32 recall values for all the thresholds
278 mAP (tf.Tensor): shape (1, ) FLOAT32 mean Average Precision value
282 mrec = np.concatenate(([0.0], recall, [1.0]))
283 mpre = np.concatenate(([1.0], precision, [0.0]))
286 mpre = np.flip(np.maximum.accumulate(np.flip(mpre)))
288 _,i_mrec = np.unique(mrec,return_index=
True)
294 x = np.linspace(0, 1, 101)
295 interpolation = np.interp(x, mrec, mpre)
296 ap = np.trapz(interpolation, x)
298 return ap, mpre, mrec
300 def compute_ap(tp:tf.Tensor, conf:tf.Tensor, nb_gt:tf.Tensor, maskpad:tf.Tensor, plot_metrics:bool):
302 Compute the AP (Average Precision) for each threshold values
305 tp (tf.Tensor): shape (batch*M,thresh) FLOAT32 0's and 1's representing the true positives
306 conf (tf.Tensor): shape (batch*M,) FLOAT32 box confidences of the detections
307 nb_gt (tf.Tensor): shape (1,) FLOAT32 number ground truths
308 maskpad (tf.Tensor): shape (batch*M,) FLOAT32 mask for the padding of predictions
309 plot_metrics (bool): shape (1,) BOOL if true the precision/recall curve will be drawn
312 mAPs (tf.Tensor): shape (thresh, ) FLOAT32 mean Average Precision values
317 sp = tf.shape(precision)
321 for i
in range(sp[1]):
322 ac =
_auc(precision[:,i],recall[:,i])
326 plt.plot(recall[:,0],precision[:,0])
def _auc(tf.Tensor precision, tf.Tensor recall)
def compute_ap(tf.Tensor tp, tf.Tensor conf, tf.Tensor nb_gt, tf.Tensor maskpad, bool plot_metrics)
def _precision_recall(tf.Tensor tp, tf.Tensor conf, tf.Tensor nb_gt, tf.Tensor maskpad, Optional[float] eps=1e-7)
def multi_pose_oks_mAP(tf.Tensor y_true, tf.Tensor y_pred)
def single_pose_heatmaps_oks(tf.Tensor y_true, tf.Tensor y_pred)
def _pose_area_calculation(tf.Tensor tensor)
def _oks_matrix(tf.Tensor kpt0, tf.Tensor kpt1, tf.Tensor area, tf.Tensor stddev, Optional[float] eps=1e-7)
def single_pose_oks(tf.Tensor y_true, tf.Tensor y_pred)
def _matching_predictions(tf.Tensor tensor, tf.Tensor thres)
def heatmaps_spe_postprocess(tf.Tensor tensor)