| from collections import namedtuple |
| from abc import ABCMeta, abstractmethod |
| import os |
| import json |
|
|
| Label = namedtuple( 'Label' , [ |
|
|
| 'name' , |
| |
|
|
| 'id' , |
| |
| |
| |
| |
| |
|
|
| 'trainId' , |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 'category' , |
|
|
| 'categoryId' , |
| |
|
|
| 'hasInstances', |
|
|
| 'ignoreInEval', |
| |
|
|
| 'color' , |
| ] ) |
|
|
| labels = [ |
| |
| Label( 'unlabeled' , 0 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ), |
| Label( 'ego vehicle' , 1 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ), |
| Label( 'rectification border' , 2 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ), |
| Label( 'out of roi' , 3 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ), |
| Label( 'static' , 4 , 255 , 'void' , 0 , False , True , ( 0, 0, 0) ), |
| Label( 'dynamic' , 5 , 255 , 'void' , 0 , False , True , (111, 74, 0) ), |
| Label( 'ground' , 6 , 255 , 'void' , 0 , False , True , ( 81, 0, 81) ), |
| Label( 'road' , 7 , 0 , 'flat' , 1 , False , False , (128, 64,128) ), |
| Label( 'sidewalk' , 8 , 1 , 'flat' , 1 , False , False , (244, 35,232) ), |
| Label( 'parking' , 9 , 255 , 'flat' , 1 , False , True , (250,170,160) ), |
| Label( 'rail track' , 10 , 255 , 'flat' , 1 , False , True , (230,150,140) ), |
| Label( 'building' , 11 , 2 , 'construction' , 2 , False , False , ( 70, 70, 70) ), |
| Label( 'wall' , 12 , 3 , 'construction' , 2 , False , False , (102,102,156) ), |
| Label( 'fence' , 13 , 4 , 'construction' , 2 , False , False , (190,153,153) ), |
| Label( 'guard rail' , 14 , 255 , 'construction' , 2 , False , True , (180,165,180) ), |
| Label( 'bridge' , 15 , 255 , 'construction' , 2 , False , True , (150,100,100) ), |
| Label( 'tunnel' , 16 , 255 , 'construction' , 2 , False , True , (150,120, 90) ), |
| Label( 'pole' , 17 , 5 , 'object' , 3 , False , False , (153,153,153) ), |
| Label( 'polegroup' , 18 , 255 , 'object' , 3 , False , True , (153,153,153) ), |
| Label( 'traffic light' , 19 , 6 , 'object' , 3 , False , False , (250,170, 30) ), |
| Label( 'traffic sign' , 20 , 7 , 'object' , 3 , False , False , (220,220, 0) ), |
| Label( 'vegetation' , 21 , 8 , 'nature' , 4 , False , False , (107,142, 35) ), |
| Label( 'terrain' , 22 , 9 , 'nature' , 4 , False , False , (152,251,152) ), |
| Label( 'sky' , 23 , 10 , 'sky' , 5 , False , False , ( 70,130,180) ), |
| Label( 'person' , 24 , 11 , 'human' , 6 , True , False , (220, 20, 60) ), |
| Label( 'rider' , 25 , 12 , 'human' , 6 , True , False , (255, 0, 0) ), |
| Label( 'car' , 26 , 13 , 'vehicle' , 7 , True , False , ( 0, 0,142) ), |
| Label( 'truck' , 27 , 14 , 'vehicle' , 7 , True , False , ( 0, 0, 70) ), |
| Label( 'bus' , 28 , 15 , 'vehicle' , 7 , True , False , ( 0, 60,100) ), |
| Label( 'caravan' , 29 , 255 , 'vehicle' , 7 , True , True , ( 0, 0, 90) ), |
| Label( 'trailer' , 30 , 255 , 'vehicle' , 7 , True , True , ( 0, 0,110) ), |
| Label( 'train' , 31 , 16 , 'vehicle' , 7 , True , False , ( 0, 80,100) ), |
| Label( 'motorcycle' , 32 , 17 , 'vehicle' , 7 , True , False , ( 0, 0,230) ), |
| Label( 'bicycle' , 33 , 18 , 'vehicle' , 7 , True , False , (119, 11, 32) ), |
| Label( 'license plate' , -1 , -1 , 'vehicle' , 7 , False , True , ( 0, 0,142) ), |
| ] |
|
|
|
|
| |
| name2label = { label.name : label for label in labels } |
|
|
| |
| Point = namedtuple('Point', ['x', 'y']) |
|
|
| class CsObjectType(): |
| POLY = 1 |
| BBOX = 2 |
|
|
|
|
| |
| class CsObject: |
| __metaclass__ = ABCMeta |
|
|
| def __init__(self, objType): |
| self.objectType = objType |
| |
| self.label = "" |
|
|
| |
| self.deleted = 0 |
| |
| self.verified = 0 |
| |
| self.date = "" |
| |
| self.user = "" |
| |
| |
| |
| |
| self.draw = True |
|
|
| @abstractmethod |
| def __str__(self): pass |
|
|
| @abstractmethod |
| def fromJsonText(self, jsonText, objId=-1): pass |
|
|
| @abstractmethod |
| def toJsonText(self): pass |
|
|
| def updateDate( self ): |
| try: |
| locale.setlocale( locale.LC_ALL , 'en_US.utf8' ) |
| except locale.Error: |
| locale.setlocale( locale.LC_ALL , 'en_US' ) |
| except locale.Error: |
| locale.setlocale( locale.LC_ALL , 'us_us.utf8' ) |
| except locale.Error: |
| locale.setlocale( locale.LC_ALL , 'us_us' ) |
| except: |
| pass |
| self.date = datetime.datetime.now().strftime("%d-%b-%Y %H:%M:%S") |
|
|
| |
| def delete(self): |
| self.deleted = 1 |
| self.draw = False |
|
|
|
|
| |
| class CsPoly(CsObject): |
| |
| def __init__(self): |
| CsObject.__init__(self, CsObjectType.POLY) |
| |
| self.polygon = [] |
| |
| self.id = -1 |
|
|
| def __str__(self): |
| polyText = "" |
| if self.polygon: |
| if len(self.polygon) <= 4: |
| for p in self.polygon: |
| polyText += '({},{}) '.format( p.x , p.y ) |
| else: |
| polyText += '({},{}) ({},{}) ... ({},{}) ({},{})'.format( |
| self.polygon[ 0].x , self.polygon[ 0].y , |
| self.polygon[ 1].x , self.polygon[ 1].y , |
| self.polygon[-2].x , self.polygon[-2].y , |
| self.polygon[-1].x , self.polygon[-1].y ) |
| else: |
| polyText = "none" |
| text = "Object: {} - {}".format( self.label , polyText ) |
| return text |
|
|
| def fromJsonText(self, jsonText, objId): |
| self.id = objId |
| self.label = str(jsonText['label']) |
| self.polygon = [ Point(p[0],p[1]) for p in jsonText['polygon'] ] |
| if 'deleted' in jsonText.keys(): |
| self.deleted = jsonText['deleted'] |
| else: |
| self.deleted = 0 |
| if 'verified' in jsonText.keys(): |
| self.verified = jsonText['verified'] |
| else: |
| self.verified = 1 |
| if 'user' in jsonText.keys(): |
| self.user = jsonText['user'] |
| else: |
| self.user = '' |
| if 'date' in jsonText.keys(): |
| self.date = jsonText['date'] |
| else: |
| self.date = '' |
| if self.deleted == 1: |
| self.draw = False |
| else: |
| self.draw = True |
|
|
| def toJsonText(self): |
| objDict = {} |
| objDict['label'] = self.label |
| objDict['id'] = self.id |
| objDict['deleted'] = self.deleted |
| objDict['verified'] = self.verified |
| objDict['user'] = self.user |
| objDict['date'] = self.date |
| objDict['polygon'] = [] |
| for pt in self.polygon: |
| objDict['polygon'].append([pt.x, pt.y]) |
|
|
| return objDict |
|
|
| |
| class Annotation: |
| |
| def __init__(self, objType=CsObjectType.POLY): |
| |
| self.imgWidth = 0 |
| |
| self.imgHeight = 0 |
| |
| self.objects = [] |
| assert objType in CsObjectType.__dict__.values() |
| self.objectType = objType |
|
|
| def toJson(self): |
| return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) |
|
|
| def fromJsonText(self, jsonText): |
| jsonDict = json.loads(jsonText) |
| self.imgWidth = int(jsonDict['imgWidth']) |
| self.imgHeight = int(jsonDict['imgHeight']) |
| self.objects = [] |
| for objId, objIn in enumerate(jsonDict[ 'objects' ]): |
| if self.objectType == CsObjectType.POLY: |
| obj = CsPoly() |
| elif self.objectType == CsObjectType.BBOX: |
| obj = CsBbox() |
| obj.fromJsonText(objIn, objId) |
| self.objects.append(obj) |
|
|
| def toJsonText(self): |
| jsonDict = {} |
| jsonDict['imgWidth'] = self.imgWidth |
| jsonDict['imgHeight'] = self.imgHeight |
| jsonDict['objects'] = [] |
| for obj in self.objects: |
| objDict = obj.toJsonText() |
| jsonDict['objects'].append(objDict) |
|
|
| return jsonDict |
|
|
| |
| def fromJsonFile(self, jsonFile): |
| if not os.path.isfile(jsonFile): |
| |
| return |
| with open(jsonFile, 'r') as f: |
| jsonText = f.read() |
| self.fromJsonText(jsonText) |
|
|
| def toJsonFile(self, jsonFile): |
| with open(jsonFile, 'w') as f: |
| f.write(self.toJson()) |