in libs/solaris/eval/base.py [0:0]
def eval_iou_spacenet_csv(self, miniou=0.5, iou_field_prefix="iou_score",
imageIDField="ImageId", debug=False, min_area=0):
"""Evaluate IoU between the ground truth and proposals in CSVs.
Arguments
---------
miniou : float , optional
Minimum intersection over union score to qualify as a successful
object detection event. Defaults to ``0.5``.
iou_field_prefix : str , optional
The name of the IoU score column in ``self.proposal_GDF``. Defaults
to ``"iou_score"`` .
imageIDField : str , optional
The name of the column corresponding to the image IDs in the
ground truth data. Defaults to ``"ImageId"``.
debug : bool , optional
Argument for verbose execution during debugging. Defaults to
``False`` (silent execution).
min_area : float or int , optional
Minimum area of a ground truth polygon to be considered during
evaluation. Often set to ``20`` in SpaceNet competitions. Defaults
to ``0`` (consider all ground truth polygons).
Returns
-------
scoring_dict_list : list
list of score output dicts for each image in the ground
truth and evaluated image datasets. The dicts contain
the following keys: ::
('imageID', 'iou_field', 'TruePos', 'FalsePos', 'FalseNeg',
'Precision', 'Recall', 'F1Score')
"""
# Get List of all ImageID in both ground truth and proposals
imageIDList = []
imageIDList.extend(list(self.ground_truth_GDF[imageIDField].unique()))
if not self.proposal_GDF.empty:
imageIDList.extend(list(self.proposal_GDF[imageIDField].unique()))
imageIDList = list(set(imageIDList))
iou_field = iou_field_prefix
scoring_dict_list = []
self.ground_truth_GDF[iou_field] = 0.
iou_index = self.ground_truth_GDF.columns.get_loc(iou_field)
id_cols = 2
ground_truth_ids = self.ground_truth_GDF.iloc[:, :id_cols]
for imageID in tqdm(imageIDList):
self.ground_truth_GDF_Edit = self.ground_truth_GDF[
self.ground_truth_GDF[imageIDField] == imageID
].copy(deep=True)
self.ground_truth_GDF_Edit = self.ground_truth_GDF_Edit[
self.ground_truth_GDF_Edit.area >= min_area
]
proposal_GDF_copy = self.proposal_GDF[self.proposal_GDF[
imageIDField] == imageID].copy(deep=True)
proposal_GDF_copy = proposal_GDF_copy[proposal_GDF_copy.area
> min_area]
if debug:
print(iou_field)
for _, pred_row in proposal_GDF_copy.iterrows():
if debug:
print(pred_row.name)
if pred_row.geometry.area > 0:
pred_poly = pred_row.geometry
iou_GDF = iou.calculate_iou(pred_poly,
self.ground_truth_GDF_Edit)
# Get max iou
if not iou_GDF.empty:
max_index = iou_GDF['iou_score'].idxmax(axis=0,
skipna=True)
max_iou_row = iou_GDF.loc[max_index]
# Update entry in full ground truth table
previous_iou = self.ground_truth_GDF.iloc[
max_index, iou_index]
new_iou = max_iou_row[iou_field]
if new_iou > previous_iou:
self.ground_truth_GDF.iloc[max_index, iou_index] \
= new_iou
if max_iou_row['iou_score'] > miniou:
self.proposal_GDF.loc[pred_row.name, iou_field] \
= max_iou_row['iou_score']
self.ground_truth_GDF_Edit \
= self.ground_truth_GDF_Edit.drop(
max_iou_row.name, axis=0)
else:
self.proposal_GDF.loc[pred_row.name, iou_field] = 0
else:
self.proposal_GDF.loc[pred_row.name, iou_field] = 0
else:
self.proposal_GDF.loc[pred_row.name, iou_field] = 0
if debug:
print(self.proposal_GDF.loc[pred_row.name])
if self.proposal_GDF.empty:
TruePos = 0
FalsePos = 0
else:
proposal_GDF_copy = self.proposal_GDF[
self.proposal_GDF[imageIDField] == imageID].copy(deep=True)
proposal_GDF_copy = proposal_GDF_copy[
proposal_GDF_copy.area > min_area]
if not proposal_GDF_copy.empty:
if iou_field in proposal_GDF_copy.columns:
TruePos = proposal_GDF_copy[
proposal_GDF_copy[iou_field] >= miniou].shape[0]
FalsePos = proposal_GDF_copy[
proposal_GDF_copy[iou_field] < miniou].shape[0]
else:
print("iou field {} missing".format(iou_field))
TruePos = 0
FalsePos = 0
else:
print("Empty Proposal Id")
TruePos = 0
FalsePos = 0
# false negatives is the number of objects remaining in ground
# truth after pulling out matched objects
FalseNeg = self.ground_truth_GDF_Edit[
self.ground_truth_GDF_Edit.area > 0].shape[0]
if float(TruePos+FalsePos) > 0:
Precision = TruePos / float(TruePos + FalsePos)
else:
Precision = 0
if float(TruePos + FalseNeg) > 0:
Recall = TruePos / float(TruePos + FalseNeg)
else:
Recall = 0
if Recall * Precision > 0:
F1Score = 2*Precision*Recall/(Precision+Recall)
else:
F1Score = 0
score_calc = {'imageID': imageID,
'iou_field': iou_field,
'TruePos': TruePos,
'FalsePos': FalsePos,
'FalseNeg': FalseNeg,
'Precision': Precision,
'Recall': Recall,
'F1Score': F1Score
}
scoring_dict_list.append(score_calc)
return scoring_dict_list