{
  "id": 475234,
  "title": "110th Place,  Did Not Work: Splitting Thin/Thick Vessels Approach",
  "url": "/competitions/blood-vessel-segmentation/discussion/475234",
  "author_name": "suguuuuu",
  "post_date": "2024-02-07T15:17:15.525000",
  "votes": 3,
  "comment_count": 0,
  "views": 0,
  "content": "<h1>110th Place, Did Not Work: Splitting Thin/Thick Vessels Approach</h1>\n<p>Thank you for hosting the competition.</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2F6d623087b77192ed018bb4216e81f873%2Fvessel.png?generation=1707318307890041&amp;alt=media\"></p>\n<h2>Overview</h2>\n<ul>\n<li>Employed both 2D Unet and 3D Unet approaches.</li>\n<li>Expectation: The 2D model was expected to capture larger vessels, while the 3D model should have been better at capturing smaller vessels.</li>\n<li>2D Unet 512 x 512 (xy,yz,xz)<ul>\n<li>backbone: SE_resnext50</li></ul></li>\n<li>3D Unet 128 x 128 x 128<ul>\n<li>backbone : Resnet18</li></ul></li>\n</ul>\n<h2>Training</h2>\n<ul>\n<li>Pre-training with all data</li>\n<li>Fine-tuning with dense dataset(kidney1&amp;3)<ul>\n<li>augmentation with monai API for multi mask</li></ul></li>\n</ul>\n<pre><code>    aug_list = [\n                    RandRotated(keys=[, , , ],range_x = np.pi/180 * 90, =np.pi/180 * 90, =np.pi/180 * 90, =1, =),\n                    RandFlipd(keys=[, , , ], =1),\n                    RandGridDistortiond(keys=(, , , ), =1, distort_limit=(-0.03, 0.03), =), \n                    RandZoomd(keys=[, , , ], min_zoom = 1 , max_zoom = 6/5, =1, =),\n                    RandAdjustContrastd(keys=[],=1, gamma=(0.8, 2.5)),\n                    ]\n</code></pre>\n<h2>Data preprocessing</h2>\n<ul>\n<li>Thin/thick vessel split approach<ul>\n<li>Hypothesis: The premise was that a difference in contrast, dependent on vessel thickness, would result in unstable thresholding.This challenge was similar to issues discussed in papers on retinal vessel detection.</li>\n<li>Reference: <a href=\"https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full\" target=\"_blank\">https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full</a><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2Fadb0df2308c1f3db2936a04bfd945f3e%2Ffbioe-09-697915-g002.jpg?generation=1707318581847217&amp;alt=media\"></li>\n<li>But overfitted to CV…</li>\n<li>Source code: 3d splitting code</li></ul></li>\n</ul>\n<pre><code>from scipy.ndimage import distance_transform_edt\nfrom skimage.morphology import skeletonize_3d\n\n\ndist_transform_varied_thickness = distance_transform_edt(mask_data)\n\n\nskeleton_varied_thickness = skeletonize_3d(mask_data)\n\n\nz_varied_thickness, y_varied_thickness, x_varied_thickness = np.where(skeleton_varied_thickness)\n\n\nnum_points = len(x_varied_thickness)\n\n\n\nthicknesses_varied_thickness = np.array([dist_transform_varied_thickness[z, y, x] * 2 \n                                         for z, y, x in zip(z_varied_thickness, y_varied_thickness, x_varied_thickness)])\n\n\nthicknesses_varied_thickness.shape, thicknesses_varied_thickness[:10]  \n\nfrom scipy.spatial import cKDTree\n\n\n\nskeleton_coords_3d = np.column_stack([z_varied_thickness, y_varied_thickness, x_varied_thickness])\nskeleton_thicknesses_3d = thicknesses_varied_thickness\n\n\nskeleton_tree_3d = cKDTree(skeleton_coords_3d)\n\n\nmask_coords_3d = np.column_stack(np.where(mask_data))\n\n\ndistances_3d, indices_3d = skeleton_tree_3d.query(mask_coords_3d)\n\n\ncolored_mask_3d = np.zeros_like(mask_data, dtype=float)\n\n\nfor idx, coord in enumerate(mask_coords_3d):\n    colored_mask_3d[coord[0], coord[1], coord[2]] = skeleton_thicknesses_3d[indices_3d[idx]]\n\n\ncolored_mask_3d.shape\n\nthickess = colored_mask_3d\nskeleton = skeleton_varied_thickness \n\nthickess_mask = np.zeros_like(thickess, dtype=np.uint8)\nthickess_mask[thickess&gt;0] = 1  \nthickess_mask[thickess&gt;5] = 2  \n\nthick_mask = np.zeros_like(thickess, dtype=np.uint8)\nthick_mask[thickess_mask==2] = 1\nthick_mask = thick_mask | skeleton\n\nthin_mask = np.zeros_like(thickess, dtype=np.uint8)\nthin_mask[thickess_mask==1] = 1\nthin_mask = thin_mask | skeleton\n</code></pre>\n<h2>Inference</h2>\n<ul>\n<li>or ensemble ( 2D and 3D )</li>\n<li>Threshold adjusted with kidney2</li>\n</ul>\n<h1>post processing</h1>\n<ul>\n<li>merge each estimations with each threshold</li>\n</ul>\n<pre><code> post_processing(y_pred:torch.Tensor, thr=[.,.,.], k= ):\n    \n     = y_pred[,:]*k\n     = y_pred[,:]\n     = y_pred[,:]\n\n     = (y_pred0 &gt; int(thr[]*))\n     = (y_pred1 &gt; int(thr[]*))\n     = (y_pred2 &gt; int(thr[]*))\n\n     = y_pred0 | y_pred1 | y_pred2\n    \n\n     y_pred\n</code></pre>",
  "messages": [
    {
      "id": 2641614,
      "postDate": "2024-02-07T15:17:15.527Z",
      "content": "<h1>110th Place, Did Not Work: Splitting Thin/Thick Vessels Approach</h1>\n<p>Thank you for hosting the competition.</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2F6d623087b77192ed018bb4216e81f873%2Fvessel.png?generation=1707318307890041&amp;alt=media\"></p>\n<h2>Overview</h2>\n<ul>\n<li>Employed both 2D Unet and 3D Unet approaches.</li>\n<li>Expectation: The 2D model was expected to capture larger vessels, while the 3D model should have been better at capturing smaller vessels.</li>\n<li>2D Unet 512 x 512 (xy,yz,xz)<ul>\n<li>backbone: SE_resnext50</li></ul></li>\n<li>3D Unet 128 x 128 x 128<ul>\n<li>backbone : Resnet18</li></ul></li>\n</ul>\n<h2>Training</h2>\n<ul>\n<li>Pre-training with all data</li>\n<li>Fine-tuning with dense dataset(kidney1&amp;3)<ul>\n<li>augmentation with monai API for multi mask</li></ul></li>\n</ul>\n<pre><code>    aug_list = [\n                    RandRotated(keys=[, , , ],range_x = np.pi/180 * 90, =np.pi/180 * 90, =np.pi/180 * 90, =1, =),\n                    RandFlipd(keys=[, , , ], =1),\n                    RandGridDistortiond(keys=(, , , ), =1, distort_limit=(-0.03, 0.03), =), \n                    RandZoomd(keys=[, , , ], min_zoom = 1 , max_zoom = 6/5, =1, =),\n                    RandAdjustContrastd(keys=[],=1, gamma=(0.8, 2.5)),\n                    ]\n</code></pre>\n<h2>Data preprocessing</h2>\n<ul>\n<li>Thin/thick vessel split approach<ul>\n<li>Hypothesis: The premise was that a difference in contrast, dependent on vessel thickness, would result in unstable thresholding.This challenge was similar to issues discussed in papers on retinal vessel detection.</li>\n<li>Reference: <a href=\"https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full\" target=\"_blank\">https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full</a><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2Fadb0df2308c1f3db2936a04bfd945f3e%2Ffbioe-09-697915-g002.jpg?generation=1707318581847217&amp;alt=media\"></li>\n<li>But overfitted to CV…</li>\n<li>Source code: 3d splitting code</li></ul></li>\n</ul>\n<pre><code>from scipy.ndimage import distance_transform_edt\nfrom skimage.morphology import skeletonize_3d\n\n\ndist_transform_varied_thickness = distance_transform_edt(mask_data)\n\n\nskeleton_varied_thickness = skeletonize_3d(mask_data)\n\n\nz_varied_thickness, y_varied_thickness, x_varied_thickness = np.where(skeleton_varied_thickness)\n\n\nnum_points = len(x_varied_thickness)\n\n\n\nthicknesses_varied_thickness = np.array([dist_transform_varied_thickness[z, y, x] * 2 \n                                         for z, y, x in zip(z_varied_thickness, y_varied_thickness, x_varied_thickness)])\n\n\nthicknesses_varied_thickness.shape, thicknesses_varied_thickness[:10]  \n\nfrom scipy.spatial import cKDTree\n\n\n\nskeleton_coords_3d = np.column_stack([z_varied_thickness, y_varied_thickness, x_varied_thickness])\nskeleton_thicknesses_3d = thicknesses_varied_thickness\n\n\nskeleton_tree_3d = cKDTree(skeleton_coords_3d)\n\n\nmask_coords_3d = np.column_stack(np.where(mask_data))\n\n\ndistances_3d, indices_3d = skeleton_tree_3d.query(mask_coords_3d)\n\n\ncolored_mask_3d = np.zeros_like(mask_data, dtype=float)\n\n\nfor idx, coord in enumerate(mask_coords_3d):\n    colored_mask_3d[coord[0], coord[1], coord[2]] = skeleton_thicknesses_3d[indices_3d[idx]]\n\n\ncolored_mask_3d.shape\n\nthickess = colored_mask_3d\nskeleton = skeleton_varied_thickness \n\nthickess_mask = np.zeros_like(thickess, dtype=np.uint8)\nthickess_mask[thickess&gt;0] = 1  \nthickess_mask[thickess&gt;5] = 2  \n\nthick_mask = np.zeros_like(thickess, dtype=np.uint8)\nthick_mask[thickess_mask==2] = 1\nthick_mask = thick_mask | skeleton\n\nthin_mask = np.zeros_like(thickess, dtype=np.uint8)\nthin_mask[thickess_mask==1] = 1\nthin_mask = thin_mask | skeleton\n</code></pre>\n<h2>Inference</h2>\n<ul>\n<li>or ensemble ( 2D and 3D )</li>\n<li>Threshold adjusted with kidney2</li>\n</ul>\n<h1>post processing</h1>\n<ul>\n<li>merge each estimations with each threshold</li>\n</ul>\n<pre><code> post_processing(y_pred:torch.Tensor, thr=[.,.,.], k= ):\n    \n     = y_pred[,:]*k\n     = y_pred[,:]\n     = y_pred[,:]\n\n     = (y_pred0 &gt; int(thr[]*))\n     = (y_pred1 &gt; int(thr[]*))\n     = (y_pred2 &gt; int(thr[]*))\n\n     = y_pred0 | y_pred1 | y_pred2\n    \n\n     y_pred\n</code></pre>",
      "rawMarkdown": "# 110th Place, Did Not Work: Splitting Thin/Thick Vessels Approach\nThank you for hosting the competition.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2F6d623087b77192ed018bb4216e81f873%2Fvessel.png?generation=1707318307890041&alt=media)\n\n## Overview\n- Employed both 2D Unet and 3D Unet approaches.\n- Expectation: The 2D model was expected to capture larger vessels, while the 3D model should have been better at capturing smaller vessels.\n- 2D Unet 512 x 512 (xy,yz,xz)\n  - backbone: SE_resnext50\n- 3D Unet 128 x 128 x 128\n  - backbone : Resnet18\n\n## Training\n- Pre-training with all data\n- Fine-tuning with dense dataset(kidney1&3)\n  - augmentation with monai API for multi mask\n```\n    aug_list = [\n                    RandRotated(keys=[\"image\", \"mask\", \"mask2\", \"mask3\"],range_x = np.pi/180 * 90, range_y=np.pi/180 * 90, range_z=np.pi/180 * 90, prob=1, mode=\"nearest\"),\n                    RandFlipd(keys=[\"image\", \"mask\", \"mask2\", \"mask3\"], prob=1),\n                    RandGridDistortiond(keys=(\"image\", \"mask\", \"mask2\", \"mask3\"), prob=1, distort_limit=(-0.03, 0.03), mode=\"nearest\"), \n                    RandZoomd(keys=[\"image\", \"mask\", \"mask2\", \"mask3\"], min_zoom = 1 , max_zoom = 6/5, prob=1, mode=\"nearest\"),\n                    RandAdjustContrastd(keys=[\"image\"],prob=1, gamma=(0.8, 2.5)),\n                    ]\n```\n\n\n## Data preprocessing\n- Thin/thick vessel split approach\n  - Hypothesis: The premise was that a difference in contrast, dependent on vessel thickness, would result in unstable thresholding.This challenge was similar to issues discussed in papers on retinal vessel detection.\n  - Reference: [https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full](https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full)\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2Fadb0df2308c1f3db2936a04bfd945f3e%2Ffbioe-09-697915-g002.jpg?generation=1707318581847217&alt=media)\n - But overfitted to CV...\n  - Source code: 3d splitting code\n```\nfrom scipy.ndimage import distance_transform_edt\nfrom skimage.morphology import skeletonize_3d\n\n# Perform distance transform\ndist_transform_varied_thickness = distance_transform_edt(mask_data)\n\n# Perform skeletonization for 3D\nskeleton_varied_thickness = skeletonize_3d(mask_data)\n\n# Get the coordinates of the skeleton\nz_varied_thickness, y_varied_thickness, x_varied_thickness = np.where(skeleton_varied_thickness)\n\n# Display some basic information about the skeleton and thickness\nnum_points = len(x_varied_thickness)\n# thicknesses_varied_thickness.shape, num_points\n\n# Calculate thicknesses in a memory-efficient way\nthicknesses_varied_thickness = np.array([dist_transform_varied_thickness[z, y, x] * 2 \n                                         for z, y, x in zip(z_varied_thickness, y_varied_thickness, x_varied_thickness)])\n\n# Checking the shape of the calculated thicknesses\nthicknesses_varied_thickness.shape, thicknesses_varied_thickness[:10]  # Displaying first 10 thickness values\n\nfrom scipy.spatial import cKDTree\n\n# Adjusting the process for 3D data\n# Get the skeleton coordinates and thicknesses in 3D\nskeleton_coords_3d = np.column_stack([z_varied_thickness, y_varied_thickness, x_varied_thickness])\nskeleton_thicknesses_3d = thicknesses_varied_thickness\n\n# Create a KDTree for the points on the skeleton in 3D\nskeleton_tree_3d = cKDTree(skeleton_coords_3d)\n\n# Get the coordinates of all pixels in the original mask in 3D\nmask_coords_3d = np.column_stack(np.where(mask_data))\n\n# Find the nearest point on the skeleton for each pixel in the original mask\ndistances_3d, indices_3d = skeleton_tree_3d.query(mask_coords_3d)\n\n# Initialize a colored mask for 3D data\ncolored_mask_3d = np.zeros_like(mask_data, dtype=float)\n\n# Assign the corresponding thickness to each pixel in the original mask\nfor idx, coord in enumerate(mask_coords_3d):\n    colored_mask_3d[coord[0], coord[1], coord[2]] = skeleton_thicknesses_3d[indices_3d[idx]]\n\n# Check the shape of the colored mask\ncolored_mask_3d.shape\n\nthickess = colored_mask_3d\nskeleton = skeleton_varied_thickness \n    \nthickess_mask = np.zeros_like(thickess, dtype=np.uint8)\nthickess_mask[thickess>0] = 1  # thin\nthickess_mask[thickess>5] = 2  # thick\n        \nthick_mask = np.zeros_like(thickess, dtype=np.uint8)\nthick_mask[thickess_mask==2] = 1\nthick_mask = thick_mask | skeleton\n            \nthin_mask = np.zeros_like(thickess, dtype=np.uint8)\nthin_mask[thickess_mask==1] = 1\nthin_mask = thin_mask | skeleton\n\n```\n\n## Inference\n- or ensemble ( 2D and 3D )\n- Threshold adjusted with kidney2\n\n# post processing\n* merge each estimations with each threshold\n```\ndef post_processing(y_pred:torch.Tensor, thr=[0.5,0.5,0.5], k=1 ):\n    # or でマスクを作成。eze(1)\n    y_pred0 = y_pred[0,:]*k\n    y_pred1 = y_pred[1,:]\n    y_pred2 = y_pred[2,:]\n    \n    y_pred0 = (y_pred0 > int(thr[0]*255))\n    y_pred1 = (y_pred1 > int(thr[1]*255))\n    y_pred2 = (y_pred2 > int(thr[2]*255))\n\n    y_pred = y_pred0 | y_pred1 | y_pred2\n    #y_pred = y_pred.astype(np.float32) \n    \n    return y_pred\n```\n",
      "votes": 3
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "2641614": "# 110th Place, Did Not Work: Splitting Thin/Thick Vessels Approach\nThank you for hosting the competition.\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2F6d623087b77192ed018bb4216e81f873%2Fvessel.png?generation=1707318307890041&alt=media)\n\n## Overview\n- Employed both 2D Unet and 3D Unet approaches.\n- Expectation: The 2D model was expected to capture larger vessels, while the 3D model should have been better at capturing smaller vessels.\n- 2D Unet 512 x 512 (xy,yz,xz)\n  - backbone: SE_resnext50\n- 3D Unet 128 x 128 x 128\n  - backbone : Resnet18\n\n## Training\n- Pre-training with all data\n- Fine-tuning with dense dataset(kidney1&3)\n  - augmentation with monai API for multi mask\n```\n    aug_list = [\n                    RandRotated(keys=[\"image\", \"mask\", \"mask2\", \"mask3\"],range_x = np.pi/180 * 90, range_y=np.pi/180 * 90, range_z=np.pi/180 * 90, prob=1, mode=\"nearest\"),\n                    RandFlipd(keys=[\"image\", \"mask\", \"mask2\", \"mask3\"], prob=1),\n                    RandGridDistortiond(keys=(\"image\", \"mask\", \"mask2\", \"mask3\"), prob=1, distort_limit=(-0.03, 0.03), mode=\"nearest\"), \n                    RandZoomd(keys=[\"image\", \"mask\", \"mask2\", \"mask3\"], min_zoom = 1 , max_zoom = 6/5, prob=1, mode=\"nearest\"),\n                    RandAdjustContrastd(keys=[\"image\"],prob=1, gamma=(0.8, 2.5)),\n                    ]\n```\n\n\n## Data preprocessing\n- Thin/thick vessel split approach\n  - Hypothesis: The premise was that a difference in contrast, dependent on vessel thickness, would result in unstable thresholding.This challenge was similar to issues discussed in papers on retinal vessel detection.\n  - Reference: [https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full](https://www.frontiersin.org/articles/10.3389/fbioe.2021.697915/full)\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F2930242%2Fadb0df2308c1f3db2936a04bfd945f3e%2Ffbioe-09-697915-g002.jpg?generation=1707318581847217&alt=media)\n - But overfitted to CV...\n  - Source code: 3d splitting code\n```\nfrom scipy.ndimage import distance_transform_edt\nfrom skimage.morphology import skeletonize_3d\n\n# Perform distance transform\ndist_transform_varied_thickness = distance_transform_edt(mask_data)\n\n# Perform skeletonization for 3D\nskeleton_varied_thickness = skeletonize_3d(mask_data)\n\n# Get the coordinates of the skeleton\nz_varied_thickness, y_varied_thickness, x_varied_thickness = np.where(skeleton_varied_thickness)\n\n# Display some basic information about the skeleton and thickness\nnum_points = len(x_varied_thickness)\n# thicknesses_varied_thickness.shape, num_points\n\n# Calculate thicknesses in a memory-efficient way\nthicknesses_varied_thickness = np.array([dist_transform_varied_thickness[z, y, x] * 2 \n                                         for z, y, x in zip(z_varied_thickness, y_varied_thickness, x_varied_thickness)])\n\n# Checking the shape of the calculated thicknesses\nthicknesses_varied_thickness.shape, thicknesses_varied_thickness[:10]  # Displaying first 10 thickness values\n\nfrom scipy.spatial import cKDTree\n\n# Adjusting the process for 3D data\n# Get the skeleton coordinates and thicknesses in 3D\nskeleton_coords_3d = np.column_stack([z_varied_thickness, y_varied_thickness, x_varied_thickness])\nskeleton_thicknesses_3d = thicknesses_varied_thickness\n\n# Create a KDTree for the points on the skeleton in 3D\nskeleton_tree_3d = cKDTree(skeleton_coords_3d)\n\n# Get the coordinates of all pixels in the original mask in 3D\nmask_coords_3d = np.column_stack(np.where(mask_data))\n\n# Find the nearest point on the skeleton for each pixel in the original mask\ndistances_3d, indices_3d = skeleton_tree_3d.query(mask_coords_3d)\n\n# Initialize a colored mask for 3D data\ncolored_mask_3d = np.zeros_like(mask_data, dtype=float)\n\n# Assign the corresponding thickness to each pixel in the original mask\nfor idx, coord in enumerate(mask_coords_3d):\n    colored_mask_3d[coord[0], coord[1], coord[2]] = skeleton_thicknesses_3d[indices_3d[idx]]\n\n# Check the shape of the colored mask\ncolored_mask_3d.shape\n\nthickess = colored_mask_3d\nskeleton = skeleton_varied_thickness \n    \nthickess_mask = np.zeros_like(thickess, dtype=np.uint8)\nthickess_mask[thickess>0] = 1  # thin\nthickess_mask[thickess>5] = 2  # thick\n        \nthick_mask = np.zeros_like(thickess, dtype=np.uint8)\nthick_mask[thickess_mask==2] = 1\nthick_mask = thick_mask | skeleton\n            \nthin_mask = np.zeros_like(thickess, dtype=np.uint8)\nthin_mask[thickess_mask==1] = 1\nthin_mask = thin_mask | skeleton\n\n```\n\n## Inference\n- or ensemble ( 2D and 3D )\n- Threshold adjusted with kidney2\n\n# post processing\n* merge each estimations with each threshold\n```\ndef post_processing(y_pred:torch.Tensor, thr=[0.5,0.5,0.5], k=1 ):\n    # or でマスクを作成。eze(1)\n    y_pred0 = y_pred[0,:]*k\n    y_pred1 = y_pred[1,:]\n    y_pred2 = y_pred[2,:]\n    \n    y_pred0 = (y_pred0 > int(thr[0]*255))\n    y_pred1 = (y_pred1 > int(thr[1]*255))\n    y_pred2 = (y_pred2 > int(thr[2]*255))\n\n    y_pred = y_pred0 | y_pred1 | y_pred2\n    #y_pred = y_pred.astype(np.float32) \n    \n    return y_pred\n```\n"
  }
}