Skip to content

Commit

Permalink
Implement WSI instantiation from URL; related to #1
Browse files Browse the repository at this point in the history
  • Loading branch information
afrendeiro committed Dec 7, 2023
1 parent 1422340 commit 6c66b10
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 13 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
# LazySlide


## Installation

```bash
pip install git+ssh://git@github.com/rendeirolab/LazySlide.git
```

## Usage

```python
import lazyslide as zs

slide = '' # Your SVS file
slide = 'https://github.com/camicroscope/Distro/raw/master/images/sample.svs' # Your SVS file
wsi = zs.WSI(slide)
wsi.plot_tissue()

Expand All @@ -21,10 +28,9 @@ wsi.plot_tissue(contours=True)

wsi.create_tiles(tile_px=256, mpp=.5)
wsi.plot_tissue(tiles=True)

```

If you want to do feature extration
To do feature extraction:
```python
import torch
from torch.utils.data import DataLoader
Expand All @@ -37,19 +43,18 @@ loader = DataLoader(
resnet = torch.hub.load("pytorch/vision", "resnet50", weights="IMAGENET1K_V2")

with torch.no_grad():
for tile in loader():
for tile in loader:
tile_feature = resnet(tile)

```

### Developer Notes

To make pyvips works on Windows:
To make pyvips work on Windows:

```python
import os
vipsbin = ''
os.environ['PATH'] = vipsbin + ';' + os.environ['PATH']

import pyvips as vips
```
```
44 changes: 39 additions & 5 deletions lazyslide/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from pathlib import Path
from dataclasses import dataclass, field
from itertools import tee
from typing import Type
from urllib.parse import urlparse

import requests

from .readers.base import ReaderBase
from .readers.vips import VipsReader
Expand All @@ -17,11 +21,7 @@ def pairwise(iterable):
def get_reader(reader="auto") -> Type[ReaderBase]:
"""Return an available backend"""

readers = {
"openslide": None,
"vips": None,
"cucim": None
}
readers = {"openslide": None, "vips": None, "cucim": None}

try:
import openslide
Expand Down Expand Up @@ -53,6 +53,40 @@ def get_reader(reader="auto") -> Type[ReaderBase]:
return readers[reader]


def is_url(s: str) -> bool:
try:
result = urlparse(s)
return all([result.scheme, result.netloc])
except ValueError:
return False


def download_file(url: str, file_path: Path, chunk_size: int = 1024):
"""Download a file in chunks"""
r = requests.get(url, stream=True)
with file_path.open("wb") as fd:
for chunk in r.iter_content(chunk_size=chunk_size):
fd.write(chunk)


def check_wsi_path(path: str | Path, allow_download: bool = True) -> Path:
import tempfile

# Check path is URL or Path
if isinstance(path, str):
if is_url(path):
if not allow_download:
raise ValueError("Given a URL but not allowed to download.")
file_path = Path(tempfile.mkdtemp()) / path.split("/")[-1].split("?")[0]
download_file(path, file_path)
return file_path
elif Path(path).exists():
return Path(path)
elif isinstance(path, Path):
if path.exists():
return path
raise ValueError("Path must be a URL or Path to existing file.")

@dataclass
class TileOps:
level: int = 0
Expand Down
11 changes: 10 additions & 1 deletion lazyslide/wsi.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@ def get_split_image_indices(image_height, image_width, min_side=20000):


class WSI:
from .utils import check_wsi_path

def __init__(self,
self.image = check_wsi_path(image)
image: Path | str,
h5_file: Path | str = None,
reader="auto", # openslide, vips, cucim
Expand Down Expand Up @@ -220,6 +221,14 @@ def reader(self):
def metadata(self):
return self.reader.metadata

def move_wsi_file(self, new_path: Path) -> None:
new_path = Path(new_path)
if not new_path.exists():
self.image.rename(new_path)
self.image = new_path
else:
raise FileExistsError(f"File {new_path} already exists.")

def create_mask(self, transform, name="user", level=-1, save=False):
level = self.reader.translate_level(level)
image = self.reader.get_level(level)
Expand Down

0 comments on commit 6c66b10

Please sign in to comment.