{
  "id": 679241,
  "title": "9th Place Solution SUPER-CONSERVATIVE(0.623->0.616)",
  "url": "/competitions/vesuvius-challenge-surface-detection/discussion/679241",
  "author_name": "tingyi",
  "post_date": "2026-02-28T04:24:45.950000",
  "votes": 24,
  "comment_count": 14,
  "views": 0,
  "content": "<blockquote>\n  <p><strong>This is my first time participating in a competition, so please bear with me if my solution write-up isn't perfect.</strong></p>\n</blockquote>\n<p>Thank you to the organizers for hosting a competition where we could fully unleash our creativity. I would also like to thank the Competition Grandmasters in the discussion forums for enthusiastically sharing their solutions. Some of my methods were adapted directly from the discussions. Although some of them ultimately didn't work out, I still learned a lot of highly valuable things.</p>\n<hr>\n<h2>Equipment requirements</h2>\n<ul>\n<li>We used 9800X3D + 64GB RAM + RTX 5090 (by TINGYI).</li>\n</ul>\n<hr>\n<h2>Model Training</h2>\n<ul>\n<li>Trained the baseline model (<code>nnUNetTrainerMedialSurfaceRecall</code>) provided by the organizers using YOLO26's MUSGD.</li>\n<li><strong>Patch Size</strong> was set to <strong>192</strong>. Increasing it to 224 or 256 improved the Dice score but caused the Topo score to drop.</li>\n<li>Used <strong>Group Norm</strong> (group = 32) and <strong>GELU</strong> (not necessarily helpful; increases VRAM usage).</li>\n</ul>\n<hr>\n<h2>Inference</h2>\n<ul>\n<li>Single Fold + TTA + tile size 0.4</li>\n</ul>\n<hr>\n<h2>Post-processing</h2>\n<h3>1. Remove Small 6-Connected Components (&lt; 5000)</h3>\n<table>\n<thead>\n<tr>\n<th>Connectivity</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>None</strong></td>\n<td>0.5968</td>\n<td>0.8800</td>\n<td>0.5680</td>\n<td>0.2998</td>\n</tr>\n<tr>\n<td><strong>6</strong></td>\n<td>0.6096</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3426</td>\n</tr>\n<tr>\n<td><strong>18</strong></td>\n<td>0.6029</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3202</td>\n</tr>\n<tr>\n<td><strong>26</strong></td>\n<td>0.6027</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3196</td>\n</tr>\n</tbody>\n</table>\n<h3>2. Line Normalization</h3>\n<p>To reduce b1 errors caused by thin sheet predictions, a line normalization step is applied:</p>\n<ol>\n<li>For each 2D slice along the Z-axis, apply <strong>skeletonize</strong> to extract the centerline of thin paper structures.</li>\n<li>Reconstruct via <strong>EDT</strong>, expanding the skeleton back to a uniform thickness of radius <code>r=1.5</code>.</li>\n<li>The volume is split into <strong>8×160×160×160 blocks</strong>; pixels within border ≤ 8 of each block are left untouched to avoid artifacts near ignore mask boundaries.</li>\n<li>The reconstructed result is <strong>OR-ed</strong> back into the original prediction (additive, not replacement).</li>\n</ol>\n<p>This ensures extremely thin paper sheets are thickened without removing any existing predictions, reducing topological breaks along fragile thin regions.</p>\n<table>\n<thead>\n<tr>\n<th>Radius</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Only &lt;5000</td>\n<td>0.6096</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3426</td>\n</tr>\n<tr>\n<td>1px</td>\n<td>0.6132</td>\n<td>0.8800</td>\n<td>0.5682</td>\n<td>0.3545</td>\n</tr>\n<tr>\n<td>1.5px</td>\n<td>0.6132</td>\n<td>0.8801</td>\n<td>0.5669</td>\n<td>0.3558</td>\n</tr>\n<tr>\n<td>2px</td>\n<td>0.6085</td>\n<td>0.8769</td>\n<td>0.5637</td>\n<td>0.3475</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h3>3. Gap Filling &amp; Diagonal Repair</h3>\n<p>Thin paper structures often have small holes or diagonal breaks in the prediction mask. A two-stage morphological repair is applied — and critically, <strong>the entire process is run in a loop</strong>. Experiments show a <strong>linear improvement in score from iteration 1 through iteration 5</strong>, making repeated application strongly beneficial.</p>\n<p><strong>Stage 1 — Gap Filling</strong></p>\n<p>The key idea: <em>\"if both sides of a gap are solid, fill the gap in between.\"</em></p>\n<ul>\n<li>For each axis, precompute a <strong>support map</strong> — a pixel is a reliable anchor only if it is already predicted positive and has at least <code>min_neighbors</code> neighbors in the same 2D plane.</li>\n<li>Scan across each axis: if two anchor pixels are separated by a gap of ≤ <code>max_gap</code> voxels, the voxels in between are OR-ed to 1.</li>\n<li>This reliably bridges small breaks without over-filling, since both endpoints must independently pass the support check.</li>\n</ul>\n<p><strong>Stage 2 — Diagonal Fill</strong></p>\n<p>Axis-aligned filling misses diagonal breaks (e.g., a sheet running diagonally in XZ or YZ). This step applies the same sandwich logic along diagonal directions using small <strong>3×3×3 kernels</strong> with two opposing off-center taps. If both diagonal neighbors of an empty voxel are positive, the voxel is filled.</p>\n<blockquote>\n  <p>📈 <strong>Iterative Gain:</strong> Each additional pass of Gap Filling + Diagonal Fill continues to close newly exposed breaks revealed by previous iterations, yielding consistent linear score gains up to at least 5 iterations.</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th>Iteration</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RM&lt;5000 + LN</td>\n<td>0.6132</td>\n<td>0.8801</td>\n<td>0.5669</td>\n<td>0.3558</td>\n</tr>\n<tr>\n<td>1</td>\n<td>0.6199</td>\n<td>0.8796</td>\n<td>0.5672</td>\n<td>0.3784</td>\n</tr>\n<tr>\n<td>2</td>\n<td>0.6239</td>\n<td>0.8795</td>\n<td>0.5672</td>\n<td>0.3918</td>\n</tr>\n<tr>\n<td>3</td>\n<td>0.6248</td>\n<td>0.8794</td>\n<td>0.5673</td>\n<td>0.3950</td>\n</tr>\n<tr>\n<td>4</td>\n<td>0.6258</td>\n<td>0.8793</td>\n<td>0.5673</td>\n<td>0.3983</td>\n</tr>\n<tr>\n<td>5</td>\n<td>0.6264</td>\n<td>0.8792</td>\n<td>0.5673</td>\n<td>0.4005</td>\n</tr>\n<tr>\n<td>6</td>\n<td>0.6264</td>\n<td>0.8791</td>\n<td>0.5673</td>\n<td>0.4004</td>\n</tr>\n</tbody>\n</table>\n<h3>4. Gaussian Filtering</h3>\n<p>Apply a Gaussian filter (<code>sigma=1</code>) to the boolean mask, then threshold back to <code>bool</code> via <code>&gt; 0.5</code>. This trick turned out to be surprisingly effective, though the exact mechanism is not entirely clear.</p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RM&lt;5000 + LN+SW</td>\n<td>0.6264</td>\n<td>0.8792</td>\n<td>0.5673</td>\n<td>0.4005</td>\n</tr>\n<tr>\n<td>RM&lt;5000 + LN+SW+GU</td>\n<td>0.6323</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4232</td>\n</tr>\n</tbody>\n</table>\n<h3>5. Second Removal of Small 6-Connected Components (&lt; 5000)</h3>\n<h3>6. Block-wise Small Component Removal</h3>\n<p>Divide into 8 blocks following the TOPO algorithm, then remove 6-connected components &lt; 10.</p>\n<h3>7. 2×2 Diagonal Bridging</h3>\n<p>Proposed as a targeted response to <a href=\"https://www.kaggle.com/competitions/vesuvius-challenge-surface-detection/discussion/672447\" target=\"_blank\">this discussion</a>.</p>\n<p>The method specifically detects the pattern shown below and fills the entire area if detected. It is highly effective and carries almost zero risk of dropping the score for any given case.<br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2Fc9c5ac10149133ffb22cfa1818cc2b7f%2F2026-02-28%20173905.png?generation=1772272259038976&amp;alt=media\"></p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RM&lt;5000 + LN+SW+GU</td>\n<td>0.6323</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4232</td>\n</tr>\n<tr>\n<td>RM&lt;5000 + LN+SW+GU+2x2DG</td>\n<td>0.6337</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4277</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>Unused Post-processing Methods</h2>\n<h3>1. Separating Touching Objects / De-adhesion</h3>\n<p><em>(Based on <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a>'s killer ant method. Hard to see score improvements from this component, but it remains critical for topological correctness.)</em></p>\n<p>To balance computational efficiency and segmentation accuracy, the algorithm uses a <strong>block-wise (8-slice block) iterative mechanism</strong> with six core steps.</p>\n<h4>Step 1 — 2D Ray-Casting Collision Detection</h4>\n<p>Within 2D slices along the Z-axis, <strong>PCA</strong> computes the local normal direction at each object's edge. Virtual rays are cast along these normal vectors. If a ray passes through background and collides with another high-confidence prediction, the location is flagged as a <strong>potential adhesion point</strong>.</p>\n<h4>Step 2 — High-Confidence Target Voting</h4>\n<p>To handle simultaneous multi-object adhesion:</p>\n<ul>\n<li>All collision pairs are aggregated globally.</li>\n<li>The two <strong>high-confidence (&gt; 0.9) predicted 6-connected components</strong> most frequently co-occurring in 3D space are identified.</li>\n<li>The pair with the <strong>highest vote count</strong> is selected as the sole cutting target for the current iteration.</li>\n<li>Remaining adhesions are deferred to subsequent iterations.</li>\n</ul>\n<h4>Step 3 — Shortest Path &amp; Midpoint Sampling</h4>\n<p>Once the adhesion pair is established:</p>\n<ul>\n<li>The shortest path between the ray's start and collision point is computed.</li>\n<li>The <strong>midpoint</strong> of this path is designated as the adhesion boundary.</li>\n<li>A <strong>sparse sampling strategy</strong> selects only <strong>3 representative collision points</strong>, dramatically improving throughput.</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F48433614f38811f5ed3e9bc860e9d6e9%2F2026-02-28%20135156.png?generation=1772272283710430&amp;alt=media\" alt=\"\">\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F479a8cc301bb3b76ca5a32e762b95565%2F.png?generation=1772272300688802&amp;alt=media\" alt=\"\"></p>\n<h4>Step 4 — Geodesic Basin &amp; Marker-Controlled Watershed</h4>\n<p>Using the 3 midpoints from Step 3 as seeds:</p>\n<ul>\n<li><strong>BFS</strong> computes the 3D geodesic distance to adjacent connected components.</li>\n<li>The <strong>negative</strong> of these distances forms the topographic basin for the watershed.</li>\n<li>The two high-confidence components from Step 2 serve as <strong>initial markers</strong>, guiding watershed flows to converge within the basin and precisely delineating the <strong>3D separation plane</strong>.</li>\n</ul>\n<h4>Step 5 — Boundary Cleanup &amp; Gap Generation</h4>\n<ul>\n<li><strong>Morphological dilation</strong> is applied around the identified segmentation interface.</li>\n<li>A physical gap of <strong>~2 pixels wide</strong> is forcibly removed to guarantee complete disconnection.</li>\n</ul>\n<h4>Step 6 — Iterative Processing</h4>\n<p>Steps 1–5 repeat until either:</p>\n<ul>\n<li>No new valid cutting points are found, <strong>or</strong></li>\n<li>The pre-set <strong>maximum iteration count</strong> is reached.</li>\n</ul>\n<hr>\n<h4>⚠️ Methodological Limitations</h4>\n<p><strong>Limitation 1: Seed Adhesion Dependency</strong></p>\n<p>This algorithm relies heavily on <code>high_conf_labels</code> from the neural network as watershed anchor points. If the model's high-confidence predictions are <strong>already merged</strong> (i.e., two distinct objects predicted as a single connected component), the Step 2 voting mechanism cannot distinguish them — rendering the algorithm <strong>ineffective in that region</strong>.</p>\n<p><strong>Limitation 2: Hole Generation at Boundaries</strong></p>\n<p>The fixed ~2-pixel removal in Step 5 is a blunt instrument. While it reliably severs the adhesion, the rigid width is not adaptive to local structure thickness. In practice, this hardcoded gap can introduce more holes than it resolves.</p>\n<hr>\n<h3>2. 2D Slice Line Interpolation / Completion</h3>\n<h4>Step 1 — Skeletonization</h4>\n<p>All 2D slices (both Z-axis and Y-axis) are skeletonized before processing. This ensures they can be jointly handled during the later <strong>Line Norm</strong> stage.</p>\n<h4>Step 2 — Endpoint Detection</h4>\n<p>Using a <strong>3×3 kernel</strong>, we scan each skeletonized slice. A pixel is classified as an <strong>endpoint</strong> if its value is <code>1</code> and exactly <strong>one</strong> of its eight neighbors is also <code>1</code>.</p>\n<h4>Step 3 — Tangent Estimation via PCA + DFS</h4>\n<p>For each detected endpoint, we perform <strong>DFS backtracking</strong> along the skeleton to collect its local neighboring pixels, then apply <strong>PCA</strong> on these points to estimate the <strong>tangent direction</strong> — determining the orientation the endpoint is pointing toward.</p>\n<h4>Step 4 — Endpoint Pairing</h4>\n<p>After collecting all endpoints and their PCA-estimated tangent angles, we perform <strong>endpoint pairing</strong>. A pair is considered valid if both of the following conditions are met (thresholds are tunable):</p>\n<ul>\n<li>The angle between the connecting line and both tangent directions is <strong>&lt; 45°</strong></li>\n<li>The <strong>Euclidean distance</strong> between the two endpoints is <strong>≤ 40 pixels</strong></li>\n</ul>\n<h4>Step 5 — Skeleton-level Connection</h4>\n<p>For each valid endpoint pair, we directly <strong>draw a line on the skeleton</strong> to bridge the gap between the two endpoints.</p>\n<h4>Step 6 — Line Norm</h4>\n<p>Once all connections are completed, the repaired skeleton is passed into the <strong>Line Norm</strong> pipeline. This process is applied independently on both the <strong>Z-axis</strong> and <strong>Y-axis</strong> slices.</p>\n<p>⚠️ Methodological Limitations</p>\n<p><strong>Limitation : Randomness</strong></p>\n<ul>\n<li>In certain cases, when model predictions are already poor, applying this patch will make matters worse. (PB's situation)</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F47248887941907be3509938872e50c29%2Fimage.png?generation=1772280595398226&amp;alt=media\" alt=\"\"></p>\n<p>Due to the negative feedback from PB, we abandoned many CV-boosting methods until after the competition ended, when we uploaded the highest CV version for testing.</p>\n<table>\n<thead>\n<tr>\n<th>CV</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>RM&lt;5000 + LN+SW(kernel=3)+GU+2x2DG</strong></td>\n<td>0.6337</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4277</td>\n<td><strong>Competition Submission Version</strong></td>\n</tr>\n<tr>\n<td><strong>RM&lt;5000 + LN+SW(kernel=5)+GU+2x2DG+ZLine+YLine</strong></td>\n<td>0.6391</td>\n<td>0.8757</td>\n<td>0.5672</td>\n<td>0.4468</td>\n<td><strong>Submit the version after the competition</strong></td>\n</tr>\n</tbody>\n</table>",
  "messages": [
    {
      "id": 3415016,
      "postDate": "2026-02-28T04:24:45.950Z",
      "content": "<blockquote>\n  <p><strong>This is my first time participating in a competition, so please bear with me if my solution write-up isn't perfect.</strong></p>\n</blockquote>\n<p>Thank you to the organizers for hosting a competition where we could fully unleash our creativity. I would also like to thank the Competition Grandmasters in the discussion forums for enthusiastically sharing their solutions. Some of my methods were adapted directly from the discussions. Although some of them ultimately didn't work out, I still learned a lot of highly valuable things.</p>\n<hr>\n<h2>Equipment requirements</h2>\n<ul>\n<li>We used 9800X3D + 64GB RAM + RTX 5090 (by TINGYI).</li>\n</ul>\n<hr>\n<h2>Model Training</h2>\n<ul>\n<li>Trained the baseline model (<code>nnUNetTrainerMedialSurfaceRecall</code>) provided by the organizers using YOLO26's MUSGD.</li>\n<li><strong>Patch Size</strong> was set to <strong>192</strong>. Increasing it to 224 or 256 improved the Dice score but caused the Topo score to drop.</li>\n<li>Used <strong>Group Norm</strong> (group = 32) and <strong>GELU</strong> (not necessarily helpful; increases VRAM usage).</li>\n</ul>\n<hr>\n<h2>Inference</h2>\n<ul>\n<li>Single Fold + TTA + tile size 0.4</li>\n</ul>\n<hr>\n<h2>Post-processing</h2>\n<h3>1. Remove Small 6-Connected Components (&lt; 5000)</h3>\n<table>\n<thead>\n<tr>\n<th>Connectivity</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>None</strong></td>\n<td>0.5968</td>\n<td>0.8800</td>\n<td>0.5680</td>\n<td>0.2998</td>\n</tr>\n<tr>\n<td><strong>6</strong></td>\n<td>0.6096</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3426</td>\n</tr>\n<tr>\n<td><strong>18</strong></td>\n<td>0.6029</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3202</td>\n</tr>\n<tr>\n<td><strong>26</strong></td>\n<td>0.6027</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3196</td>\n</tr>\n</tbody>\n</table>\n<h3>2. Line Normalization</h3>\n<p>To reduce b1 errors caused by thin sheet predictions, a line normalization step is applied:</p>\n<ol>\n<li>For each 2D slice along the Z-axis, apply <strong>skeletonize</strong> to extract the centerline of thin paper structures.</li>\n<li>Reconstruct via <strong>EDT</strong>, expanding the skeleton back to a uniform thickness of radius <code>r=1.5</code>.</li>\n<li>The volume is split into <strong>8×160×160×160 blocks</strong>; pixels within border ≤ 8 of each block are left untouched to avoid artifacts near ignore mask boundaries.</li>\n<li>The reconstructed result is <strong>OR-ed</strong> back into the original prediction (additive, not replacement).</li>\n</ol>\n<p>This ensures extremely thin paper sheets are thickened without removing any existing predictions, reducing topological breaks along fragile thin regions.</p>\n<table>\n<thead>\n<tr>\n<th>Radius</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Only &lt;5000</td>\n<td>0.6096</td>\n<td>0.8799</td>\n<td>0.5682</td>\n<td>0.3426</td>\n</tr>\n<tr>\n<td>1px</td>\n<td>0.6132</td>\n<td>0.8800</td>\n<td>0.5682</td>\n<td>0.3545</td>\n</tr>\n<tr>\n<td>1.5px</td>\n<td>0.6132</td>\n<td>0.8801</td>\n<td>0.5669</td>\n<td>0.3558</td>\n</tr>\n<tr>\n<td>2px</td>\n<td>0.6085</td>\n<td>0.8769</td>\n<td>0.5637</td>\n<td>0.3475</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h3>3. Gap Filling &amp; Diagonal Repair</h3>\n<p>Thin paper structures often have small holes or diagonal breaks in the prediction mask. A two-stage morphological repair is applied — and critically, <strong>the entire process is run in a loop</strong>. Experiments show a <strong>linear improvement in score from iteration 1 through iteration 5</strong>, making repeated application strongly beneficial.</p>\n<p><strong>Stage 1 — Gap Filling</strong></p>\n<p>The key idea: <em>\"if both sides of a gap are solid, fill the gap in between.\"</em></p>\n<ul>\n<li>For each axis, precompute a <strong>support map</strong> — a pixel is a reliable anchor only if it is already predicted positive and has at least <code>min_neighbors</code> neighbors in the same 2D plane.</li>\n<li>Scan across each axis: if two anchor pixels are separated by a gap of ≤ <code>max_gap</code> voxels, the voxels in between are OR-ed to 1.</li>\n<li>This reliably bridges small breaks without over-filling, since both endpoints must independently pass the support check.</li>\n</ul>\n<p><strong>Stage 2 — Diagonal Fill</strong></p>\n<p>Axis-aligned filling misses diagonal breaks (e.g., a sheet running diagonally in XZ or YZ). This step applies the same sandwich logic along diagonal directions using small <strong>3×3×3 kernels</strong> with two opposing off-center taps. If both diagonal neighbors of an empty voxel are positive, the voxel is filled.</p>\n<blockquote>\n  <p>📈 <strong>Iterative Gain:</strong> Each additional pass of Gap Filling + Diagonal Fill continues to close newly exposed breaks revealed by previous iterations, yielding consistent linear score gains up to at least 5 iterations.</p>\n</blockquote>\n<table>\n<thead>\n<tr>\n<th>Iteration</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RM&lt;5000 + LN</td>\n<td>0.6132</td>\n<td>0.8801</td>\n<td>0.5669</td>\n<td>0.3558</td>\n</tr>\n<tr>\n<td>1</td>\n<td>0.6199</td>\n<td>0.8796</td>\n<td>0.5672</td>\n<td>0.3784</td>\n</tr>\n<tr>\n<td>2</td>\n<td>0.6239</td>\n<td>0.8795</td>\n<td>0.5672</td>\n<td>0.3918</td>\n</tr>\n<tr>\n<td>3</td>\n<td>0.6248</td>\n<td>0.8794</td>\n<td>0.5673</td>\n<td>0.3950</td>\n</tr>\n<tr>\n<td>4</td>\n<td>0.6258</td>\n<td>0.8793</td>\n<td>0.5673</td>\n<td>0.3983</td>\n</tr>\n<tr>\n<td>5</td>\n<td>0.6264</td>\n<td>0.8792</td>\n<td>0.5673</td>\n<td>0.4005</td>\n</tr>\n<tr>\n<td>6</td>\n<td>0.6264</td>\n<td>0.8791</td>\n<td>0.5673</td>\n<td>0.4004</td>\n</tr>\n</tbody>\n</table>\n<h3>4. Gaussian Filtering</h3>\n<p>Apply a Gaussian filter (<code>sigma=1</code>) to the boolean mask, then threshold back to <code>bool</code> via <code>&gt; 0.5</code>. This trick turned out to be surprisingly effective, though the exact mechanism is not entirely clear.</p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RM&lt;5000 + LN+SW</td>\n<td>0.6264</td>\n<td>0.8792</td>\n<td>0.5673</td>\n<td>0.4005</td>\n</tr>\n<tr>\n<td>RM&lt;5000 + LN+SW+GU</td>\n<td>0.6323</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4232</td>\n</tr>\n</tbody>\n</table>\n<h3>5. Second Removal of Small 6-Connected Components (&lt; 5000)</h3>\n<h3>6. Block-wise Small Component Removal</h3>\n<p>Divide into 8 blocks following the TOPO algorithm, then remove 6-connected components &lt; 10.</p>\n<h3>7. 2×2 Diagonal Bridging</h3>\n<p>Proposed as a targeted response to <a href=\"https://www.kaggle.com/competitions/vesuvius-challenge-surface-detection/discussion/672447\" target=\"_blank\">this discussion</a>.</p>\n<p>The method specifically detects the pattern shown below and fills the entire area if detected. It is highly effective and carries almost zero risk of dropping the score for any given case.<br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2Fc9c5ac10149133ffb22cfa1818cc2b7f%2F2026-02-28%20173905.png?generation=1772272259038976&amp;alt=media\"></p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RM&lt;5000 + LN+SW+GU</td>\n<td>0.6323</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4232</td>\n</tr>\n<tr>\n<td>RM&lt;5000 + LN+SW+GU+2x2DG</td>\n<td>0.6337</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4277</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>Unused Post-processing Methods</h2>\n<h3>1. Separating Touching Objects / De-adhesion</h3>\n<p><em>(Based on <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a>'s killer ant method. Hard to see score improvements from this component, but it remains critical for topological correctness.)</em></p>\n<p>To balance computational efficiency and segmentation accuracy, the algorithm uses a <strong>block-wise (8-slice block) iterative mechanism</strong> with six core steps.</p>\n<h4>Step 1 — 2D Ray-Casting Collision Detection</h4>\n<p>Within 2D slices along the Z-axis, <strong>PCA</strong> computes the local normal direction at each object's edge. Virtual rays are cast along these normal vectors. If a ray passes through background and collides with another high-confidence prediction, the location is flagged as a <strong>potential adhesion point</strong>.</p>\n<h4>Step 2 — High-Confidence Target Voting</h4>\n<p>To handle simultaneous multi-object adhesion:</p>\n<ul>\n<li>All collision pairs are aggregated globally.</li>\n<li>The two <strong>high-confidence (&gt; 0.9) predicted 6-connected components</strong> most frequently co-occurring in 3D space are identified.</li>\n<li>The pair with the <strong>highest vote count</strong> is selected as the sole cutting target for the current iteration.</li>\n<li>Remaining adhesions are deferred to subsequent iterations.</li>\n</ul>\n<h4>Step 3 — Shortest Path &amp; Midpoint Sampling</h4>\n<p>Once the adhesion pair is established:</p>\n<ul>\n<li>The shortest path between the ray's start and collision point is computed.</li>\n<li>The <strong>midpoint</strong> of this path is designated as the adhesion boundary.</li>\n<li>A <strong>sparse sampling strategy</strong> selects only <strong>3 representative collision points</strong>, dramatically improving throughput.</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F48433614f38811f5ed3e9bc860e9d6e9%2F2026-02-28%20135156.png?generation=1772272283710430&amp;alt=media\" alt=\"\">\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F479a8cc301bb3b76ca5a32e762b95565%2F.png?generation=1772272300688802&amp;alt=media\" alt=\"\"></p>\n<h4>Step 4 — Geodesic Basin &amp; Marker-Controlled Watershed</h4>\n<p>Using the 3 midpoints from Step 3 as seeds:</p>\n<ul>\n<li><strong>BFS</strong> computes the 3D geodesic distance to adjacent connected components.</li>\n<li>The <strong>negative</strong> of these distances forms the topographic basin for the watershed.</li>\n<li>The two high-confidence components from Step 2 serve as <strong>initial markers</strong>, guiding watershed flows to converge within the basin and precisely delineating the <strong>3D separation plane</strong>.</li>\n</ul>\n<h4>Step 5 — Boundary Cleanup &amp; Gap Generation</h4>\n<ul>\n<li><strong>Morphological dilation</strong> is applied around the identified segmentation interface.</li>\n<li>A physical gap of <strong>~2 pixels wide</strong> is forcibly removed to guarantee complete disconnection.</li>\n</ul>\n<h4>Step 6 — Iterative Processing</h4>\n<p>Steps 1–5 repeat until either:</p>\n<ul>\n<li>No new valid cutting points are found, <strong>or</strong></li>\n<li>The pre-set <strong>maximum iteration count</strong> is reached.</li>\n</ul>\n<hr>\n<h4>⚠️ Methodological Limitations</h4>\n<p><strong>Limitation 1: Seed Adhesion Dependency</strong></p>\n<p>This algorithm relies heavily on <code>high_conf_labels</code> from the neural network as watershed anchor points. If the model's high-confidence predictions are <strong>already merged</strong> (i.e., two distinct objects predicted as a single connected component), the Step 2 voting mechanism cannot distinguish them — rendering the algorithm <strong>ineffective in that region</strong>.</p>\n<p><strong>Limitation 2: Hole Generation at Boundaries</strong></p>\n<p>The fixed ~2-pixel removal in Step 5 is a blunt instrument. While it reliably severs the adhesion, the rigid width is not adaptive to local structure thickness. In practice, this hardcoded gap can introduce more holes than it resolves.</p>\n<hr>\n<h3>2. 2D Slice Line Interpolation / Completion</h3>\n<h4>Step 1 — Skeletonization</h4>\n<p>All 2D slices (both Z-axis and Y-axis) are skeletonized before processing. This ensures they can be jointly handled during the later <strong>Line Norm</strong> stage.</p>\n<h4>Step 2 — Endpoint Detection</h4>\n<p>Using a <strong>3×3 kernel</strong>, we scan each skeletonized slice. A pixel is classified as an <strong>endpoint</strong> if its value is <code>1</code> and exactly <strong>one</strong> of its eight neighbors is also <code>1</code>.</p>\n<h4>Step 3 — Tangent Estimation via PCA + DFS</h4>\n<p>For each detected endpoint, we perform <strong>DFS backtracking</strong> along the skeleton to collect its local neighboring pixels, then apply <strong>PCA</strong> on these points to estimate the <strong>tangent direction</strong> — determining the orientation the endpoint is pointing toward.</p>\n<h4>Step 4 — Endpoint Pairing</h4>\n<p>After collecting all endpoints and their PCA-estimated tangent angles, we perform <strong>endpoint pairing</strong>. A pair is considered valid if both of the following conditions are met (thresholds are tunable):</p>\n<ul>\n<li>The angle between the connecting line and both tangent directions is <strong>&lt; 45°</strong></li>\n<li>The <strong>Euclidean distance</strong> between the two endpoints is <strong>≤ 40 pixels</strong></li>\n</ul>\n<h4>Step 5 — Skeleton-level Connection</h4>\n<p>For each valid endpoint pair, we directly <strong>draw a line on the skeleton</strong> to bridge the gap between the two endpoints.</p>\n<h4>Step 6 — Line Norm</h4>\n<p>Once all connections are completed, the repaired skeleton is passed into the <strong>Line Norm</strong> pipeline. This process is applied independently on both the <strong>Z-axis</strong> and <strong>Y-axis</strong> slices.</p>\n<p>⚠️ Methodological Limitations</p>\n<p><strong>Limitation : Randomness</strong></p>\n<ul>\n<li>In certain cases, when model predictions are already poor, applying this patch will make matters worse. (PB's situation)</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F47248887941907be3509938872e50c29%2Fimage.png?generation=1772280595398226&amp;alt=media\" alt=\"\"></p>\n<p>Due to the negative feedback from PB, we abandoned many CV-boosting methods until after the competition ended, when we uploaded the highest CV version for testing.</p>\n<table>\n<thead>\n<tr>\n<th>CV</th>\n<th>Final Score</th>\n<th>Surf Dice</th>\n<th>VOI Score</th>\n<th>Topo Score</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>RM&lt;5000 + LN+SW(kernel=3)+GU+2x2DG</strong></td>\n<td>0.6337</td>\n<td>0.8771</td>\n<td>0.5668</td>\n<td>0.4277</td>\n<td><strong>Competition Submission Version</strong></td>\n</tr>\n<tr>\n<td><strong>RM&lt;5000 + LN+SW(kernel=5)+GU+2x2DG+ZLine+YLine</strong></td>\n<td>0.6391</td>\n<td>0.8757</td>\n<td>0.5672</td>\n<td>0.4468</td>\n<td><strong>Submit the version after the competition</strong></td>\n</tr>\n</tbody>\n</table>",
      "rawMarkdown": "> **This is my first time participating in a competition, so please bear with me if my solution write-up isn't perfect.**\n\nThank you to the organizers for hosting a competition where we could fully unleash our creativity. I would also like to thank the Competition Grandmasters in the discussion forums for enthusiastically sharing their solutions. Some of my methods were adapted directly from the discussions. Although some of them ultimately didn't work out, I still learned a lot of highly valuable things.\n\n***\n\n## Equipment requirements\n\n- We used 9800X3D + 64GB RAM + RTX 5090 (by TINGYI).\n\n***\n\n## Model Training\n\n- Trained the baseline model (`nnUNetTrainerMedialSurfaceRecall`) provided by the organizers using YOLO26's MUSGD.\n- **Patch Size** was set to **192**. Increasing it to 224 or 256 improved the Dice score but caused the Topo score to drop.\n- Used **Group Norm** (group = 32) and **GELU** (not necessarily helpful; increases VRAM usage).\n\n***\n\n## Inference\n\n- Single Fold + TTA + tile size 0.4\n\n***\n\n## Post-processing\n\n### 1. Remove Small 6-Connected Components (< 5000)\n\n| Connectivity | Final Score | Surf Dice | VOI Score | Topo Score |\n|---|---|---|---|---|\n| **None** | 0.5968 | 0.8800 | 0.5680 | 0.2998 |\n| **6** | 0.6096 | 0.8799 | 0.5682 | 0.3426 |\n| **18** | 0.6029 | 0.8799 | 0.5682 | 0.3202 |\n| **26** | 0.6027 | 0.8799 | 0.5682 | 0.3196 |\n\n### 2. Line Normalization\n\nTo reduce b1 errors caused by thin sheet predictions, a line normalization step is applied:\n\n1. For each 2D slice along the Z-axis, apply **skeletonize** to extract the centerline of thin paper structures.\n2. Reconstruct via **EDT**, expanding the skeleton back to a uniform thickness of radius `r=1.5`.\n3. The volume is split into **8×160×160×160 blocks**; pixels within border ≤ 8 of each block are left untouched to avoid artifacts near ignore mask boundaries.\n4. The reconstructed result is **OR-ed** back into the original prediction (additive, not replacement).\n\nThis ensures extremely thin paper sheets are thickened without removing any existing predictions, reducing topological breaks along fragile thin regions.\n| Radius | Final Score | Surf Dice | VOI Score | Topo Score |\n|--------|-------------|-----------|-----------|------------|\n| Only <5000 | 0.6096 | 0.8799 | 0.5682 | 0.3426 |\n| 1px | 0.6132 | 0.8800 | 0.5682 | 0.3545 |\n| 1.5px | 0.6132 | 0.8801 | 0.5669 | 0.3558 |\n| 2px | 0.6085 | 0.8769 | 0.5637 | 0.3475 |\n***\n\n### 3. Gap Filling & Diagonal Repair\n\nThin paper structures often have small holes or diagonal breaks in the prediction mask. A two-stage morphological repair is applied — and critically, **the entire process is run in a loop**. Experiments show a **linear improvement in score from iteration 1 through iteration 5**, making repeated application strongly beneficial.\n\n**Stage 1 — Gap Filling**\n\nThe key idea: *\"if both sides of a gap are solid, fill the gap in between.\"*\n\n- For each axis, precompute a **support map** — a pixel is a reliable anchor only if it is already predicted positive and has at least `min_neighbors` neighbors in the same 2D plane.\n- Scan across each axis: if two anchor pixels are separated by a gap of ≤ `max_gap` voxels, the voxels in between are OR-ed to 1.\n- This reliably bridges small breaks without over-filling, since both endpoints must independently pass the support check.\n\n**Stage 2 — Diagonal Fill**\n\nAxis-aligned filling misses diagonal breaks (e.g., a sheet running diagonally in XZ or YZ). This step applies the same sandwich logic along diagonal directions using small **3×3×3 kernels** with two opposing off-center taps. If both diagonal neighbors of an empty voxel are positive, the voxel is filled.\n> 📈 **Iterative Gain:** Each additional pass of Gap Filling + Diagonal Fill continues to close newly exposed breaks revealed by previous iterations, yielding consistent linear score gains up to at least 5 iterations.\n\n| Iteration | Final Score | Surf Dice | VOI Score | Topo Score |\n|-----------|-------------|-----------|-----------|------------|\n| RM<5000 + LN | 0.6132 | 0.8801 | 0.5669 | 0.3558 |\n| 1 | 0.6199 | 0.8796 | 0.5672 | 0.3784 |\n| 2 | 0.6239 | 0.8795 | 0.5672 | 0.3918 |\n| 3 | 0.6248 | 0.8794 | 0.5673 | 0.3950 |\n| 4 | 0.6258 | 0.8793 | 0.5673 | 0.3983 |\n| 5 | 0.6264 | 0.8792 | 0.5673 | 0.4005 |\n| 6 | 0.6264 | 0.8791 | 0.5673 | 0.4004 |\n\n### 4. Gaussian Filtering\n\nApply a Gaussian filter (`sigma=1`) to the boolean mask, then threshold back to `bool` via `> 0.5`. This trick turned out to be surprisingly effective, though the exact mechanism is not entirely clear.\n| Method| Final Score | Surf Dice | VOI Score | Topo Score |\n|--------|-------------|-----------|-----------|------------|\n| RM<5000 + LN+SW | 0.6264 | 0.8792 | 0.5673 | 0.4005 |\n| RM<5000 + LN+SW+GU | 0.6323 | 0.8771 | 0.5668 | 0.4232 |\n### 5. Second Removal of Small 6-Connected Components (< 5000)\n\n### 6. Block-wise Small Component Removal\n\nDivide into 8 blocks following the TOPO algorithm, then remove 6-connected components < 10.\n\n### 7. 2×2 Diagonal Bridging\n\nProposed as a targeted response to [this discussion](https://www.kaggle.com/competitions/vesuvius-challenge-surface-detection/discussion/672447).\n\nThe method specifically detects the pattern shown below and fills the entire area if detected. It is highly effective and carries almost zero risk of dropping the score for any given case.  \n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2Fc9c5ac10149133ffb22cfa1818cc2b7f%2F2026-02-28%20173905.png?generation=1772272259038976&alt=media\" width=\"400\">\n Method| Final Score | Surf Dice | VOI Score | Topo Score |\n|--------|-------------|-----------|-----------|------------|\n| RM<5000 + LN+SW+GU | 0.6323 | 0.8771 | 0.5668 | 0.4232 |\n| RM<5000 + LN+SW+GU+2x2DG | 0.6337 | 0.8771 | 0.5668 | 0.4277 |\n\n***\n\n## Unused Post-processing Methods\n\n### 1. Separating Touching Objects / De-adhesion\n\n*(Based on @hengck23's killer ant method. Hard to see score improvements from this component, but it remains critical for topological correctness.)*\n\nTo balance computational efficiency and segmentation accuracy, the algorithm uses a **block-wise (8-slice block) iterative mechanism** with six core steps.\n\n#### Step 1 — 2D Ray-Casting Collision Detection\n\nWithin 2D slices along the Z-axis, **PCA** computes the local normal direction at each object's edge. Virtual rays are cast along these normal vectors. If a ray passes through background and collides with another high-confidence prediction, the location is flagged as a **potential adhesion point**.\n\n#### Step 2 — High-Confidence Target Voting\n\nTo handle simultaneous multi-object adhesion:\n\n- All collision pairs are aggregated globally.\n- The two **high-confidence (> 0.9) predicted 6-connected components** most frequently co-occurring in 3D space are identified.\n- The pair with the **highest vote count** is selected as the sole cutting target for the current iteration.\n- Remaining adhesions are deferred to subsequent iterations.\n\n#### Step 3 — Shortest Path & Midpoint Sampling\n\nOnce the adhesion pair is established:\n\n- The shortest path between the ray's start and collision point is computed.\n- The **midpoint** of this path is designated as the adhesion boundary.\n- A **sparse sampling strategy** selects only **3 representative collision points**, dramatically improving throughput.\n\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F48433614f38811f5ed3e9bc860e9d6e9%2F2026-02-28%20135156.png?generation=1772272283710430&alt=media)\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F479a8cc301bb3b76ca5a32e762b95565%2F.png?generation=1772272300688802&alt=media)\n\n\n#### Step 4 — Geodesic Basin & Marker-Controlled Watershed\n\nUsing the 3 midpoints from Step 3 as seeds:\n\n- **BFS** computes the 3D geodesic distance to adjacent connected components.\n- The **negative** of these distances forms the topographic basin for the watershed.\n- The two high-confidence components from Step 2 serve as **initial markers**, guiding watershed flows to converge within the basin and precisely delineating the **3D separation plane**.\n\n#### Step 5 — Boundary Cleanup & Gap Generation\n\n- **Morphological dilation** is applied around the identified segmentation interface.\n- A physical gap of **~2 pixels wide** is forcibly removed to guarantee complete disconnection.\n\n#### Step 6 — Iterative Processing\n\nSteps 1–5 repeat until either:\n- No new valid cutting points are found, **or**\n- The pre-set **maximum iteration count** is reached.\n\n***\n\n#### ⚠️ Methodological Limitations\n\n**Limitation 1: Seed Adhesion Dependency**\n\nThis algorithm relies heavily on `high_conf_labels` from the neural network as watershed anchor points. If the model's high-confidence predictions are **already merged** (i.e., two distinct objects predicted as a single connected component), the Step 2 voting mechanism cannot distinguish them — rendering the algorithm **ineffective in that region**.\n\n**Limitation 2: Hole Generation at Boundaries**\n\nThe fixed ~2-pixel removal in Step 5 is a blunt instrument. While it reliably severs the adhesion, the rigid width is not adaptive to local structure thickness. In practice, this hardcoded gap can introduce more holes than it resolves.\n\n***\n\n### 2. 2D Slice Line Interpolation / Completion\n#### Step 1 — Skeletonization\nAll 2D slices (both Z-axis and Y-axis) are skeletonized before processing. This ensures they can be jointly handled during the later **Line Norm** stage.\n\n#### Step 2 — Endpoint Detection\nUsing a **3×3 kernel**, we scan each skeletonized slice. A pixel is classified as an **endpoint** if its value is `1` and exactly **one** of its eight neighbors is also `1`.\n\n#### Step 3 — Tangent Estimation via PCA + DFS\nFor each detected endpoint, we perform **DFS backtracking** along the skeleton to collect its local neighboring pixels, then apply **PCA** on these points to estimate the **tangent direction** — determining the orientation the endpoint is pointing toward.\n\n#### Step 4 — Endpoint Pairing\nAfter collecting all endpoints and their PCA-estimated tangent angles, we perform **endpoint pairing**. A pair is considered valid if both of the following conditions are met (thresholds are tunable):\n- The angle between the connecting line and both tangent directions is **< 45°**\n- The **Euclidean distance** between the two endpoints is **≤ 40 pixels**\n\n#### Step 5 — Skeleton-level Connection\nFor each valid endpoint pair, we directly **draw a line on the skeleton** to bridge the gap between the two endpoints.\n\n#### Step 6 — Line Norm\nOnce all connections are completed, the repaired skeleton is passed into the **Line Norm** pipeline. This process is applied independently on both the **Z-axis** and **Y-axis** slices.\n\n⚠️ Methodological Limitations\n\n**Limitation : Randomness**\n- In certain cases, when model predictions are already poor, applying this patch will make matters worse. (PB's situation)\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F47248887941907be3509938872e50c29%2Fimage.png?generation=1772280595398226&alt=media)\n\nDue to the negative feedback from PB, we abandoned many CV-boosting methods until after the competition ended, when we uploaded the highest CV version for testing.\n\n\n| CV | Final Score | Surf Dice | VOI Score | Topo Score |  | \n|---|---|---|---|---|---|\n| **RM<5000 + LN+SW(kernel=3)+GU+2x2DG** | 0.6337 | 0.8771 | 0.5668 | 0.4277 | **Competition Submission Version** |\n| **RM<5000 + LN+SW(kernel=5)+GU+2x2DG+ZLine+YLine** | 0.6391 | 0.8757 | 0.5672 | 0.4468 | **Submit the version after the competition** |",
      "votes": 24
    },
    {
      "id": 3415703,
      "postDate": "2026-03-01T06:59:33.170Z",
      "content": "<p><a href=\"https://www.kaggle.com/code/chengtingyi/nnu-net-predict\" target=\"_blank\">https://www.kaggle.com/code/chengtingyi/nnu-net-predict</a>  </p>\n<p>The code is a bit too large, it's not very easy to organize — I'm sorry about that. But if you have any questions, I'm happy to respond.\n<a href=\"https://www.kaggle.com/seanjohnsonsp\" target=\"_blank\">@seanjohnsonsp</a> </p>",
      "rawMarkdown": "https://www.kaggle.com/code/chengtingyi/nnu-net-predict  \n\nThe code is a bit too large, it's not very easy to organize — I'm sorry about that. But if you have any questions, I'm happy to respond.\n@seanjohnsonsp ",
      "votes": 3,
      "replies": [
        {
          "id": 3419255,
          "postDate": "2026-03-10T08:43:20.937Z",
          "rawMarkdown": "",
          "isDeleted": true
        }
      ]
    },
    {
      "id": 3416808,
      "postDate": "2026-03-03T19:57:04.353Z",
      "content": "<p>Wow just reading that your best CV methods would have 0.6391! Impressive!</p>",
      "rawMarkdown": "Wow just reading that your best CV methods would have 0.6391! Impressive!",
      "votes": 2
    },
    {
      "id": 3416154,
      "postDate": "2026-03-02T07:22:14.277Z",
      "content": "<p>Your line normalization approach using skeletonize and EDT reconstruction (radius 1.5) is really neat. We struggled a bit with maintaining the topology of those extremely thin sheets too.</p>\n<p>Also, totally feel your pain on the unused methods. The \"CV vs LB\" dilemma is brutal. Scrapping the slice line interpolation because of PB feedback sucks, but getting top 10 solo on your first try proves your core pipeline is robust. Nice job.</p>",
      "rawMarkdown": "Your line normalization approach using skeletonize and EDT reconstruction (radius 1.5) is really neat. We struggled a bit with maintaining the topology of those extremely thin sheets too.\n\nAlso, totally feel your pain on the unused methods. The \"CV vs LB\" dilemma is brutal. Scrapping the slice line interpolation because of PB feedback sucks, but getting top 10 solo on your first try proves your core pipeline is robust. Nice job.",
      "votes": 2
    },
    {
      "id": 3415528,
      "postDate": "2026-03-01T01:16:44.693Z",
      "content": "<p>Thanks for the writeup and congrats! Would be great to see the code for some of these more complex post-processing methods, it's something i have not explored nearly enough</p>",
      "rawMarkdown": "Thanks for the writeup and congrats! Would be great to see the code for some of these more complex post-processing methods, it's something i have not explored nearly enough",
      "votes": 2,
      "replies": [
        {
          "id": 3415665,
          "postDate": "2026-03-01T05:06:51.933Z",
          "content": "<p>I'll let you know after I've tidied up the code.</p>",
          "rawMarkdown": "I'll let you know after I've tidied up the code."
        }
      ]
    },
    {
      "id": 3415140,
      "postDate": "2026-02-28T08:40:12.203Z",
      "content": "<p>I was looking forward to read your solution!!\nvery nice work and creative postprocessing.\ncongrats on the win</p>",
      "rawMarkdown": "I was looking forward to read your solution!!\nvery nice work and creative postprocessing.\ncongrats on the win",
      "votes": 2
    },
    {
      "id": 3415112,
      "postDate": "2026-02-28T07:33:07.393Z",
      "content": "<p>Really cool work, seen you guyss work hard consistently for 3+ months 🎉🎉</p>",
      "rawMarkdown": "Really cool work, seen you guyss work hard consistently for 3+ months 🎉🎉",
      "votes": 2,
      "replies": [
        {
          "id": 3415125,
          "postDate": "2026-02-28T07:57:46.057Z",
          "content": "<p>It's all thanks to the notebook you wrote that I was able to discover some of my own issues.</p>",
          "rawMarkdown": "It's all thanks to the notebook you wrote that I was able to discover some of my own issues.",
          "votes": 1
        }
      ]
    },
    {
      "id": 3415025,
      "postDate": "2026-02-28T04:34:49.370Z",
      "content": "<pre><code>The Patch Size was set to 192. Although increasing it to 224 or 256 improved the Dice score, it actually caused the Topo score to drop.\n</code></pre>\n<p>Congrats team! I wonder do you experiment smaller patch sizes? In my exp, smaller patch size can increase topo and voi but lowering the surface. I think large context would lead more missing components.</p>",
      "rawMarkdown": "```\nThe Patch Size was set to 192. Although increasing it to 224 or 256 improved the Dice score, it actually caused the Topo score to drop.\n```\nCongrats team! I wonder do you experiment smaller patch sizes? In my exp, smaller patch size can increase topo and voi but lowering the surface. I think large context would lead more missing components.",
      "votes": 2,
      "replies": [
        {
          "id": 3415041,
          "postDate": "2026-02-28T05:04:06.307Z",
          "content": "<p>In the very early stages of the competition, I experimented with patch sizes of 96, 128, 160, 192, and 224. At the time I was using the original nnUNet, so performance appeared to saturate around 160. However, what I observed was that scaling from 96 to 192 showed linear growth in both Topo and VOI metrics. That said, the evaluation code I was using back then wasn't the official one — it was something someone had written on the forum — and it also didn't account for the influence of labels containing b1 and b2. So I'm not entirely confident that experimental data was accurate, especially since I never re-ran those experiments later.</p>",
          "rawMarkdown": "In the very early stages of the competition, I experimented with patch sizes of 96, 128, 160, 192, and 224. At the time I was using the original nnUNet, so performance appeared to saturate around 160. However, what I observed was that scaling from 96 to 192 showed linear growth in both Topo and VOI metrics. That said, the evaluation code I was using back then wasn't the official one — it was something someone had written on the forum — and it also didn't account for the influence of labels containing b1 and b2. So I'm not entirely confident that experimental data was accurate, especially since I never re-ran those experiments later.",
          "votes": 2
        },
        {
          "id": 3415603,
          "postDate": "2026-03-01T03:18:22.117Z",
          "content": "<p>This is the training log for 224, and it's quite obvious that he's already overfitting.<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15255201%2F58e75aae69042f04fcd570162b3394e1%2FScreenshot%202026-02-28%20213145.png?generation=1772335100779408&amp;alt=media\" alt=\"\"></p>",
          "rawMarkdown": "This is the training log for 224, and it's quite obvious that he's already overfitting.![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15255201%2F58e75aae69042f04fcd570162b3394e1%2FScreenshot%202026-02-28%20213145.png?generation=1772335100779408&alt=media)",
          "replies": [
            {
              "id": 3415620,
              "postDate": "2026-03-01T03:51:03.583Z",
              "content": "<p>i'd be hesitant to draw such a firm conclusion from the nnunet progress pngs. These are sampled from random validation samples, and log only metrics which you're actively training with. If your validation set for example has 8 rather easy samples and 2 rather hard ones, a training session in which your improvement on those hard samples is continuing but your easy samples have plateaued you'd never be able to discern that from this noisy loss plot.   you'd need to log more involved evaluation metrics and also stratify them a bit more</p>",
              "rawMarkdown": "i'd be hesitant to draw such a firm conclusion from the nnunet progress pngs. These are sampled from random validation samples, and log only metrics which you're actively training with. If your validation set for example has 8 rather easy samples and 2 rather hard ones, a training session in which your improvement on those hard samples is continuing but your easy samples have plateaued you'd never be able to discern that from this noisy loss plot.   you'd need to log more involved evaluation metrics and also stratify them a bit more",
              "votes": 1
            },
            {
              "id": 3415637,
              "postDate": "2026-03-01T04:19:21.077Z",
              "content": "<p>In terms of CV, 224 is also lower than 192. It is just for the convenience of display, so it is presented in a LOSS manner. And in this competition, this observation method is significant (192&gt;224&gt;256).</p>",
              "rawMarkdown": "In terms of CV, 224 is also lower than 192. It is just for the convenience of display, so it is presented in a LOSS manner. And in this competition, this observation method is significant (192>224>256)."
            }
          ]
        }
      ]
    }
  ],
  "comments": [
    {
      "id": 3415703,
      "author_name": "tingyi",
      "author_url": "",
      "post_date": "2026-03-01T06:59:33.170000",
      "content": "<p><a href=\"https://www.kaggle.com/code/chengtingyi/nnu-net-predict\" target=\"_blank\">https://www.kaggle.com/code/chengtingyi/nnu-net-predict</a>  </p>\n<p>The code is a bit too large, it's not very easy to organize — I'm sorry about that. But if you have any questions, I'm happy to respond.\n<a href=\"https://www.kaggle.com/seanjohnsonsp\" target=\"_blank\">@seanjohnsonsp</a> </p>",
      "votes": 3,
      "replies": [
        {
          "id": 3419255,
          "author_name": "",
          "author_url": "",
          "post_date": "2026-03-10T08:43:20.937000",
          "content": "",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3416808,
      "author_name": "Giorgio Angelotti",
      "author_url": "",
      "post_date": "2026-03-03T19:57:04.353000",
      "content": "<p>Wow just reading that your best CV methods would have 0.6391! Impressive!</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 3416154,
      "author_name": "DECEM",
      "author_url": "",
      "post_date": "2026-03-02T07:22:14.277000",
      "content": "<p>Your line normalization approach using skeletonize and EDT reconstruction (radius 1.5) is really neat. We struggled a bit with maintaining the topology of those extremely thin sheets too.</p>\n<p>Also, totally feel your pain on the unused methods. The \"CV vs LB\" dilemma is brutal. Scrapping the slice line interpolation because of PB feedback sucks, but getting top 10 solo on your first try proves your core pipeline is robust. Nice job.</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 3415528,
      "author_name": "Sean Johnson_SP",
      "author_url": "",
      "post_date": "2026-03-01T01:16:44.693000",
      "content": "<p>Thanks for the writeup and congrats! Would be great to see the code for some of these more complex post-processing methods, it's something i have not explored nearly enough</p>",
      "votes": 2,
      "replies": [
        {
          "id": 3415665,
          "author_name": "tingyi",
          "author_url": "",
          "post_date": "2026-03-01T05:06:51.933000",
          "content": "<p>I'll let you know after I've tidied up the code.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3415140,
      "author_name": "ArjunB",
      "author_url": "",
      "post_date": "2026-02-28T08:40:12.203000",
      "content": "<p>I was looking forward to read your solution!!\nvery nice work and creative postprocessing.\ncongrats on the win</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 3415112,
      "author_name": "Manas Choudhary",
      "author_url": "",
      "post_date": "2026-02-28T07:33:07.393000",
      "content": "<p>Really cool work, seen you guyss work hard consistently for 3+ months 🎉🎉</p>",
      "votes": 2,
      "replies": [
        {
          "id": 3415125,
          "author_name": "tingyi",
          "author_url": "",
          "post_date": "2026-02-28T07:57:46.057000",
          "content": "<p>It's all thanks to the notebook you wrote that I was able to discover some of my own issues.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 3415025,
      "author_name": "Tom",
      "author_url": "",
      "post_date": "2026-02-28T04:34:49.370000",
      "content": "<pre><code>The Patch Size was set to 192. Although increasing it to 224 or 256 improved the Dice score, it actually caused the Topo score to drop.\n</code></pre>\n<p>Congrats team! I wonder do you experiment smaller patch sizes? In my exp, smaller patch size can increase topo and voi but lowering the surface. I think large context would lead more missing components.</p>",
      "votes": 2,
      "replies": [
        {
          "id": 3415041,
          "author_name": "tingyi",
          "author_url": "",
          "post_date": "2026-02-28T05:04:06.307000",
          "content": "<p>In the very early stages of the competition, I experimented with patch sizes of 96, 128, 160, 192, and 224. At the time I was using the original nnUNet, so performance appeared to saturate around 160. However, what I observed was that scaling from 96 to 192 showed linear growth in both Topo and VOI metrics. That said, the evaluation code I was using back then wasn't the official one — it was something someone had written on the forum — and it also didn't account for the influence of labels containing b1 and b2. So I'm not entirely confident that experimental data was accurate, especially since I never re-ran those experiments later.</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 3415603,
          "author_name": "GG Ayo (AyoGG)",
          "author_url": "",
          "post_date": "2026-03-01T03:18:22.117000",
          "content": "<p>This is the training log for 224, and it's quite obvious that he's already overfitting.<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15255201%2F58e75aae69042f04fcd570162b3394e1%2FScreenshot%202026-02-28%20213145.png?generation=1772335100779408&amp;alt=media\" alt=\"\"></p>",
          "votes": 0,
          "replies": [
            {
              "id": 3415620,
              "author_name": "Sean Johnson_SP",
              "author_url": "",
              "post_date": "2026-03-01T03:51:03.583000",
              "content": "<p>i'd be hesitant to draw such a firm conclusion from the nnunet progress pngs. These are sampled from random validation samples, and log only metrics which you're actively training with. If your validation set for example has 8 rather easy samples and 2 rather hard ones, a training session in which your improvement on those hard samples is continuing but your easy samples have plateaued you'd never be able to discern that from this noisy loss plot.   you'd need to log more involved evaluation metrics and also stratify them a bit more</p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 3415637,
              "author_name": "GG Ayo (AyoGG)",
              "author_url": "",
              "post_date": "2026-03-01T04:19:21.077000",
              "content": "<p>In terms of CV, 224 is also lower than 192. It is just for the convenience of display, so it is presented in a LOSS manner. And in this competition, this observation method is significant (192&gt;224&gt;256).</p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "3415016": "> **This is my first time participating in a competition, so please bear with me if my solution write-up isn't perfect.**\n\nThank you to the organizers for hosting a competition where we could fully unleash our creativity. I would also like to thank the Competition Grandmasters in the discussion forums for enthusiastically sharing their solutions. Some of my methods were adapted directly from the discussions. Although some of them ultimately didn't work out, I still learned a lot of highly valuable things.\n\n***\n\n## Equipment requirements\n\n- We used 9800X3D + 64GB RAM + RTX 5090 (by TINGYI).\n\n***\n\n## Model Training\n\n- Trained the baseline model (`nnUNetTrainerMedialSurfaceRecall`) provided by the organizers using YOLO26's MUSGD.\n- **Patch Size** was set to **192**. Increasing it to 224 or 256 improved the Dice score but caused the Topo score to drop.\n- Used **Group Norm** (group = 32) and **GELU** (not necessarily helpful; increases VRAM usage).\n\n***\n\n## Inference\n\n- Single Fold + TTA + tile size 0.4\n\n***\n\n## Post-processing\n\n### 1. Remove Small 6-Connected Components (< 5000)\n\n| Connectivity | Final Score | Surf Dice | VOI Score | Topo Score |\n|---|---|---|---|---|\n| **None** | 0.5968 | 0.8800 | 0.5680 | 0.2998 |\n| **6** | 0.6096 | 0.8799 | 0.5682 | 0.3426 |\n| **18** | 0.6029 | 0.8799 | 0.5682 | 0.3202 |\n| **26** | 0.6027 | 0.8799 | 0.5682 | 0.3196 |\n\n### 2. Line Normalization\n\nTo reduce b1 errors caused by thin sheet predictions, a line normalization step is applied:\n\n1. For each 2D slice along the Z-axis, apply **skeletonize** to extract the centerline of thin paper structures.\n2. Reconstruct via **EDT**, expanding the skeleton back to a uniform thickness of radius `r=1.5`.\n3. The volume is split into **8×160×160×160 blocks**; pixels within border ≤ 8 of each block are left untouched to avoid artifacts near ignore mask boundaries.\n4. The reconstructed result is **OR-ed** back into the original prediction (additive, not replacement).\n\nThis ensures extremely thin paper sheets are thickened without removing any existing predictions, reducing topological breaks along fragile thin regions.\n| Radius | Final Score | Surf Dice | VOI Score | Topo Score |\n|--------|-------------|-----------|-----------|------------|\n| Only <5000 | 0.6096 | 0.8799 | 0.5682 | 0.3426 |\n| 1px | 0.6132 | 0.8800 | 0.5682 | 0.3545 |\n| 1.5px | 0.6132 | 0.8801 | 0.5669 | 0.3558 |\n| 2px | 0.6085 | 0.8769 | 0.5637 | 0.3475 |\n***\n\n### 3. Gap Filling & Diagonal Repair\n\nThin paper structures often have small holes or diagonal breaks in the prediction mask. A two-stage morphological repair is applied — and critically, **the entire process is run in a loop**. Experiments show a **linear improvement in score from iteration 1 through iteration 5**, making repeated application strongly beneficial.\n\n**Stage 1 — Gap Filling**\n\nThe key idea: *\"if both sides of a gap are solid, fill the gap in between.\"*\n\n- For each axis, precompute a **support map** — a pixel is a reliable anchor only if it is already predicted positive and has at least `min_neighbors` neighbors in the same 2D plane.\n- Scan across each axis: if two anchor pixels are separated by a gap of ≤ `max_gap` voxels, the voxels in between are OR-ed to 1.\n- This reliably bridges small breaks without over-filling, since both endpoints must independently pass the support check.\n\n**Stage 2 — Diagonal Fill**\n\nAxis-aligned filling misses diagonal breaks (e.g., a sheet running diagonally in XZ or YZ). This step applies the same sandwich logic along diagonal directions using small **3×3×3 kernels** with two opposing off-center taps. If both diagonal neighbors of an empty voxel are positive, the voxel is filled.\n> 📈 **Iterative Gain:** Each additional pass of Gap Filling + Diagonal Fill continues to close newly exposed breaks revealed by previous iterations, yielding consistent linear score gains up to at least 5 iterations.\n\n| Iteration | Final Score | Surf Dice | VOI Score | Topo Score |\n|-----------|-------------|-----------|-----------|------------|\n| RM<5000 + LN | 0.6132 | 0.8801 | 0.5669 | 0.3558 |\n| 1 | 0.6199 | 0.8796 | 0.5672 | 0.3784 |\n| 2 | 0.6239 | 0.8795 | 0.5672 | 0.3918 |\n| 3 | 0.6248 | 0.8794 | 0.5673 | 0.3950 |\n| 4 | 0.6258 | 0.8793 | 0.5673 | 0.3983 |\n| 5 | 0.6264 | 0.8792 | 0.5673 | 0.4005 |\n| 6 | 0.6264 | 0.8791 | 0.5673 | 0.4004 |\n\n### 4. Gaussian Filtering\n\nApply a Gaussian filter (`sigma=1`) to the boolean mask, then threshold back to `bool` via `> 0.5`. This trick turned out to be surprisingly effective, though the exact mechanism is not entirely clear.\n| Method| Final Score | Surf Dice | VOI Score | Topo Score |\n|--------|-------------|-----------|-----------|------------|\n| RM<5000 + LN+SW | 0.6264 | 0.8792 | 0.5673 | 0.4005 |\n| RM<5000 + LN+SW+GU | 0.6323 | 0.8771 | 0.5668 | 0.4232 |\n### 5. Second Removal of Small 6-Connected Components (< 5000)\n\n### 6. Block-wise Small Component Removal\n\nDivide into 8 blocks following the TOPO algorithm, then remove 6-connected components < 10.\n\n### 7. 2×2 Diagonal Bridging\n\nProposed as a targeted response to [this discussion](https://www.kaggle.com/competitions/vesuvius-challenge-surface-detection/discussion/672447).\n\nThe method specifically detects the pattern shown below and fills the entire area if detected. It is highly effective and carries almost zero risk of dropping the score for any given case.  \n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2Fc9c5ac10149133ffb22cfa1818cc2b7f%2F2026-02-28%20173905.png?generation=1772272259038976&alt=media\" width=\"400\">\n Method| Final Score | Surf Dice | VOI Score | Topo Score |\n|--------|-------------|-----------|-----------|------------|\n| RM<5000 + LN+SW+GU | 0.6323 | 0.8771 | 0.5668 | 0.4232 |\n| RM<5000 + LN+SW+GU+2x2DG | 0.6337 | 0.8771 | 0.5668 | 0.4277 |\n\n***\n\n## Unused Post-processing Methods\n\n### 1. Separating Touching Objects / De-adhesion\n\n*(Based on @hengck23's killer ant method. Hard to see score improvements from this component, but it remains critical for topological correctness.)*\n\nTo balance computational efficiency and segmentation accuracy, the algorithm uses a **block-wise (8-slice block) iterative mechanism** with six core steps.\n\n#### Step 1 — 2D Ray-Casting Collision Detection\n\nWithin 2D slices along the Z-axis, **PCA** computes the local normal direction at each object's edge. Virtual rays are cast along these normal vectors. If a ray passes through background and collides with another high-confidence prediction, the location is flagged as a **potential adhesion point**.\n\n#### Step 2 — High-Confidence Target Voting\n\nTo handle simultaneous multi-object adhesion:\n\n- All collision pairs are aggregated globally.\n- The two **high-confidence (> 0.9) predicted 6-connected components** most frequently co-occurring in 3D space are identified.\n- The pair with the **highest vote count** is selected as the sole cutting target for the current iteration.\n- Remaining adhesions are deferred to subsequent iterations.\n\n#### Step 3 — Shortest Path & Midpoint Sampling\n\nOnce the adhesion pair is established:\n\n- The shortest path between the ray's start and collision point is computed.\n- The **midpoint** of this path is designated as the adhesion boundary.\n- A **sparse sampling strategy** selects only **3 representative collision points**, dramatically improving throughput.\n\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F48433614f38811f5ed3e9bc860e9d6e9%2F2026-02-28%20135156.png?generation=1772272283710430&alt=media)\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F479a8cc301bb3b76ca5a32e762b95565%2F.png?generation=1772272300688802&alt=media)\n\n\n#### Step 4 — Geodesic Basin & Marker-Controlled Watershed\n\nUsing the 3 midpoints from Step 3 as seeds:\n\n- **BFS** computes the 3D geodesic distance to adjacent connected components.\n- The **negative** of these distances forms the topographic basin for the watershed.\n- The two high-confidence components from Step 2 serve as **initial markers**, guiding watershed flows to converge within the basin and precisely delineating the **3D separation plane**.\n\n#### Step 5 — Boundary Cleanup & Gap Generation\n\n- **Morphological dilation** is applied around the identified segmentation interface.\n- A physical gap of **~2 pixels wide** is forcibly removed to guarantee complete disconnection.\n\n#### Step 6 — Iterative Processing\n\nSteps 1–5 repeat until either:\n- No new valid cutting points are found, **or**\n- The pre-set **maximum iteration count** is reached.\n\n***\n\n#### ⚠️ Methodological Limitations\n\n**Limitation 1: Seed Adhesion Dependency**\n\nThis algorithm relies heavily on `high_conf_labels` from the neural network as watershed anchor points. If the model's high-confidence predictions are **already merged** (i.e., two distinct objects predicted as a single connected component), the Step 2 voting mechanism cannot distinguish them — rendering the algorithm **ineffective in that region**.\n\n**Limitation 2: Hole Generation at Boundaries**\n\nThe fixed ~2-pixel removal in Step 5 is a blunt instrument. While it reliably severs the adhesion, the rigid width is not adaptive to local structure thickness. In practice, this hardcoded gap can introduce more holes than it resolves.\n\n***\n\n### 2. 2D Slice Line Interpolation / Completion\n#### Step 1 — Skeletonization\nAll 2D slices (both Z-axis and Y-axis) are skeletonized before processing. This ensures they can be jointly handled during the later **Line Norm** stage.\n\n#### Step 2 — Endpoint Detection\nUsing a **3×3 kernel**, we scan each skeletonized slice. A pixel is classified as an **endpoint** if its value is `1` and exactly **one** of its eight neighbors is also `1`.\n\n#### Step 3 — Tangent Estimation via PCA + DFS\nFor each detected endpoint, we perform **DFS backtracking** along the skeleton to collect its local neighboring pixels, then apply **PCA** on these points to estimate the **tangent direction** — determining the orientation the endpoint is pointing toward.\n\n#### Step 4 — Endpoint Pairing\nAfter collecting all endpoints and their PCA-estimated tangent angles, we perform **endpoint pairing**. A pair is considered valid if both of the following conditions are met (thresholds are tunable):\n- The angle between the connecting line and both tangent directions is **< 45°**\n- The **Euclidean distance** between the two endpoints is **≤ 40 pixels**\n\n#### Step 5 — Skeleton-level Connection\nFor each valid endpoint pair, we directly **draw a line on the skeleton** to bridge the gap between the two endpoints.\n\n#### Step 6 — Line Norm\nOnce all connections are completed, the repaired skeleton is passed into the **Line Norm** pipeline. This process is applied independently on both the **Z-axis** and **Y-axis** slices.\n\n⚠️ Methodological Limitations\n\n**Limitation : Randomness**\n- In certain cases, when model predictions are already poor, applying this patch will make matters worse. (PB's situation)\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F8788200%2F47248887941907be3509938872e50c29%2Fimage.png?generation=1772280595398226&alt=media)\n\nDue to the negative feedback from PB, we abandoned many CV-boosting methods until after the competition ended, when we uploaded the highest CV version for testing.\n\n\n| CV | Final Score | Surf Dice | VOI Score | Topo Score |  | \n|---|---|---|---|---|---|\n| **RM<5000 + LN+SW(kernel=3)+GU+2x2DG** | 0.6337 | 0.8771 | 0.5668 | 0.4277 | **Competition Submission Version** |\n| **RM<5000 + LN+SW(kernel=5)+GU+2x2DG+ZLine+YLine** | 0.6391 | 0.8757 | 0.5672 | 0.4468 | **Submit the version after the competition** |",
    "3415703": "https://www.kaggle.com/code/chengtingyi/nnu-net-predict  \n\nThe code is a bit too large, it's not very easy to organize — I'm sorry about that. But if you have any questions, I'm happy to respond.\n@seanjohnsonsp ",
    "3416808": "Wow just reading that your best CV methods would have 0.6391! Impressive!",
    "3416154": "Your line normalization approach using skeletonize and EDT reconstruction (radius 1.5) is really neat. We struggled a bit with maintaining the topology of those extremely thin sheets too.\n\nAlso, totally feel your pain on the unused methods. The \"CV vs LB\" dilemma is brutal. Scrapping the slice line interpolation because of PB feedback sucks, but getting top 10 solo on your first try proves your core pipeline is robust. Nice job.",
    "3415528": "Thanks for the writeup and congrats! Would be great to see the code for some of these more complex post-processing methods, it's something i have not explored nearly enough",
    "3415140": "I was looking forward to read your solution!!\nvery nice work and creative postprocessing.\ncongrats on the win",
    "3415112": "Really cool work, seen you guyss work hard consistently for 3+ months 🎉🎉",
    "3415025": "```\nThe Patch Size was set to 192. Although increasing it to 224 or 256 improved the Dice score, it actually caused the Topo score to drop.\n```\nCongrats team! I wonder do you experiment smaller patch sizes? In my exp, smaller patch size can increase topo and voi but lowering the surface. I think large context would lead more missing components."
  }
}