|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__author__ = "tsungyi"
|
|
|
|
import copy
|
|
import datetime
|
|
import logging
|
|
import numpy as np
|
|
import pickle
|
|
import time
|
|
from collections import defaultdict
|
|
from enum import Enum
|
|
from typing import Any, Dict, Tuple
|
|
import scipy.spatial.distance as ssd
|
|
import torch
|
|
import torch.nn.functional as F
|
|
from pycocotools import mask as maskUtils
|
|
from scipy.io import loadmat
|
|
from scipy.ndimage import zoom as spzoom
|
|
|
|
from detectron2.utils.file_io import PathManager
|
|
|
|
from densepose.converters.chart_output_to_chart_result import resample_uv_tensors_to_bbox
|
|
from densepose.converters.segm_to_mask import (
|
|
resample_coarse_segm_tensor_to_bbox,
|
|
resample_fine_and_coarse_segm_tensors_to_bbox,
|
|
)
|
|
from densepose.modeling.cse.utils import squared_euclidean_distance_matrix
|
|
from densepose.structures import DensePoseDataRelative
|
|
from densepose.structures.mesh import create_mesh
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class DensePoseEvalMode(str, Enum):
|
|
|
|
GPSM = "gpsm"
|
|
|
|
GPS = "gps"
|
|
|
|
IOU = "iou"
|
|
|
|
|
|
class DensePoseDataMode(str, Enum):
|
|
|
|
IUV_DT = "iuvdt"
|
|
|
|
IUV_GT = "iuvgt"
|
|
|
|
I_GT_UV_0 = "igtuv0"
|
|
|
|
I_GT_UV_DT = "igtuvdt"
|
|
|
|
I_DT_UV_0 = "idtuv0"
|
|
|
|
|
|
class DensePoseCocoEval:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
self,
|
|
cocoGt=None,
|
|
cocoDt=None,
|
|
iouType: str = "densepose",
|
|
multi_storage=None,
|
|
embedder=None,
|
|
dpEvalMode: DensePoseEvalMode = DensePoseEvalMode.GPS,
|
|
dpDataMode: DensePoseDataMode = DensePoseDataMode.IUV_DT,
|
|
):
|
|
"""
|
|
Initialize CocoEval using coco APIs for gt and dt
|
|
:param cocoGt: coco object with ground truth annotations
|
|
:param cocoDt: coco object with detection results
|
|
:return: None
|
|
"""
|
|
self.cocoGt = cocoGt
|
|
self.cocoDt = cocoDt
|
|
self.multi_storage = multi_storage
|
|
self.embedder = embedder
|
|
self._dpEvalMode = dpEvalMode
|
|
self._dpDataMode = dpDataMode
|
|
self.evalImgs = defaultdict(list)
|
|
self.eval = {}
|
|
self._gts = defaultdict(list)
|
|
self._dts = defaultdict(list)
|
|
self.params = Params(iouType=iouType)
|
|
self._paramsEval = {}
|
|
self.stats = []
|
|
self.ious = {}
|
|
if cocoGt is not None:
|
|
self.params.imgIds = sorted(cocoGt.getImgIds())
|
|
self.params.catIds = sorted(cocoGt.getCatIds())
|
|
self.ignoreThrBB = 0.7
|
|
self.ignoreThrUV = 0.9
|
|
|
|
def _loadGEval(self):
|
|
smpl_subdiv_fpath = PathManager.get_local_path(
|
|
"https://dl.fbaipublicfiles.com/densepose/data/SMPL_subdiv.mat"
|
|
)
|
|
pdist_transform_fpath = PathManager.get_local_path(
|
|
"https://dl.fbaipublicfiles.com/densepose/data/SMPL_SUBDIV_TRANSFORM.mat"
|
|
)
|
|
pdist_matrix_fpath = PathManager.get_local_path(
|
|
"https://dl.fbaipublicfiles.com/densepose/data/Pdist_matrix.pkl", timeout_sec=120
|
|
)
|
|
SMPL_subdiv = loadmat(smpl_subdiv_fpath)
|
|
self.PDIST_transform = loadmat(pdist_transform_fpath)
|
|
self.PDIST_transform = self.PDIST_transform["index"].squeeze()
|
|
UV = np.array([SMPL_subdiv["U_subdiv"], SMPL_subdiv["V_subdiv"]]).squeeze()
|
|
ClosestVertInds = np.arange(UV.shape[1]) + 1
|
|
self.Part_UVs = []
|
|
self.Part_ClosestVertInds = []
|
|
for i in np.arange(24):
|
|
self.Part_UVs.append(UV[:, SMPL_subdiv["Part_ID_subdiv"].squeeze() == (i + 1)])
|
|
self.Part_ClosestVertInds.append(
|
|
ClosestVertInds[SMPL_subdiv["Part_ID_subdiv"].squeeze() == (i + 1)]
|
|
)
|
|
|
|
with open(pdist_matrix_fpath, "rb") as hFile:
|
|
arrays = pickle.load(hFile, encoding="latin1")
|
|
self.Pdist_matrix = arrays["Pdist_matrix"]
|
|
self.Part_ids = np.array(SMPL_subdiv["Part_ID_subdiv"].squeeze())
|
|
|
|
self.Mean_Distances = np.array([0, 0.351, 0.107, 0.126, 0.237, 0.173, 0.142, 0.128, 0.150])
|
|
|
|
self.CoarseParts = np.array(
|
|
[0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8]
|
|
)
|
|
|
|
def _prepare(self):
|
|
"""
|
|
Prepare ._gts and ._dts for evaluation based on params
|
|
:return: None
|
|
"""
|
|
|
|
def _toMask(anns, coco):
|
|
|
|
for ann in anns:
|
|
|
|
|
|
|
|
|
|
segm = ann["segmentation"]
|
|
if type(segm) is list and len(segm) == 0:
|
|
ann["segmentation"] = None
|
|
continue
|
|
rle = coco.annToRLE(ann)
|
|
ann["segmentation"] = rle
|
|
|
|
def _getIgnoreRegion(iid, coco):
|
|
img = coco.imgs[iid]
|
|
|
|
if "ignore_regions_x" not in img.keys():
|
|
return None
|
|
|
|
if len(img["ignore_regions_x"]) == 0:
|
|
return None
|
|
|
|
rgns_merged = [
|
|
[v for xy in zip(region_x, region_y) for v in xy]
|
|
for region_x, region_y in zip(img["ignore_regions_x"], img["ignore_regions_y"])
|
|
]
|
|
rles = maskUtils.frPyObjects(rgns_merged, img["height"], img["width"])
|
|
rle = maskUtils.merge(rles)
|
|
return maskUtils.decode(rle)
|
|
|
|
def _checkIgnore(dt, iregion):
|
|
if iregion is None:
|
|
return True
|
|
|
|
bb = np.array(dt["bbox"]).astype(int)
|
|
x1, y1, x2, y2 = bb[0], bb[1], bb[0] + bb[2], bb[1] + bb[3]
|
|
x2 = min([x2, iregion.shape[1]])
|
|
y2 = min([y2, iregion.shape[0]])
|
|
|
|
if bb[2] * bb[3] == 0:
|
|
return False
|
|
|
|
crop_iregion = iregion[y1:y2, x1:x2]
|
|
|
|
if crop_iregion.sum() == 0:
|
|
return True
|
|
|
|
if "densepose" not in dt.keys():
|
|
return crop_iregion.sum() / bb[2] / bb[3] < self.ignoreThrBB
|
|
|
|
|
|
ignoremask = np.require(crop_iregion, requirements=["F"])
|
|
mask = self._extract_mask(dt)
|
|
uvmask = np.require(np.asarray(mask > 0), dtype=np.uint8, requirements=["F"])
|
|
uvmask_ = maskUtils.encode(uvmask)
|
|
ignoremask_ = maskUtils.encode(ignoremask)
|
|
uviou = maskUtils.iou([uvmask_], [ignoremask_], [1])[0]
|
|
return uviou < self.ignoreThrUV
|
|
|
|
p = self.params
|
|
|
|
if p.useCats:
|
|
gts = self.cocoGt.loadAnns(self.cocoGt.getAnnIds(imgIds=p.imgIds, catIds=p.catIds))
|
|
dts = self.cocoDt.loadAnns(self.cocoDt.getAnnIds(imgIds=p.imgIds, catIds=p.catIds))
|
|
else:
|
|
gts = self.cocoGt.loadAnns(self.cocoGt.getAnnIds(imgIds=p.imgIds))
|
|
dts = self.cocoDt.loadAnns(self.cocoDt.getAnnIds(imgIds=p.imgIds))
|
|
|
|
imns = self.cocoGt.loadImgs(p.imgIds)
|
|
self.size_mapping = {}
|
|
for im in imns:
|
|
self.size_mapping[im["id"]] = [im["height"], im["width"]]
|
|
|
|
|
|
if p.iouType == "densepose":
|
|
self._loadGEval()
|
|
|
|
|
|
if p.iouType == "segm":
|
|
_toMask(gts, self.cocoGt)
|
|
_toMask(dts, self.cocoDt)
|
|
|
|
|
|
for gt in gts:
|
|
gt["ignore"] = gt["ignore"] if "ignore" in gt else 0
|
|
gt["ignore"] = "iscrowd" in gt and gt["iscrowd"]
|
|
if p.iouType == "keypoints":
|
|
gt["ignore"] = (gt["num_keypoints"] == 0) or gt["ignore"]
|
|
if p.iouType == "densepose":
|
|
gt["ignore"] = ("dp_x" in gt) == 0
|
|
if p.iouType == "segm":
|
|
gt["ignore"] = gt["segmentation"] is None
|
|
|
|
self._gts = defaultdict(list)
|
|
self._dts = defaultdict(list)
|
|
self._igrgns = defaultdict(list)
|
|
|
|
for gt in gts:
|
|
iid = gt["image_id"]
|
|
if iid not in self._igrgns.keys():
|
|
self._igrgns[iid] = _getIgnoreRegion(iid, self.cocoGt)
|
|
if _checkIgnore(gt, self._igrgns[iid]):
|
|
self._gts[iid, gt["category_id"]].append(gt)
|
|
for dt in dts:
|
|
iid = dt["image_id"]
|
|
if (iid not in self._igrgns) or _checkIgnore(dt, self._igrgns[iid]):
|
|
self._dts[iid, dt["category_id"]].append(dt)
|
|
|
|
self.evalImgs = defaultdict(list)
|
|
self.eval = {}
|
|
|
|
def evaluate(self):
|
|
"""
|
|
Run per image evaluation on given images and store results (a list of dict) in self.evalImgs
|
|
:return: None
|
|
"""
|
|
tic = time.time()
|
|
logger.info("Running per image DensePose evaluation... {}".format(self.params.iouType))
|
|
p = self.params
|
|
|
|
if p.useSegm is not None:
|
|
p.iouType = "segm" if p.useSegm == 1 else "bbox"
|
|
logger.info("useSegm (deprecated) is not None. Running DensePose evaluation")
|
|
p.imgIds = list(np.unique(p.imgIds))
|
|
if p.useCats:
|
|
p.catIds = list(np.unique(p.catIds))
|
|
p.maxDets = sorted(p.maxDets)
|
|
self.params = p
|
|
|
|
self._prepare()
|
|
|
|
catIds = p.catIds if p.useCats else [-1]
|
|
|
|
if p.iouType in ["segm", "bbox"]:
|
|
computeIoU = self.computeIoU
|
|
elif p.iouType == "keypoints":
|
|
computeIoU = self.computeOks
|
|
elif p.iouType == "densepose":
|
|
computeIoU = self.computeOgps
|
|
if self._dpEvalMode in {DensePoseEvalMode.GPSM, DensePoseEvalMode.IOU}:
|
|
self.real_ious = {
|
|
(imgId, catId): self.computeDPIoU(imgId, catId)
|
|
for imgId in p.imgIds
|
|
for catId in catIds
|
|
}
|
|
|
|
self.ious = {
|
|
(imgId, catId): computeIoU(imgId, catId) for imgId in p.imgIds for catId in catIds
|
|
}
|
|
|
|
evaluateImg = self.evaluateImg
|
|
maxDet = p.maxDets[-1]
|
|
self.evalImgs = [
|
|
evaluateImg(imgId, catId, areaRng, maxDet)
|
|
for catId in catIds
|
|
for areaRng in p.areaRng
|
|
for imgId in p.imgIds
|
|
]
|
|
self._paramsEval = copy.deepcopy(self.params)
|
|
toc = time.time()
|
|
logger.info("DensePose evaluation DONE (t={:0.2f}s).".format(toc - tic))
|
|
|
|
def getDensePoseMask(self, polys):
|
|
maskGen = np.zeros([256, 256])
|
|
stop = min(len(polys) + 1, 15)
|
|
for i in range(1, stop):
|
|
if polys[i - 1]:
|
|
currentMask = maskUtils.decode(polys[i - 1])
|
|
maskGen[currentMask > 0] = i
|
|
return maskGen
|
|
|
|
def _generate_rlemask_on_image(self, mask, imgId, data):
|
|
bbox_xywh = np.array(data["bbox"])
|
|
x, y, w, h = bbox_xywh
|
|
im_h, im_w = self.size_mapping[imgId]
|
|
im_mask = np.zeros((im_h, im_w), dtype=np.uint8)
|
|
if mask is not None:
|
|
x0 = max(int(x), 0)
|
|
x1 = min(int(x + w), im_w, int(x) + mask.shape[1])
|
|
y0 = max(int(y), 0)
|
|
y1 = min(int(y + h), im_h, int(y) + mask.shape[0])
|
|
y = int(y)
|
|
x = int(x)
|
|
im_mask[y0:y1, x0:x1] = mask[y0 - y : y1 - y, x0 - x : x1 - x]
|
|
im_mask = np.require(np.asarray(im_mask > 0), dtype=np.uint8, requirements=["F"])
|
|
rle_mask = maskUtils.encode(np.array(im_mask[:, :, np.newaxis], order="F"))[0]
|
|
return rle_mask
|
|
|
|
def computeDPIoU(self, imgId, catId):
|
|
p = self.params
|
|
if p.useCats:
|
|
gt = self._gts[imgId, catId]
|
|
dt = self._dts[imgId, catId]
|
|
else:
|
|
gt = [_ for cId in p.catIds for _ in self._gts[imgId, cId]]
|
|
dt = [_ for cId in p.catIds for _ in self._dts[imgId, cId]]
|
|
if len(gt) == 0 and len(dt) == 0:
|
|
return []
|
|
inds = np.argsort([-d["score"] for d in dt], kind="mergesort")
|
|
dt = [dt[i] for i in inds]
|
|
if len(dt) > p.maxDets[-1]:
|
|
dt = dt[0 : p.maxDets[-1]]
|
|
|
|
gtmasks = []
|
|
for g in gt:
|
|
if DensePoseDataRelative.S_KEY in g:
|
|
|
|
mask = np.minimum(self.getDensePoseMask(g[DensePoseDataRelative.S_KEY]), 1.0)
|
|
_, _, w, h = g["bbox"]
|
|
scale_x = float(max(w, 1)) / mask.shape[1]
|
|
scale_y = float(max(h, 1)) / mask.shape[0]
|
|
mask = spzoom(mask, (scale_y, scale_x), order=1, prefilter=False)
|
|
mask = np.array(mask > 0.5, dtype=np.uint8)
|
|
rle_mask = self._generate_rlemask_on_image(mask, imgId, g)
|
|
elif "segmentation" in g:
|
|
segmentation = g["segmentation"]
|
|
if isinstance(segmentation, list) and segmentation:
|
|
|
|
im_h, im_w = self.size_mapping[imgId]
|
|
rles = maskUtils.frPyObjects(segmentation, im_h, im_w)
|
|
rle_mask = maskUtils.merge(rles)
|
|
elif isinstance(segmentation, dict):
|
|
if isinstance(segmentation["counts"], list):
|
|
|
|
im_h, im_w = self.size_mapping[imgId]
|
|
rle_mask = maskUtils.frPyObjects(segmentation, im_h, im_w)
|
|
else:
|
|
|
|
rle_mask = segmentation
|
|
else:
|
|
rle_mask = self._generate_rlemask_on_image(None, imgId, g)
|
|
else:
|
|
rle_mask = self._generate_rlemask_on_image(None, imgId, g)
|
|
gtmasks.append(rle_mask)
|
|
|
|
dtmasks = []
|
|
for d in dt:
|
|
mask = self._extract_mask(d)
|
|
mask = np.require(np.asarray(mask > 0), dtype=np.uint8, requirements=["F"])
|
|
rle_mask = self._generate_rlemask_on_image(mask, imgId, d)
|
|
dtmasks.append(rle_mask)
|
|
|
|
|
|
iscrowd = [int(o.get("iscrowd", 0)) for o in gt]
|
|
iousDP = maskUtils.iou(dtmasks, gtmasks, iscrowd)
|
|
return iousDP
|
|
|
|
def computeIoU(self, imgId, catId):
|
|
p = self.params
|
|
if p.useCats:
|
|
gt = self._gts[imgId, catId]
|
|
dt = self._dts[imgId, catId]
|
|
else:
|
|
gt = [_ for cId in p.catIds for _ in self._gts[imgId, cId]]
|
|
dt = [_ for cId in p.catIds for _ in self._dts[imgId, cId]]
|
|
if len(gt) == 0 and len(dt) == 0:
|
|
return []
|
|
inds = np.argsort([-d["score"] for d in dt], kind="mergesort")
|
|
dt = [dt[i] for i in inds]
|
|
if len(dt) > p.maxDets[-1]:
|
|
dt = dt[0 : p.maxDets[-1]]
|
|
|
|
if p.iouType == "segm":
|
|
g = [g["segmentation"] for g in gt if g["segmentation"] is not None]
|
|
d = [d["segmentation"] for d in dt if d["segmentation"] is not None]
|
|
elif p.iouType == "bbox":
|
|
g = [g["bbox"] for g in gt]
|
|
d = [d["bbox"] for d in dt]
|
|
else:
|
|
raise Exception("unknown iouType for iou computation")
|
|
|
|
|
|
iscrowd = [int(o.get("iscrowd", 0)) for o in gt]
|
|
ious = maskUtils.iou(d, g, iscrowd)
|
|
return ious
|
|
|
|
def computeOks(self, imgId, catId):
|
|
p = self.params
|
|
|
|
gts = self._gts[imgId, catId]
|
|
dts = self._dts[imgId, catId]
|
|
inds = np.argsort([-d["score"] for d in dts], kind="mergesort")
|
|
dts = [dts[i] for i in inds]
|
|
if len(dts) > p.maxDets[-1]:
|
|
dts = dts[0 : p.maxDets[-1]]
|
|
|
|
if len(gts) == 0 or len(dts) == 0:
|
|
return []
|
|
ious = np.zeros((len(dts), len(gts)))
|
|
sigmas = (
|
|
np.array(
|
|
[
|
|
0.26,
|
|
0.25,
|
|
0.25,
|
|
0.35,
|
|
0.35,
|
|
0.79,
|
|
0.79,
|
|
0.72,
|
|
0.72,
|
|
0.62,
|
|
0.62,
|
|
1.07,
|
|
1.07,
|
|
0.87,
|
|
0.87,
|
|
0.89,
|
|
0.89,
|
|
]
|
|
)
|
|
/ 10.0
|
|
)
|
|
vars = (sigmas * 2) ** 2
|
|
k = len(sigmas)
|
|
|
|
for j, gt in enumerate(gts):
|
|
|
|
g = np.array(gt["keypoints"])
|
|
xg = g[0::3]
|
|
yg = g[1::3]
|
|
vg = g[2::3]
|
|
k1 = np.count_nonzero(vg > 0)
|
|
bb = gt["bbox"]
|
|
x0 = bb[0] - bb[2]
|
|
x1 = bb[0] + bb[2] * 2
|
|
y0 = bb[1] - bb[3]
|
|
y1 = bb[1] + bb[3] * 2
|
|
for i, dt in enumerate(dts):
|
|
d = np.array(dt["keypoints"])
|
|
xd = d[0::3]
|
|
yd = d[1::3]
|
|
if k1 > 0:
|
|
|
|
dx = xd - xg
|
|
dy = yd - yg
|
|
else:
|
|
|
|
z = np.zeros(k)
|
|
dx = np.max((z, x0 - xd), axis=0) + np.max((z, xd - x1), axis=0)
|
|
dy = np.max((z, y0 - yd), axis=0) + np.max((z, yd - y1), axis=0)
|
|
e = (dx**2 + dy**2) / vars / (gt["area"] + np.spacing(1)) / 2
|
|
if k1 > 0:
|
|
e = e[vg > 0]
|
|
ious[i, j] = np.sum(np.exp(-e)) / e.shape[0]
|
|
return ious
|
|
|
|
def _extract_mask(self, dt: Dict[str, Any]) -> np.ndarray:
|
|
if "densepose" in dt:
|
|
densepose_results_quantized = dt["densepose"]
|
|
return densepose_results_quantized.labels_uv_uint8[0].numpy()
|
|
elif "cse_mask" in dt:
|
|
return dt["cse_mask"]
|
|
elif "coarse_segm" in dt:
|
|
dy = max(int(dt["bbox"][3]), 1)
|
|
dx = max(int(dt["bbox"][2]), 1)
|
|
return (
|
|
F.interpolate(
|
|
dt["coarse_segm"].unsqueeze(0),
|
|
(dy, dx),
|
|
mode="bilinear",
|
|
align_corners=False,
|
|
)
|
|
.squeeze(0)
|
|
.argmax(0)
|
|
.numpy()
|
|
.astype(np.uint8)
|
|
)
|
|
elif "record_id" in dt:
|
|
assert (
|
|
self.multi_storage is not None
|
|
), f"Storage record id encountered in a detection {dt}, but no storage provided!"
|
|
record = self.multi_storage.get(dt["rank"], dt["record_id"])
|
|
coarse_segm = record["coarse_segm"]
|
|
dy = max(int(dt["bbox"][3]), 1)
|
|
dx = max(int(dt["bbox"][2]), 1)
|
|
return (
|
|
F.interpolate(
|
|
coarse_segm.unsqueeze(0),
|
|
(dy, dx),
|
|
mode="bilinear",
|
|
align_corners=False,
|
|
)
|
|
.squeeze(0)
|
|
.argmax(0)
|
|
.numpy()
|
|
.astype(np.uint8)
|
|
)
|
|
else:
|
|
raise Exception(f"No mask data in the detection: {dt}")
|
|
raise ValueError('The prediction dict needs to contain either "densepose" or "cse_mask"')
|
|
|
|
def _extract_iuv(
|
|
self, densepose_data: np.ndarray, py: np.ndarray, px: np.ndarray, gt: Dict[str, Any]
|
|
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
"""
|
|
Extract arrays of I, U and V values at given points as numpy arrays
|
|
given the data mode stored in self._dpDataMode
|
|
"""
|
|
if self._dpDataMode == DensePoseDataMode.IUV_DT:
|
|
|
|
ipoints = densepose_data[0, py, px]
|
|
upoints = densepose_data[1, py, px] / 255.0
|
|
vpoints = densepose_data[2, py, px] / 255.0
|
|
elif self._dpDataMode == DensePoseDataMode.IUV_GT:
|
|
|
|
ipoints = np.array(gt["dp_I"])
|
|
upoints = np.array(gt["dp_U"])
|
|
vpoints = np.array(gt["dp_V"])
|
|
elif self._dpDataMode == DensePoseDataMode.I_GT_UV_0:
|
|
|
|
ipoints = np.array(gt["dp_I"])
|
|
upoints = upoints * 0.0
|
|
vpoints = vpoints * 0.0
|
|
elif self._dpDataMode == DensePoseDataMode.I_GT_UV_DT:
|
|
|
|
ipoints = np.array(gt["dp_I"])
|
|
upoints = densepose_data[1, py, px] / 255.0
|
|
vpoints = densepose_data[2, py, px] / 255.0
|
|
elif self._dpDataMode == DensePoseDataMode.I_DT_UV_0:
|
|
|
|
ipoints = densepose_data[0, py, px]
|
|
upoints = upoints * 0.0
|
|
vpoints = vpoints * 0.0
|
|
else:
|
|
raise ValueError(f"Unknown data mode: {self._dpDataMode}")
|
|
return ipoints, upoints, vpoints
|
|
|
|
def computeOgps_single_pair(self, dt, gt, py, px, pt_mask):
|
|
if "densepose" in dt:
|
|
ipoints, upoints, vpoints = self.extract_iuv_from_quantized(dt, gt, py, px, pt_mask)
|
|
return self.computeOgps_single_pair_iuv(dt, gt, ipoints, upoints, vpoints)
|
|
elif "u" in dt:
|
|
ipoints, upoints, vpoints = self.extract_iuv_from_raw(dt, gt, py, px, pt_mask)
|
|
return self.computeOgps_single_pair_iuv(dt, gt, ipoints, upoints, vpoints)
|
|
elif "record_id" in dt:
|
|
assert (
|
|
self.multi_storage is not None
|
|
), f"Storage record id encountered in detection {dt}, but no storage provided!"
|
|
record = self.multi_storage.get(dt["rank"], dt["record_id"])
|
|
record["bbox"] = dt["bbox"]
|
|
if "u" in record:
|
|
ipoints, upoints, vpoints = self.extract_iuv_from_raw(record, gt, py, px, pt_mask)
|
|
return self.computeOgps_single_pair_iuv(dt, gt, ipoints, upoints, vpoints)
|
|
elif "embedding" in record:
|
|
return self.computeOgps_single_pair_cse(
|
|
dt,
|
|
gt,
|
|
py,
|
|
px,
|
|
pt_mask,
|
|
record["coarse_segm"],
|
|
record["embedding"],
|
|
record["bbox"],
|
|
)
|
|
else:
|
|
raise Exception(f"Unknown record format: {record}")
|
|
elif "embedding" in dt:
|
|
return self.computeOgps_single_pair_cse(
|
|
dt, gt, py, px, pt_mask, dt["coarse_segm"], dt["embedding"], dt["bbox"]
|
|
)
|
|
raise Exception(f"Unknown detection format: {dt}")
|
|
|
|
def extract_iuv_from_quantized(self, dt, gt, py, px, pt_mask):
|
|
densepose_results_quantized = dt["densepose"]
|
|
ipoints, upoints, vpoints = self._extract_iuv(
|
|
densepose_results_quantized.labels_uv_uint8.numpy(), py, px, gt
|
|
)
|
|
ipoints[pt_mask == -1] = 0
|
|
return ipoints, upoints, vpoints
|
|
|
|
def extract_iuv_from_raw(self, dt, gt, py, px, pt_mask):
|
|
labels_dt = resample_fine_and_coarse_segm_tensors_to_bbox(
|
|
dt["fine_segm"].unsqueeze(0),
|
|
dt["coarse_segm"].unsqueeze(0),
|
|
dt["bbox"],
|
|
)
|
|
uv = resample_uv_tensors_to_bbox(
|
|
dt["u"].unsqueeze(0), dt["v"].unsqueeze(0), labels_dt.squeeze(0), dt["bbox"]
|
|
)
|
|
labels_uv_uint8 = torch.cat((labels_dt.byte(), (uv * 255).clamp(0, 255).byte()))
|
|
ipoints, upoints, vpoints = self._extract_iuv(labels_uv_uint8.numpy(), py, px, gt)
|
|
ipoints[pt_mask == -1] = 0
|
|
return ipoints, upoints, vpoints
|
|
|
|
def computeOgps_single_pair_iuv(self, dt, gt, ipoints, upoints, vpoints):
|
|
cVertsGT, ClosestVertsGTTransformed = self.findAllClosestVertsGT(gt)
|
|
cVerts = self.findAllClosestVertsUV(upoints, vpoints, ipoints)
|
|
|
|
dist = self.getDistancesUV(ClosestVertsGTTransformed, cVerts)
|
|
|
|
|
|
|
|
Current_Mean_Distances = self.Mean_Distances[
|
|
self.CoarseParts[self.Part_ids[cVertsGT[cVertsGT > 0].astype(int) - 1]]
|
|
]
|
|
return dist, Current_Mean_Distances
|
|
|
|
def computeOgps_single_pair_cse(
|
|
self, dt, gt, py, px, pt_mask, coarse_segm, embedding, bbox_xywh_abs
|
|
):
|
|
|
|
cVertsGT = torch.as_tensor(gt["dp_vertex"], dtype=torch.int64)
|
|
|
|
labels_dt = resample_coarse_segm_tensor_to_bbox(
|
|
coarse_segm.unsqueeze(0), bbox_xywh_abs
|
|
).squeeze(0)
|
|
x, y, w, h = bbox_xywh_abs
|
|
|
|
embedding = F.interpolate(
|
|
embedding.unsqueeze(0), (int(h), int(w)), mode="bilinear", align_corners=False
|
|
).squeeze(0)
|
|
|
|
py_pt = torch.from_numpy(py[pt_mask > -1])
|
|
px_pt = torch.from_numpy(px[pt_mask > -1])
|
|
cVerts = torch.ones_like(cVertsGT) * -1
|
|
cVerts[pt_mask > -1] = self.findClosestVertsCse(
|
|
embedding, py_pt, px_pt, labels_dt, gt["ref_model"]
|
|
)
|
|
|
|
dist = self.getDistancesCse(cVertsGT, cVerts, gt["ref_model"])
|
|
|
|
if (gt["ref_model"] == "smpl_27554") and ("dp_I" in gt):
|
|
Current_Mean_Distances = self.Mean_Distances[
|
|
self.CoarseParts[np.array(gt["dp_I"], dtype=int)]
|
|
]
|
|
else:
|
|
Current_Mean_Distances = 0.255
|
|
return dist, Current_Mean_Distances
|
|
|
|
def computeOgps(self, imgId, catId):
|
|
p = self.params
|
|
|
|
g = self._gts[imgId, catId]
|
|
d = self._dts[imgId, catId]
|
|
inds = np.argsort([-d_["score"] for d_ in d], kind="mergesort")
|
|
d = [d[i] for i in inds]
|
|
if len(d) > p.maxDets[-1]:
|
|
d = d[0 : p.maxDets[-1]]
|
|
|
|
if len(g) == 0 or len(d) == 0:
|
|
return []
|
|
ious = np.zeros((len(d), len(g)))
|
|
|
|
|
|
|
|
|
|
for j, gt in enumerate(g):
|
|
if not gt["ignore"]:
|
|
g_ = gt["bbox"]
|
|
for i, dt in enumerate(d):
|
|
|
|
dy = int(dt["bbox"][3])
|
|
dx = int(dt["bbox"][2])
|
|
dp_x = np.array(gt["dp_x"]) * g_[2] / 255.0
|
|
dp_y = np.array(gt["dp_y"]) * g_[3] / 255.0
|
|
py = (dp_y + g_[1] - dt["bbox"][1]).astype(int)
|
|
px = (dp_x + g_[0] - dt["bbox"][0]).astype(int)
|
|
|
|
pts = np.zeros(len(px))
|
|
pts[px >= dx] = -1
|
|
pts[py >= dy] = -1
|
|
pts[px < 0] = -1
|
|
pts[py < 0] = -1
|
|
if len(pts) < 1:
|
|
ogps = 0.0
|
|
elif np.max(pts) == -1:
|
|
ogps = 0.0
|
|
else:
|
|
px[pts == -1] = 0
|
|
py[pts == -1] = 0
|
|
dists_between_matches, dist_norm_coeffs = self.computeOgps_single_pair(
|
|
dt, gt, py, px, pts
|
|
)
|
|
|
|
ogps_values = np.exp(
|
|
-(dists_between_matches**2) / (2 * (dist_norm_coeffs**2))
|
|
)
|
|
|
|
ogps = np.mean(ogps_values) if len(ogps_values) > 0 else 0.0
|
|
ious[i, j] = ogps
|
|
|
|
gbb = [gt["bbox"] for gt in g]
|
|
dbb = [dt["bbox"] for dt in d]
|
|
|
|
|
|
iscrowd = [int(o.get("iscrowd", 0)) for o in g]
|
|
ious_bb = maskUtils.iou(dbb, gbb, iscrowd)
|
|
return ious, ious_bb
|
|
|
|
def evaluateImg(self, imgId, catId, aRng, maxDet):
|
|
"""
|
|
perform evaluation for single category and image
|
|
:return: dict (single image results)
|
|
"""
|
|
|
|
p = self.params
|
|
if p.useCats:
|
|
gt = self._gts[imgId, catId]
|
|
dt = self._dts[imgId, catId]
|
|
else:
|
|
gt = [_ for cId in p.catIds for _ in self._gts[imgId, cId]]
|
|
dt = [_ for cId in p.catIds for _ in self._dts[imgId, cId]]
|
|
if len(gt) == 0 and len(dt) == 0:
|
|
return None
|
|
|
|
for g in gt:
|
|
|
|
if g["ignore"] or (g["area"] < aRng[0] or g["area"] > aRng[1]):
|
|
g["_ignore"] = True
|
|
else:
|
|
g["_ignore"] = False
|
|
|
|
|
|
gtind = np.argsort([g["_ignore"] for g in gt], kind="mergesort")
|
|
gt = [gt[i] for i in gtind]
|
|
dtind = np.argsort([-d["score"] for d in dt], kind="mergesort")
|
|
dt = [dt[i] for i in dtind[0:maxDet]]
|
|
iscrowd = [int(o.get("iscrowd", 0)) for o in gt]
|
|
|
|
if p.iouType == "densepose":
|
|
|
|
|
|
|
|
ious = (
|
|
self.ious[imgId, catId][0][:, gtind]
|
|
if len(self.ious[imgId, catId]) > 0
|
|
else self.ious[imgId, catId]
|
|
)
|
|
ioubs = (
|
|
self.ious[imgId, catId][1][:, gtind]
|
|
if len(self.ious[imgId, catId]) > 0
|
|
else self.ious[imgId, catId]
|
|
)
|
|
if self._dpEvalMode in {DensePoseEvalMode.GPSM, DensePoseEvalMode.IOU}:
|
|
iousM = (
|
|
self.real_ious[imgId, catId][:, gtind]
|
|
if len(self.real_ious[imgId, catId]) > 0
|
|
else self.real_ious[imgId, catId]
|
|
)
|
|
else:
|
|
ious = (
|
|
self.ious[imgId, catId][:, gtind]
|
|
if len(self.ious[imgId, catId]) > 0
|
|
else self.ious[imgId, catId]
|
|
)
|
|
|
|
T = len(p.iouThrs)
|
|
G = len(gt)
|
|
D = len(dt)
|
|
gtm = np.zeros((T, G))
|
|
dtm = np.zeros((T, D))
|
|
gtIg = np.array([g["_ignore"] for g in gt])
|
|
dtIg = np.zeros((T, D))
|
|
if np.all(gtIg) and p.iouType == "densepose":
|
|
dtIg = np.logical_or(dtIg, True)
|
|
|
|
if len(ious) > 0:
|
|
for tind, t in enumerate(p.iouThrs):
|
|
for dind, d in enumerate(dt):
|
|
|
|
iou = min([t, 1 - 1e-10])
|
|
m = -1
|
|
for gind, _g in enumerate(gt):
|
|
|
|
if gtm[tind, gind] > 0 and not iscrowd[gind]:
|
|
continue
|
|
|
|
if m > -1 and gtIg[m] == 0 and gtIg[gind] == 1:
|
|
break
|
|
if p.iouType == "densepose":
|
|
if self._dpEvalMode == DensePoseEvalMode.GPSM:
|
|
new_iou = np.sqrt(iousM[dind, gind] * ious[dind, gind])
|
|
elif self._dpEvalMode == DensePoseEvalMode.IOU:
|
|
new_iou = iousM[dind, gind]
|
|
elif self._dpEvalMode == DensePoseEvalMode.GPS:
|
|
new_iou = ious[dind, gind]
|
|
else:
|
|
new_iou = ious[dind, gind]
|
|
if new_iou < iou:
|
|
continue
|
|
if new_iou == 0.0:
|
|
continue
|
|
|
|
iou = new_iou
|
|
m = gind
|
|
|
|
if m == -1:
|
|
continue
|
|
dtIg[tind, dind] = gtIg[m]
|
|
dtm[tind, dind] = gt[m]["id"]
|
|
gtm[tind, m] = d["id"]
|
|
|
|
if p.iouType == "densepose":
|
|
if not len(ioubs) == 0:
|
|
for dind, d in enumerate(dt):
|
|
|
|
if dtm[tind, dind] == 0:
|
|
ioub = 0.8
|
|
m = -1
|
|
for gind, _g in enumerate(gt):
|
|
|
|
if gtm[tind, gind] > 0 and not iscrowd[gind]:
|
|
continue
|
|
|
|
if ioubs[dind, gind] < ioub:
|
|
continue
|
|
|
|
ioub = ioubs[dind, gind]
|
|
m = gind
|
|
|
|
if m > -1:
|
|
dtIg[:, dind] = gtIg[m]
|
|
if gtIg[m]:
|
|
dtm[tind, dind] = gt[m]["id"]
|
|
gtm[tind, m] = d["id"]
|
|
|
|
a = np.array([d["area"] < aRng[0] or d["area"] > aRng[1] for d in dt]).reshape((1, len(dt)))
|
|
dtIg = np.logical_or(dtIg, np.logical_and(dtm == 0, np.repeat(a, T, 0)))
|
|
|
|
|
|
return {
|
|
"image_id": imgId,
|
|
"category_id": catId,
|
|
"aRng": aRng,
|
|
"maxDet": maxDet,
|
|
"dtIds": [d["id"] for d in dt],
|
|
"gtIds": [g["id"] for g in gt],
|
|
"dtMatches": dtm,
|
|
"gtMatches": gtm,
|
|
"dtScores": [d["score"] for d in dt],
|
|
"gtIgnore": gtIg,
|
|
"dtIgnore": dtIg,
|
|
}
|
|
|
|
def accumulate(self, p=None):
|
|
"""
|
|
Accumulate per image evaluation results and store the result in self.eval
|
|
:param p: input params for evaluation
|
|
:return: None
|
|
"""
|
|
logger.info("Accumulating evaluation results...")
|
|
tic = time.time()
|
|
if not self.evalImgs:
|
|
logger.info("Please run evaluate() first")
|
|
|
|
if p is None:
|
|
p = self.params
|
|
p.catIds = p.catIds if p.useCats == 1 else [-1]
|
|
T = len(p.iouThrs)
|
|
R = len(p.recThrs)
|
|
K = len(p.catIds) if p.useCats else 1
|
|
A = len(p.areaRng)
|
|
M = len(p.maxDets)
|
|
precision = -(np.ones((T, R, K, A, M)))
|
|
recall = -(np.ones((T, K, A, M)))
|
|
|
|
|
|
logger.info("Categories: {}".format(p.catIds))
|
|
_pe = self._paramsEval
|
|
catIds = _pe.catIds if _pe.useCats else [-1]
|
|
setK = set(catIds)
|
|
setA = set(map(tuple, _pe.areaRng))
|
|
setM = set(_pe.maxDets)
|
|
setI = set(_pe.imgIds)
|
|
|
|
k_list = [n for n, k in enumerate(p.catIds) if k in setK]
|
|
m_list = [m for n, m in enumerate(p.maxDets) if m in setM]
|
|
a_list = [n for n, a in enumerate(map(lambda x: tuple(x), p.areaRng)) if a in setA]
|
|
i_list = [n for n, i in enumerate(p.imgIds) if i in setI]
|
|
I0 = len(_pe.imgIds)
|
|
A0 = len(_pe.areaRng)
|
|
|
|
for k, k0 in enumerate(k_list):
|
|
Nk = k0 * A0 * I0
|
|
for a, a0 in enumerate(a_list):
|
|
Na = a0 * I0
|
|
for m, maxDet in enumerate(m_list):
|
|
E = [self.evalImgs[Nk + Na + i] for i in i_list]
|
|
E = [e for e in E if e is not None]
|
|
if len(E) == 0:
|
|
continue
|
|
dtScores = np.concatenate([e["dtScores"][0:maxDet] for e in E])
|
|
|
|
|
|
|
|
inds = np.argsort(-dtScores, kind="mergesort")
|
|
|
|
dtm = np.concatenate([e["dtMatches"][:, 0:maxDet] for e in E], axis=1)[:, inds]
|
|
dtIg = np.concatenate([e["dtIgnore"][:, 0:maxDet] for e in E], axis=1)[:, inds]
|
|
gtIg = np.concatenate([e["gtIgnore"] for e in E])
|
|
npig = np.count_nonzero(gtIg == 0)
|
|
if npig == 0:
|
|
continue
|
|
tps = np.logical_and(dtm, np.logical_not(dtIg))
|
|
fps = np.logical_and(np.logical_not(dtm), np.logical_not(dtIg))
|
|
tp_sum = np.cumsum(tps, axis=1).astype(dtype=float)
|
|
fp_sum = np.cumsum(fps, axis=1).astype(dtype=float)
|
|
for t, (tp, fp) in enumerate(zip(tp_sum, fp_sum)):
|
|
tp = np.array(tp)
|
|
fp = np.array(fp)
|
|
nd = len(tp)
|
|
rc = tp / npig
|
|
pr = tp / (fp + tp + np.spacing(1))
|
|
q = np.zeros((R,))
|
|
|
|
if nd:
|
|
recall[t, k, a, m] = rc[-1]
|
|
else:
|
|
recall[t, k, a, m] = 0
|
|
|
|
|
|
|
|
pr = pr.tolist()
|
|
q = q.tolist()
|
|
|
|
for i in range(nd - 1, 0, -1):
|
|
if pr[i] > pr[i - 1]:
|
|
pr[i - 1] = pr[i]
|
|
|
|
inds = np.searchsorted(rc, p.recThrs, side="left")
|
|
try:
|
|
for ri, pi in enumerate(inds):
|
|
q[ri] = pr[pi]
|
|
except Exception:
|
|
pass
|
|
precision[t, :, k, a, m] = np.array(q)
|
|
logger.info(
|
|
"Final: max precision {}, min precision {}".format(np.max(precision), np.min(precision))
|
|
)
|
|
self.eval = {
|
|
"params": p,
|
|
"counts": [T, R, K, A, M],
|
|
"date": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
"precision": precision,
|
|
"recall": recall,
|
|
}
|
|
toc = time.time()
|
|
logger.info("DONE (t={:0.2f}s).".format(toc - tic))
|
|
|
|
def summarize(self):
|
|
"""
|
|
Compute and display summary metrics for evaluation results.
|
|
Note this function can *only* be applied on the default parameter setting
|
|
"""
|
|
|
|
def _summarize(ap=1, iouThr=None, areaRng="all", maxDets=100):
|
|
p = self.params
|
|
iStr = " {:<18} {} @[ {}={:<9} | area={:>6s} | maxDets={:>3d} ] = {:0.3f}"
|
|
titleStr = "Average Precision" if ap == 1 else "Average Recall"
|
|
typeStr = "(AP)" if ap == 1 else "(AR)"
|
|
measure = "IoU"
|
|
if self.params.iouType == "keypoints":
|
|
measure = "OKS"
|
|
elif self.params.iouType == "densepose":
|
|
measure = "OGPS"
|
|
iouStr = (
|
|
"{:0.2f}:{:0.2f}".format(p.iouThrs[0], p.iouThrs[-1])
|
|
if iouThr is None
|
|
else "{:0.2f}".format(iouThr)
|
|
)
|
|
|
|
aind = [i for i, aRng in enumerate(p.areaRngLbl) if aRng == areaRng]
|
|
mind = [i for i, mDet in enumerate(p.maxDets) if mDet == maxDets]
|
|
if ap == 1:
|
|
|
|
s = self.eval["precision"]
|
|
|
|
if iouThr is not None:
|
|
t = np.where(np.abs(iouThr - p.iouThrs) < 0.001)[0]
|
|
s = s[t]
|
|
s = s[:, :, :, aind, mind]
|
|
else:
|
|
|
|
s = self.eval["recall"]
|
|
if iouThr is not None:
|
|
t = np.where(np.abs(iouThr - p.iouThrs) < 0.001)[0]
|
|
s = s[t]
|
|
s = s[:, :, aind, mind]
|
|
if len(s[s > -1]) == 0:
|
|
mean_s = -1
|
|
else:
|
|
mean_s = np.mean(s[s > -1])
|
|
logger.info(iStr.format(titleStr, typeStr, measure, iouStr, areaRng, maxDets, mean_s))
|
|
return mean_s
|
|
|
|
def _summarizeDets():
|
|
stats = np.zeros((12,))
|
|
stats[0] = _summarize(1)
|
|
stats[1] = _summarize(1, iouThr=0.5, maxDets=self.params.maxDets[2])
|
|
stats[2] = _summarize(1, iouThr=0.75, maxDets=self.params.maxDets[2])
|
|
stats[3] = _summarize(1, areaRng="small", maxDets=self.params.maxDets[2])
|
|
stats[4] = _summarize(1, areaRng="medium", maxDets=self.params.maxDets[2])
|
|
stats[5] = _summarize(1, areaRng="large", maxDets=self.params.maxDets[2])
|
|
stats[6] = _summarize(0, maxDets=self.params.maxDets[0])
|
|
stats[7] = _summarize(0, maxDets=self.params.maxDets[1])
|
|
stats[8] = _summarize(0, maxDets=self.params.maxDets[2])
|
|
stats[9] = _summarize(0, areaRng="small", maxDets=self.params.maxDets[2])
|
|
stats[10] = _summarize(0, areaRng="medium", maxDets=self.params.maxDets[2])
|
|
stats[11] = _summarize(0, areaRng="large", maxDets=self.params.maxDets[2])
|
|
return stats
|
|
|
|
def _summarizeKps():
|
|
stats = np.zeros((10,))
|
|
stats[0] = _summarize(1, maxDets=20)
|
|
stats[1] = _summarize(1, maxDets=20, iouThr=0.5)
|
|
stats[2] = _summarize(1, maxDets=20, iouThr=0.75)
|
|
stats[3] = _summarize(1, maxDets=20, areaRng="medium")
|
|
stats[4] = _summarize(1, maxDets=20, areaRng="large")
|
|
stats[5] = _summarize(0, maxDets=20)
|
|
stats[6] = _summarize(0, maxDets=20, iouThr=0.5)
|
|
stats[7] = _summarize(0, maxDets=20, iouThr=0.75)
|
|
stats[8] = _summarize(0, maxDets=20, areaRng="medium")
|
|
stats[9] = _summarize(0, maxDets=20, areaRng="large")
|
|
return stats
|
|
|
|
def _summarizeUvs():
|
|
stats = [_summarize(1, maxDets=self.params.maxDets[0])]
|
|
min_threshold = self.params.iouThrs.min()
|
|
if min_threshold <= 0.201:
|
|
stats += [_summarize(1, maxDets=self.params.maxDets[0], iouThr=0.2)]
|
|
if min_threshold <= 0.301:
|
|
stats += [_summarize(1, maxDets=self.params.maxDets[0], iouThr=0.3)]
|
|
if min_threshold <= 0.401:
|
|
stats += [_summarize(1, maxDets=self.params.maxDets[0], iouThr=0.4)]
|
|
stats += [
|
|
_summarize(1, maxDets=self.params.maxDets[0], iouThr=0.5),
|
|
_summarize(1, maxDets=self.params.maxDets[0], iouThr=0.75),
|
|
_summarize(1, maxDets=self.params.maxDets[0], areaRng="medium"),
|
|
_summarize(1, maxDets=self.params.maxDets[0], areaRng="large"),
|
|
_summarize(0, maxDets=self.params.maxDets[0]),
|
|
_summarize(0, maxDets=self.params.maxDets[0], iouThr=0.5),
|
|
_summarize(0, maxDets=self.params.maxDets[0], iouThr=0.75),
|
|
_summarize(0, maxDets=self.params.maxDets[0], areaRng="medium"),
|
|
_summarize(0, maxDets=self.params.maxDets[0], areaRng="large"),
|
|
]
|
|
return np.array(stats)
|
|
|
|
def _summarizeUvsOld():
|
|
stats = np.zeros((18,))
|
|
stats[0] = _summarize(1, maxDets=self.params.maxDets[0])
|
|
stats[1] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.5)
|
|
stats[2] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.55)
|
|
stats[3] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.60)
|
|
stats[4] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.65)
|
|
stats[5] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.70)
|
|
stats[6] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.75)
|
|
stats[7] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.80)
|
|
stats[8] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.85)
|
|
stats[9] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.90)
|
|
stats[10] = _summarize(1, maxDets=self.params.maxDets[0], iouThr=0.95)
|
|
stats[11] = _summarize(1, maxDets=self.params.maxDets[0], areaRng="medium")
|
|
stats[12] = _summarize(1, maxDets=self.params.maxDets[0], areaRng="large")
|
|
stats[13] = _summarize(0, maxDets=self.params.maxDets[0])
|
|
stats[14] = _summarize(0, maxDets=self.params.maxDets[0], iouThr=0.5)
|
|
stats[15] = _summarize(0, maxDets=self.params.maxDets[0], iouThr=0.75)
|
|
stats[16] = _summarize(0, maxDets=self.params.maxDets[0], areaRng="medium")
|
|
stats[17] = _summarize(0, maxDets=self.params.maxDets[0], areaRng="large")
|
|
return stats
|
|
|
|
if not self.eval:
|
|
raise Exception("Please run accumulate() first")
|
|
iouType = self.params.iouType
|
|
if iouType in ["segm", "bbox"]:
|
|
summarize = _summarizeDets
|
|
elif iouType in ["keypoints"]:
|
|
summarize = _summarizeKps
|
|
elif iouType in ["densepose"]:
|
|
summarize = _summarizeUvs
|
|
self.stats = summarize()
|
|
|
|
def __str__(self):
|
|
self.summarize()
|
|
|
|
|
|
def findAllClosestVertsUV(self, U_points, V_points, Index_points):
|
|
ClosestVerts = np.ones(Index_points.shape) * -1
|
|
for i in np.arange(24):
|
|
|
|
if (i + 1) in Index_points:
|
|
UVs = np.array(
|
|
[U_points[Index_points == (i + 1)], V_points[Index_points == (i + 1)]]
|
|
)
|
|
Current_Part_UVs = self.Part_UVs[i]
|
|
Current_Part_ClosestVertInds = self.Part_ClosestVertInds[i]
|
|
D = ssd.cdist(Current_Part_UVs.transpose(), UVs.transpose()).squeeze()
|
|
ClosestVerts[Index_points == (i + 1)] = Current_Part_ClosestVertInds[
|
|
np.argmin(D, axis=0)
|
|
]
|
|
ClosestVertsTransformed = self.PDIST_transform[ClosestVerts.astype(int) - 1]
|
|
ClosestVertsTransformed[ClosestVerts < 0] = 0
|
|
return ClosestVertsTransformed
|
|
|
|
def findClosestVertsCse(self, embedding, py, px, mask, mesh_name):
|
|
mesh_vertex_embeddings = self.embedder(mesh_name)
|
|
pixel_embeddings = embedding[:, py, px].t().to(device="cuda")
|
|
mask_vals = mask[py, px]
|
|
edm = squared_euclidean_distance_matrix(pixel_embeddings, mesh_vertex_embeddings)
|
|
vertex_indices = edm.argmin(dim=1).cpu()
|
|
vertex_indices[mask_vals <= 0] = -1
|
|
return vertex_indices
|
|
|
|
def findAllClosestVertsGT(self, gt):
|
|
|
|
I_gt = np.array(gt["dp_I"])
|
|
U_gt = np.array(gt["dp_U"])
|
|
V_gt = np.array(gt["dp_V"])
|
|
|
|
|
|
|
|
ClosestVertsGT = np.ones(I_gt.shape) * -1
|
|
for i in np.arange(24):
|
|
if (i + 1) in I_gt:
|
|
UVs = np.array([U_gt[I_gt == (i + 1)], V_gt[I_gt == (i + 1)]])
|
|
Current_Part_UVs = self.Part_UVs[i]
|
|
Current_Part_ClosestVertInds = self.Part_ClosestVertInds[i]
|
|
D = ssd.cdist(Current_Part_UVs.transpose(), UVs.transpose()).squeeze()
|
|
ClosestVertsGT[I_gt == (i + 1)] = Current_Part_ClosestVertInds[np.argmin(D, axis=0)]
|
|
|
|
ClosestVertsGTTransformed = self.PDIST_transform[ClosestVertsGT.astype(int) - 1]
|
|
ClosestVertsGTTransformed[ClosestVertsGT < 0] = 0
|
|
return ClosestVertsGT, ClosestVertsGTTransformed
|
|
|
|
def getDistancesCse(self, cVertsGT, cVerts, mesh_name):
|
|
geodists_vertices = torch.ones_like(cVertsGT) * float("inf")
|
|
selected = (cVertsGT >= 0) * (cVerts >= 0)
|
|
mesh = create_mesh(mesh_name, "cpu")
|
|
geodists_vertices[selected] = mesh.geodists[cVertsGT[selected], cVerts[selected]]
|
|
return geodists_vertices.numpy()
|
|
|
|
def getDistancesUV(self, cVertsGT, cVerts):
|
|
|
|
n = 27554
|
|
dists = []
|
|
for d in range(len(cVertsGT)):
|
|
if cVertsGT[d] > 0:
|
|
if cVerts[d] > 0:
|
|
i = cVertsGT[d] - 1
|
|
j = cVerts[d] - 1
|
|
if j == i:
|
|
dists.append(0)
|
|
elif j > i:
|
|
ccc = i
|
|
i = j
|
|
j = ccc
|
|
i = n - i - 1
|
|
j = n - j - 1
|
|
k = (n * (n - 1) / 2) - (n - i) * ((n - i) - 1) / 2 + j - i - 1
|
|
k = (n * n - n) / 2 - k - 1
|
|
dists.append(self.Pdist_matrix[int(k)][0])
|
|
else:
|
|
i = n - i - 1
|
|
j = n - j - 1
|
|
k = (n * (n - 1) / 2) - (n - i) * ((n - i) - 1) / 2 + j - i - 1
|
|
k = (n * n - n) / 2 - k - 1
|
|
dists.append(self.Pdist_matrix[int(k)][0])
|
|
else:
|
|
dists.append(np.inf)
|
|
return np.atleast_1d(np.array(dists).squeeze())
|
|
|
|
|
|
class Params:
|
|
"""
|
|
Params for coco evaluation api
|
|
"""
|
|
|
|
def setDetParams(self):
|
|
self.imgIds = []
|
|
self.catIds = []
|
|
|
|
self.iouThrs = np.linspace(0.5, 0.95, int(np.round((0.95 - 0.5) / 0.05)) + 1, endpoint=True)
|
|
self.recThrs = np.linspace(0.0, 1.00, int(np.round((1.00 - 0.0) / 0.01)) + 1, endpoint=True)
|
|
self.maxDets = [1, 10, 100]
|
|
self.areaRng = [
|
|
[0**2, 1e5**2],
|
|
[0**2, 32**2],
|
|
[32**2, 96**2],
|
|
[96**2, 1e5**2],
|
|
]
|
|
self.areaRngLbl = ["all", "small", "medium", "large"]
|
|
self.useCats = 1
|
|
|
|
def setKpParams(self):
|
|
self.imgIds = []
|
|
self.catIds = []
|
|
|
|
self.iouThrs = np.linspace(0.5, 0.95, np.round((0.95 - 0.5) / 0.05) + 1, endpoint=True)
|
|
self.recThrs = np.linspace(0.0, 1.00, np.round((1.00 - 0.0) / 0.01) + 1, endpoint=True)
|
|
self.maxDets = [20]
|
|
self.areaRng = [[0**2, 1e5**2], [32**2, 96**2], [96**2, 1e5**2]]
|
|
self.areaRngLbl = ["all", "medium", "large"]
|
|
self.useCats = 1
|
|
|
|
def setUvParams(self):
|
|
self.imgIds = []
|
|
self.catIds = []
|
|
self.iouThrs = np.linspace(0.5, 0.95, int(np.round((0.95 - 0.5) / 0.05)) + 1, endpoint=True)
|
|
self.recThrs = np.linspace(0.0, 1.00, int(np.round((1.00 - 0.0) / 0.01)) + 1, endpoint=True)
|
|
self.maxDets = [20]
|
|
self.areaRng = [[0**2, 1e5**2], [32**2, 96**2], [96**2, 1e5**2]]
|
|
self.areaRngLbl = ["all", "medium", "large"]
|
|
self.useCats = 1
|
|
|
|
def __init__(self, iouType="segm"):
|
|
if iouType == "segm" or iouType == "bbox":
|
|
self.setDetParams()
|
|
elif iouType == "keypoints":
|
|
self.setKpParams()
|
|
elif iouType == "densepose":
|
|
self.setUvParams()
|
|
else:
|
|
raise Exception("iouType not supported")
|
|
self.iouType = iouType
|
|
|
|
self.useSegm = None
|
|
|