Skip to content

Commit e5c897f

Browse files
committed
Add data merging when there are multiple scorers
1 parent 5e72106 commit e5c897f

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

src/napari_deeplabcut/_reader.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ def read_hdf(filename: str) -> List[LayerData]:
182182
layers = []
183183
for filename in glob.iglob(filename):
184184
temp = pd.read_hdf(filename)
185+
temp = misc.merge_multiple_scorers(temp)
185186
header = misc.DLCHeader(temp.columns)
186187
temp = temp.droplevel("scorer", axis=1)
187188
if "individuals" not in temp.columns.names:

src/napari_deeplabcut/_tests/test_misc.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import numpy as np
12
import os
23
import pandas as pd
34
import pytest
@@ -24,6 +25,31 @@ def test_encode_categories():
2425
inds = misc.encode_categories(categories, return_map=False)
2526

2627

28+
def test_merge_multiple_scorers_no_likelihood(fake_keypoints):
29+
temp = fake_keypoints.copy(deep=True)
30+
temp.columns = temp.columns.set_levels(["you"], level="scorer")
31+
df = fake_keypoints.merge(temp, left_index=True, right_index=True)
32+
df = misc.merge_multiple_scorers(df)
33+
pd.testing.assert_frame_equal(df, fake_keypoints)
34+
35+
36+
def test_merge_multiple_scorers(fake_keypoints):
37+
new_columns = pd.MultiIndex.from_product(
38+
fake_keypoints.columns.levels[:-1] + [["x", "y", "likelihood"]],
39+
names=fake_keypoints.columns.names,
40+
)
41+
fake_keypoints = fake_keypoints.reindex(new_columns, axis=1)
42+
fake_keypoints.loc(axis=1)[:, :, :, "likelihood"] = 1
43+
temp = fake_keypoints.copy(deep=True)
44+
temp.columns = temp.columns.set_levels(["you"], level="scorer")
45+
fake_keypoints.iloc[:5] = np.nan
46+
temp.iloc[5:] = np.nan
47+
df = fake_keypoints.merge(temp, left_index=True, right_index=True)
48+
df = misc.merge_multiple_scorers(df)
49+
pd.testing.assert_index_equal(df.columns, fake_keypoints.columns)
50+
assert not df.isna().any(axis=None)
51+
52+
2753
@pytest.mark.parametrize(
2854
"path",
2955
["/home/to/fake/path", "C:\\Users\\with\\fake\\name"],

src/napari_deeplabcut/misc.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,34 @@ def encode_categories(
2727
return inds
2828

2929

30+
def merge_multiple_scorers(
31+
df: pd.DataFrame,
32+
) -> pd.DataFrame:
33+
n_frames = df.shape[0]
34+
header = DLCHeader(df.columns)
35+
n_scorers = len(header._get_unique("scorer"))
36+
if n_scorers == 1:
37+
return df
38+
39+
n_bodyparts = len(header.bodyparts)
40+
if "likelihood" in header.coords:
41+
# Merge annotations from multiple scorers to keep
42+
# detections with highest confidence
43+
data = df.to_numpy().reshape((n_frames, n_scorers, n_bodyparts, -1))
44+
idx = np.nanargmax(data[..., 2], axis=1)
45+
data_best = data[
46+
np.arange(n_frames)[:, None], idx, np.arange(n_bodyparts)
47+
].reshape((n_frames, -1))
48+
df = pd.DataFrame(
49+
data_best,
50+
index=df.index,
51+
columns=header.columns[: data_best.shape[1]],
52+
)
53+
else: # Arbitrarily pick data from the first scorer
54+
df = df.loc(axis=1)[: header.scorer]
55+
return df
56+
57+
3058
def to_os_dir_sep(path: str) -> str:
3159
"""
3260
Replace all directory separators in `path` with `os.path.sep`.

0 commit comments

Comments
 (0)