Skip to content

Commit 10b590e

Browse files
author
yxdragon
committed
simplize skeleton
1 parent 8cf9fca commit 10b590e

File tree

5 files changed

+143
-12
lines changed

5 files changed

+143
-12
lines changed

imagepy/menus/Analysis/Skeleton Network/graph_plgs.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from imagepy.core.engine import Filter, Simple
22
from imagepy.ipyalg.graph import sknw
33
import numpy as np
4+
from numpy.linalg import norm
45
import networkx as nx, wx
56
from imagepy import IPy
67
from numba import jit
@@ -104,10 +105,11 @@ def load(self, ips):
104105
if not isinstance(ips.data, nx.MultiGraph):
105106
IPy.alert("Please build graph!");
106107
return False;
108+
self.buf = ips.data
107109
return True;
108110

109111
def run(self, ips, snap, img, para = None):
110-
g = ips.data.copy()
112+
g = ips.data = self.buf.copy()
111113
k, unit = ips.unit
112114
while True:
113115
rm = []
@@ -121,9 +123,15 @@ def run(self, ips, snap, img, para = None):
121123
img *= 0
122124
sknw.draw_graph(img, g)
123125

126+
def cancel(self, ips):
127+
if 'auto_snap' in self.note:
128+
ips.swap()
129+
ips.update()
130+
ips.data = self.buf
131+
124132
class RemoveIsolate(Filter):
125133
title = 'Remove Isolate Node'
126-
note = ['all']
134+
note = ['all', 'not_slice', 'not_channel', 'auto_snap']
127135

128136
def load(self, ips):
129137
if not isinstance(ips.data, nx.MultiGraph):
@@ -137,6 +145,36 @@ def run(self, ips, snap, img, para = None):
137145
if len(g[n])==0: g.remove_node(n)
138146
img *= 0
139147
sknw.draw_graph(img, g)
148+
ips.mark = Mark(ips.data)
149+
150+
class Remove2Node(Simple):
151+
title = 'Remove 2Path Node'
152+
note = ['all']
153+
154+
def load(self, ips):
155+
if not isinstance(ips.data, nx.MultiGraph):
156+
IPy.alert("Please build graph!");
157+
return False;
158+
return True;
159+
160+
def run(self, ips, imgs, para = None):
161+
g = ips.data
162+
for n in g.nodes():
163+
if len(g[n])!=2 or n in g[n]: continue
164+
(k1, e1), (k2, e2) = g[n].items()
165+
if isinstance(g, nx.MultiGraph):
166+
if len(e1)!=1 or len(e2)!=1: continue
167+
e1, e2 = e1[0], e2[0]
168+
l1, l2 = e1['pts'], e2['pts']
169+
d1 = norm(l1[0]-g.node[n]['o']) > norm(l1[-1]-g.node[n]['o'])
170+
d2 = norm(l2[0]-g.node[n]['o']) < norm(l2[-1]-g.node[n]['o'])
171+
pts = np.vstack((l1[::[-1,1][d1]], l2[::[-1,1][d2]]))
172+
l = np.linalg.norm(pts[1:]-pts[:-1], axis=1).sum()
173+
g.remove_node(n)
174+
g.add_edge(k1, k2, pts=pts, weight=l)
175+
ips.img[:] = 0
176+
sknw.draw_graph(ips.img, g)
177+
ips.mark = Mark(ips.data)
140178

141179
@jit
142180
def floodfill(img, x, y):
@@ -204,4 +242,4 @@ def run(self, ips, imgs, para = None):
204242

205243

206244

207-
plgs = [BuildGraph, Statistic, Sumerise, '-', RemoveIsolate, CutBranch, CutROI, '-', ShortestPath]
245+
plgs = [BuildGraph, Statistic, Sumerise, '-', RemoveIsolate, Remove2Node, CutBranch, CutROI, '-', ShortestPath]

imagepy/menus/Kit3D/Analysis 3D/regionprops3d_plgs.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class RegionLabel(Simple):
1616

1717
#process
1818
def run(self, ips, imgs, para = None):
19-
buf = imgs.astype(np.uint16)
19+
buf = imgs.astype(np.int32)
2020
strc = generate_binary_structure(3, 1 if para['con']=='4-connect' else 2)
2121
label(imgs, strc, output=buf)
2222
IPy.show_img(buf, ips.title+'-label')
@@ -27,14 +27,15 @@ class RegionCounter(Simple):
2727
note = ['8-bit', '16-bit', 'stack3d']
2828

2929
para = {'con':'8-connect', 'center':True, 'extent':False, 'vol':True,
30-
'ed':False, 'holes':False, 'fa':False}
30+
'ed':False, 'holes':False, 'fa':False, 'cov':False}
3131

3232
view = [(list, 'con', ['4-connect', '8-connect'], str, 'conection', 'pix'),
3333
('lab', None, '========= indecate ========='),
3434
(bool, 'center', 'center'),
3535
(bool, 'vol', 'volume'),
3636
(bool, 'extent', 'extent'),
37-
(bool, 'ed', 'equivalent diameter')]
37+
(bool, 'ed', 'equivalent diameter'),
38+
(bool, 'cov', 'eigen values')]
3839

3940
#process
4041
def run(self, ips, imgs, para = None):
@@ -46,10 +47,10 @@ def run(self, ips, imgs, para = None):
4647
if para['extent']:titles.extend(['Min-Z','Min-Y','Min-X','Max-Z','Max-Y','Max-X'])
4748
if para['ed']:titles.extend(['Diameter'])
4849
if para['fa']:titles.extend(['FilledArea'])
50+
if para['cov']:titles.extend(['Axis1', 'Axis2', 'Axis3'])
4951

50-
buf = imgs.astype(np.uint32)
5152
strc = generate_binary_structure(3, 1 if para['con']=='4-connect' else 2)
52-
label(imgs, strc, output=buf)
53+
buf, n = label(imgs, strc, output=np.uint32)
5354
ls = regionprops(buf)
5455

