diff --git a/PythonAPI/pycocotools/_mask.pyx b/PythonAPI/pycocotools/_mask.pyx index 55e1b1c6..d065837f 100644 --- a/PythonAPI/pycocotools/_mask.pyx +++ b/PythonAPI/pycocotools/_mask.pyx @@ -10,6 +10,9 @@ __author__ = 'tsungyi' +import sys +PYTHON_VERSION = sys.version_info[0] + # import both Python-level and C-level symbols of Numpy # the API uses Numpy to interface C and Python import numpy as np @@ -38,7 +41,7 @@ cdef extern from "maskApi.h": void rlesInit( RLE **R, siz n ) void rleEncode( RLE *R, const byte *M, siz h, siz w, siz n ) void rleDecode( const RLE *R, byte *mask, siz n ) - void rleMerge( const RLE *R, RLE *M, siz n, bint intersect ) + 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 bbIou( BB dt, BB gt, siz m, siz n, byte *iscrowd, double *o ) @@ -119,7 +122,12 @@ def _frString(rleObjs): cdef bytes py_string cdef char* c_string for i, obj in enumerate(rleObjs): - py_string = str(obj['counts']).encode('utf8') + if PYTHON_VERSION == 2: + py_string = str(obj['counts']).encode('utf8') + elif PYTHON_VERSION == 3: + py_string = str.encode(obj['counts']) if type(obj['counts']) == str else obj['counts'] + else: + raise Exception('Python version must be 2 or 3') c_string = py_string rleFrString( &Rs._R[i], c_string, obj['size'][0], obj['size'][1] ) return Rs @@ -138,10 +146,10 @@ def decode(rleObjs): cdef RLEs Rs = _frString(rleObjs) h, w, n = Rs._R[0].h, Rs._R[0].w, Rs._n masks = Masks(h, w, n) - rleDecode( Rs._R, masks._mask, n ); + rleDecode(Rs._R, masks._mask, n); return np.array(masks) -def merge(rleObjs, bint intersect=0): +def merge(rleObjs, intersect=0): cdef RLEs Rs = _frString(rleObjs) cdef RLEs R = RLEs(1) rleMerge(Rs._R, R._R, Rs._n, intersect) @@ -277,15 +285,24 @@ def frUncompressedRLE(ucRles, siz h, siz w): objs.append(_toString(Rs)[0]) return objs -def frPyObjects(pyobj, siz h, w): +def frPyObjects(pyobj, h, w): + # encode rle from a list of python objects if type(pyobj) == np.ndarray: - objs = frBbox(pyobj, h, w ) + objs = frBbox(pyobj, h, w) elif type(pyobj) == list and len(pyobj[0]) == 4: - objs = frBbox(pyobj, h, w ) + objs = frBbox(pyobj, h, w) elif type(pyobj) == list and len(pyobj[0]) > 4: - objs = frPoly(pyobj, h, w ) - elif type(pyobj) == list and type(pyobj[0]) == dict: + objs = frPoly(pyobj, h, w) + elif type(pyobj) == list and type(pyobj[0]) == dict \ + and 'counts' in pyobj[0] and 'size' in pyobj[0]: objs = frUncompressedRLE(pyobj, h, w) + # encode rle from single python object + elif type(pyobj) == list and len(pyobj) == 4: + objs = frBbox([pyobj], h, w)[0] + elif type(pyobj) == list and len(pyobj) > 4: + objs = frPoly([pyobj], h, w)[0] + elif type(pyobj) == dict and 'counts' in pyobj and 'size' in pyobj: + objs = frUncompressedRLE([pyobj], h, w)[0] else: raise Exception('input type is not supported.') return objs diff --git a/PythonAPI/pycocotools/coco.py b/PythonAPI/pycocotools/coco.py index f23c73ff..a5d023ce 100644 --- a/PythonAPI/pycocotools/coco.py +++ b/PythonAPI/pycocotools/coco.py @@ -27,7 +27,7 @@ # loadAnns - Load anns with the specified ids. # loadCats - Load cats with the specified ids. # loadImgs - Load imgs with the specified ids. -# segToMask - Convert polygon segmentation to binary mask. +# annToMask - Convert segmentation in an annotation to binary mask. # showAnns - Display the specified annotations. # loadRes - Load algorithm results and create API for accessing them. # download - Download COCO images from mscoco.org server. @@ -37,7 +37,7 @@ # See also COCO>decodeMask, # COCO>encodeMask, COCO>getAnnIds, COCO>getCatIds, # COCO>getImgIds, COCO>loadAnns, COCO>loadCats, -# COCO>loadImgs, COCO>segToMask, COCO>showAnns +# COCO>loadImgs, COCO>annToMask, COCO>showAnns # Microsoft COCO Toolbox. version 2.0 # Data, paper, and tutorials available at: http://mscoco.org/ @@ -50,12 +50,17 @@ from matplotlib.collections import PatchCollection from matplotlib.patches import Polygon import numpy as np -import urllib import copy import itertools -import mask +import pycocotools.mask as maskUtils import os from collections import defaultdict +import sys +PYTHON_VERSION = sys.version_info[0] +if PYTHON_VERSION == 2: + from urllib import urlretrieve +elif PYTHON_VERSION == 3: + from urllib.request import urlretrieve class COCO: def __init__(self, annotation_file=None): @@ -69,18 +74,18 @@ def __init__(self, annotation_file=None): self.dataset,self.anns,self.cats,self.imgs = dict(),dict(),dict(),dict() self.imgToAnns, self.catToImgs = defaultdict(list), defaultdict(list) if not annotation_file == None: - print 'loading annotations into memory...' + print('loading annotations into memory...') tic = time.time() dataset = json.load(open(annotation_file, 'r')) - assert type(dataset)==dict, "annotation file format %s not supported"%(type(dataset)) - print 'Done (t=%0.2fs)'%(time.time()- tic) + assert type(dataset)==dict, 'annotation file format {} not supported'.format(type(dataset)) + print('Done (t={:0.2f}s)'.format(time.time()- tic)) self.dataset = dataset self.createIndex() def createIndex(self): # create index - print 'creating index...' - anns,cats,imgs = dict(),dict(),dict() + print('creating index...') + anns, cats, imgs = {}, {}, {} imgToAnns,catToImgs = defaultdict(list),defaultdict(list) if 'annotations' in self.dataset: for ann in self.dataset['annotations']: @@ -94,10 +99,12 @@ def createIndex(self): if 'categories' in self.dataset: for cat in self.dataset['categories']: cats[cat['id']] = cat + + if 'annotations' in self.dataset and 'categories' in self.dataset: for ann in self.dataset['annotations']: catToImgs[ann['category_id']].append(ann['image_id']) - print 'index created!' + print('index created!') # create class members self.anns = anns @@ -112,7 +119,7 @@ def info(self): :return: """ for key, value in self.dataset['info'].items(): - print '%s: %s'%(key, value) + print('{}: {}'.format(key, value)) def getAnnIds(self, imgIds=[], catIds=[], areaRng=[], iscrowd=None): """ @@ -231,7 +238,7 @@ def showAnns(self, anns): elif 'caption' in anns[0]: datasetType = 'captions' else: - raise Exception("datasetType not supported") + raise Exception('datasetType not supported') if datasetType == 'instances': ax = plt.gca() ax.set_autoscale_on(False) @@ -243,17 +250,17 @@ def showAnns(self, anns): if type(ann['segmentation']) == list: # polygon for seg in ann['segmentation']: - poly = np.array(seg).reshape((len(seg)/2, 2)) + poly = np.array(seg).reshape((int(len(seg)/2), 2)) polygons.append(Polygon(poly)) color.append(c) else: # mask t = self.imgs[ann['image_id']] if type(ann['segmentation']['counts']) == list: - rle = mask.frPyObjects([ann['segmentation']], t['height'], t['width']) + rle = maskUtils.frPyObjects([ann['segmentation']], t['height'], t['width']) else: rle = [ann['segmentation']] - m = mask.decode(rle) + m = maskUtils.decode(rle) img = np.ones( (m.shape[0], m.shape[1], 3) ) if ann['iscrowd'] == 1: color_mask = np.array([2.0,166.0,101.0])/255 @@ -276,11 +283,11 @@ def showAnns(self, anns): plt.plot(x[v>1], y[v>1],'o',markersize=8, markerfacecolor=c, markeredgecolor=c, markeredgewidth=2) p = PatchCollection(polygons, facecolor=color, linewidths=0, alpha=0.4) ax.add_collection(p) - p = PatchCollection(polygons, facecolor="none", edgecolors=color, linewidths=2) + p = PatchCollection(polygons, facecolor='none', edgecolors=color, linewidths=2) ax.add_collection(p) elif datasetType == 'captions': for ann in anns: - print ann['caption'] + print(ann['caption']) def loadRes(self, resFile): """ @@ -291,7 +298,7 @@ def loadRes(self, resFile): res = COCO() res.dataset['images'] = [img for img in self.dataset['images']] - print 'Loading and preparing results... ' + print('Loading and preparing results...') tic = time.time() if type(resFile) == str or type(resFile) == unicode: anns = json.load(open(resFile)) @@ -322,9 +329,9 @@ def loadRes(self, resFile): res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) for id, ann in enumerate(anns): # now only support compressed RLE format as segmentation results - ann['area'] = mask.area([ann['segmentation']])[0] + ann['area'] = maskUtils.area(ann['segmentation']) if not 'bbox' in ann: - ann['bbox'] = mask.toBbox([ann['segmentation']])[0] + ann['bbox'] = maskUtils.toBbox(ann['segmentation']) ann['id'] = id+1 ann['iscrowd'] = 0 elif 'keypoints' in anns[0]: @@ -337,13 +344,13 @@ def loadRes(self, resFile): ann['area'] = (x1-x0)*(y1-y0) ann['id'] = id + 1 ann['bbox'] = [x0,y0,x1-x0,y1-y0] - print 'DONE (t=%0.2fs)'%(time.time()- tic) + print('DONE (t={:0.2f}s)'.format(time.time()- tic)) res.dataset['annotations'] = anns res.createIndex() return res - def download( self, tarDir = None, imgIds = [] ): + def download(self, tarDir = None, imgIds = [] ): ''' Download COCO images from mscoco.org server. :param tarDir (str): COCO results directory name @@ -351,7 +358,7 @@ def download( self, tarDir = None, imgIds = [] ): :return: ''' if tarDir is None: - print 'Please specify target directory' + print('Please specify target directory') return -1 if len(imgIds) == 0: imgs = self.imgs.values() @@ -364,8 +371,8 @@ def download( self, tarDir = None, imgIds = [] ): tic = time.time() fname = os.path.join(tarDir, img['file_name']) if not os.path.exists(fname): - urllib.urlretrieve(img['coco_url'], fname) - print 'downloaded %d/%d images (t=%.1fs)'%(i, N, time.time()- tic) + urlretrieve(img['coco_url'], fname) + print('downloaded {}/{} images (t={:0.1f}s)'.format(i, N, time.time()- tic)) def loadNumpyAnnotations(self, data): """ @@ -373,7 +380,7 @@ def loadNumpyAnnotations(self, data): :param data (numpy.ndarray) :return: annotations (python nested list) """ - print("Converting ndarray to lists...") + print('Converting ndarray to lists...') assert(type(data) == np.ndarray) print(data.shape) assert(data.shape[1] == 7) @@ -381,7 +388,7 @@ def loadNumpyAnnotations(self, data): ann = [] for i in range(N): if i % 1000000 == 0: - print("%d/%d" % (i,N)) + print('{}/{}'.format(i,N)) ann += [{ 'image_id' : int(data[i, 0]), 'bbox' : [ data[i, 1], data[i, 2], data[i, 3], data[i, 4] ], @@ -389,3 +396,33 @@ def loadNumpyAnnotations(self, data): 'category_id': int(data[i, 6]), }] return ann + + def annToRLE(self, ann): + """ + Convert annotation which can be polygons, uncompressed RLE to RLE. + :return: binary mask (numpy 2D array) + """ + t = self.imgs[ann['image_id']] + h, w = t['height'], t['width'] + segm = ann['segmentation'] + if type(segm) == list: + # polygon -- a single object might consist of multiple parts + # we merge all parts into one mask rle code + rles = maskUtils.frPyObjects(segm, h, w) + rle = maskUtils.merge(rles) + elif type(segm['counts']) == list: + # uncompressed RLE + rle = maskUtils.frPyObjects(segm, h, w) + else: + # rle + rle = ann['segmentation'] + return rle + + def annToMask(self, ann): + """ + Convert annotation which can be polygons, uncompressed RLE, or RLE to binary mask. + :return: binary mask (numpy 2D array) + """ + rle = self.annToRLE(ann) + m = maskUtils.decode(rle) + return m \ No newline at end of file diff --git a/PythonAPI/pycocotools/cocoeval.py b/PythonAPI/pycocotools/cocoeval.py index 59ee52e1..21446971 100644 --- a/PythonAPI/pycocotools/cocoeval.py +++ b/PythonAPI/pycocotools/cocoeval.py @@ -4,7 +4,7 @@ import datetime import time from collections import defaultdict -import mask +import pycocotools.mask as maskUtils import copy class COCOeval: @@ -57,7 +57,7 @@ class COCOeval: # 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] - def __init__(self, cocoGt=None, cocoDt=None, iouType="segm"): + def __init__(self, cocoGt=None, cocoDt=None, iouType='segm'): ''' Initialize CocoEval using coco APIs for gt and dt :param cocoGt: coco object with ground truth annotations @@ -65,7 +65,7 @@ def __init__(self, cocoGt=None, cocoDt=None, iouType="segm"): :return: None ''' if not iouType: - print("iouType not specified. use default iouType segm") + print('iouType not specified. use default iouType segm') self.cocoGt = cocoGt # ground truth COCO API self.cocoDt = cocoDt # detections COCO API self.params = {} # evaluation parameters @@ -87,27 +87,11 @@ def _prepare(self): Prepare ._gts and ._dts for evaluation based on params :return: None ''' - def _toMask(objs, coco): - # modify segmentation by reference - for obj in objs: - t = coco.imgs[obj['image_id']] - if type(obj['segmentation']) == list: - if type(obj['segmentation'][0]) == dict: - print 'debug' - obj['segmentation'] = mask.frPyObjects(obj['segmentation'],t['height'],t['width']) - if len(obj['segmentation']) == 1: - obj['segmentation'] = obj['segmentation'][0] - else: - # an object can have multiple polygon regions - # merge them into one RLE mask - obj['segmentation'] = mask.merge(obj['segmentation']) - elif type(obj['segmentation']) == dict and type(obj['segmentation']['counts']) == list: - obj['segmentation'] = mask.frPyObjects([obj['segmentation']],t['height'],t['width'])[0] - elif type(obj['segmentation']) == dict and \ - (type(obj['segmentation']['counts']) == unicode or type(obj['segmentation']['counts']) == str): - pass - else: - raise Exception('segmentation format not supported.') + def _toMask(anns, coco): + # modify ann['segmentation'] by reference + for ann in anns: + rle = coco.annToRLE(ann) + ann['segmentation'] = rle p = self.params if p.useCats: gts=self.cocoGt.loadAnns(self.cocoGt.getAnnIds(imgIds=p.imgIds, catIds=p.catIds)) @@ -116,16 +100,16 @@ def _toMask(objs, coco): gts=self.cocoGt.loadAnns(self.cocoGt.getAnnIds(imgIds=p.imgIds)) dts=self.cocoDt.loadAnns(self.cocoDt.getAnnIds(imgIds=p.imgIds)) - # convert ground truth to mask if iouType == "segm" - if p.iouType == "segm": + # convert ground truth to mask if iouType == 'segm' + if p.iouType == 'segm': _toMask(gts, self.cocoGt) _toMask(dts, self.cocoDt) # set ignore flag 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"] + 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'] self._gts = defaultdict(list) # gt for evaluation self._dts = defaultdict(list) # dt for evaluation for gt in gts: @@ -141,12 +125,13 @@ def evaluate(self): :return: None ''' tic = time.time() - print 'Running per image evaluation... ' + print('Running per image evaluation...') p = self.params # add backward compatibility if useSegm is specified in params if not p.useSegm is None: - p.iouType = "segm" if p.useSegm == 1 else "bbox" - print("useSegm (deprecated) is not None. Running %s evaluation"%(p.iouType)) + p.iouType = 'segm' if p.useSegm == 1 else 'bbox' + print('useSegm (deprecated) is not None. Running {} evaluation'.format(p.iouType)) + print('Evaluate annotation type *{}*'.format(p.iouType)) p.imgIds = list(np.unique(p.imgIds)) if p.useCats: p.catIds = list(np.unique(p.catIds)) @@ -157,9 +142,9 @@ def evaluate(self): # loop through images, area range, max detection number catIds = p.catIds if p.useCats else [-1] - if p.iouType == "segm" or p.iouType == "bbox": + if p.iouType == 'segm' or p.iouType == 'bbox': computeIoU = self.computeIoU - elif p.iouType == "keypoints": + elif p.iouType == 'keypoints': computeIoU = self.computeOks self.ious = {(imgId, catId): computeIoU(imgId, catId) \ for imgId in p.imgIds @@ -174,7 +159,7 @@ def evaluate(self): ] self._paramsEval = copy.deepcopy(self.params) toc = time.time() - print 'DONE (t=%0.2fs).'%(toc-tic) + print('DONE (t={:0.2f}s).'.format(toc-tic)) def computeIoU(self, imgId, catId): p = self.params @@ -186,23 +171,23 @@ def computeIoU(self, imgId, catId): dt = [_ for cId in p.catIds for _ in self._dts[imgId,cId]] if len(gt) == 0 and len(dt) ==0: return [] - inds = np.argsort(map(lambda x:-x["score"], dt),kind='mergesort') + 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": + if p.iouType == 'segm': g = [g['segmentation'] for g in gt] d = [d['segmentation'] for d in dt] - elif p.iouType == "bbox": + 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") + raise Exception('unknown iouType for iou computation') # compute iou between each dt and gt region iscrowd = [int(o['iscrowd']) for o in gt] - ious = mask.iou(d,g,iscrowd) + ious = maskUtils.iou(d,g,iscrowd) return ious def computeOks(self, imgId, catId): @@ -210,7 +195,7 @@ def computeOks(self, imgId, catId): # dimention here should be Nxm gts = self._gts[imgId, catId] dts = self._dts[imgId, catId] - inds = np.argsort(map(lambda x: -x["score"], dts), kind='mergesort') + 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]] @@ -224,14 +209,14 @@ def computeOks(self, imgId, catId): # compute oks between each detection and ground truth object for j, gt in enumerate(gts): # create bounds for ignore regions(double the gt bbox) - g = np.array(gt["keypoints"]) + 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"] + 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"]) + d = np.array(dt['keypoints']) xd = d[0::3]; yd = d[1::3] if k1>0: # measure the per-keypoint distance if keypoints visible @@ -242,7 +227,7 @@ def computeOks(self, imgId, catId): 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 + 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] @@ -270,10 +255,10 @@ def evaluateImg(self, imgId, catId, aRng, maxDet): g['_ignore'] = 0 # sort dt highest score first, sort gt ignore last - gtind = np.argsort([g['_ignore'] for g in gt], kind="mergesort") - gt = map(lambda i: gt[i], gtind) - dtind = np.argsort([-d['score'] for d in dt], kind="mergesort") - dt = map(lambda i: dt[i], dtind[0:maxDet]) + 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['iscrowd']) for o in gt] # load computed ious ious = self.ious[imgId, catId][:, gtind] if len(self.ious[imgId, catId]) > 0 else self.ious[imgId, catId] @@ -334,10 +319,10 @@ def accumulate(self, p = None): :param p: input params for evaluation :return: None ''' - print 'Accumulating evaluation results... ' + print('Accumulating evaluation results...') tic = time.time() if not self.evalImgs: - print 'Please run evaluate() first' + print('Please run evaluate() first') # allows input customized parameters if p is None: p = self.params @@ -370,8 +355,8 @@ def accumulate(self, p = None): 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 = filter(None, E) + E = [self.evalImgs[Nk + Na + i] for i in i_list] + E = [e for e in E if not e is None] if len(E) == 0: continue dtScores = np.concatenate([e['dtScores'][0:maxDet] for e in E]) @@ -422,12 +407,12 @@ def accumulate(self, p = None): self.eval = { 'params': p, 'counts': [T, R, K, A, M], - 'date': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + 'date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'precision': precision, 'recall': recall, } toc = time.time() - print 'DONE (t=%0.2fs).'%( toc-tic ) + print('DONE (t={:0.2f}s).'.format( toc-tic)) def summarize(self): ''' @@ -436,12 +421,11 @@ def summarize(self): ''' def _summarize( ap=1, iouThr=None, areaRng='all', maxDets=100 ): p = self.params - iStr = ' {:<18} {} @[ IoU={:<9} | area={:>6} | maxDets={:>3} ] = {}' - titleStr = 'Average Precision' if ap == 1 else 'Average Recall' - typeStr = '(AP)' if ap==1 else '(AR)' - iouStr = '%0.2f:%0.2f'%(p.iouThrs[0], p.iouThrs[-1]) if iouThr is None else '%0.2f'%(iouThr) - areaStr = areaRng - maxDetsStr = '%d'%(maxDets) + iStr = ' {:<18} {} @[ IoU={:<9} | area={:>6s} | maxDets={:>3d} ] = {:0.3f}' + titleStr = 'Average Precision' if ap == 1 else 'Average Recall' + typeStr = '(AP)' if ap==1 else '(AR)' + 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] @@ -464,22 +448,22 @@ def _summarize( ap=1, iouThr=None, areaRng='all', maxDets=100 ): mean_s = -1 else: mean_s = np.mean(s[s>-1]) - print iStr.format(titleStr, typeStr, iouStr, areaStr, maxDetsStr, '%.3f'%(float(mean_s))) + print(iStr.format(titleStr, typeStr, iouStr, areaRng, maxDets, mean_s)) return mean_s def _summarizeDets(): stats = np.zeros((12,)) stats[0] = _summarize(1) - stats[1] = _summarize(1, iouThr=.5) - stats[2] = _summarize(1, iouThr=.75) - stats[3] = _summarize(1, areaRng='small') - stats[4] = _summarize(1, areaRng='medium') - stats[5] = _summarize(1, areaRng='large') - stats[6] = _summarize(0, maxDets=1) - stats[7] = _summarize(0, maxDets=10) - stats[8] = _summarize(0, maxDets=100) - stats[9] = _summarize(0, areaRng='small') - stats[10] = _summarize(0, areaRng='medium') - stats[11] = _summarize(0, areaRng='large') + stats[1] = _summarize(1, iouThr=.5, maxDets=self.params.maxDets[2]) + stats[2] = _summarize(1, iouThr=.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,)) @@ -497,9 +481,9 @@ def _summarizeKps(): if not self.eval: raise Exception('Please run accumulate() first') iouType = self.params.iouType - if iouType == "segm" or iouType == "bbox": + if iouType == 'segm' or iouType == 'bbox': summarize = _summarizeDets - elif iouType == "keypoints": + elif iouType == 'keypoints': summarize = _summarizeKps self.stats = summarize() @@ -532,13 +516,13 @@ def setKpParams(self): self.areaRngLbl = ['all', 'medium', 'large'] self.useCats = 1 - def __init__(self, iouType="segm"): - if iouType == "segm" or iouType == "bbox": + def __init__(self, iouType='segm'): + if iouType == 'segm' or iouType == 'bbox': self.setDetParams() - elif iouType == "keypoints": + elif iouType == 'keypoints': self.setKpParams() else: - raise Exception("iouType not supported") + raise Exception('iouType not supported') self.iouType = iouType # useSegm is deprecated self.useSegm = None \ No newline at end of file diff --git a/PythonAPI/pycocotools/mask.py b/PythonAPI/pycocotools/mask.py index 67325467..40853ba0 100644 --- a/PythonAPI/pycocotools/mask.py +++ b/PythonAPI/pycocotools/mask.py @@ -73,10 +73,31 @@ # Code written by Piotr Dollar and Tsung-Yi Lin, 2015. # Licensed under the Simplified BSD License [see coco/license.txt] -encode = _mask.encode -decode = _mask.decode iou = _mask.iou merge = _mask.merge -area = _mask.area -toBbox = _mask.toBbox -frPyObjects = _mask.frPyObjects \ No newline at end of file +frPyObjects = _mask.frPyObjects + +def encode(bimask): + if len(bimask.shape) == 3: + return _mask.encode(bimask) + elif len(bimask.shape) == 2: + h, w = bimask.shape + return _mask.encode(bimask.reshape((h, w, 1), order='F'))[0] + +def decode(rleObjs): + if type(rleObjs) == list: + return _mask.decode(rleObjs) + else: + return _mask.decode([rleObjs])[:,:,0] + +def area(rleObjs): + if type(rleObjs) == list: + return _mask.area(rleObjs) + else: + return _mask.area([rleObjs])[0] + +def toBbox(rleObjs): + if type(rleObjs) == list: + return _mask.toBbox(rleObjs) + else: + return _mask.toBbox([rleObjs])[0] \ No newline at end of file