Path: blob/master/Background-Subtraction/evaluator.py
3118 views
import argparse1import glob2import os3import time45import cv26import numpy as np7import pybgs as bgs89ALGORITHMS_TO_EVALUATE = [10(cv2.bgsegm.createBackgroundSubtractorGSOC, "GSoC", {}),11(bgs.SuBSENSE, "SuBSENSE", {}),12]131415# https://github.com/opencv/opencv_contrib/blob/master/modules/bgsegm/samples/evaluation.py16def contains_relevant_files(root):17return os.path.isdir(os.path.join(root, "groundtruth")) and os.path.isdir(18os.path.join(root, "input"),19)202122def find_relevant_dirs(root):23relevant_dirs = []24for d in sorted(os.listdir(root)):25d = os.path.join(root, d)26if os.path.isdir(d):27if contains_relevant_files(d):28relevant_dirs += [d]29else:30relevant_dirs += find_relevant_dirs(d)31return relevant_dirs323334def load_sequence(root):35gt_dir, frames_dir = os.path.join(root, "groundtruth"), os.path.join(root, "input")36gt = sorted(glob.glob(os.path.join(gt_dir, "*.png")))37f = sorted(glob.glob(os.path.join(frames_dir, "*.jpg")))38assert len(gt) == len(f)39return gt, f404142def evaluate_algorithm(gt, frames, algo, algo_arguments):43# instantiate background subtraction model44bgs = algo(**algo_arguments)45mask = []46# start time evaluation47t_start = time.time()4849for i in range(len(gt)):50# read frames51frame = np.uint8(cv2.imread(frames[i], cv2.IMREAD_COLOR))52# feed the frames into the model53mask.append(bgs.apply(frame))5455average_duration = (time.time() - t_start) / len(gt)56average_precision, average_recall, average_f1, average_accuracy = [], [], [], []5758# initiate iteration over GT frames59for i in range(len(gt)):60# get GT masks61gt_mask = np.uint8(cv2.imread(gt[i], cv2.IMREAD_GRAYSCALE))62# obtain region of interest63roi = (gt_mask == 255) | (gt_mask == 0)64if roi.sum() > 0:65gt_answer, answer = gt_mask[roi], mask[i][roi]6667# calculate true positives, true negatives, false positives, false negatives68tp = ((answer == 255) & (gt_answer == 255)).sum()69tn = ((answer == 0) & (gt_answer == 0)).sum()70fp = ((answer == 255) & (gt_answer == 0)).sum()71fn = ((answer == 0) & (gt_answer == 255)).sum()7273# compute precision, recall, F1, accuracy to evaluate BS-model work74if tp + fp > 0:75average_precision.append(float(tp) / (tp + fp))76if tp + fn > 0:77average_recall.append(float(tp) / (tp + fn))78if tp + fn + fp > 0:79average_f1.append(2.0 * tp / (2.0 * tp + fn + fp))80average_accuracy.append(float(tp + tn) / (tp + tn + fp + fn))8182return (83average_duration,84np.mean(average_precision),85np.mean(average_recall),86np.mean(average_f1),87np.mean(average_accuracy),88)899091def evaluate_on_sequence(seq, summary):92gt, frames = load_sequence(seq)93category, video_name = os.path.basename(os.path.dirname(seq)), os.path.basename(seq)94print("=== %s:%s ===" % (category, video_name))9596for algo, algo_name, algo_arguments in ALGORITHMS_TO_EVALUATE:97print("Algorithm name: %s" % algo_name)98sec_per_step, precision, recall, f1, accuracy = evaluate_algorithm(99gt, frames, algo, algo_arguments,100)101print("Average accuracy: %.3f" % accuracy)102print("Average precision: %.3f" % precision)103print("Average recall: %.3f" % recall)104print("Average F1: %.3f" % f1)105print("Average sec. per step: %.4f" % sec_per_step)106print("")107108if category not in summary:109summary[category] = {}110if algo_name not in summary[category]:111summary[category][algo_name] = []112summary[category][algo_name].append((precision, recall, f1, accuracy))113114115def main():116parser = argparse.ArgumentParser(117description="Evaluate all background subtractors using Change Detection dataset",118)119parser.add_argument(120"--dataset_path",121help="Path to the directory with dataset. It may contain multiple inner directories. It will be scanned recursively.",122required=True,123)124parser.add_argument("--algorithm", help="Test particular algorithm instead of all.")125126args = parser.parse_args()127dataset_dirs = find_relevant_dirs(args.dataset_path)128assert len(dataset_dirs) > 0, (129"Passed directory must contain at least one sequence from the Change Detection dataset. There is no relevant directories in %s. Check that this directory is correct."130% (args.dataset_path)131)132if args.algorithm is not None:133global ALGORITHMS_TO_EVALUATE134ALGORITHMS_TO_EVALUATE = filter(135lambda a: a[1].lower() == args.algorithm.lower(), ALGORITHMS_TO_EVALUATE,136)137summary = {}138139for seq in dataset_dirs:140evaluate_on_sequence(seq, summary)141142for category in summary:143for algo_name in summary[category]:144summary[category][algo_name] = np.mean(summary[category][algo_name], axis=0)145146algorithms_results = {147"GSoC": [],148"SuBSENSE": [],149}150151for category in summary:152print("=== SUMMARY for %s (Precision, Recall, F1, Accuracy) ===" % category)153for algo_name in summary[category]:154print(155"%05s: %.3f %.3f %.3f %.3f"156% ((algo_name,) + tuple(summary[category][algo_name])),157)158algorithms_results[algo_name].append(summary[category][algo_name])159160print("=== SUMMARY for all video categories (Precision, Recall, F1, Accuracy) ===")161for algo_name in algorithms_results:162algorithms_results[algo_name] = np.mean(163np.array(algorithms_results[algo_name]), axis=0,164)165res_array = algorithms_results[algo_name]166print(167"{}: {:.3f}, {:.3f}, {:.3f}, {:.3f}".format(168algo_name, res_array[0], res_array[1], res_array[2], res_array[3],169),170)171172173if __name__ == "__main__":174main()175176177