From 8c7eba3f37a5dc0626211105eea2177420b73c43 Mon Sep 17 00:00:00 2001 From: Julius Bier Kirkegaard Date: Thu, 8 Jun 2023 13:07:59 +0200 Subject: [PATCH 1/5] Add relabel argument Option such that labels are `[0, 1, 2, ..., max_label]`. --- cc_torch/connected_components.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cc_torch/connected_components.py b/cc_torch/connected_components.py index beffb21..7252f91 100644 --- a/cc_torch/connected_components.py +++ b/cc_torch/connected_components.py @@ -2,19 +2,28 @@ from cc_torch import _C -def connected_components_labeling(x): +def connected_components_labeling(x, relabel=False): """ Connected Components Labeling by Block Union Find(BUF) algorithm. Args: x (cuda.ByteTensor): must be uint8, cuda and even num shapes + relabel (bool): whether to return labels in range [0, max_label] Return: label (cuda.IntTensor) """ if x.ndim == 2: - return _C.cc_2d(x) + assert x.shape[0] % 2 == 0 and x.shape[1] % 2 == 0 + ret = _C.cc_2d(x) elif x.ndim == 3: - return _C.cc_3d(x) + assert x.shape[0] % 2 == 0 and x.shape[1] % 2 == 0 and x.shape[2] % 2 == 0 + ret = _C.cc_3d(x) else: raise ValueError("x must be [H, W] or [D, H, W] shapes") + + if relabel: + vs, idxs = torch.unique(ret, return_inverse=True, sorted=True) + a = torch.arange(len(vs), device=vs.device)[idxs] + + return ret From 6628c5ec823fb332a077a6bbdb33b104bdee5cab Mon Sep 17 00:00:00 2001 From: Julius Bier Kirkegaard Date: Thu, 8 Jun 2023 13:11:14 +0200 Subject: [PATCH 2/5] add test for relabel argument --- tests/test_cc.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_cc.py b/tests/test_cc.py index d5f1041..472b779 100644 --- a/tests/test_cc.py +++ b/tests/test_cc.py @@ -31,6 +31,34 @@ def test_2d(self): output = cc_torch.connected_components_labeling(img_2d) self.assertTrue((output == expected_output).all()) + + def test_relabel(self): + img_2d = torch.tensor([ + 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0], dtype=torch.uint8).reshape(12, 8).cuda() + + expected_output = torch.tensor( + [[1, 1, 0, 1, 1, 1, 1, 1], + [0, 1, 1, 0, 1, 1, 1, 0], + [1, 1, 1, 0, 1, 1, 1, 0], + [1, 1, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 0, 1, 0, 0, 2], + [0, 0, 0, 1, 0, 0, 2, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 3, 0, 0], + [0, 0, 0, 0, 0, 3, 0, 0], + [0, 4, 0, 3, 3, 3, 3, 3], + [0, 4, 0, 0, 3, 3, 3, 0], + [0, 4, 0, 0, 3, 3, 3, 0]], dtype=torch.int32).cuda() + + output = cc_torch.connected_components_labeling(img_2d) + self.assertTrue((output == expected_output).all()) def test_3d(self): img_2d = torch.tensor([ From 80e7e10e0901ab7451a4e2d569f7d4ed1b34a61e Mon Sep 17 00:00:00 2001 From: Julius Bier Kirkegaard Date: Thu, 8 Jun 2023 13:29:48 +0200 Subject: [PATCH 3/5] fix test problem --- tests/test_cc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cc.py b/tests/test_cc.py index 472b779..f29765e 100644 --- a/tests/test_cc.py +++ b/tests/test_cc.py @@ -57,7 +57,7 @@ def test_relabel(self): [0, 4, 0, 0, 3, 3, 3, 0], [0, 4, 0, 0, 3, 3, 3, 0]], dtype=torch.int32).cuda() - output = cc_torch.connected_components_labeling(img_2d) + output = cc_torch.connected_components_labeling(img_2d, relabel=True) self.assertTrue((output == expected_output).all()) def test_3d(self): From a2ea9bbe1aa179b134eab950bae9447b62d1e0f3 Mon Sep 17 00:00:00 2001 From: Julius Bier Kirkegaard Date: Thu, 8 Jun 2023 13:30:22 +0200 Subject: [PATCH 4/5] Update connected_components.py (sorry, I just edited files in github and only now checked if they were correct -- test now passes) --- cc_torch/connected_components.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cc_torch/connected_components.py b/cc_torch/connected_components.py index 7252f91..83dd811 100644 --- a/cc_torch/connected_components.py +++ b/cc_torch/connected_components.py @@ -24,6 +24,6 @@ def connected_components_labeling(x, relabel=False): if relabel: vs, idxs = torch.unique(ret, return_inverse=True, sorted=True) - a = torch.arange(len(vs), device=vs.device)[idxs] + ret = torch.arange(len(vs), device=vs.device)[idxs] return ret From a0221a55e96665c2726675204d6c924673135a51 Mon Sep 17 00:00:00 2001 From: Julius Bier Kirkegaard Date: Thu, 8 Jun 2023 13:32:22 +0200 Subject: [PATCH 5/5] Update connected_components.py --- cc_torch/connected_components.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cc_torch/connected_components.py b/cc_torch/connected_components.py index 83dd811..0c69754 100644 --- a/cc_torch/connected_components.py +++ b/cc_torch/connected_components.py @@ -14,10 +14,8 @@ def connected_components_labeling(x, relabel=False): label (cuda.IntTensor) """ if x.ndim == 2: - assert x.shape[0] % 2 == 0 and x.shape[1] % 2 == 0 ret = _C.cc_2d(x) elif x.ndim == 3: - assert x.shape[0] % 2 == 0 and x.shape[1] % 2 == 0 and x.shape[2] % 2 == 0 ret = _C.cc_3d(x) else: raise ValueError("x must be [H, W] or [D, H, W] shapes")