Commit 64b02fb6 authored by liangjing's avatar liangjing
Browse files

version 1

parents
Pipeline #176 failed with stages
in 0 seconds
# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
import torch
import torch._six
import pycocotools.mask as mask_util
class CocoEvaluator(object):
def prepare(self, predictions, iou_type):
if iou_type == "bbox":
return self.prepare_for_coco_detection(predictions)
elif iou_type == "segm":
return self.prepare_for_coco_segmentation(predictions)
elif iou_type == "keypoints":
return self.prepare_for_coco_keypoint(predictions)
else:
raise ValueError("Unknown iou type {}".format(iou_type))
def prepare_for_coco_detection(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
boxes = prediction["boxes"]
boxes = convert_to_xywh(boxes).tolist()
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
coco_results.extend(
[
{
"image_id": original_id,
"category_id": label,
"bbox": bbox,
"score": score,
}
for (bbox, label, score) in zip(boxes, labels, scores)
]
)
return coco_results
def prepare_for_coco_segmentation(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
scores = prediction["scores"]
labels = prediction["labels"]
masks = prediction["masks"]
masks = masks > 0.5
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
rles = [
mask_util.encode(np.array(mask[0, :, :, np.newaxis], dtype=np.uint8, order="F"))[0]
for mask in masks
]
for rle in rles:
rle["counts"] = rle["counts"].decode("utf-8")
coco_results.extend(
[
{
"image_id": original_id,
"category_id": labels[k],
"segmentation": rle,
"score": scores[k],
}
for k, rle in enumerate(rles)
]
)
return coco_results
def prepare_for_coco_keypoint(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
boxes = prediction["boxes"]
boxes = convert_to_xywh(boxes).tolist()
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
keypoints = prediction["keypoints"]
keypoints = keypoints.flatten(start_dim=1).tolist()
coco_results.extend(
[
{
"image_id": original_id,
"category_id": labels[k],
'keypoints': keypoint,
"score": scores[k],
}
for k, keypoint in enumerate(keypoints)
]
)
return coco_results
def convert_to_xywh(boxes):
xmin, ymin, xmax, ymax = boxes.unbind(1)
return torch.stack((xmin, ymin, xmax - xmin, ymax - ymin), dim=1)
# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import torch
import torch.utils.data
import torchvision
from pycocotools import mask as coco_mask
from pycocotools.coco import COCO
import transforms as T
def convert_coco_poly_to_mask(segmentations, height, width):
masks = []
for polygons in segmentations:
rles = coco_mask.frPyObjects(polygons, height, width)
mask = coco_mask.decode(rles)
if len(mask.shape) < 3:
mask = mask[..., None]
mask = torch.as_tensor(mask, dtype=torch.uint8)
mask = mask.any(dim=2)
masks.append(mask)
if masks:
masks = torch.stack(masks, dim=0)
else:
masks = torch.zeros((0, height, width), dtype=torch.uint8)
return masks
class ConvertCocoPolysToMask(object):
def __init__(self, filter_iscrowd=True):
self.filter_iscrowd = filter_iscrowd
def __call__(self, image, target):
w, h = image.size
image_id = target["image_id"]
image_id = torch.tensor([image_id])
anno = target["annotations"]
if self.filter_iscrowd:
anno = [obj for obj in anno if obj['iscrowd'] == 0]
boxes = [obj["bbox"] for obj in anno]
# guard against no boxes via resizing
boxes = torch.as_tensor(boxes, dtype=torch.float32).reshape(-1, 4)
boxes[:, 2:] += boxes[:, :2]
boxes[:, 0::2].clamp_(min=0, max=w)
boxes[:, 1::2].clamp_(min=0, max=h)
classes = [obj["category_id"] for obj in anno]
classes = torch.tensor(classes, dtype=torch.int64)
keypoints = None
if anno and "keypoints" in anno[0]:
keypoints = [obj["keypoints"] for obj in anno]
keypoints = torch.as_tensor(keypoints, dtype=torch.float32)
num_keypoints = keypoints.shape[0]
if num_keypoints:
keypoints = keypoints.view(num_keypoints, -1, 3)
keep = (boxes[:, 3] > boxes[:, 1]) & (boxes[:, 2] > boxes[:, 0])
boxes = boxes[keep]
classes = classes[keep]
target = {"boxes": boxes, "labels": classes, "image_id": image_id}
# for conversion to coco api
area = torch.tensor([obj["area"] for obj in anno])
iscrowd = torch.tensor([obj["iscrowd"] for obj in anno])
target["area"] = area
target["iscrowd"] = iscrowd
return image, target
def _coco_remove_images_without_annotations(dataset, cat_list=None):
def _has_only_empty_bbox(anno):
return all(any(o <= 1 for o in obj["bbox"][2:]) for obj in anno)
def _count_visible_keypoints(anno):
return sum(sum(1 for v in ann["keypoints"][2::3] if v > 0) for ann in anno)
min_keypoints_per_image = 10
def _has_valid_annotation(anno):
# if it's empty, there is no annotation
if len(anno) == 0:
return False
# if all boxes have close to zero area, there is no annotation
if _has_only_empty_bbox(anno):
return False
# keypoints task have a slight different critera for considering
# if an annotation is valid
if "keypoints" not in anno[0]:
return True
# for keypoint detection tasks, only consider valid images those
# containing at least min_keypoints_per_image
if _count_visible_keypoints(anno) >= min_keypoints_per_image:
return True
return False
assert isinstance(dataset, torchvision.datasets.CocoDetection)
ids = []
for ds_idx, img_id in enumerate(dataset.ids):
ann_ids = dataset.coco.getAnnIds(imgIds=img_id, iscrowd=None)
anno = dataset.coco.loadAnns(ann_ids)
if cat_list:
anno = [obj for obj in anno if obj["category_id"] in cat_list]
if _has_valid_annotation(anno):
ids.append(ds_idx)
dataset = torch.utils.data.Subset(dataset, ids)
return dataset
def convert_to_coco_api(ds):
coco_ds = COCO()
# annotation IDs need to start at 1, not 0, see torchvision issue #1530
ann_id = 1
dataset = {'images': [], 'categories': [], 'annotations': []}
categories = set()
for img_idx in range(len(ds)):
# find better way to get target
# targets = ds.get_annotations(img_idx)
img, targets = ds[img_idx]
image_id = targets["image_id"].item()
img_dict = {}
img_dict['id'] = image_id
img_dict['height'] = img.shape[-2]
img_dict['width'] = img.shape[-1]
dataset['images'].append(img_dict)
bboxes = targets["boxes"]
bboxes[:, 2:] -= bboxes[:, :2]
bboxes = bboxes.tolist()
labels = targets['labels'].tolist()
areas = targets['area'].tolist()
iscrowd = targets['iscrowd'].tolist()
num_objs = len(bboxes)
for i in range(num_objs):
ann = {}
ann['image_id'] = image_id
ann['bbox'] = bboxes[i]
ann['category_id'] = labels[i]
categories.add(labels[i])
ann['area'] = areas[i]
ann['iscrowd'] = iscrowd[i]
ann['id'] = ann_id
dataset['annotations'].append(ann)
ann_id += 1
dataset['categories'] = [{'id': i} for i in sorted(categories)]
coco_ds.dataset = dataset
coco_ds.createIndex()
return coco_ds
def get_coco_api_from_dataset(dataset):
for _ in range(10):
if isinstance(dataset, torchvision.datasets.CocoDetection):
break
if isinstance(dataset, torch.utils.data.Subset):
dataset = dataset.dataset
if isinstance(dataset, torchvision.datasets.CocoDetection):
return dataset.coco
return convert_to_coco_api(dataset)
class CocoDetection(torchvision.datasets.CocoDetection):
def __init__(self, img_folder, ann_file, transforms):
super(CocoDetection, self).__init__(img_folder, ann_file)
self._transforms = transforms
def __getitem__(self, idx):
img, target = super(CocoDetection, self).__getitem__(idx)
image_id = self.ids[idx]
target = dict(image_id=image_id, annotations=target)
if self._transforms is not None:
img, target = self._transforms(img, target)
return img, target
def get_coco(dataset_path, annotations_file, transforms, training=True):
t = [ConvertCocoPolysToMask(filter_iscrowd=True)]
if transforms is not None:
t.append(transforms)
transforms = T.Compose(t)
dataset = CocoDetection(dataset_path, annotations_file, transforms=transforms)
if training:
dataset = _coco_remove_images_without_annotations(dataset)
return dataset
def get_openimages(dataset_path, annotations_file, transforms, training=True):
t = [ConvertCocoPolysToMask(filter_iscrowd=False)]
if transforms is not None:
t.append(transforms)
transforms = T.Compose(t)
dataset = CocoDetection(dataset_path, annotations_file, transforms=transforms)
return dataset
# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import torch
import numpy as np
from pycocotools.cocoeval import COCOeval
from pycocotools.coco import COCO
import utils
from coco.coco_eval import CocoEvaluator
#import pdb
class NVCocoEvaluator(CocoEvaluator):
def __init__(self, annotations_file, iou_types, num_threads=1, group=None):
assert isinstance(iou_types, (list, tuple))
self.annotations_file = annotations_file
self.coco_gt = None
self.num_threads = num_threads
self.multi_procs = (1, None) # TODO(ahmadki): support nvcoco multi processing
self.iou_types = iou_types
self.coco_eval = {}
self._results = {}
for iou_type in iou_types:
self._results[iou_type] = []
@property
def results(self):
return self._results
def update(self, predictions):
for iou_type in self.iou_types:
results = self.prepare(predictions, iou_type)
results = np.array(results, dtype=np.float32)
self._results[iou_type].extend(results)
def synchronize_between_processes(self, group=None):
for iou_type in self.iou_types:
#pdb.set_trace()
self._results[iou_type] = np.vstack(self._results[iou_type])
self._results[iou_type] = utils.all_gather(self._results[iou_type], group=group)
self._results[iou_type] = np.concatenate(self._results[iou_type], axis=0)
def accumulate(self):
if self.coco_gt is None:
self.coco_gt = NVCocoEvaluator.get_coco_gt(annotations_file=self.annotations_file,
num_threads=self.num_threads)
for iou_type in self.iou_types:
coco_dt = self.coco_gt.loadRes(self._results[iou_type])
coco_eval = COCOeval(self.coco_gt,
coco_dt,
iouType=iou_type,
num_threads=self.num_threads,
multi_procs=self.multi_procs,
use_ext=True)
coco_eval.evaluate()
coco_eval.accumulate()
self.coco_eval[iou_type] = coco_eval
def summarize(self):
for iou_type, coco_eval in self.coco_eval.items():
print("IoU metric: {}".format(iou_type))
coco_eval.summarize()
def get_stats(self):
stats = {}
for iou_type, coco_eval in self.coco_eval.items():
stats[iou_type] = coco_eval.stats
return stats
@staticmethod
@functools.lru_cache(maxsize=None)
def get_coco_gt(annotations_file=None, num_threads=8):
multi_procs = (1, None) # TODO(ahmadki)
return COCO(annotation_file=annotations_file,
multi_procs=multi_procs,
num_threads=num_threads,
use_ext=True)
@staticmethod
def get_stats_from_evaluator(evaluator):
evaluator.accumulate()
evaluator.summarize()
return evaluator.get_stats()
def prepare_for_coco_detection(self, predictions):
coco_results = []
for original_id, prediction in predictions.items():
if len(prediction) == 0:
continue
boxes = prediction["boxes"]
boxes = convert_to_xywh(boxes).tolist()
scores = prediction["scores"].tolist()
labels = prediction["labels"].tolist()
for (bbox, label, score) in zip(boxes, labels, scores):
coco_results.extend([[original_id, label, bbox[0], bbox[1], bbox[2], bbox[3], score]])
return coco_results
def convert_to_xywh(boxes):
xmin, ymin, xmax, ymax = boxes.unbind(1)
return torch.stack((xmin, ymin, xmax - xmin, ymax - ymin), dim=1)
# Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import copy
from contextlib import redirect_stdout
import numpy as np
from pycocotools.cocoeval import COCOeval
from pycocotools.coco import COCO
import utils
from coco.coco_eval import CocoEvaluator
class PythonCocoEvaluator(CocoEvaluator):
def __init__(self, annotations_file, iou_types, group=None):
assert isinstance(iou_types, (list, tuple))
self.annotations_file = annotations_file
self.coco_gt = PythonCocoEvaluator.get_coco_gt(annotations_file=annotations_file)
self.iou_types = iou_types
self.coco_eval = {}
for iou_type in iou_types:
self.coco_eval[iou_type] = COCOeval(self.coco_gt, iouType=iou_type)
self.img_ids = []
self.eval_imgs = {k: [] for k in iou_types}
def update(self, predictions):
img_ids = list(np.unique(list(predictions.keys())))
self.img_ids.extend(img_ids)
for iou_type in self.iou_types:
results = self.prepare(predictions, iou_type)
with redirect_stdout(None):
coco_dt = self.coco_gt.loadRes(results)
coco_eval = self.coco_eval[iou_type]
coco_eval.cocoDt = coco_dt
coco_eval.params.imgIds = list(img_ids)
img_ids, eval_imgs = evaluate(coco_eval)
self.eval_imgs[iou_type].append(eval_imgs)
def synchronize_between_processes(self, group=None):
for iou_type in self.iou_types:
self.eval_imgs[iou_type] = np.concatenate(self.eval_imgs[iou_type], 2)
create_common_coco_eval(self.coco_eval[iou_type], self.img_ids, self.eval_imgs[iou_type], group=group)
def accumulate(self):
for coco_eval in self.coco_eval.values():
coco_eval.accumulate()
def summarize(self):
for iou_type, coco_eval in self.coco_eval.items():
print("IoU metric: {}".format(iou_type))
coco_eval.summarize()
def get_stats(self):
stats = {}
for iou_type, coco_eval in self.coco_eval.items():
stats[iou_type] = coco_eval.stats
return stats
@staticmethod
@functools.lru_cache(maxsize=None)
def get_coco_gt(annotations_file=None):
return COCO(annotation_file=annotations_file)
@staticmethod
def get_stats_from_evaluator(evaluator):
evaluator.accumulate()
evaluator.summarize()
return evaluator.get_stats()
def merge(img_ids, eval_imgs, group=None):
all_img_ids = utils.all_gather(img_ids, group=group)
all_eval_imgs = utils.all_gather(eval_imgs, group=group)
merged_img_ids = []
for p in all_img_ids:
merged_img_ids.extend(p)
merged_eval_imgs = []
for p in all_eval_imgs:
merged_eval_imgs.append(p)
merged_img_ids = np.array(merged_img_ids)
merged_eval_imgs = np.concatenate(merged_eval_imgs, 2)
# keep only unique (and in sorted order) images
merged_img_ids, idx = np.unique(merged_img_ids, return_index=True)
merged_eval_imgs = merged_eval_imgs[..., idx]
return merged_img_ids, merged_eval_imgs
def create_common_coco_eval(coco_eval, img_ids, eval_imgs, group=None):
img_ids, eval_imgs = merge(img_ids, eval_imgs, group=group)
img_ids = list(img_ids)
eval_imgs = list(eval_imgs.flatten())
coco_eval.evalImgs = eval_imgs
coco_eval.params.imgIds = img_ids
coco_eval._paramsEval = copy.deepcopy(coco_eval.params)
def evaluate(imgs):
with redirect_stdout(None):
imgs.evaluate()
return imgs.params.imgIds, np.asarray(imgs.evalImgs).reshape(-1, len(imgs.params.areaRng), len(imgs.params.imgIds))
images/
annotations/
results/
external/
.DS_Store
MatlabAPI/analyze*/
MatlabAPI/visualize*/
MatlabAPI/private/maskApiMex.*
PythonAPI/pycocotools/__init__.pyc
PythonAPI/pycocotools/_mask.c
PythonAPI/pycocotools/_mask.so
PythonAPI/pycocotools/coco.pyc
PythonAPI/pycocotools/cocoeval.pyc
PythonAPI/pycocotools/mask.pyc
group: travis_latest
language: python
cache: pip
python:
- 2.7
- 3.6
install:
- pip install --upgrade pip
- pip install pycocotools
script:
- true
--[[----------------------------------------------------------------------------
Interface for accessing the Common Objects in COntext (COCO) dataset.
For an overview of the API please see http://mscoco.org/dataset/#download.
CocoApi.lua (this file) is modeled after the Matlab CocoApi.m:
https://github.com/pdollar/coco/blob/master/MatlabAPI/CocoApi.m
The following API functions are defined in the Lua API:
CocoApi - Load COCO annotation file and prepare data structures.
getAnnIds - Get ann ids that satisfy given filter conditions.
getCatIds - Get cat ids that satisfy given filter conditions.
getImgIds - Get img ids that satisfy given filter conditions.
loadAnns - Load anns with the specified ids.
loadCats - Load cats with the specified ids.
loadImgs - Load imgs with the specified ids.
showAnns - Display the specified annotations.
Throughout the API "ann"=annotation, "cat"=category, and "img"=image.
For detailed usage information please see cocoDemo.lua.
LIMITATIONS: the following API functions are NOT defined in the Lua API:
loadRes - Load algorithm results and create API for accessing them.
download - Download COCO images from mscoco.org server.
In addition, currently the getCatIds() and getImgIds() do not accept filters.
getAnnIds() can be called using getAnnIds({imgId=id}) and getAnnIds({catId=id}).
Note: loading COCO JSON annotations to Lua tables is quite slow. Hence, a call
to CocApi(annFile) converts the annotations to a custom 'flattened' format that
is more efficient. The first time a COCO JSON is loaded, the conversion is
invoked (this may take up to a minute). The converted data is then stored in a
t7 file (the code must have write permission to the dir of the JSON file).
Future calls of cocoApi=CocApi(annFile) take a fraction of a second. To view the
created data just inspect cocoApi.data of a created instance of the CocoApi.
Common Objects in COntext (COCO) Toolbox. version 3.0
Data, paper, and tutorials available at: http://mscoco.org/
Code written by Pedro O. Pinheiro and Piotr Dollar, 2016.
Licensed under the Simplified BSD License [see coco/license.txt]
------------------------------------------------------------------------------]]
local json = require 'cjson'
local coco = require 'coco.env'
local TensorTable = torch.class('TensorTable',coco)
local CocoSeg = torch.class('CocoSeg',coco)
local CocoApi = torch.class('CocoApi',coco)
--------------------------------------------------------------------------------
--[[ TensorTable is a lightweight data structure for storing variable size 1D
tensors. Tables of tensors are slow to save/load to disk. Instead, TensorTable
stores all the data in a single long tensor (along with indices into the tensor)
making serialization fast. A TensorTable may only contain 1D same-type torch
tensors or strings. It supports only creation from a table and indexing. ]]
function TensorTable:__init( T )
local n = #T; assert(n>0)
local isStr = torch.type(T[1])=='string'
assert(isStr or torch.isTensor(T[1]))
local c=function(s) return torch.CharTensor(torch.CharStorage():string(s)) end
if isStr then local S=T; T={}; for i=1,n do T[i]=c(S[i]) end end
local ms, idx = torch.LongTensor(n), torch.LongTensor(n+1)
for i=1,n do ms[i]=T[i]:numel() end
idx[1]=1; idx:narrow(1,2,n):copy(ms); idx=idx:cumsum()
local type = string.sub(torch.type(T[1]),7,-1)
local data = torch[type](idx[n+1]-1)
if isStr then type='string' end
for i=1,n do if ms[i]>0 then data:sub(idx[i],idx[i+1]-1):copy(T[i]) end end
if ms:eq(ms[1]):all() and ms[1]>0 then data=data:view(n,ms[1]); idx=nil end
self.data, self.idx, self.type = data, idx, type
end
function TensorTable:__index__( i )
if torch.type(i)~='number' then return false end
local d, idx, type = self.data, self.idx, self.type
if idx and idx[i]==idx[i+1] then
if type=='string' then d='' else d=torch[type]() end
else
if idx then d=d:sub(idx[i],idx[i+1]-1) else d=d[i] end
if type=='string' then d=d:clone():storage():string() end
end
return d, true
end
--------------------------------------------------------------------------------
--[[ CocoSeg is an efficient data structure for storing COCO segmentations. ]]
function CocoSeg:__init( segs )
local polys, pIdx, sizes, rles, p, isStr = {}, {}, {}, {}, 0, 0
for i,seg in pairs(segs) do if seg.size then isStr=seg.counts break end end
isStr = torch.type(isStr)=='string'
for i,seg in pairs(segs) do
pIdx[i], sizes[i] = {}, {}
if seg.size then
sizes[i],rles[i] = seg.size,seg.counts
else
if isStr then rles[i]='' else rles[i]={} end
for j=1,#seg do p=p+1; pIdx[i][j],polys[p] = p,seg[j] end
end
pIdx[i],sizes[i] = torch.LongTensor(pIdx[i]),torch.IntTensor(sizes[i])
if not isStr then rles[i]=torch.IntTensor(rles[i]) end
end
for i=1,p do polys[i]=torch.DoubleTensor(polys[i]) end
self.polys, self.pIdx = coco.TensorTable(polys), coco.TensorTable(pIdx)
self.sizes, self.rles = coco.TensorTable(sizes), coco.TensorTable(rles)
end
function CocoSeg:__index__( i )
if torch.type(i)~='number' then return false end
if self.sizes[i]:numel()>0 then
return {size=self.sizes[i],counts=self.rles[i]}, true
else
local ids, polys = self.pIdx[i], {}
for i=1,ids:numel() do polys[i]=self.polys[ids[i]] end
return polys, true
end
end
--------------------------------------------------------------------------------
--[[ CocoApi is the API to the COCO dataset, see main comment for details. ]]
function CocoApi:__init( annFile )
assert( string.sub(annFile,-4,-1)=='json' and paths.filep(annFile) )
local torchFile = string.sub(annFile,1,-6) .. '.t7'
if not paths.filep(torchFile) then self:__convert(annFile,torchFile) end
local data = torch.load(torchFile)
self.data, self.inds = data, {}
for k,v in pairs({images='img',categories='cat',annotations='ann'}) do
local M = {}; self.inds[v..'IdsMap']=M
if data[k] then for i=1,data[k].id:size(1) do M[data[k].id[i]]=i end end
end
end
function CocoApi:__convert( annFile, torchFile )
print('convert: '..annFile..' --> .t7 [please be patient]')
local tic = torch.tic()
-- load data and decode json
local data = torch.CharStorage(annFile):string()
data = json.decode(data); collectgarbage()
-- transpose and flatten each field in the coco data struct
local convert = {images=true, categories=true, annotations=true}
for field, d in pairs(data) do if convert[field] then
print('converting: '..field)
local n, out = #d, {}
if n==0 then d,n={d},1 end
for k,v in pairs(d[1]) do
local t, isReg = torch.type(v), true
for i=1,n do isReg=isReg and torch.type(d[i][k])==t end
if t=='number' and isReg then
out[k] = torch.DoubleTensor(n)
for i=1,n do out[k][i]=d[i][k] end
elseif t=='string' and isReg then
out[k]={}; for i=1,n do out[k][i]=d[i][k] end
out[k] = coco.TensorTable(out[k])
elseif t=='table' and isReg and torch.type(v[1])=='number' then
out[k]={}; for i=1,n do out[k][i]=torch.DoubleTensor(d[i][k]) end
out[k] = coco.TensorTable(out[k])
if not out[k].idx then out[k]=out[k].data end
else
out[k]={}; for i=1,n do out[k][i]=d[i][k] end
if k=='segmentation' then out[k] = coco.CocoSeg(out[k]) end
end
collectgarbage()
end
if out.id then out.idx=torch.range(1,out.id:size(1)) end
data[field] = out
collectgarbage()
end end
-- create mapping from cat/img index to anns indices for that cat/img
print('convert: building indices')
local makeMap = function( type, type_id )
if not data[type] or not data.annotations then return nil end
local invmap, n = {}, data[type].id:size(1)
for i=1,n do invmap[data[type].id[i]]=i end
local map = {}; for i=1,n do map[i]={} end
data.annotations[type_id..'x'] = data.annotations[type_id]:clone()
for i=1,data.annotations.id:size(1) do
local id = invmap[data.annotations[type_id][i]]
data.annotations[type_id..'x'][i] = id
table.insert(map[id],data.annotations.id[i])
end
for i=1,n do map[i]=torch.LongTensor(map[i]) end
return coco.TensorTable(map)
end
data.annIdsPerImg = makeMap('images','image_id')
data.annIdsPerCat = makeMap('categories','category_id')
-- save to disk
torch.save( torchFile, data )
print(('convert: complete [%.2f s]'):format(torch.toc(tic)))
end
function CocoApi:getAnnIds( filters )
if not filters then filters = {} end
if filters.imgId then
return self.data.annIdsPerImg[self.inds.imgIdsMap[filters.imgId]] or {}
elseif filters.catId then
return self.data.annIdsPerCat[self.inds.catIdsMap[filters.catId]] or {}
else
return self.data.annotations.id
end
end
function CocoApi:getCatIds()
return self.data.categories.id
end
function CocoApi:getImgIds()
return self.data.images.id
end
function CocoApi:loadAnns( ids )
return self:__load(self.data.annotations,self.inds.annIdsMap,ids)
end
function CocoApi:loadCats( ids )
return self:__load(self.data.categories,self.inds.catIdsMap,ids)
end
function CocoApi:loadImgs( ids )
return self:__load(self.data.images,self.inds.imgIdsMap,ids)
end
function CocoApi:showAnns( img, anns )
local n, h, w = #anns, img:size(2), img:size(3)
local MaskApi, clrs = coco.MaskApi, torch.rand(n,3)*.6+.4
local O = img:clone():contiguous():float()
if n==0 then anns,n={anns},1 end
if anns[1].keypoints then for i=1,n do if anns[i].iscrowd==0 then
local sk, kp, j, k = self:loadCats(anns[i].category_id)[1].skeleton
kp=anns[i].keypoints; k=kp:size(1); j=torch.range(1,k,3):long(); k=k/3;
local x,y,v = kp:index(1,j), kp:index(1,j+1), kp:index(1,j+2)
for _,s in pairs(sk) do if v[s[1]]>0 and v[s[2]]>0 then
MaskApi.drawLine(O,x[s[1]],y[s[1]],x[s[2]],y[s[2]],.75,clrs[i])
end end
for j=1,k do if v[j]==1 then MaskApi.drawCirc(O,x[j],y[j],4,{0,0,0}) end end
for j=1,k do if v[j]>0 then MaskApi.drawCirc(O,x[j],y[j],3,clrs[i]) end end
end end end
if anns[1].segmentation or anns[1].bbox then
local Rs, alpha = {}, anns[1].keypoints and .25 or .4
for i=1,n do
Rs[i]=anns[i].segmentation
if Rs[i] and #Rs[i]>0 then Rs[i]=MaskApi.frPoly(Rs[i],h,w) end
if not Rs[i] then Rs[i]=MaskApi.frBbox(anns[i].bbox,h,w)[1] end
end
MaskApi.drawMasks(O,MaskApi.decode(Rs),nil,alpha,clrs)
end
return O
end
function CocoApi:__load( data, map, ids )
if not torch.isTensor(ids) then ids=torch.LongTensor({ids}) end
local out, idx = {}, nil
for i=1,ids:numel() do
out[i], idx = {}, map[ids[i]]
for k,v in pairs(data) do out[i][k]=v[idx] end
end
return out
end
--[[----------------------------------------------------------------------------
Interface for manipulating masks stored in RLE format.
For an overview of RLE please see http://mscoco.org/dataset/#download.
Additionally, more detailed information can be found in the Matlab MaskApi.m:
https://github.com/pdollar/coco/blob/master/MatlabAPI/MaskApi.m
The following API functions are defined:
encode - Encode binary masks using RLE.
decode - Decode binary masks encoded via RLE.
merge - Compute union or intersection of encoded masks.
iou - Compute intersection over union between masks.
nms - Compute non-maximum suppression between ordered masks.
area - Compute area of encoded masks.
toBbox - Get bounding boxes surrounding encoded masks.
frBbox - Convert bounding boxes to encoded masks.
frPoly - Convert polygon to encoded mask.
drawCirc - Draw circle into image (alters input).
drawLine - Draw line into image (alters input).
drawMasks - Draw masks into image (alters input).
Usage:
Rs = MaskApi.encode( masks )
masks = MaskApi.decode( Rs )
R = MaskApi.merge( Rs, [intersect=false] )
o = MaskApi.iou( dt, gt, [iscrowd=false] )
keep = MaskApi.nms( dt, thr )
a = MaskApi.area( Rs )
bbs = MaskApi.toBbox( Rs )
Rs = MaskApi.frBbox( bbs, h, w )
R = MaskApi.frPoly( poly, h, w )
MaskApi.drawCirc( img, x, y, rad, clr )
MaskApi.drawLine( img, x0, y0, x1, y1, rad, clr )
MaskApi.drawMasks( img, masks, [maxn=n], [alpha=.4], [clrs] )
For detailed usage information please see cocoDemo.lua.
In the API the following formats are used:
R,Rs - [table] Run-length encoding of binary mask(s)
masks - [nxhxw] Binary mask(s)
bbs - [nx4] Bounding box(es) stored as [x y w h]
poly - Polygon stored as {[x1 y1 x2 y2...],[x1 y1 ...],...}
dt,gt - May be either bounding boxes or encoded masks
Both poly and bbs are 0-indexed (bbox=[0 0 1 1] encloses first pixel).
Common Objects in COntext (COCO) Toolbox. version 3.0
Data, paper, and tutorials available at: http://mscoco.org/
Code written by Pedro O. Pinheiro and Piotr Dollar, 2016.
Licensed under the Simplified BSD License [see coco/license.txt]
------------------------------------------------------------------------------]]
local ffi = require 'ffi'
local coco = require 'coco.env'
coco.MaskApi = {}
local MaskApi = coco.MaskApi
coco.libmaskapi = ffi.load(package.searchpath('libmaskapi',package.cpath))
local libmaskapi = coco.libmaskapi
--------------------------------------------------------------------------------
MaskApi.encode = function( masks )
local n, h, w = masks:size(1), masks:size(2), masks:size(3)
masks = masks:type('torch.ByteTensor'):transpose(2,3)
local data = masks:contiguous():data()
local Qs = MaskApi._rlesInit(n)
libmaskapi.rleEncode(Qs[0],data,h,w,n)
return MaskApi._rlesToLua(Qs,n)
end
MaskApi.decode = function( Rs )
local Qs, n, h, w = MaskApi._rlesFrLua(Rs)
local masks = torch.ByteTensor(n,w,h):zero():contiguous()
libmaskapi.rleDecode(Qs,masks:data(),n)
MaskApi._rlesFree(Qs,n)
return masks:transpose(2,3)
end
MaskApi.merge = function( Rs, intersect )
intersect = intersect or 0
local Qs, n, h, w = MaskApi._rlesFrLua(Rs)
local Q = MaskApi._rlesInit(1)
libmaskapi.rleMerge(Qs,Q,n,intersect)
MaskApi._rlesFree(Qs,n)
return MaskApi._rlesToLua(Q,1)[1]
end
MaskApi.iou = function( dt, gt, iscrowd )
if not iscrowd then iscrowd = NULL else
iscrowd = iscrowd:type('torch.ByteTensor'):contiguous():data()
end
if torch.isTensor(gt) and torch.isTensor(dt) then
local nDt, k = dt:size(1), dt:size(2); assert(k==4)
local nGt, k = gt:size(1), gt:size(2); assert(k==4)
local dDt = dt:type('torch.DoubleTensor'):contiguous():data()
local dGt = gt:type('torch.DoubleTensor'):contiguous():data()
local o = torch.DoubleTensor(nGt,nDt):contiguous()
libmaskapi.bbIou(dDt,dGt,nDt,nGt,iscrowd,o:data())
return o:transpose(1,2)
else
local qDt, nDt = MaskApi._rlesFrLua(dt)
local qGt, nGt = MaskApi._rlesFrLua(gt)
local o = torch.DoubleTensor(nGt,nDt):contiguous()
libmaskapi.rleIou(qDt,qGt,nDt,nGt,iscrowd,o:data())
MaskApi._rlesFree(qDt,nDt); MaskApi._rlesFree(qGt,nGt)
return o:transpose(1,2)
end
end
MaskApi.nms = function( dt, thr )
if torch.isTensor(dt) then
local n, k = dt:size(1), dt:size(2); assert(k==4)
local Q = dt:type('torch.DoubleTensor'):contiguous():data()
local kp = torch.IntTensor(n):contiguous()
libmaskapi.bbNms(Q,n,kp:data(),thr)
return kp
else
local Q, n = MaskApi._rlesFrLua(dt)
local kp = torch.IntTensor(n):contiguous()
libmaskapi.rleNms(Q,n,kp:data(),thr)
MaskApi._rlesFree(Q,n)
return kp
end
end
MaskApi.area = function( Rs )
local Qs, n, h, w = MaskApi._rlesFrLua(Rs)
local a = torch.IntTensor(n):contiguous()
libmaskapi.rleArea(Qs,n,a:data())
MaskApi._rlesFree(Qs,n)
return a
end
MaskApi.toBbox = function( Rs )
local Qs, n, h, w = MaskApi._rlesFrLua(Rs)
local bb = torch.DoubleTensor(n,4):contiguous()
libmaskapi.rleToBbox(Qs,bb:data(),n)
MaskApi._rlesFree(Qs,n)
return bb
end
MaskApi.frBbox = function( bbs, h, w )
if bbs:dim()==1 then bbs=bbs:view(1,bbs:size(1)) end
local n, k = bbs:size(1), bbs:size(2); assert(k==4)
local data = bbs:type('torch.DoubleTensor'):contiguous():data()
local Qs = MaskApi._rlesInit(n)
libmaskapi.rleFrBbox(Qs[0],data,h,w,n)
return MaskApi._rlesToLua(Qs,n)
end
MaskApi.frPoly = function( poly, h, w )
local n = #poly
local Qs, Q = MaskApi._rlesInit(n), MaskApi._rlesInit(1)
for i,p in pairs(poly) do
local xy = p:type('torch.DoubleTensor'):contiguous():data()
libmaskapi.rleFrPoly(Qs[i-1],xy,p:size(1)/2,h,w)
end
libmaskapi.rleMerge(Qs,Q[0],n,0)
MaskApi._rlesFree(Qs,n)
return MaskApi._rlesToLua(Q,1)[1]
end
--------------------------------------------------------------------------------
MaskApi.drawCirc = function( img, x, y, rad, clr )
assert(img:isContiguous() and img:dim()==3)
local k, h, w, data = img:size(1), img:size(2), img:size(3), img:data()
for dx=-rad,rad do for dy=-rad,rad do
local xi, yi = torch.round(x+dx), torch.round(y+dy)
if dx*dx+dy*dy<=rad*rad and xi>=0 and yi>=0 and xi<w and yi<h then
for c=1,k do data[(c-1)*h*w + yi*w + xi] = clr[c] end
end
end end
end
MaskApi.drawLine = function( img, x0, y0, x1, y1, rad, clr )
assert(img:isContiguous() and img:dim()==3)
local k, h, w, data = img:size(1), img:size(2), img:size(3), img:data()
local dx,dy,d; dx,dy=x1-x0,y1-y0; d=torch.sqrt(dx*dx+dy*dy); dx,dy=dx/d,dy/d
for i=0,d,.5 do for j=-rad,rad,.5 do
local xi, yi = torch.round(x0+dx*i+j*dy), torch.round(y0+dy*i-j*dx)
if xi>=0 and yi>=0 and xi<w and yi<h then
for c=1,k do data[(c-1)*h*w + yi*w + xi] = clr[c] end
end
end end
end
MaskApi.drawMasks = function( img, masks, maxn, alpha, clrs )
assert(img:isContiguous() and img:dim()==3)
local n, h, w = masks:size(1), masks:size(2), masks:size(3)
if not maxn then maxn=n end
if not alpha then alpha=.4 end
if not clrs then clrs=torch.rand(n,3)*.6+.4 end
for i=1,math.min(maxn,n) do
local M = masks[i]:contiguous():data()
local B = torch.ByteTensor(h,w):zero():contiguous():data()
-- get boundaries B in masks M quickly
for y=0,h-2 do for x=0,w-2 do
local k=y*w+x
if M[k]~=M[k+1] then B[k],B[k+1]=1,1 end
if M[k]~=M[k+w] then B[k],B[k+w]=1,1 end
if M[k]~=M[k+1+w] then B[k],B[k+1+w]=1,1 end
end end
-- softly embed masks into image and add solid boundaries
for j=1,3 do
local O,c,a = img[j]:data(), clrs[i][j], alpha
for k=0,w*h-1 do if M[k]==1 then O[k]=O[k]*(1-a)+c*a end end
for k=0,w*h-1 do if B[k]==1 then O[k]=c end end
end
end
end
--------------------------------------------------------------------------------
MaskApi._rlesToLua = function( Qs, n )
local h, w, Rs = tonumber(Qs[0].h), tonumber(Qs[0].w), {}
for i=1,n do Rs[i]={size={h,w}, counts={}} end
for i=1,n do
local s = libmaskapi.rleToString(Qs[i-1])
Rs[i].counts=ffi.string(s)
ffi.C.free(s)
end
MaskApi._rlesFree(Qs,n)
return Rs
end
MaskApi._rlesFrLua = function( Rs )
if #Rs==0 then Rs={Rs} end
local n, h, w = #Rs, Rs[1].size[1], Rs[1].size[2]
local Qs = MaskApi._rlesInit(n)
for i=1,n do
local c = Rs[i].counts
if( torch.type(c)=='string' ) then
local s=ffi.new("char[?]",#c+1); ffi.copy(s,c)
libmaskapi.rleFrString(Qs[i-1],s,h,w)
elseif( torch.type(c)=='torch.IntTensor' ) then
libmaskapi.rleInit(Qs[i-1],h,w,c:size(1),c:contiguous():data())
else
assert(false,"invalid RLE")
end
end
return Qs, n, h, w
end
MaskApi._rlesInit = function( n )
local Qs = ffi.new("RLE[?]",n)
for i=1,n do libmaskapi.rleInit(Qs[i-1],0,0,0,NULL) end
return Qs
end
MaskApi._rlesFree = function( Qs, n )
for i=1,n do libmaskapi.rleFree(Qs[i-1]) end
end
--------------------------------------------------------------------------------
ffi.cdef[[
void free(void *ptr);
typedef unsigned int uint;
typedef unsigned long siz;
typedef unsigned char byte;
typedef double* BB;
typedef struct { siz h, w, m; uint *cnts; } RLE;
void rleInit( RLE *R, siz h, siz w, siz m, uint *cnts );
void rleFree( RLE *R );
void rlesInit( RLE **R, siz n );
void rlesFree( RLE **R, siz n );
void rleEncode( RLE *R, const byte *mask, siz h, siz w, siz n );
void rleDecode( const RLE *R, byte *mask, siz n );
void rleMerge( const RLE *R, RLE *M, siz n, int intersect );
void rleArea( const RLE *R, siz n, uint *a );
void rleIou( RLE *dt, RLE *gt, siz m, siz n, byte *iscrowd, double *o );
void rleNms( RLE *dt, siz n, uint *keep, double thr );
void bbIou( BB dt, BB gt, siz m, siz n, byte *iscrowd, double *o );
void bbNms( BB dt, siz n, uint *keep, double thr );
void rleToBbox( const RLE *R, BB bb, siz n );
void rleFrBbox( RLE *R, const BB bb, siz h, siz w, siz n );
void rleFrPoly( RLE *R, const double *xy, siz k, siz h, siz w );
char* rleToString( const RLE *R );
void rleFrString( RLE *R, char *s, siz h, siz w );
]]
-- Demo for the CocoApi (see CocoApi.lua)
coco = require 'coco'
image = require 'image'
-- initialize COCO api (please specify dataType/annType below)
annTypes = { 'instances', 'captions', 'person_keypoints' }
dataType, annType = 'val2014', annTypes[1]; -- specify dataType/annType
annFile = '../annotations/'..annType..'_'..dataType..'.json'
cocoApi=coco.CocoApi(annFile)
-- get all image ids, select one at random
imgIds = cocoApi:getImgIds()
imgId = imgIds[torch.random(imgIds:numel())]
-- load image
img = cocoApi:loadImgs(imgId)[1]
I = image.load('../images/'..dataType..'/'..img.file_name,3)
-- load and display instance annotations
annIds = cocoApi:getAnnIds({imgId=imgId})
anns = cocoApi:loadAnns(annIds)
J = cocoApi:showAnns(I,anns)
image.save('RES_'..img.file_name,J:double())
--[[----------------------------------------------------------------------------
Common Objects in COntext (COCO) Toolbox. version 3.0
Data, paper, and tutorials available at: http://mscoco.org/
Code written by Pedro O. Pinheiro and Piotr Dollar, 2016.
Licensed under the Simplified BSD License [see coco/license.txt]
------------------------------------------------------------------------------]]
local coco = {}
return coco
--[[----------------------------------------------------------------------------
Common Objects in COntext (COCO) Toolbox. version 3.0
Data, paper, and tutorials available at: http://mscoco.org/
Code written by Pedro O. Pinheiro and Piotr Dollar, 2016.
Licensed under the Simplified BSD License [see coco/license.txt]
------------------------------------------------------------------------------]]
local coco = require 'coco.env'
require 'coco.CocoApi'
require 'coco.MaskApi'
return coco
package = "coco"
version = "scm-1"
source = {
url = "git://github.com/pdollar/coco.git"
}
description = {
summary = "Interface for accessing the Microsoft COCO dataset",
detailed = "See http://mscoco.org/ for more details",
homepage = "https://github.com/pdollar/coco",
license = "Simplified BSD"
}
dependencies = {
"lua >= 5.1",
"torch >= 7.0",
"lua-cjson"
}
build = {
type = "builtin",
modules = {
["coco.env"] = "LuaAPI/env.lua",
["coco.init"] = "LuaAPI/init.lua",
["coco.MaskApi"] = "LuaAPI/MaskApi.lua",
["coco.CocoApi"] = "LuaAPI/CocoApi.lua",
libmaskapi = {
sources = { "common/maskApi.c" },
incdirs = { "common/" }
}
}
}
-- luarocks make LuaAPI/rocks/coco-scm-1.rockspec
-- https://github.com/pdollar/coco/raw/master/LuaAPI/rocks/coco-scm-1.rockspec
classdef CocoApi
% Interface for accessing the Microsoft COCO dataset.
%
% Microsoft COCO is a large image dataset designed for object detection,
% segmentation, and caption generation. CocoApi.m is a Matlab API that
% assists in loading, parsing and visualizing the annotations in COCO.
% Please visit http://mscoco.org/ for more information on COCO, including
% for the data, paper, and tutorials. The exact format of the annotations
% is also described on the COCO website. For example usage of the CocoApi
% please see cocoDemo.m. In addition to this API, please download both
% the COCO images and annotations in order to run the demo.
%
% An alternative to using the API is to load the annotations directly
% into a Matlab struct. This can be achieved via:
% data = gason(fileread(annFile));
% Using the API provides additional utility functions. Note that this API
% supports both *instance* and *caption* annotations. In the case of
% captions not all functions are defined (e.g. categories are undefined).
%
% The following API functions are defined:
% CocoApi - Load COCO annotation file and prepare data structures.
% getAnnIds - Get ann ids that satisfy given filter conditions.
% getCatIds - Get cat ids that satisfy given filter conditions.
% getImgIds - Get img ids that satisfy given filter conditions.
% loadAnns - Load anns with the specified ids.
% loadCats - Load cats with the specified ids.
% loadImgs - Load imgs with the specified ids.
% showAnns - Display the specified annotations.
% loadRes - Load algorithm results and create API for accessing them.
% Throughout the API "ann"=annotation, "cat"=category, and "img"=image.
% Help on each functions can be accessed by: "help CocoApi>function".
%
% See also CocoApi>CocoApi, CocoApi>getAnnIds, CocoApi>getCatIds,
% CocoApi>getImgIds, CocoApi>loadAnns, CocoApi>loadCats,
% CocoApi>loadImgs, CocoApi>showAnns, CocoApi>loadRes
%
% Microsoft COCO Toolbox. version 2.0
% Data, paper, and tutorials available at: http://mscoco.org/
% Code written by Piotr Dollar and Tsung-Yi Lin, 2015.
% Licensed under the Simplified BSD License [see coco/license.txt]
properties
data % COCO annotation data structure
inds % data structures for fast indexing
end
methods
function coco = CocoApi( annFile )
% Load COCO annotation file and prepare data structures.
%
% USAGE
% coco = CocoApi( annFile )
%
% INPUTS
% annFile - COCO annotation filename
%
% OUTPUTS
% coco - initialized coco object
fprintf('Loading and preparing annotations... '); clk=clock;
if(isstruct(annFile)), coco.data=annFile; else
coco.data=gason(fileread(annFile)); end
is.imgIds = [coco.data.images.id]';
is.imgIdsMap = makeMap(is.imgIds);
if( isfield(coco.data,'annotations') )
ann=coco.data.annotations; o=[ann.image_id];
if(isfield(ann,'category_id')), o=o*1e10+[ann.category_id]; end
[~,o]=sort(o); ann=ann(o); coco.data.annotations=ann;
s={'category_id','area','iscrowd','id','image_id'};
t={'annCatIds','annAreas','annIscrowd','annIds','annImgIds'};
for f=1:5, if(isfield(ann,s{f})), is.(t{f})=[ann.(s{f})]'; end; end
is.annIdsMap = makeMap(is.annIds);
is.imgAnnIdsMap = makeMultiMap(is.imgIds,...
is.imgIdsMap,is.annImgIds,is.annIds,0);
end
if( isfield(coco.data,'categories') )
is.catIds = [coco.data.categories.id]';
is.catIdsMap = makeMap(is.catIds);
if(isfield(is,'annCatIds')), is.catImgIdsMap = makeMultiMap(...
is.catIds,is.catIdsMap,is.annCatIds,is.annImgIds,1); end
end
coco.inds=is; fprintf('DONE (t=%0.2fs).\n',etime(clock,clk));
function map = makeMap( keys )
% Make map from key to integer id associated with key.
if(isempty(keys)), map=containers.Map(); return; end
map=containers.Map(keys,1:length(keys));
end
function map = makeMultiMap( keys, keysMap, keysAll, valsAll, sqz )
% Make map from keys to set of vals associated with each key.
js=values(keysMap,num2cell(keysAll)); js=[js{:}];
m=length(js); n=length(keys); k=zeros(1,n);
for i=1:m, j=js(i); k(j)=k(j)+1; end; vs=zeros(n,max(k)); k(:)=0;
for i=1:m, j=js(i); k(j)=k(j)+1; vs(j,k(j))=valsAll(i); end
map = containers.Map('KeyType','double','ValueType','any');
if(sqz), for j=1:n, map(keys(j))=unique(vs(j,1:k(j))); end
else for j=1:n, map(keys(j))=vs(j,1:k(j)); end; end
end
end
function ids = getAnnIds( coco, varargin )
% Get ann ids that satisfy given filter conditions.
%
% USAGE
% ids = coco.getAnnIds( params )
%
% INPUTS
% params - filtering parameters (struct or name/value pairs)
% setting any filter to [] skips that filter
% .imgIds - [] get anns for given imgs
% .catIds - [] get anns for given cats
% .areaRng - [] get anns for given area range (e.g. [0 inf])
% .iscrowd - [] get anns for given crowd label (0 or 1)
%
% OUTPUTS
% ids - integer array of ann ids
def = {'imgIds',[],'catIds',[],'areaRng',[],'iscrowd',[]};
[imgIds,catIds,ar,iscrowd] = getPrmDflt(varargin,def,1);
if( length(imgIds)==1 )
t = coco.loadAnns(coco.inds.imgAnnIdsMap(imgIds));
if(~isempty(catIds)), t = t(ismember([t.category_id],catIds)); end
if(~isempty(ar)), a=[t.area]; t = t(a>=ar(1) & a<=ar(2)); end
if(~isempty(iscrowd)), t = t([t.iscrowd]==iscrowd); end
ids = [t.id];
else
ids=coco.inds.annIds; K = true(length(ids),1); t = coco.inds;
if(~isempty(imgIds)), K = K & ismember(t.annImgIds,imgIds); end
if(~isempty(catIds)), K = K & ismember(t.annCatIds,catIds); end
if(~isempty(ar)), a=t.annAreas; K = K & a>=ar(1) & a<=ar(2); end
if(~isempty(iscrowd)), K = K & t.annIscrowd==iscrowd; end
ids=ids(K);
end
end
function ids = getCatIds( coco, varargin )
% Get cat ids that satisfy given filter conditions.
%
% USAGE
% ids = coco.getCatIds( params )
%
% INPUTS
% params - filtering parameters (struct or name/value pairs)
% setting any filter to [] skips that filter
% .catNms - [] get cats for given cat names
% .supNms - [] get cats for given supercategory names
% .catIds - [] get cats for given cat ids
%
% OUTPUTS
% ids - integer array of cat ids
if(~isfield(coco.data,'categories')), ids=[]; return; end
def={'catNms',[],'supNms',[],'catIds',[]}; t=coco.data.categories;
[catNms,supNms,catIds] = getPrmDflt(varargin,def,1);
if(~isempty(catNms)), t = t(ismember({t.name},catNms)); end
if(~isempty(supNms)), t = t(ismember({t.supercategory},supNms)); end
if(~isempty(catIds)), t = t(ismember([t.id],catIds)); end
ids = [t.id];
end
function ids = getImgIds( coco, varargin )
% Get img ids that satisfy given filter conditions.
%
% USAGE
% ids = coco.getImgIds( params )
%
% INPUTS
% params - filtering parameters (struct or name/value pairs)
% setting any filter to [] skips that filter
% .imgIds - [] get imgs for given ids
% .catIds - [] get imgs with all given cats
%
% OUTPUTS
% ids - integer array of img ids
def={'imgIds',[],'catIds',[]}; ids=coco.inds.imgIds;
[imgIds,catIds] = getPrmDflt(varargin,def,1);
if(~isempty(imgIds)), ids=intersect(ids,imgIds); end
if(isempty(catIds)), return; end
t=values(coco.inds.catImgIdsMap,num2cell(catIds));
for i=1:length(t), ids=intersect(ids,t{i}); end
end
function anns = loadAnns( coco, ids )
% Load anns with the specified ids.
%
% USAGE
% anns = coco.loadAnns( ids )
%
% INPUTS
% ids - integer ids specifying anns
%
% OUTPUTS
% anns - loaded ann objects
ids = values(coco.inds.annIdsMap,num2cell(ids));
anns = coco.data.annotations([ids{:}]);
end
function cats = loadCats( coco, ids )
% Load cats with the specified ids.
%
% USAGE
% cats = coco.loadCats( ids )
%
% INPUTS
% ids - integer ids specifying cats
%
% OUTPUTS
% cats - loaded cat objects
if(~isfield(coco.data,'categories')), cats=[]; return; end
ids = values(coco.inds.catIdsMap,num2cell(ids));
cats = coco.data.categories([ids{:}]);
end
function imgs = loadImgs( coco, ids )
% Load imgs with the specified ids.
%
% USAGE
% imgs = coco.loadImgs( ids )
%
% INPUTS
% ids - integer ids specifying imgs
%
% OUTPUTS
% imgs - loaded img objects
ids = values(coco.inds.imgIdsMap,num2cell(ids));
imgs = coco.data.images([ids{:}]);
end
function hs = showAnns( coco, anns )
% Display the specified annotations.
%
% USAGE
% hs = coco.showAnns( anns )
%
% INPUTS
% anns - annotations to display
%
% OUTPUTS
% hs - handles to segment graphic objects
n=length(anns); if(n==0), return; end
r=.4:.2:1; [r,g,b]=ndgrid(r,r,r); cs=[r(:) g(:) b(:)];
cs=cs(randperm(size(cs,1)),:); cs=repmat(cs,100,1);
if( isfield( anns,'keypoints') )
for i=1:n
a=anns(i); if(isfield(a,'iscrowd') && a.iscrowd), continue; end
seg={}; if(isfield(a,'segmentation')), seg=a.segmentation; end
k=a.keypoints; x=k(1:3:end)+1; y=k(2:3:end)+1; v=k(3:3:end);
k=coco.loadCats(a.category_id); k=k.skeleton; c=cs(i,:); hold on
p={'FaceAlpha',.25,'LineWidth',2,'EdgeColor',c}; % polygon
for j=seg, xy=j{1}+.5; fill(xy(1:2:end),xy(2:2:end),c,p{:}); end
p={'Color',c,'LineWidth',3}; % skeleton
for j=k, s=j{1}; if(all(v(s)>0)), line(x(s),y(s),p{:}); end; end
p={'MarkerSize',8,'MarkerFaceColor',c,'MarkerEdgeColor'}; % pnts
plot(x(v>0),y(v>0),'o',p{:},'k');
plot(x(v>1),y(v>1),'o',p{:},c); hold off;
end
elseif( any(isfield(anns,{'segmentation','bbox'})) )
if(~isfield(anns,'iscrowd')), [anns(:).iscrowd]=deal(0); end
if(~isfield(anns,'segmentation')), S={anns.bbox}; %#ok<ALIGN>
for i=1:n, x=S{i}(1); w=S{i}(3); y=S{i}(2); h=S{i}(4);
anns(i).segmentation={[x,y,x,y+h,x+w,y+h,x+w,y]}; end; end
S={anns.segmentation}; hs=zeros(10000,1); k=0; hold on;
pFill={'FaceAlpha',.4,'LineWidth',3};
for i=1:n
if(anns(i).iscrowd), C=[.01 .65 .40]; else C=rand(1,3); end
if(isstruct(S{i})), M=double(MaskApi.decode(S{i})); k=k+1;
hs(k)=imagesc(cat(3,M*C(1),M*C(2),M*C(3)),'Alphadata',M*.5);
else for j=1:length(S{i}), P=S{i}{j}+.5; k=k+1;
hs(k)=fill(P(1:2:end),P(2:2:end),C,pFill{:}); end
end
end
hs=hs(1:k); hold off;
elseif( isfield(anns,'caption') )
S={anns.caption};
for i=1:n, S{i}=[int2str(i) ') ' S{i} '\newline']; end
S=[S{:}]; title(S,'FontSize',12);
end
end
function cocoRes = loadRes( coco, resFile )
% Load algorithm results and create API for accessing them.
%
% The API for accessing and viewing algorithm results is identical to
% the CocoApi for the ground truth. The single difference is that the
% ground truth results are replaced by the algorithm results.
%
% USAGE
% cocoRes = coco.loadRes( resFile )
%
% INPUTS
% resFile - COCO results filename
%
% OUTPUTS
% cocoRes - initialized results API
fprintf('Loading and preparing results... '); clk=clock;
cdata=coco.data; R=gason(fileread(resFile)); m=length(R);
valid=ismember([R.image_id],[cdata.images.id]);
if(~all(valid)), error('Results provided for invalid images.'); end
t={'segmentation','bbox','keypoints','caption'}; t=t{isfield(R,t)};
if(strcmp(t,'caption'))
for i=1:m, R(i).id=i; end; imgs=cdata.images;
cdata.images=imgs(ismember([imgs.id],[R.image_id]));
else
assert(all(isfield(R,{'category_id','score',t})));
s=cat(1,R.(t)); if(strcmp(t,'bbox')), a=s(:,3).*s(:,4); end
if(strcmp(t,'segmentation')), a=MaskApi.area(s); end
if(strcmp(t,'keypoints')), x=s(:,1:3:end)'; y=s(:,2:3:end)';
a=(max(x)-min(x)).*(max(y)-min(y)); end
for i=1:m, R(i).area=a(i); R(i).id=i; end
end
fprintf('DONE (t=%0.2fs).\n',etime(clock,clk));
cdata.annotations=R; cocoRes=CocoApi(cdata);
end
end
end
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment