| |
| |
| |
| |
| import json |
| import os |
| import sys |
| from pathlib import Path |
| from typing import Optional, Union |
|
|
| import mmcv |
| import numpy as np |
| from mmengine.fileio import get |
|
|
| try: |
| import cityscapesscripts.evaluation.evalInstanceLevelSemanticLabeling as CSEval |
| from cityscapesscripts.evaluation.evalInstanceLevelSemanticLabeling import \ |
| CArgs |
| from cityscapesscripts.evaluation.instance import Instance |
| from cityscapesscripts.helpers.csHelpers import (id2label, labels, |
| writeDict2JSON) |
| HAS_CITYSCAPESAPI = True |
| except ImportError: |
| CArgs = object |
| HAS_CITYSCAPESAPI = False |
|
|
|
|
| def evaluateImgLists(prediction_list: list, |
| groundtruth_list: list, |
| args: CArgs, |
| backend_args: Optional[dict] = None, |
| dump_matches: bool = False) -> dict: |
| """A wrapper of obj:``cityscapesscripts.evaluation. |
| |
| evalInstanceLevelSemanticLabeling.evaluateImgLists``. Support loading |
| groundtruth image from file backend. |
| Args: |
| prediction_list (list): A list of prediction txt file. |
| groundtruth_list (list): A list of groundtruth image file. |
| args (CArgs): A global object setting in |
| obj:``cityscapesscripts.evaluation. |
| evalInstanceLevelSemanticLabeling`` |
| backend_args (dict, optional): Arguments to instantiate the |
| preifx of uri corresponding backend. Defaults to None. |
| dump_matches (bool): whether dump matches.json. Defaults to False. |
| Returns: |
| dict: The computed metric. |
| """ |
| if not HAS_CITYSCAPESAPI: |
| raise RuntimeError('Failed to import `cityscapesscripts`.' |
| 'Please try to install official ' |
| 'cityscapesscripts by ' |
| '"pip install cityscapesscripts"') |
| |
| CSEval.setInstanceLabels(args) |
| |
| gt_instances = getGtInstances( |
| groundtruth_list, args, backend_args=backend_args) |
| |
| matches = matchGtWithPreds(prediction_list, groundtruth_list, gt_instances, |
| args, backend_args) |
| if dump_matches: |
| CSEval.writeDict2JSON(matches, 'matches.json') |
| |
| apScores = CSEval.evaluateMatches(matches, args) |
| |
| avgDict = CSEval.computeAverages(apScores, args) |
| |
| resDict = CSEval.prepareJSONDataForResults(avgDict, apScores, args) |
| if args.JSONOutput: |
| |
| path = os.path.dirname(args.exportFile) |
| CSEval.ensurePath(path) |
| |
| CSEval.writeDict2JSON(resDict, args.exportFile) |
|
|
| CSEval.printResults(avgDict, args) |
|
|
| return resDict |
|
|
|
|
| def matchGtWithPreds(prediction_list: list, |
| groundtruth_list: list, |
| gt_instances: dict, |
| args: CArgs, |
| backend_args=None): |
| """A wrapper of obj:``cityscapesscripts.evaluation. |
| |
| evalInstanceLevelSemanticLabeling.matchGtWithPreds``. Support loading |
| groundtruth image from file backend. |
| Args: |
| prediction_list (list): A list of prediction txt file. |
| groundtruth_list (list): A list of groundtruth image file. |
| gt_instances (dict): Groundtruth dict. |
| args (CArgs): A global object setting in |
| obj:``cityscapesscripts.evaluation. |
| evalInstanceLevelSemanticLabeling`` |
| backend_args (dict, optional): Arguments to instantiate the |
| preifx of uri corresponding backend. Defaults to None. |
| Returns: |
| dict: The processed prediction and groundtruth result. |
| """ |
| if not HAS_CITYSCAPESAPI: |
| raise RuntimeError('Failed to import `cityscapesscripts`.' |
| 'Please try to install official ' |
| 'cityscapesscripts by ' |
| '"pip install cityscapesscripts"') |
| matches: dict = dict() |
| if not args.quiet: |
| print(f'Matching {len(prediction_list)} pairs of images...') |
|
|
| count = 0 |
| for (pred, gt) in zip(prediction_list, groundtruth_list): |
| |
| gt_image = readGTImage(gt, backend_args) |
| pred_info = readPredInfo(pred) |
| |
| unfiltered_instances = gt_instances[gt] |
| cur_gt_instances_orig = CSEval.filterGtInstances( |
| unfiltered_instances, args) |
|
|
| |
| (cur_gt_instances, |
| cur_pred_instances) = CSEval.assignGt2Preds(cur_gt_instances_orig, |
| gt_image, pred_info, args) |
|
|
| |
| matches[gt] = {} |
| matches[gt]['groundTruth'] = cur_gt_instances |
| matches[gt]['prediction'] = cur_pred_instances |
|
|
| count += 1 |
| if not args.quiet: |
| print(f'\rImages Processed: {count}', end=' ') |
| sys.stdout.flush() |
|
|
| if not args.quiet: |
| print('') |
|
|
| return matches |
|
|
|
|
| def readGTImage(image_file: Union[str, Path], |
| backend_args: Optional[dict] = None) -> np.ndarray: |
| """Read an image from path. |
| |
| Same as obj:``cityscapesscripts.evaluation. |
| evalInstanceLevelSemanticLabeling.readGTImage``, but support loading |
| groundtruth image from file backend. |
| Args: |
| image_file (str or Path): Either a str or pathlib.Path. |
| backend_args (dict, optional): Instantiates the corresponding file |
| backend. It may contain `backend` key to specify the file |
| backend. If it contains, the file backend corresponding to this |
| value will be used and initialized with the remaining values, |
| otherwise the corresponding file backend will be selected |
| based on the prefix of the file path. Defaults to None. |
| Returns: |
| np.ndarray: The groundtruth image. |
| """ |
| img_bytes = get(image_file, backend_args=backend_args) |
| img = mmcv.imfrombytes(img_bytes, flag='unchanged', backend='pillow') |
| return img |
|
|
|
|
| def readPredInfo(prediction_file: str) -> dict: |
| """A wrapper of obj:``cityscapesscripts.evaluation. |
| |
| evalInstanceLevelSemanticLabeling.readPredInfo``. |
| Args: |
| prediction_file (str): The prediction txt file. |
| Returns: |
| dict: The processed prediction results. |
| """ |
| if not HAS_CITYSCAPESAPI: |
| raise RuntimeError('Failed to import `cityscapesscripts`.' |
| 'Please try to install official ' |
| 'cityscapesscripts by ' |
| '"pip install cityscapesscripts"') |
| printError = CSEval.printError |
|
|
| predInfo = {} |
| if (not os.path.isfile(prediction_file)): |
| printError(f"Infofile '{prediction_file}' " |
| 'for the predictions not found.') |
| with open(prediction_file) as f: |
| for line in f: |
| splittedLine = line.split(' ') |
| if len(splittedLine) != 3: |
| printError('Invalid prediction file. Expected content: ' |
| 'relPathPrediction1 labelIDPrediction1 ' |
| 'confidencePrediction1') |
| if os.path.isabs(splittedLine[0]): |
| printError('Invalid prediction file. First entry in each ' |
| 'line must be a relative path.') |
|
|
| filename = os.path.join( |
| os.path.dirname(prediction_file), splittedLine[0]) |
|
|
| imageInfo = {} |
| imageInfo['labelID'] = int(float(splittedLine[1])) |
| imageInfo['conf'] = float(splittedLine[2]) |
| predInfo[filename] = imageInfo |
|
|
| return predInfo |
|
|
|
|
| def getGtInstances(groundtruth_list: list, |
| args: CArgs, |
| backend_args: Optional[dict] = None) -> dict: |
| """A wrapper of obj:``cityscapesscripts.evaluation. |
| |
| evalInstanceLevelSemanticLabeling.getGtInstances``. Support loading |
| groundtruth image from file backend. |
| Args: |
| groundtruth_list (list): A list of groundtruth image file. |
| args (CArgs): A global object setting in |
| obj:``cityscapesscripts.evaluation. |
| evalInstanceLevelSemanticLabeling`` |
| backend_args (dict, optional): Arguments to instantiate the |
| preifx of uri corresponding backend. Defaults to None. |
| Returns: |
| dict: The computed metric. |
| """ |
| if not HAS_CITYSCAPESAPI: |
| raise RuntimeError('Failed to import `cityscapesscripts`.' |
| 'Please try to install official ' |
| 'cityscapesscripts by ' |
| '"pip install cityscapesscripts"') |
| |
| if (os.path.isfile(args.gtInstancesFile)): |
| if not args.quiet: |
| print('Loading ground truth instances from JSON.') |
| with open(args.gtInstancesFile) as json_file: |
| gt_instances = json.load(json_file) |
| |
| else: |
| if (not args.quiet): |
| print('Creating ground truth instances from png files.') |
| gt_instances = instances2dict( |
| groundtruth_list, args, backend_args=backend_args) |
| writeDict2JSON(gt_instances, args.gtInstancesFile) |
|
|
| return gt_instances |
|
|
|
|
| def instances2dict(image_list: list, |
| args: CArgs, |
| backend_args: Optional[dict] = None) -> dict: |
| """A wrapper of obj:``cityscapesscripts.evaluation. |
| |
| evalInstanceLevelSemanticLabeling.instances2dict``. Support loading |
| groundtruth image from file backend. |
| Args: |
| image_list (list): A list of image file. |
| args (CArgs): A global object setting in |
| obj:``cityscapesscripts.evaluation. |
| evalInstanceLevelSemanticLabeling`` |
| backend_args (dict, optional): Arguments to instantiate the |
| preifx of uri corresponding backend. Defaults to None. |
| Returns: |
| dict: The processed groundtruth results. |
| """ |
| if not HAS_CITYSCAPESAPI: |
| raise RuntimeError('Failed to import `cityscapesscripts`.' |
| 'Please try to install official ' |
| 'cityscapesscripts by ' |
| '"pip install cityscapesscripts"') |
| imgCount = 0 |
| instanceDict = {} |
|
|
| if not isinstance(image_list, list): |
| image_list = [image_list] |
|
|
| if not args.quiet: |
| print(f'Processing {len(image_list)} images...') |
|
|
| for image_name in image_list: |
| |
| img_bytes = get(image_name, backend_args=backend_args) |
| imgNp = mmcv.imfrombytes(img_bytes, flag='unchanged', backend='pillow') |
|
|
| |
| instances: dict = {} |
| for label in labels: |
| instances[label.name] = [] |
|
|
| |
| for instanceId in np.unique(imgNp): |
| instanceObj = Instance(imgNp, instanceId) |
|
|
| instances[id2label[instanceObj.labelID].name].append( |
| instanceObj.toDict()) |
|
|
| instanceDict[image_name] = instances |
| imgCount += 1 |
|
|
| if not args.quiet: |
| print(f'\rImages Processed: {imgCount}', end=' ') |
| sys.stdout.flush() |
|
|
| return instanceDict |
|
|