Skip to content

Commit db57c8e

Browse files
committed
docs: add todays status update presentation
1 parent 8fe32f4 commit db57c8e

2 files changed

Lines changed: 256 additions & 0 deletions

File tree

docs/update_06_23.pdf

90.9 KB
Binary file not shown.

docs/update_06_23.typ

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#set page(
2+
width: 28.8cm,
3+
height: 16.2cm,
4+
margin: (top: 1.4cm, bottom: 1cm, left: 1.8cm, right: 1.8cm),
5+
fill: white,
6+
numbering: "1",
7+
number-align: right,
8+
)
9+
10+
#set text(font: "New Computer Modern", size: 16pt)
11+
#set par(justify: true, leading: 0.65em)
12+
13+
#let accent = rgb("#1d4ed8")
14+
#let accent-light = rgb("#eff6ff")
15+
#let accent-mid = rgb("#93c5fd")
16+
#let muted = rgb("#6b7280")
17+
#let dark = rgb("#111827")
18+
#let green-bg = rgb("#f0fdf4")
19+
#let green-border = rgb("#bbf7d0")
20+
#let green-text = rgb("#166534")
21+
22+
#let slide(title, body) = {
23+
pagebreak()
24+
block(
25+
width: 100%,
26+
inset: (top: 8pt, bottom: 10pt, left: 0pt, right: 0pt),
27+
stroke: (bottom: 2.5pt + accent),
28+
)[
29+
#text(size: 24pt, fill: accent, weight: "bold")[#title]
30+
]
31+
v(0.5cm)
32+
body
33+
}
34+
35+
#let highlight(body) = {
36+
block(
37+
width: 100%,
38+
fill: accent-light,
39+
inset: 14pt,
40+
radius: 6pt,
41+
stroke: 1pt + accent-mid,
42+
)[
43+
#body
44+
]
45+
}
46+
47+
#let proofbox(body) = {
48+
block(
49+
width: 100%,
50+
fill: green-bg,
51+
inset: 14pt,
52+
radius: 6pt,
53+
stroke: 1pt + green-border,
54+
)[
55+
#body
56+
]
57+
}
58+
59+
#let color-cell(c, label) = {
60+
block(
61+
width: 1.2em,
62+
height: 1.2em,
63+
fill: c,
64+
inset: 0pt,
65+
align(center + horizon, text(size: 0.55em, weight: "bold", fill: if label == "D" { black } else { white }, label)),
66+
)
67+
}
68+
69+
#let color-row(colors, labels, sz: 1.2em) = {
70+
let cells = ()
71+
for i in range(colors.len()) {
72+
cells.push(block(width: sz, height: sz, fill: colors.at(i), inset: 0pt))
73+
}
74+
grid(columns: (sz,) * colors.len(), rows: (sz,), gutter: 0pt, ..cells)
75+
}
76+
77+
#align(center + horizon)[
78+
#block(width: 80%)[
79+
#align(center)[
80+
#text(size: 34pt, fill: accent, weight: "bold")[
81+
VesSkel\
82+
]
83+
#v(1.0cm)
84+
#text(size: 20pt, fill: dark)[
85+
Vessel Skeletonization and Graph-Based\
86+
Phenotype Analysis in Retinal Fundus Images
87+
]
88+
#v(1.2cm)
89+
#line(length: 40%, stroke: 1.5pt + accent)
90+
#v(0.8cm)
91+
#text(size: 16pt, fill: muted)[
92+
Simon Wittmann
93+
94+
Supervisor: Anna Möller
95+
]
96+
#v(0.3cm)
97+
#text(size: 14pt, fill: muted)[
98+
23. Juni 2026
99+
]
100+
]
101+
]
102+
]
103+
104+
#slide("Implementation Progress")[
105+
#v(-0.3cm)
106+
+ preprocessing: binary closing & hole filling
107+
+ new features & updated Feature Comparison Table
108+
+ 3D thinning performance (#sym.arrow parallel scanning, epoch removal tracking)
109+
+ benchmark results (2D + 3D vs skimage & VesselVio)
110+
+ nicer CLI UX (shorter subcommands, worker feedback)
111+
+ paper draft started
112+
+ prediction notebook refactored
113+
]
114+
115+
#slide("Preprocessing: Binary Closing & Hole Filling")[
116+
*Binary closing* bridges small gaps in segmented vessels before thinning
117+
118+
*Hole filling* fills enclosed background regions inside vessels
119+
120+
#v(0.3cm)
121+
#table(
122+
columns: (auto, auto, 1fr),
123+
stroke: 0.5pt + rgb("#e5e7eb"),
124+
inset: 7pt,
125+
fill: (x, y) => if y == 0 { accent-light } else if calc.odd(y) { rgb("#f9fafb") },
126+
[*Config Key*], [*Default*], [*Description*],
127+
[`closing_iterations`], [`0`], [binary closing iterations (0 = off)],
128+
[`fill_holes`], [`false`], [fill enclosed background regions],
129+
[`max_hole_size`], [`0`], [max filled hole area (0 = unlimited)],
130+
[`show_preprocessed`], [`false`], [show preprocessed binary in napari],
131+
)
132+
133+
#v(0.3cm)
134+
#highlight[
135+
Supporting tests: in `test_preprocessing.py` covering closing, hole filling, size thresholding.
136+
]
137+
]
138+
139+
#slide("New Features")[
140+
*Key additions since last update:*
141+
+ Mean segment volume ($V = pi sum r_i^2$ for each segment)
142+
+ Mean segment surface area ($A = 2 pi sum r_i$)
143+
+ Added to `per_segment_radii` output and summary features
144+
+ Used in downstream classification
145+
146+
#v(0.3cm)
147+
*Feature Table Update:*
148+
+ Re-mapped which features are feasible (many marked "nope")
149+
+ only TODO left: per-node metrics
150+
151+
SHOW TABLE
152+
]
153+
154+
#slide("3D Thinning Performance Improvements")[
155+
#columns(2, gutter: 1.5em)[
156+
*Epoch-Based Removal Tracking*
157+
158+
Problem: vanilla Lee94 re-checks simplicity (DFS on 26-neighbor graph) for *every* candidate before removal
159+
160+
Insight: `_mark_removable_candidates` already verified all candidates before any removals in this batch. If none of a candidate's 26 neighbors have been removed yet, the old verdict is still valid - skip the DFS.
161+
162+
163+
#colbreak()
164+
Mechanism:
165+
+ `epoch` increments per batch; stamped at each removed voxel
166+
+ Scan 26 neighbors for stamp == current epoch (cheap, 26 int comparisons)
167+
+ If no neighbor stamped → remove immediately
168+
+ If neighbor stamped → re-run DFS to verify still simple
169+
+ Never reset; monotonically increasing epoch makes old stamps invisible
170+
]
171+
]
172+
173+
#slide("Benchmark Results")[
174+
#v(-0.3cm)
175+
#columns(2, gutter: 1.5em)[
176+
177+
*2D (HRF dataset, 45 images)*
178+
#table(
179+
columns: (auto, auto, auto),
180+
stroke: 0.5pt + rgb("#e5e7eb"),
181+
inset: 5pt,
182+
fill: (x, y) => if y == 0 { accent-light } else if calc.odd(y) { rgb("#f9fafb") },
183+
[], [*Mean (s)*], [*vs vesskel*],
184+
[vesskel], [0.084], [-],
185+
[skimage Zhang], [0.157], [1.87x slower],
186+
[skimage Lee], [0.438], [5.21x slower],
187+
[VesselVio Lee], [0.796], [9.46x slower],
188+
)
189+
190+
#colbreak()
191+
*3D (vessap test volume)*
192+
#table(
193+
columns: (auto, auto, auto),
194+
stroke: 0.5pt + rgb("#e5e7eb"),
195+
inset: 5pt,
196+
fill: (x, y) => if y == 0 { accent-light } else if calc.odd(y) { rgb("#f9fafb") },
197+
[], [*Mean (s)*], [*vs vesskel*],
198+
[vesskel], [0.730], [-],
199+
[skimage Lee], [1.024], [1.4x slower],
200+
[VesselVio Lee], [0.804], [1.10x slower],
201+
)
202+
]
203+
204+
*Key Takeaways*
205+
#highlight[
206+
+ 2D is highly optimized via LUT-based simplicity check
207+
+ 3D competitive with skimage and VesselVio
208+
+ Pure Python + Numba - no Cython, no compiled extensions
209+
]
210+
]
211+
212+
#slide("CLI Improvements")[
213+
*Shorter Subcommands*
214+
- `vesskel init config.json` instead of `vesskel config-init --out config.json`
215+
- `vesskel validate config.json` instead of `vesskel validate-config --config config.json`
216+
217+
*Instant Worker Feedback*
218+
- `vesskel run (-j N)` now prints: `Spawning N worker processes...`
219+
220+
*Default Config Changed*
221+
- `branches`, `branch_text`, `summary` now default `false`
222+
]
223+
224+
#slide("Paper Draft")[
225+
*First Table of Content draft started*
226+
227+
#v(0.3cm)
228+
*also: Prediction Notebook Refactored*
229+
+ `analysis/HRF_Prediction.ipynb` restructured
230+
+ Pipeline runs within the notebook
231+
+ Cleaner separation between analysis and reporting
232+
+ No notable Performance improvements, even though cleanup ran and more features available #sym.arrow more investigation needed
233+
]
234+
235+
#slide("Summary & Next Steps")[
236+
#columns(2, gutter: 1.5em)[
237+
*What I did:*
238+
+ Preprocessing (closing, hole filling)
239+
+ Per-segment volume & surface area
240+
+ 3D thinning speedups (parallel scanning, epoch tracking)
241+
+ Benchmark scripts (2D + 3D)
242+
+ CLI polish (shorter cmds, worker feedback)
243+
+ Table of Content draft
244+
+ Feature table finalized
245+
+ Prediction notebook refactored
246+
247+
#colbreak()
248+
249+
*Next steps:*
250+
+ per_node features finalization
251+
+ finalize Phenotype Prediction
252+
+ nice documentation
253+
+ Write the paper
254+
+ (optional) more tests
255+
]
256+
]

0 commit comments

Comments
 (0)