5556
dt = [range(len(ls))]
@@ -68,6 +69,10 @@ def run(self, ips, imgs, para = None):
6869
dt.append([round(i.equivalent_diameter*k, 1) for i in ls])
6970
if para['fa']:
7071
dt.append([i.filled_area*k**3 for i in ls])
72+
if para['cov']:
73+
ites = np.array([i.inertia_tensor_eigvals for i in ls])
74+
rst = np.sqrt(np.clip(ites.sum(axis=1)//2-ites.T, 0, 1e10)) * 4
75+
for i in rst[::-1]: dt.append(np.abs(i))
7176
IPy.show_table(pd.DataFrame(list(zip(*dt)), columns=titles), ips.title+'-region')
7277

7378
# center, area, l, extent, cov

imagepy/menus/Kit3D/Network 3D/toolkit3d_plgs.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,4 +283,32 @@ def run(self, ips, imgs, para = None):
283283
imgs *= 0
284284
sknw.draw_graph(imgs, g)
285285

286-
plgs = [Skeleton3D, BuildGraph, '-', CutBranch, RemoveIsolate, '-', Statistic, Sumerise, '-', Show3DGraph, Show3DGraphR]
286+
class Remove2Node(Simple):
287+
title = 'Remove 2Path Node 3D'
288+
note = ['all']
289+
290+
def load(self, ips):
291+
if not isinstance(ips.data, nx.MultiGraph):
292+
IPy.alert("Please build graph!");
293+
return False;
294+
return True;
295+
296+
def run(self, ips, imgs, para = None):
297+
g = ips.data
298+
for n in g.nodes():
299+
if len(g[n])!=2 or n in g[n]: continue
300+
(k1, e1), (k2, e2) = g[n].items()
301+
if isinstance(g, nx.MultiGraph):
302+
if len(e1)!=1 or len(e2)!=1: continue
303+
e1, e2 = e1[0], e2[0]
304+
l1, l2 = e1['pts'], e2['pts']
305+
d1 = norm(l1[0]-g.node[n]['o']) > norm(l1[-1]-g.node[n]['o'])
306+
d2 = norm(l2[0]-g.node[n]['o']) < norm(l2[-1]-g.node[n]['o'])
307+
pts = np.vstack((l1[::[-1,1][d1]], l2[::[-1,1][d2]]))
308+
l = np.linalg.norm(pts[1:]-pts[:-1], axis=1).sum()
309+
g.remove_node(n)
310+
g.add_edge(k1, k2, pts=pts, weight=l)
311+
imgs *= 0
312+
sknw.draw_graph(imgs, g)
313+
314+
plgs = [Skeleton3D, BuildGraph, '-', CutBranch, RemoveIsolate, Remove2Node, '-', Statistic, Sumerise, '-', Show3DGraph, Show3DGraphR]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import numpy as np
2+
from imagepy import IPy
3+
from imagepy.core import ImagePlus
4+
from imagepy.core.engine import Free, Tool
5+
from scipy.ndimage import label
6+
from scipy.signal import convolve2d
7+
8+
def generate(scr, size):
9+
row, col = scr.shape
10+
arr = np.ones((row*(size)+1, col*(size)+1), dtype=np.uint8)
11+
xs, ys = np.where(arr[:-1,:-1])
12+
arr[xs, ys] = scr[xs//size, ys//size]
13+
arr[::size,:] = 2; arr[:,::size] = 2
14+
return np.array([128,255,0], dtype=np.uint8)[arr]
15+
16+
def getscr(arr, size): return arr[1::size, 1::size]//255
17+
18+
def run(scr):
19+
pad = np.pad(scr, 1, 'constant')
20+
core = np.array([[1,1,1],[1,9,1],[1,1,1]])
21+
cov = convolve2d(pad, core, 'valid')
22+
lut = [0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0]
23+
return np.array(lut, dtype=np.uint8)[cov.astype(np.uint8)]
24+
25+
class Painter(Tool):
26+
def __init__(self, size): self.size = size
27+
title = 'Life Painter'
28+
29+
def mouse_down(self, ips, x, y, btn, **key):
30+
if btn == 1:
31+
r, c = int(y), int(x)
32+
if r<0 or r>ips.img.shape[0]: return
33+
if c<0 or c>ips.img.shape[1]: return
34+
if ips.img[r,c] == 0: return
35+
lab, n = label(ips.img>0)
36+
ips.img[lab==lab[r,c]] = (128,255)[ips.img[r,c]!=255]
37+
ips.update()
38+
if btn == 3:
39+
img = getscr(ips.img, self.size)
40+
for i in range(len(ips.imgs)):
41+
ips.imgs[i][:] = generate(img, self.size)
42+
img = run(img)
43+
IPy.alert('Complete!')
44+
45+
class Plugin(Free):
46+
title = 'Game Of Life'
47+
para = {'name':'Game01','width':15, 'height':15, 'size':30,'slice':30}
48+
view = [(str, 'name', 'name', ''),
49+
(int, 'width', (1,2048), 0, 'width', 'pix'),
50+
(int, 'height', (1,2048), 0, 'height', 'pix'),
51+
(int, 'size', (10, 50), 0, 'size', ''),
52+
(int, 'slice', (1,100), 0, 'slice', '')]
53+
54+
#process
55+
def run(self, para = None):
56+
first = generate(np.zeros((para['height'], para['width'])), para['size'])
57+
imgs = [first.copy() for i in range(para['slice'])]
58+
ips = ImagePlus(imgs, para['name'])
59+
ips.tool = Painter(para['size'])
60+
IPy.show_ips(ips)

imagepy/tools/Standard/painter_tol.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ def __init__(self):
2020

2121
def mouse_down(self, ips, x, y, btn, **key):
2222
self.sta = 1
23-
self.paint.set_curpt(x,y)
23+
self.paint.set_curpt(int(x), int(y))
2424
ips.snapshot()
2525

2626
def mouse_up(self, ips, x, y, btn, **key):
27-
self.paint.lineto(ips.img,x,y, self.para['width'])
27+
self.paint.lineto(ips.img, int(x), int(y), self.para['width'])
2828
ips.update()
2929
self.sta = 0
3030

3131
def mouse_move(self, ips, x, y, btn, **key):
3232
if self.sta==0:return
33-
self.paint.lineto(ips.img,x,y, self.para['width'])
33+
self.paint.lineto(ips.img, int(x), int(y), self.para['width'])
3434
ips.update()
3535

3636
def mouse_wheel(self, ips, x, y, d, **key):pass

0 commit comments

Comments
 (0)