From 86f818b06780c0d9dcc7aad531a85c4780e487f9 Mon Sep 17 00:00:00 2001 From: Aus Abdalrasul Date: Tue, 22 Mar 2022 18:24:24 +0100 Subject: [PATCH 1/5] Variable edge buf size. int64 coordinates. --- sknw/sknw.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sknw/sknw.py b/sknw/sknw.py index bb5e838..d28e3dc 100644 --- a/sknw/sknw.py +++ b/sknw/sknw.py @@ -25,7 +25,7 @@ def mark(img, nbs): # mark the array use (0, 1, 2) @jit(nopython=True) # trans index to r, c... def idx2rc(idx, acc): - rst = np.zeros((len(idx), len(acc)), dtype=np.int16) + rst = np.zeros((len(idx), len(acc)), dtype=np.int64) for i in range(len(idx)): for j in range(len(acc)): rst[i,j] = idx[i]//acc[j] @@ -77,9 +77,9 @@ def trace(img, p, nbs, acc, buf): return (c1-10, c2-10, idx2rc(buf[:cur+1], acc)) @jit(nopython=True) # parse the image then get the nodes and edges -def parse_struc(img, nbs, acc, iso, ring): +def parse_struc(img, nbs, acc, iso, ring, buf_size): img = img.ravel() - buf = np.zeros(131072, dtype=np.int64) + buf = np.zeros(buf_size, dtype=np.int64) num = 10 nodes = [] for p in range(len(img)): @@ -126,12 +126,12 @@ def mark_node(ske): mark(buf, nbs) return buf -def build_sknw(ske, multi=False, iso=True, ring=True, full=True): +def build_sknw(ske, buf_size=131072, multi=False, iso=True, ring=True, full=True): buf = np.pad(ske, (1,1), mode='constant').astype(np.uint16) nbs = neighbors(buf.shape) acc = np.cumprod((1,)+buf.shape[::-1][:-1])[::-1] mark(buf, nbs) - nodes, edges = parse_struc(buf, nbs, acc, iso, ring) + nodes, edges = parse_struc(buf, nbs, acc, iso, ring, buf_size) return build_graph(nodes, edges, multi, full) # draw the graph From 9b1dc50bb7ee990498c27dfff86dde93f0e75891 Mon Sep 17 00:00:00 2001 From: Aus Abdalrasul Date: Wed, 23 Mar 2022 01:57:54 +0100 Subject: [PATCH 2/5] Change pixel type int16 to int64 Allows large images to be marked with higher values. That fixes the bugs when "trace" can't find the end node due to integer limit of the x,y address. --- sknw/sknw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sknw/sknw.py b/sknw/sknw.py index d28e3dc..e211c2b 100644 --- a/sknw/sknw.py +++ b/sknw/sknw.py @@ -127,7 +127,7 @@ def mark_node(ske): return buf def build_sknw(ske, buf_size=131072, multi=False, iso=True, ring=True, full=True): - buf = np.pad(ske, (1,1), mode='constant').astype(np.uint16) + buf = np.pad(ske, (1,1), mode='constant').astype(np.int64) nbs = neighbors(buf.shape) acc = np.cumprod((1,)+buf.shape[::-1][:-1])[::-1] mark(buf, nbs) From 6bef547b218aa72bd4322ee9a7a656b421542db1 Mon Sep 17 00:00:00 2001 From: Aus Abdalrasul Date: Wed, 23 Mar 2022 13:18:00 +0100 Subject: [PATCH 3/5] Return exception if --- sknw/sknw.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/sknw/sknw.py b/sknw/sknw.py index e211c2b..f639a86 100644 --- a/sknw/sknw.py +++ b/sknw/sknw.py @@ -57,6 +57,8 @@ def trace(img, p, nbs, acc, buf): c1 = 0; c2 = 0; newp = 0 cur = 1 + buf_len = len(buf) + buf_overflow = False while True: buf[cur] = p img[p] = 0 @@ -74,7 +76,10 @@ def trace(img, p, nbs, acc, buf): newp = cp p = newp if c2!=0:break - return (c1-10, c2-10, idx2rc(buf[:cur+1], acc)) + if cur >= buf_len: + buf_overflow = True + break + return (c1-10, c2-10, idx2rc(buf[:cur+1], acc)), buf_overflow @jit(nopython=True) # parse the image then get the nodes and edges def parse_struc(img, nbs, acc, iso, ring, buf_size): @@ -93,18 +98,22 @@ def parse_struc(img, nbs, acc, iso, ring, buf_size): if img[p] <10: continue for dp in nbs: if img[p+dp]==1: - edge = trace(img, p+dp, nbs, acc, buf) + edge, buf_overflow = trace(img, p+dp, nbs, acc, buf) + if buf_overflow: + return nodes, edges, buf_overflow edges.append(edge) - if not ring: return nodes, edges + if not ring: return nodes, edges, False for p in range(len(img)): if img[p]!=1: continue img[p] = num; num += 1 nodes.append(idx2rc([p], acc)) for dp in nbs: if img[p+dp]==1: - edge = trace(img, p+dp, nbs, acc, buf) + edge, buf_overflow = trace(img, p+dp, nbs, acc, buf) + if buf_overflow: + return nodes, edges, buf_overflow edges.append(edge) - return nodes, edges + return nodes, edges, False # use nodes and edges build a networkx graph def build_graph(nodes, edges, multi=False, full=True): @@ -131,7 +140,9 @@ def build_sknw(ske, buf_size=131072, multi=False, iso=True, ring=True, full=True nbs = neighbors(buf.shape) acc = np.cumprod((1,)+buf.shape[::-1][:-1])[::-1] mark(buf, nbs) - nodes, edges = parse_struc(buf, nbs, acc, iso, ring, buf_size) + nodes, edges, buf_overflow = parse_struc(buf, nbs, acc, iso, ring, buf_size) + if buf_overflow: + raise Exception('Buffer overflow') return build_graph(nodes, edges, multi, full) # draw the graph From c534be9c6108332a35f4ed7f0a664510c0634898 Mon Sep 17 00:00:00 2001 From: jmo Date: Thu, 19 Jan 2023 17:51:20 +0100 Subject: [PATCH 4/5] Fix the `uint16` overflow An overflow was happening for reasonably big images (a dimension greater than 2^16). It is now `uint32`. Note that `mark_node` hasn't been touched because it's not involved in the graph generation. --- sknw/sknw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sknw/sknw.py b/sknw/sknw.py index f639a86..5615ef7 100644 --- a/sknw/sknw.py +++ b/sknw/sknw.py @@ -118,7 +118,7 @@ def parse_struc(img, nbs, acc, iso, ring, buf_size): # use nodes and edges build a networkx graph def build_graph(nodes, edges, multi=False, full=True): os = np.array([i.mean(axis=0) for i in nodes]) - if full: os = os.round().astype(np.uint16) + if full: os = os.round().astype(np.uint32) graph = nx.MultiGraph() if multi else nx.Graph() for i in range(len(nodes)): graph.add_node(i, pts=nodes[i], o=os[i]) From c70e981c074be2a2362b6486e7edb219fef7e225 Mon Sep 17 00:00:00 2001 From: Aus Abdalrasul Date: Wed, 9 Apr 2025 11:26:53 +0200 Subject: [PATCH 5/5] Place buf_size arg to end to avoid breaking code that uses positional args. --- sknw/sknw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sknw/sknw.py b/sknw/sknw.py index 5615ef7..99bc1f7 100644 --- a/sknw/sknw.py +++ b/sknw/sknw.py @@ -135,7 +135,7 @@ def mark_node(ske): mark(buf, nbs) return buf -def build_sknw(ske, buf_size=131072, multi=False, iso=True, ring=True, full=True): +def build_sknw(ske, multi=False, iso=True, ring=True, full=True, buf_size=131072): buf = np.pad(ske, (1,1), mode='constant').astype(np.int64) nbs = neighbors(buf.shape) acc = np.cumprod((1,)+buf.shape[::-1][:-1])[::-1]