<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PyTorch on Benedykt Huszcza | Blog</title><link>https://blog.huszcza.dev/tags/pytorch/</link><description>Recent content in PyTorch on Benedykt Huszcza | Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 23 Feb 2025 18:00:00 +0000</lastBuildDate><atom:link href="https://blog.huszcza.dev/tags/pytorch/index.xml" rel="self" type="application/rss+xml"/><item><title>Vessel Extraction – Image Processing Using Python and OpenCV</title><link>https://blog.huszcza.dev/p/vessel-extraction/</link><pubDate>Sun, 23 Feb 2025 18:00:00 +0000</pubDate><guid>https://blog.huszcza.dev/p/vessel-extraction/</guid><description>&lt;img src="https://blog.huszcza.dev/p/vessel-extraction/cover.jpg" alt="Featured image of post Vessel Extraction – Image Processing Using Python and OpenCV" />&lt;h2 id="introduction">Introduction
&lt;/h2>&lt;p>This project was developed as part of the course &lt;strong>Medical Informatics&lt;/strong>. Except for a hackathon (by the way, I highly recommend reading &lt;a class="link" href="https://kaszkowiak.org/blog/ensemble-ai/" target="_blank" rel="noopener"
>Maciej&amp;rsquo;s post&lt;/a> about this event), this was my &lt;strong>first serious encounter with libraries&lt;/strong> such as &lt;strong>PyTorch&lt;/strong> and &lt;strong>OpenCV&lt;/strong>.&lt;/p>
&lt;p>Since the task turned out to be quite challenging, it forced me to &lt;strong>dive deep into research&lt;/strong> on various image processing methods. I explored literally everything – from the simplest filters to more advanced &lt;strong>computer vision&lt;/strong> techniques. As a result, I learned the fundamental methods used in this field, significantly broadening my knowledge.&lt;/p>
&lt;p>I won&amp;rsquo;t lie – it was tough at times, especially when noise in the images ruined hours of coding. Nevertheless, the &lt;strong>vision of using technology to analyze medical images&lt;/strong> inspired me and kept me going. There were moments of frustration when things didn&amp;rsquo;t work as expected, but the &lt;strong>satisfaction of a working solution&lt;/strong> definitely made up for all the struggles.&lt;/p>
&lt;h2 id="k-nearest-neighbors-knn--blood-vessel-classification">K-Nearest Neighbors (KNN) – Blood Vessel Classification
&lt;/h2>&lt;h3 id="what-is-k-nearest-neighbors">What is K-Nearest Neighbors?
&lt;/h3>&lt;p>&lt;strong>K-Nearest Neighbors (KNN)&lt;/strong> is one of the simplest and most intuitive &lt;strong>machine learning&lt;/strong> algorithms. It operates on the assumption that &lt;strong>similar data points are close to each other in feature space&lt;/strong>. In short – if you want to know the class of a new point, check the class of its nearest neighbors.&lt;/p>
&lt;p>In the case of &lt;strong>Vessel Extraction&lt;/strong>, KNN was used for:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Classifying pixels&lt;/strong> as &amp;ldquo;blood vessels&amp;rdquo; or &amp;ldquo;background,&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>Analyzing pixel neighborhoods&lt;/strong> to better distinguish vessels from noise.&lt;/li>
&lt;/ul>
&lt;h3 id="undersampling--how-did-i-deal-with-imbalanced-data">Undersampling – How Did I Deal with Imbalanced Data?
&lt;/h3>&lt;h3 id="what-were-the-challenges">What Were the Challenges?
&lt;/h3>&lt;ul>
&lt;li>
&lt;p>&lt;strong>Overwhelming amount of background data&lt;/strong> – Areas without blood vessels (background) dominated the images, causing the model to learn to recognize mainly the background and not the vessels.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Underrepresentation of blood vessels&lt;/strong> – Pixels belonging to blood vessels made up &lt;strong>less than 10%&lt;/strong> of all data, leading to model overfitting.&lt;/p>
&lt;p>&lt;img src="https://blog.huszcza.dev/p/vessel-extraction/mask.png"
width="512"
height="512"
srcset="https://blog.huszcza.dev/p/vessel-extraction/mask_hub25e895537f1a182441b7f28296fe610_37737_480x0_resize_box_3.png 480w, https://blog.huszcza.dev/p/vessel-extraction/mask_hub25e895537f1a182441b7f28296fe610_37737_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="Example mask showing that blood vessels make up a small portion of the entire image"
class="gallery-image"
data-flex-grow="100"
data-flex-basis="240px"
>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="how-did-i-handle-it">How Did I Handle It?
&lt;/h3>&lt;p>I decided to use &lt;strong>undersampling&lt;/strong> – intentionally &lt;strong>reducing the number of background samples&lt;/strong> so that the number of vessel and background pixels was more balanced. Sounds simple, but it required a few thoughtful steps:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Selecting Background Samples&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>I didn&amp;rsquo;t randomly discard background data, as this could lead to a loss of important contextual information.&lt;/li>
&lt;li>I focused on &lt;strong>representative samples&lt;/strong>, specifically those located near blood vessels. This gave the model better learning context.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Reducing Background Samples&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>I ultimately &lt;strong>reduced the number of background samples by about 70%&lt;/strong>, resulting in a more &lt;strong>balanced ratio&lt;/strong> of vessel to background data.&lt;/li>
&lt;li>It was crucial not to overdo it – I had to leave enough background to prevent the model from confusing it with vessels.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Preserving Local Patterns&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>By using &lt;strong>3x3 pixel patches&lt;/strong>, the model retained local patterns, which improved &lt;strong>accuracy&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="how-did-knn-work-in-this-project">How Did KNN Work in This Project?
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Feature Extraction&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Each pixel was described by its brightness value and the values of neighboring pixels.&lt;/li>
&lt;li>This provided the model with more information about the local context.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Choosing the Number of Neighbors (k)&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>The key parameter in KNN is &lt;strong>k&lt;/strong> – the number of nearest neighbors whose class is considered for classification.&lt;/li>
&lt;li>I conducted &lt;strong>cross-validation&lt;/strong> to find the optimal value for &lt;strong>k&lt;/strong>.&lt;/li>
&lt;li>The best results were achieved with &lt;strong>k = 5&lt;/strong>, ensuring a &lt;strong>balance between accuracy and recall&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Classification&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>For each pixel, the classes of its &lt;strong>k nearest neighbors&lt;/strong> were checked.&lt;/li>
&lt;li>The pixel was assigned to the class with the most representatives in its neighborhood.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="results-and-performance">Results and Performance
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Accuracy&lt;/strong>: &lt;strong>89%&lt;/strong> – pretty good for a simple model without deep learning!&lt;/li>
&lt;li>&lt;strong>Recall&lt;/strong>: &lt;strong>85%&lt;/strong> – effectively detected blood vessels but sometimes confused them with thin background lines.&lt;/li>
&lt;li>&lt;strong>Precision&lt;/strong>: &lt;strong>91%&lt;/strong> – the model successfully avoided false positives (mistaking the background for vessels).&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://blog.huszcza.dev/p/vessel-extraction/knn_results.png"
width="877"
height="231"
srcset="https://blog.huszcza.dev/p/vessel-extraction/knn_results_huab335b82c4c70e0ad9aa232b7bc3a084_116236_480x0_resize_box_3.png 480w, https://blog.huszcza.dev/p/vessel-extraction/knn_results_huab335b82c4c70e0ad9aa232b7bc3a084_116236_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="From left: original image, mask, reconstructed mask based on classification"
class="gallery-image"
data-flex-grow="379"
data-flex-basis="911px"
>
I know, at first glance, the &lt;strong>results don&amp;rsquo;t look impressive&lt;/strong>, and it&amp;rsquo;s hard to believe I got such good &lt;strong>&amp;ldquo;numbers&amp;rdquo;&lt;/strong> (i.e., accuracy). But here&amp;rsquo;s the trick – it&amp;rsquo;s all about the chosen approach.&lt;/p>
&lt;p>I used &lt;strong>3x3 pixel patches&lt;/strong> because smaller fragments make it easier for the model to detect local patterns characteristic of blood vessels. The total image size was &lt;strong>512x512 pixels&lt;/strong>, so if the classifier recognized a &lt;strong>3x3 patch as a vessel&lt;/strong>, all &lt;strong>9 pixels&lt;/strong> in that patch were &lt;strong>completely filled in white&lt;/strong>.&lt;/p>
&lt;p>This approach meant the model was &lt;strong>more confident in its decisions&lt;/strong>, which positively impacted accuracy and Dice score.&lt;/p>
&lt;hr>
&lt;h2 id="fastai--deep-learning-for-blood-vessel-classification">FastAi – Deep Learning for Blood Vessel Classification
&lt;/h2>&lt;h3 id="why-fastai">Why FastAi?
&lt;/h3>&lt;p>After testing the classic KNN approach, I decided to take it up a notch and use &lt;strong>FastAi&lt;/strong> – a framework built on &lt;strong>PyTorch&lt;/strong> that is excellent for rapid prototyping of deep learning models. FastAi provides:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Easy integration with pre-trained models&lt;/strong> (e.g., ResNet),&lt;/li>
&lt;li>&lt;strong>A simple API&lt;/strong> that speeds up data preparation and model training,&lt;/li>
&lt;li>&lt;strong>Advanced optimization techniques&lt;/strong> (e.g., learning rate finder).&lt;/li>
&lt;/ul>
&lt;h3 id="how-did-fastai-work-in-this-project">How Did FastAi Work in This Project?
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Data Preparation&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Images were divided into &lt;strong>smaller patches&lt;/strong> to help the models learn patterns more effectively.&lt;/li>
&lt;li>I used &lt;strong>FastAi DataBlock API&lt;/strong> for efficient data management and labeling.&lt;/li>
&lt;li>Classification was performed on two levels:
&lt;ul>
&lt;li>&lt;strong>Blood vessels&lt;/strong>,&lt;/li>
&lt;li>&lt;strong>Background&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Deep Learning Model&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>I chose &lt;strong>ResNet34&lt;/strong> – lightweight but powerful enough for vessel recognition.&lt;/li>
&lt;li>I used &lt;strong>transfer learning&lt;/strong> with pre-trained weights (ImageNet), which sped up training.&lt;/li>
&lt;li>&lt;strong>Fine-tuning&lt;/strong> the last layers helped tailor the model to the specific task of vessel recognition.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="results-and-performance-1">Results and Performance
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Accuracy&lt;/strong>: &lt;strong>92%&lt;/strong> – a clear improvement compared to KNN.&lt;/li>
&lt;li>&lt;strong>Recall&lt;/strong>: &lt;strong>90%&lt;/strong> – the model effectively recognized vessels, even in challenging cases.&lt;/li>
&lt;li>&lt;strong>Precision&lt;/strong>: &lt;strong>94%&lt;/strong> – very few false positives, resulting in highly accurate vessel detection.&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://blog.huszcza.dev/p/vessel-extraction/fast_ai_results.png"
width="884"
height="278"
srcset="https://blog.huszcza.dev/p/vessel-extraction/fast_ai_results_hu4eebe31602d40791196e041ac3b07fee_162820_480x0_resize_box_3.png 480w, https://blog.huszcza.dev/p/vessel-extraction/fast_ai_results_hu4eebe31602d40791196e041ac3b07fee_162820_1024x0_resize_box_3.png 1024w"
loading="lazy"
alt="FastAi Results"
class="gallery-image"
data-flex-grow="317"
data-flex-basis="763px"
>&lt;/p>
&lt;h3 id="first-step-into-machine-learning">First Step into Machine Learning
&lt;/h3>&lt;p>This was my &lt;strong>first individual project&lt;/strong> in &lt;strong>machine learning&lt;/strong> and &lt;strong>computer vision&lt;/strong>, and it was an incredible learning experience. I understood how powerful image processing techniques are and how to handle imbalanced data with &lt;strong>undersampling&lt;/strong>. Although there were many challenges and frustrations, I &lt;strong>got hooked on machine learning&lt;/strong>. Experimenting with data, testing models, and optimizing algorithms turned out to be truly exciting.&lt;/p>
&lt;p>I realize that I have a lot more to learn – from advanced neural network architectures to GPU optimization – but I&amp;rsquo;m excited to continue this journey. If you want to check out the source code or learn more, visit the &lt;strong>repository on &lt;a class="link" href="https://github.com/benhus8/vessel-recognition/tree/main" target="_blank" rel="noopener"
>GitHub&lt;/a>&lt;/strong>. Who knows, maybe this project will inspire you to start your own adventure with AI?&lt;/p></description></item></channel></rss>