Skip to content

Commit

Permalink
Include comments from Or
Browse files Browse the repository at this point in the history
  • Loading branch information
johnfhima committed Jul 22, 2024
1 parent 48319d1 commit 4a2db63
Show file tree
Hide file tree
Showing 135 changed files with 861 additions and 13,958 deletions.
506 changes: 266 additions & 240 deletions .ipynb_checkpoints/pvbmtutorial-checkpoint.ipynb

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions PVBM/CentralRetinalAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,33 @@ def crve_knudtson(self,w1, w2):
"""
return 0.95 * (w1 ** 2 + w2 ** 2) ** 0.5


def apply_roi(self, segmentation, skeleton, zones_ABC):
"""
Apply a region of interest (ROI) mask to the segmentation and skeleton images.
:param segmentation: The segmentation image containing binary values within {0, 1}.
:type segmentation: np.array
:param skeleton: The skeleton image containing binary values within {0, 1}.
:type skeleton: np.array
:param zones_ABC: A mask image used to exclude specific zones, where the second channel defines the exclusion areas.
:type zones_ABC: np.array
:return: A tuple containing:
- The modified segmentation image with the ROI applied.
- The modified skeleton image with the ROI applied.
:rtype: Tuple[np.array, np.array]
"""
zone_A_ = zones_ABC[:, :, 1] / 255
zone_B_ = zones_ABC[:, :, 0] / 255
zone_C_ = zones_ABC[:, :, 2] / 255
roi = (zone_C_ - zone_B_)
segmentation_roi = (segmentation * roi)
skeleton_roi = (skeleton * roi)


return segmentation_roi, skeleton_roi

def compute_central_retinal_equivalents(self,blood_vessel, skeleton, xc,yc, radius, artery = True, Toplot = False):
"""
Compute the CRAE or CRVE equivalent for a given blood vessel graph.
Expand Down
2 changes: 1 addition & 1 deletion PVBM/Datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import zipfile


class PVBM_Datasets:
class PVBMDataDownloader:
"""A class that downloads the PVBM datasets."""
def __init__(self):
self.file_ids = {
Expand Down
53 changes: 45 additions & 8 deletions PVBM/GeometryAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,32 @@ def recursive_topology(self,A, B, i, j, n, max_radius, x_c, y_c, endpoints, inte
j_or, dico, bacount + 1, bapos, distance + dist)


def apply_roi(self, segmentation, skeleton, zones_ABC, roi):
"""
Apply a region of interest (ROI) mask to the segmentation and skeleton images.
:param segmentation: The segmentation image containing binary values within {0, 1}.
:type segmentation: np.array
:param skeleton: The skeleton image containing binary values within {0, 1}.
:type skeleton: np.array
:param zones_ABC: A mask image used to exclude specific zones, where the second channel defines the exclusion areas.
:type zones_ABC: np.array
:param roi: The region of interest mask, where the second channel defines the ROI areas.
:type roi: np.array
:return: A tuple containing:
- The modified segmentation image with the ROI applied.
- The modified skeleton image with the ROI applied.
:rtype: Tuple[np.array, np.array]
"""
segmentation_roi = segmentation * (1 - zones_ABC[:, :, 1] / 255)
segmentation_roi = segmentation_roi * roi[:, :, 1] / 255

skeleton_roi = skeleton * (1 - zones_ABC[:, :, 1] / 255)
skeleton_roi = skeleton_roi * roi[:, :, 1] / 255

return segmentation_roi, skeleton_roi

def compute_geomVBMs(self,blood_vessel, skeleton, xc,yc, radius):
"""
Compute various geometrical vascular biomarkers (VBMs) for a given blood vessel graph.
Expand Down Expand Up @@ -265,18 +291,29 @@ def compute_geomVBMs(self,blood_vessel, skeleton, xc,yc, radius):
angles = []
for key, value in angles_dico.items():
b = key
if len(value) > 1:
if len(value) == 2:
a, c = value[0], value[1]
if b != None and c != None and a != None:
b = np.array(b)
a = np.array(a)
c = np.array(c)
ba = a - b
bc = c - b

if all(x is not None for x in (a, b, c)):
ba = np.array(a) - np.array(b)
bc = np.array(c) - np.array(b)
cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.arccos(cosine_angle)
angles.append(np.degrees(angle))
elif len(value) == 3:
a, c, d = value
if all(x is not None for x in (a, b, c, d)):
ba = np.array(a) - np.array(b)
bc = np.array(c) - np.array(b)
cosine_angle_ac = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle_ac = np.arccos(cosine_angle_ac)
angles.append(np.degrees(angle_ac))

bc = np.array(c) - np.array(b)
bd = np.array(d) - np.array(b)
cosine_angle_cd = np.dot(bc, bd) / (np.linalg.norm(bc) * np.linalg.norm(bd))
angle_cd = np.arccos(cosine_angle_cd)
angles.append(np.degrees(angle_cd))

####Computing the median branching angles, the number of start/inter/endpoints
medianba = np.median(angles)
startp = len(starting_point_list)
Expand Down
Binary file modified PVBM/__pycache__/CentralRetinalAnalysis.cpython-311.pyc
Binary file not shown.
Binary file modified PVBM/__pycache__/Datasets.cpython-311.pyc
Binary file not shown.
Binary file modified PVBM/__pycache__/GeometryAnalysis.cpython-311.pyc
Binary file not shown.
81 changes: 51 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ You can access the external test set used in the LUNet paper directly from PVBM:
(These include Crop_HRF, INSPIRE, and UNAF.)

```python
from PVBM.Datasets import PVBM_Datasets
from PVBM.Datasets import PVBMDataDownloader
path_to_save_datasets = "../PVBM_datasets"
dataset_downloader = PVBM_Datasets()
dataset_downloader.download_dataset("Crop_HRF", path_to_save_datasets)
dataset_downloader.download_dataset("INSPIRE", path_to_save_datasets)
dataset_downloader.download_dataset("UNAF", path_to_save_datasets)
dataset_downloader = PVBMDataDownloader()
dataset_downloader.download_dataset(name="Crop_HRF", save_folder_path=path_to_save_datasets)
dataset_downloader.download_dataset(name="INSPIRE", save_folder_path=path_to_save_datasets)
dataset_downloader.download_dataset(name="UNAF", save_folder_path=path_to_save_datasets)
print("Images downloaded successfully")
```

Expand All @@ -85,9 +85,9 @@ segmenter = DiscSegmenter()
# Define the segmentation path and replace specific parts of the path
image_path = '../PVBM_datasets/INSPIRE/images/image13.png'
# Extract the segmentation
optic_disc = segmenter.segment(image_path)
optic_disc = segmenter.segment(image_path=image_path)
#Extract the optic disc features
center, radius, roi, zones_ABC = segmenter.post_processing(optic_disc, max_roi_size = 600)
center, radius, roi, zones_ABC = segmenter.post_processing(segmentation=optic_disc, max_roi_size = 600)
```

### Geometrical VBMs
Expand All @@ -102,30 +102,31 @@ from PIL import Image
blood_vessel_segmentation_path = '../PVBM_datasets/INSPIRE/artery/image13.png'
segmentation = np.array(Image.open(blood_vessel_segmentation_path))/255 #Open the segmentation
skeleton = skeletonize(segmentation)*1
segmentation_roi = segmentation * (1-zones_ABC[:,:,1]/255)
segmentation_roi = segmentation_roi * roi[:,:,1]/255
skeleton_roi = skeleton * (1-zones_ABC[:,:,1]/255)
skeleton_roi = skeleton_roi * roi[:,:,1]/255

geometricalVBMs = GeometricalVBMs() #Instanciate a geometrical VBM object
vbms, visual = geometricalVBMs.compute_geomVBMs(segmentation_roi, skeleton_roi, center[0], center[1], radius)
segmentation_roi, skeleton_roi = geometricalVBMs.apply_roi(
segmentation=segmentation,
skeleton=skeleton,
zones_ABC=zones_ABC,
roi=roi
)
vbms, visual = geometricalVBMs.compute_geomVBMs(
blood_vessel=segmentation_roi,
skeleton=skeleton_roi,
xc=center[0],
yc=center[1],
radius=radius
)
area, TI, medTor, ovlen, medianba, startp, endp, interp = vbms
```

### Fractal Analysis
```python
### First run the optic disc segmentation snippet to extract center, radius, roi, zones_ABC
### Then compute the segmentation_roi array as done in the previous code snippet

from PVBM.FractalAnalysis import MultifractalVBMs
import numpy as np
from PIL import Image

#Preprocessing and roi extraction
blood_vessel_segmentation_path = '../PVBM_datasets/INSPIRE/artery/image13.png'
segmentation = np.array(Image.open(blood_vessel_segmentation_path))/255 #Open the segmentation
segmentation_roi = segmentation * (1-zones_ABC[:,:,1]/255)
segmentation_roi = segmentation_roi * roi[:,:,1]/255

fractalVBMs = MultifractalVBMs(n_rotations = 25,optimize = True, min_proba = 0.0001, maxproba = 0.9999)
D0,D1,D2,SL = fractalVBMs.compute_multifractals(segmentation_roi.copy())
```
Expand All @@ -140,28 +141,48 @@ import numpy as np
from skimage.morphology import skeletonize
from PIL import Image
#Preprocessing and roi extraction
zone_A_ = zones_ABC[:,:,1]/255
zone_B_ = zones_ABC[:,:,0]/255
zone_C_ = zones_ABC[:,:,2]/255
roi = (zone_C_ - zone_B_)
creVBMs = CREVBMs()

####Artery
blood_vessel_segmentation_path = '../PVBM_datasets/INSPIRE/artery/image13.png'
segmentation = np.array(Image.open(blood_vessel_segmentation_path))/255 #Open the segmentation
skeleton = skeletonize(segmentation)*1
segmentation_roi = (segmentation * roi)
skeleton_roi = (skeleton * roi)
out = creVBMs.compute_central_retinal_equivalents(segmentation_roi.copy(), skeleton_roi.copy(),center[0],center[1], radius, artery = True, Toplot = True )
segmentation_roi, skeleton_roi = creVBMs.apply_roi(
segmentation=segmentation,
skeleton=skeleton,
zones_ABC=zones_ABC
)
out = creVBMs.compute_central_retinal_equivalents(
blood_vessel=segmentation_roi.copy(),
skeleton=skeleton_roi.copy(),
xc=center[0],
yc=center[1],
radius=radius,
artery = True,
Toplot = False #This allows to generate the CRE visualisation but require a lot of RAM
# If you are only interested about the VBMs values then set Toplot to False
)
craek, craeh = out["craek"], out["craeh"]

####Veins
blood_vessel_segmentation_path = '../PVBM_datasets/INSPIRE/veins/image13.png'
segmentation = np.array(Image.open(blood_vessel_segmentation_path))/255 #Open the segmentation
skeleton = skeletonize(segmentation)*1
segmentation_roi = (segmentation * roi)
skeleton_roi = (skeleton * roi)
out = creVBMs.compute_central_retinal_equivalents(segmentation_roi.copy(), skeleton_roi.copy(),center[0],center[1], radius, artery = False, Toplot = True )
segmentation_roi, skeleton_roi = creVBMs.apply_roi(
segmentation=segmentation,
skeleton=skeleton,
zones_ABC=zones_ABC
)
out = creVBMs.compute_central_retinal_equivalents(
blood_vessel=segmentation_roi.copy(),
skeleton=skeleton_roi.copy(),
xc=center[0],
yc=center[1],
radius=radius,
artery = False,
Toplot = False #This allows to generate the CRE visualisation but require a lot of RAM
# If you are only interested about the VBMs values then set Toplot to False
)
crvek, crveh = out["crvek"], out["crveh"]

AVR_h = craeh/crveh
Expand Down
27 changes: 27 additions & 0 deletions build/lib/PVBM/CentralRetinalAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,33 @@ def crve_knudtson(self,w1, w2):
"""
return 0.95 * (w1 ** 2 + w2 ** 2) ** 0.5


def apply_roi(self, segmentation, skeleton, zones_ABC):
"""
Apply a region of interest (ROI) mask to the segmentation and skeleton images.
:param segmentation: The segmentation image containing binary values within {0, 1}.
:type segmentation: np.array
:param skeleton: The skeleton image containing binary values within {0, 1}.
:type skeleton: np.array
:param zones_ABC: A mask image used to exclude specific zones, where the second channel defines the exclusion areas.
:type zones_ABC: np.array
:return: A tuple containing:
- The modified segmentation image with the ROI applied.
- The modified skeleton image with the ROI applied.
:rtype: Tuple[np.array, np.array]
"""
zone_A_ = zones_ABC[:, :, 1] / 255
zone_B_ = zones_ABC[:, :, 0] / 255
zone_C_ = zones_ABC[:, :, 2] / 255
roi = (zone_C_ - zone_B_)
segmentation_roi = (segmentation * roi)
skeleton_roi = (skeleton * roi)


return segmentation_roi, skeleton_roi

def compute_central_retinal_equivalents(self,blood_vessel, skeleton, xc,yc, radius, artery = True, Toplot = False):
"""
Compute the CRAE or CRVE equivalent for a given blood vessel graph.
Expand Down
2 changes: 1 addition & 1 deletion build/lib/PVBM/Datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import zipfile


class PVBM_Datasets:
class PVBMDataDownloader:
"""A class that downloads the PVBM datasets."""
def __init__(self):
self.file_ids = {
Expand Down
53 changes: 45 additions & 8 deletions build/lib/PVBM/GeometryAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,32 @@ def recursive_topology(self,A, B, i, j, n, max_radius, x_c, y_c, endpoints, inte
j_or, dico, bacount + 1, bapos, distance + dist)


def apply_roi(self, segmentation, skeleton, zones_ABC, roi):
"""
Apply a region of interest (ROI) mask to the segmentation and skeleton images.
:param segmentation: The segmentation image containing binary values within {0, 1}.
:type segmentation: np.array
:param skeleton: The skeleton image containing binary values within {0, 1}.
:type skeleton: np.array
:param zones_ABC: A mask image used to exclude specific zones, where the second channel defines the exclusion areas.
:type zones_ABC: np.array
:param roi: The region of interest mask, where the second channel defines the ROI areas.
:type roi: np.array
:return: A tuple containing:
- The modified segmentation image with the ROI applied.
- The modified skeleton image with the ROI applied.
:rtype: Tuple[np.array, np.array]
"""
segmentation_roi = segmentation * (1 - zones_ABC[:, :, 1] / 255)
segmentation_roi = segmentation_roi * roi[:, :, 1] / 255

skeleton_roi = skeleton * (1 - zones_ABC[:, :, 1] / 255)
skeleton_roi = skeleton_roi * roi[:, :, 1] / 255

return segmentation_roi, skeleton_roi

def compute_geomVBMs(self,blood_vessel, skeleton, xc,yc, radius):
"""
Compute various geometrical vascular biomarkers (VBMs) for a given blood vessel graph.
Expand Down Expand Up @@ -265,18 +291,29 @@ def compute_geomVBMs(self,blood_vessel, skeleton, xc,yc, radius):
angles = []
for key, value in angles_dico.items():
b = key
if len(value) > 1:
if len(value) == 2:
a, c = value[0], value[1]
if b != None and c != None and a != None:
b = np.array(b)
a = np.array(a)
c = np.array(c)
ba = a - b
bc = c - b

if all(x is not None for x in (a, b, c)):
ba = np.array(a) - np.array(b)
bc = np.array(c) - np.array(b)
cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.arccos(cosine_angle)
angles.append(np.degrees(angle))
elif len(value) == 3:
a, c, d = value
if all(x is not None for x in (a, b, c, d)):
ba = np.array(a) - np.array(b)
bc = np.array(c) - np.array(b)
cosine_angle_ac = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle_ac = np.arccos(cosine_angle_ac)
angles.append(np.degrees(angle_ac))

bc = np.array(c) - np.array(b)
bd = np.array(d) - np.array(b)
cosine_angle_cd = np.dot(bc, bd) / (np.linalg.norm(bc) * np.linalg.norm(bd))
angle_cd = np.arccos(cosine_angle_cd)
angles.append(np.degrees(angle_cd))

####Computing the median branching angles, the number of start/inter/endpoints
medianba = np.median(angles)
startp = len(starting_point_list)
Expand Down
Binary file added dist/pvbm-2.9.9.1-py3-none-any.whl
Binary file not shown.
Binary file added dist/pvbm-2.9.9.1.tar.gz
Binary file not shown.
2 changes: 2 additions & 0 deletions docs/CentralRetinalAnalysis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ CentralRetinalAnalysis
:members: None

.. automethod:: compute_central_retinal_equivalents
.. automethod:: apply_roi

2 changes: 1 addition & 1 deletion docs/Datasets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Datasets

.. automodule:: PVBM.Datasets

.. autoclass:: PVBM_Datasets
.. autoclass:: PVBMDataDownloader
:members: None

.. automethod:: download_dataset
1 change: 1 addition & 0 deletions docs/GeometryAnalysis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ GeometryAnalysis
:members: None

.. automethod:: compute_geomVBMs
.. automethod:: apply_roi
Binary file removed docs/_build/doctrees/CentralRetinalAnalysis.doctree
Binary file not shown.
Binary file removed docs/_build/doctrees/Datasets.doctree
Binary file not shown.
Binary file removed docs/_build/doctrees/DiscSegmenter.doctree
Binary file not shown.
Binary file removed docs/_build/doctrees/FractalAnalysis.doctree
Binary file not shown.
Binary file removed docs/_build/doctrees/GeometricalAnalysis.doctree
Binary file not shown.
Binary file removed docs/_build/doctrees/GeometryAnalysis.doctree
Binary file not shown.
Binary file removed docs/_build/doctrees/environment.pickle
Binary file not shown.
Binary file removed docs/_build/doctrees/index.doctree
Binary file not shown.
Loading

0 comments on commit 4a2db63

Please sign in to comment.