Benchmarking Cell Tracking Challenge Data

[1]:
import os
from pathlib import Path
import pprint
import urllib.request
import zipfile

from tqdm import tqdm

from traccuracy import run_metrics
from traccuracy.loaders import load_ctc_data
from traccuracy.matchers import CTCMatcher, IOUMatcher
from traccuracy.metrics import CTCMetrics, DivisionMetrics

pp = pprint.PrettyPrinter(indent=4)
[2]:
url = "http://data.celltrackingchallenge.net/training-datasets/Fluo-N2DL-HeLa.zip"
data_dir = 'downloads'

if not os.path.exists(data_dir):
    os.mkdir(data_dir)

filename = url.split('/')[-1]
file_path = os.path.join(data_dir, filename)
ds_name = filename.split('.')[0]
[3]:
# Add a utility to make a progress bar when downloading the file
class DownloadProgressBar(tqdm):
    def update_to(self, b=1, bsize=1, tsize=None):
        if tsize is not None:
            self.total = tsize
        self.update(b * bsize - self.n)

if not os.path.exists(file_path):
    print(f"Downloading {ds_name} data from the CTC website")
    # Downloading data
    with DownloadProgressBar(unit='B', unit_scale=True,
                             miniters=1, desc=url.split('/')[-1]) as t:
        urllib.request.urlretrieve(url, file_path, reporthook=t.update_to)
    # Unzip the data
    # TODO add a progress bar to zip as well
    with zipfile.ZipFile(file_path, 'r') as zip_ref:
        zip_ref.extractall(data_dir)
[4]:

gt_data = load_ctc_data( 'downloads/Fluo-N2DL-HeLa/01_GT/TRA', 'downloads/Fluo-N2DL-HeLa/01_GT/TRA/man_track.txt', name='Hela-01_GT' ) pred_data = load_ctc_data( 'sample-data/Fluo-N2DL-HeLa/01_RES', 'sample-data/Fluo-N2DL-HeLa/01_RES/res_track.txt', name='Hela-01_RES' )
Loading TIFFs:   0%|          | 0/92 [00:00<?, ?it/s]
Loading TIFFs: 100%|██████████| 92/92 [00:00<00:00, 402.71it/s]
Loading TIFFs: 100%|██████████| 92/92 [00:00<00:00, 609.62it/s]

Run CTC metrics with additional evaluation of division events.

[5]:
ctc_results = run_metrics(
    gt_data=gt_data,
    pred_data=pred_data,
    matcher=CTCMatcher(),
    metrics=[CTCMetrics(), DivisionMetrics(frame_buffer=(0,1,2))],
)
pp.pprint(ctc_results)
Matching frames: 100%|██████████| 92/92 [00:01<00:00, 90.00it/s]
Evaluating nodes: 100%|██████████| 8600/8600 [00:00<00:00, 645392.99it/s]
Evaluating FP edges: 100%|██████████| 8535/8535 [00:00<00:00, 923996.20it/s]
Evaluating FN edges: 100%|██████████| 8562/8562 [00:00<00:00, 990392.47it/s]
[   {   'gt': 'Hela-01_GT',
        'matcher': {'name': 'CTCMatcher'},
        'metric': {   'e_weights': {'fn': 1.5, 'fp': 1, 'ws': 1},
                      'name': 'CTCMetrics',
                      'v_weights': {'fn': 10, 'fp': 1, 'ns': 5}},
        'pred': 'Hela-01_RES',
        'results': {   'AOGM': 627.5,
                       'DET': 0.9954855886097927,
                       'TRA': 0.993676498745377,
                       'fn_edges': 87,
                       'fn_nodes': 39,
                       'fp_edges': 60,
                       'fp_nodes': 0,
                       'ns_nodes': 0,
                       'ws_edges': 47},
        'version': '0.0.3.dev5+gf8c982c'},
    {   'gt': 'Hela-01_GT',
        'matcher': {'name': 'CTCMatcher'},
        'metric': {'frame_buffer': (0, 1, 2), 'name': 'DivisionMetrics'},
        'pred': 'Hela-01_RES',
        'results': {   'Frame Buffer 0': {   'Division F1': 0.76,
                                             'Division Precision': 0.7169811320754716,
                                             'Division Recall': 0.8085106382978723,
                                             'False Negative Divisions': 18,
                                             'False Positive Divisions': 30,
                                             'Mitotic Branching Correctness': 0.6129032258064516,
                                             'True Positive Divisions': 76},
                       'Frame Buffer 1': {   'Division F1': 0.76,
                                             'Division Precision': 0.7169811320754716,
                                             'Division Recall': 0.8085106382978723,
                                             'False Negative Divisions': 18,
                                             'False Positive Divisions': 30,
                                             'Mitotic Branching Correctness': 0.6129032258064516,
                                             'True Positive Divisions': 76},
                       'Frame Buffer 2': {   'Division F1': 0.76,
                                             'Division Precision': 0.7169811320754716,
                                             'Division Recall': 0.8085106382978723,
                                             'False Negative Divisions': 18,
                                             'False Positive Divisions': 30,
                                             'Mitotic Branching Correctness': 0.6129032258064516,
                                             'True Positive Divisions': 76}},
        'version': '0.0.3.dev5+gf8c982c'}]

Use an IOU matcher which supports a minimum threshold for overlap and run division metrics.

[6]:
iou_results = run_metrics(
    gt_data=gt_data,
    pred_data=pred_data,
    matcher=IOUMatcher(iou_threshold=0.1),
    metrics=[DivisionMetrics(frame_buffer=(0,1,2))],
)
pp.pprint(iou_results)
Matching frames: 100%|██████████| 92/92 [00:15<00:00,  6.01it/s]
[   {   'gt': 'Hela-01_GT',
        'matcher': {'iou_threshold': 0.1, 'name': 'IOUMatcher'},
        'metric': {'frame_buffer': (0, 1, 2), 'name': 'DivisionMetrics'},
        'pred': 'Hela-01_RES',
        'results': {   'Frame Buffer 0': {   'Division F1': 0.711340206185567,
                                             'Division Precision': 0.69,
                                             'Division Recall': 0.7340425531914894,
                                             'False Negative Divisions': 25,
                                             'False Positive Divisions': 31,
                                             'Mitotic Branching Correctness': 0.552,
                                             'True Positive Divisions': 69},
                       'Frame Buffer 1': {   'Division F1': 0.711340206185567,
                                             'Division Precision': 0.69,
                                             'Division Recall': 0.7340425531914894,
                                             'False Negative Divisions': 25,
                                             'False Positive Divisions': 31,
                                             'Mitotic Branching Correctness': 0.552,
                                             'True Positive Divisions': 69},
                       'Frame Buffer 2': {   'Division F1': 0.711340206185567,
                                             'Division Precision': 0.69,
                                             'Division Recall': 0.7340425531914894,
                                             'False Negative Divisions': 25,
                                             'False Positive Divisions': 31,
                                             'Mitotic Branching Correctness': 0.552,
                                             'True Positive Divisions': 69}},
        'version': '0.0.3.dev5+gf8c982c'}]
[ ]: