Skip to content

Commit

Permalink
Merge pull request #6 from bmandracchia/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
bmandracchia authored Jul 16, 2024
2 parents 4e4cfc3 + 69fd2e9 commit 8d3573c
Show file tree
Hide file tree
Showing 110 changed files with 85,878 additions and 532 deletions.
582 changes: 582 additions & 0 deletions .virtual_documents/nbs/03_data.ipynb

Large diffs are not rendered by default.

264 changes: 264 additions & 0 deletions .virtual_documents/nbs/04_transforms.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@



#| default_exp transforms


#| hide
from nbdev.showdoc import *


#| export
from fastai.vision.all import *
from fastai.data.all import *
from monai.transforms import SpatialCrop, Flip, Rotate90








# # Define a random tensor
# orig_size = (10, 8)
# rand_tensor = torch.rand(3, *orig_size) # Random tensor with shape (3, 10, 8)

# # Specify the desired size and top-left corner for cropping
# size = (12, 9)
# tl = (2, 3)

# # Perform cropping
# result_tensor = crop_pad_tensor(rand_tensor, size, tl, orig_size)

# print("Original tensor shape:", rand_tensor.shape)
# print("Cropped tensor shape:", result_tensor.shape)


#| export

def _process_sz(size, ndim=3):
if isinstance(size,int):
size=(size,)*ndim
return fastuple(size)

def _get_sz(x):
if isinstance(x, tuple): x = x[0]
if not isinstance(x, Tensor): return fastuple(x.size)
return fastuple(getattr(x, 'img_size', getattr(x, 'sz', (x.shape[1:])))) # maybe it should swap x and y axes


# Define a random tensor
orig_size = (10, 8)
rand_tensor = torch.rand(3, *orig_size) # Random tensor with shape (3, 10, 8)

test_eq((3,)*3,_process_sz(3,ndim=3))
test_eq(orig_size,_get_sz((rand_tensor, rand_tensor)))








#| export

class RandCrop2D(RandTransform):
"Randomly crop an image to `size`"
split_idx,order = None,1
def __init__(self,
size:int|tuple, # Size to crop to, duplicated if one value is specified
lazy = False, # a flag to indicate whether this transform should execute lazily or not. Defaults to False
**kwargs
):
size = _process_sz(size, ndim=2)
store_attr()
super().__init__(**kwargs)

def before_call(self,
b,
split_idx:int # Index of the train/valid dataset
):
"Randomly positioning crop if train dataset else center crop"
self.orig_sz = _get_sz(b)
if split_idx: self.ctr = (self.orig_sz)//2
else:
wd = self.orig_sz[0] - self.size[0]
hd = self.orig_sz[1] - self.size[1]
w_rand = (wd, -1) if wd < 0 else (0, wd)
h_rand = (hd, -1) if hd < 0 else (0, hd)
self.ctr = fastuple(random.randint(*w_rand)+self.size[0]//2, random.randint(*h_rand)+self.size[1]//2)

def encodes(self, x):
return SpatialCrop(roi_center=self.ctr, roi_size=self.size, lazy=self.lazy)(x)





#| export

class RandCropND(RandTransform):
"""
Randomly crops an ND image to a specified size.

This transform randomly crops an ND image to a specified size during training and performs
a center crop during validation. It supports both 2D and 3D images and videos, assuming
the first dimension is the batch dimension.

Args:
size (int or tuple): The size to crop the image to. this can have any number of dimensions.
If a single value is provided, it will be duplicated for each spatial
dimension, up to a maximum of 3 dimensions.
**kwargs: Additional keyword arguments to be passed to the parent class.
"""

split_idx,order = None,1

def __init__(self, size: int | tuple, # Size to crop to, duplicated if one value is specified
lazy = False, # a flag to indicate whether this transform should execute lazily or not. Defaults to False
**kwargs):
size = _process_sz(size)
store_attr()
super().__init__(**kwargs)

def before_call(self, b, split_idx: int):
"Randomly position crop if train dataset else center crop"
self.orig_sz = _get_sz(b)
if split_idx:
self.tl = tuple((osz - sz) // 2 for osz, sz in zip(self.orig_sz, self.size))
self.br = tuple((osz + sz) // 2 for osz, sz in zip(self.orig_sz, self.size))
else:
tl = [] # top-left corner
br = [] # bottom-right corner
# Calculate top-left and bottom-right corner coordinates for random crop
for osz, sz in zip(self.orig_sz, self.size):
w_dif = osz - sz
if w_dif < 0:
w_rand = (0, 0) # No random cropping if input size is smaller than crop size
sz = osz # Adjust crop size to match input size
else:
w_rand = (0, w_dif)
rnd = random.randint(*w_rand)
tl.append(rnd)
br.append(rnd + sz)
self.tl = fastuple(*tl)
self.br = fastuple(*br)

def encodes(self, x):
"Apply spatial crop transformation to the input image."
return SpatialCrop(roi_start=self.tl, roi_end=self.br, lazy=self.lazy)(x)



# Define a random tensor
orig_size = (65, 65)
rand_tensor = torch.rand(8, *orig_size)

for i in range(100):
test_eq((8,64,64),RandCropND((64,64))(rand_tensor).shape)





#| export

class RandFlip(RandTransform):
"""
Randomly flips an ND image over a specified axis.

"""

split_idx,order = None,1

def __init__(self,
prob = 0.1, # Probability of flipping
spatial_axis = None, # Spatial axes along which to flip over. Default is None. The default axis=None will flip over all of the axes of the input array.
# If axis is negative it counts from the last to the first axis. If axis is a tuple of ints, flipping is performed on all of the axes specified in the tuple.
ndim = 2,
lazy = False, # Flag to indicate whether this transform should execute lazily or not. Defaults to False
**kwargs):
store_attr()
super().__init__(**kwargs)

def before_call(self, b, split_idx: int):
if split_idx:
self.flip = 0
else:
self.flip = np.random.choice([0, 1], p=[1-self.prob, self.prob])
if self.spatial_axis is None:
self.spatial_axis = np.random.choice(np.arange(self.ndim), size=np.random.randint(1, self.ndim+1), replace=False, p=None)

def encodes(self, x):
if self.flip:
return Flip(spatial_axis=self.spatial_axis, lazy=self.lazy)(x)
else:
return x


# Define a random tensor
orig_size = (1,4,4)
rand_tensor = torch.rand(*orig_size)

print('orig tensor: ', rand_tensor, '\n')

for i in range(3):
print(RandFlip(prob=.75, spatial_axis=None)(rand_tensor))





#| export

class RandRot90(RandTransform):
"""
Randomly rotate an ND image by 90 degrees in the plane specified by axes.

"""

split_idx,order = None,1

def __init__(self,
prob = 0.1, # Probability of rotating
max_k = 3, # Max number of times to rotate by 90 degrees
spatial_axes = (0, 1), # Spatial axes along which to rotate. Default: (0, 1), this is the first two axis in spatial dimensions.
ndim = 2,
lazy = False, # Flag to indicate whether this transform should execute lazily or not. Defaults to False
**kwargs):
store_attr()
super().__init__(**kwargs)

def before_call(self, b, split_idx: int):
if split_idx:
self.rot90 = 0
else:
self.rot90 = np.random.choice([0, 1], p=[1-self.prob, self.prob])
self.k = 1 + np.random.randint(self.max_k)
# if self.spatial_axes is None:
# self.spatial_axes = np.random.choice(np.arange(self.ndim), size=np.random.randint(1, self.ndim+1), replace=False, p=None)

def encodes(self, x):
if self.rot90:
return Rotate90(k=self.k, spatial_axes=self.spatial_axes, lazy=self.lazy)(x)
else:
return x


# Define a random tensor
orig_size = (1,4,4)
rand_tensor = torch.rand(*orig_size)

print('orig tensor: ', rand_tensor, '\n')

for i in range(3):
print(RandRot90(prob=.75)(rand_tensor))





#| hide
import nbdev; nbdev.nbdev_export()
3 changes: 3 additions & 0 deletions =2022.8.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Requirement already satisfied: aicspylibczi in /home/juanlocal/anaconda3/envs/bioMONAI-env/lib/python3.11/site-packages (3.1.2)
Requirement already satisfied: fsspec in /home/juanlocal/anaconda3/envs/bioMONAI-env/lib/python3.11/site-packages (2023.6.0)
Requirement already satisfied: numpy>=1.14.1 in /home/juanlocal/anaconda3/envs/bioMONAI-env/lib/python3.11/site-packages (from aicspylibczi) (1.26.2)
7 changes: 7 additions & 0 deletions =3.1.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Collecting aicspylibczi
Downloading aicspylibczi-3.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (10 kB)
Requirement already satisfied: numpy>=1.14.1 in /home/biagio/miniconda3/envs/bioMONAI-env/lib/python3.11/site-packages (from aicspylibczi) (1.26.2)
Downloading aicspylibczi-3.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.0 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.0/1.0 MB 20.1 MB/s eta 0:00:00
Installing collected packages: aicspylibczi
Successfully installed aicspylibczi-3.1.2
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ documentation.
pip install bioMONAI
```


## How to use

Fill me in please! Don’t forget code examples:
Expand Down
1 change: 1 addition & 0 deletions _proc/.quarto/idx/00_core.ipynb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"title":"core","markdown":{"yaml":{"description":"bioMONAI core","output-file":"core.html","title":"core"},"headingText":"Dataloaders","containsRefs":false,"markdown":"\n\n\n\n<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->\n\n\nGet the ground truth images located in a folder called 'gt' and divided in labeled subfolders.\n\n> These function are tailor-made for some test datasets, eventually they must be changed/adapted to more general cases\n\nGet as ground truth another noisy image randomly chosen in the same folder as the input image\n\n## Utils\n\n## Display 3D images\n\nFunction to display the 3D volume in axial, coronal or sagittal reconstruction. The display functions does not consider the spacing between pixels, so reconstructions may look unusual. \n\n# Other functions\n\nfeatures to be implemented\n","srcMarkdownNoYaml":"\n\n\n\n<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->\n\n## Dataloaders\n\nGet the ground truth images located in a folder called 'gt' and divided in labeled subfolders.\n\n> These function are tailor-made for some test datasets, eventually they must be changed/adapted to more general cases\n\nGet as ground truth another noisy image randomly chosen in the same folder as the input image\n\n## Utils\n\n## Display 3D images\n\nFunction to display the 3D volume in axial, coronal or sagittal reconstruction. The display functions does not consider the spacing between pixels, so reconstructions may look unusual. \n\n# Other functions\n\nfeatures to be implemented\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":true,"cache":null,"freeze":false,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":false,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"engine":"jupyter"},"render":{"keep-tex":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true,"format-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","css":["styles.css"],"toc":true,"output-file":"core.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.3.450","theme":"cosmo","description":"bioMONAI core","title":"core"},"extensions":{"book":{"multiFile":true}}}},"projectFormats":["html"]}
Loading

0 comments on commit 8d3573c

Please sign in to comment.