Giter Club home page Giter Club logo

diagnijmegen / pathology-whole-slide-data Goto Github PK

View Code? Open in Web Editor NEW
80.0 6.0 24.0 95.83 MB

A package for working with whole-slide data including a fast batch iterator that can be used to train deep learning models.

Home Page: https://diagnijmegen.github.io/pathology-whole-slide-data/

License: Apache License 2.0

Python 99.15% Shell 0.34% Dockerfile 0.51%
histopathology iterator whole-slide-image whole-slide-annotation pathology python whole-slide-imaging deep-learning wsa wsi

pathology-whole-slide-data's Introduction


WholeSlideData

GitHub Workflow Status Coveralls GitHub Workflow Status

This repository contains software at a major version zero. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

Please checkout the Documentation and the CHANGELOG.

Overview


Introduction

WholeSlideData aims to provide the tools to work with whole slide images and annotations from different vendors and annotation software. The main contribution is a batch iterator that enables users to sample patches from the data efficiently, fast, and easily.

Efficient

WholeSlideData preserves the annotations in a JSON format internally and uses the Shapely library to do essential computations on basic geometries. Using this design ensures that the required memory to keep all the annotations in memory is more efficient than converting the annotations to masks. Furthermore, this package allows for the generation of patches and labels on the fly, which eludes the need for saving them to disk.

Fast

Extracting patches for whole slide images is slow compared to saving the patches to PNGs or NumPy arrays and loading them directly from the disk. Though, saving to disk has some disadvantageous as this will generate a static dataset. For example, you can not switch easily to other patch shapes or magnifications with a static dataset. WholeSlideData takes advantage of Concurrent Buffer, which uses shared memory and allows for loading patches quickly via multiple workers to overcome the relatively slow serial extraction of patches from whole slide images. Using many extra CPUs will increase the RAM needed. Nevertheless, we think that with this package, a good trade-off can be made such that sampling is fast, efficient, and allows for easy switching to different settings.

Ease

WholeSlideData uses a configuration system called Dicfg that allows users to configure the batch terator in a single config file. Using multiple configuration files is also possible to create a clean and well-structured configuration for your project. Dicfg has some parallels with Hydra. So if you are familiar with Hydra, it should be straightforward to make your configuration file for the batch iterator. Dicfg lets you configure any setting, build instances, and insert these instances as dependencies for other functions or classes directly in the config file. Furthermore, users can build on top of base classes and will only need to change the configuration file to use custom code without the need to change any part of the batch iterator.


Installation

pip install git+https://github.com/DIAGNijmegen/pathology-whole-slide-data@main

Wholeslidedata supports various image backends. You will have to install at least one of these image backends.

backend installation instructions
asap https://github.com/computationalpathologygroup/ASAP/releases/tag/ASAP-2.1-(Nightly)
openslide https://openslide.org/download/
pyvips https://pypi.org/project/pyvips
tiffslide https://github.com/bayer-science-for-a-better-life/tiffslide
cucim https://github.com/rapidsai/cucim

Openslide is currently the default image backend, but you can easily switch between different image backends in the config file.

For example:

wholeslidedata:
    default:
        image_backend: asap

Main Features

Whole-slide images

Opening a Whole Slide image.

from wholeslidedata.image.wholeslideimage import WholeSlideImage

wsi = WholeSlideImage('path_to_image.tif') 
patch = wsi.get_patch(x, y, width, height, spacing)

Whole-slide annotations

Currently, wholeslidedata supports annotations from the following annotation software: ASAP, QuPath, Virtum, and Histomicstk.

from wholeslidedata.annotation.wholeslideannotation import WholeSlideAnnotation

wsa = WholeSlideAnnotation('path_to_annotation.xml')
annotations = wsa.select_annotations(x, y, width, height)

Batch iterator

The batch generator needs to be configured via user config file. In the user config file, custom and build-in sampling strategies can be configured, such as random, balanced, area-based, and more. Additionally. custom and build-in sample and batch callbacks can be composed such as fit_shape, one-hot-encoding, albumentations, and more. For a complete overview please check out the main config file and all the sub config files.

Example of a basic user config file (user_config.yml)

--- 
wholeslidedata: 
  default: 
  
    yaml_source: 
      training: 
        - 
          wsa: 
            path: /tmp/TCGA-21-5784-01Z-00-DX1.xml
          wsi: 
            path: /tmp/TCGA-21-5784-01Z-00-DX1.tif
            
    labels: 
      stroma: 1
      tumor: 2
      lymphocytes: 3
      
    batch_shape: 
      shape: [256, 256, 3]
      batch_size: 8
      spacing: 0.5

Creating a batch iterator

from wholeslidedata.iterators import create_batch_iterator

with create_batch_iterator(mode='training', 
                           user_config='user_config.yml',
                           number_of_batches=10,
                           cpus=4) as training_iterator:
                           
    for x_batch, y_batch, batch_info in training_iterator:
        pass

Acknowledgments

Created in the #EXAMODE project

pathology-whole-slide-data's People

Contributors

aswolinskiy avatar daangeijs avatar joeyspronck avatar kaczmarj avatar leandervaneekelen avatar martvanrijthoven avatar mat-po avatar rj678 avatar robinlomans avatar siemdejong avatar thijsgelton avatar tsikup avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pathology-whole-slide-data's Issues

Tissue masking

Hi Mart,

I was wondering if there is anything available yet for tissue masking. I think there is quite some use cases for tissue masking.
For example:

  1. When working with WSI's without annotations. Still being able to sample patches from tissue regions from the WSI would be a nice to have.
  2. To exclude annotations that are outside of tissue regions. In my project I'm dealing with ''lazy annotations'' where at the border of the biopsy some non tissue is often included in the annotated region to save time during the annotation process (see example below).

It might be beneficial to perform tissue masking before patch extraction for the first use case. Let me know what you think and if there is already options for this!

Best,

Michel

changing image backend to pyvips

hello @martvanrijthoven - thank you for all of the effort in releasing this code.

I followed the instructions to change the image backend to pyvips

I added:

wholeslidedata:
    default:
        image_backend: pyvips

to the config file under wholeslidedata/configuration/config_files/config.yml

but keep getting this error:

RegistrantNotRegisteredError: 
        Registrant 'pyvips' is not found in the register of class 'WholeSlideImageBackend' with registrant names ('openslide',) and register classes (<class 'wholeslidedata.accessories.openslide.backend.OpenSlideWholeSlideImageBackend'>,).

could you help me add the configuration to the correct config file please, thank you

Patch label sampler fails with point annotation

I was sampling patches that I used to sample correctly with WSD 0.15/0.16

However I got the following error:
IndexError: index 1 is out of bounds for axis 0 with size 1

at this line:

mask[int(coordinates[1]), int(coordinates[0])] = annotation.label.value

Aparantly there is an incorrect point annotation (a TIL) in a segmentation class (stoma) that im sampling, but this didnt fail before, and I think it shouldnt fail

'coordinates' in this case = [[99.7655 78.5625]]

so I think uit should be:
mask[int(coordinates[0][1]), int(coordinates[0][0])]
instead of:
mask[int(coordinates[1]), int(coordinates[0])]

add conda recipe

Daisy-chaining complex dependency chains is much better using conda (especially if a dependency uses C/C++ libraries underneath). It would be great to have the conda recipe for this project.

create_batch_iterator that associates files with exact matching

For some file keys I am running into problems with associations. For example when the following files are in my data.yml:

DATASET5-12345_HE-I.tiff
DATASET5-12345_HE-II.tiff
DATASET5-12345_HE-III.tiff

In this case associate_files() with exact matching is required. Is it possible to add the functionality of requiring exact matching to associate files to the create_batch_iterator function?

At some point it calls associate_files() in

It's default setting for requiring an exact match is False. I think I'd be useful to be able to call create_batch_iterator with requiring an exact match.

Let me know what you think about adding this or if you know a workaround solution!

Support qptiff?

Hi all,

Thanks again for the nice work. I have been testing the create_batch_iterator function using a data.yml look like below:

training:
    - wsi: 
        path:  xyz.qptiff 
      wsa: 
        path:  xyz.xml

However, I receive a error:

File ~/anaconda3/envs/xyz/lib/python3.9/site-packages/sourcelib/file.py:49, in File._get_extension(self, path)
     [48](file:///home/u0021936/anaconda3/envs/aortic-root/lib/python3.9/site-packages/sourcelib/file.py?line=47) def _get_extension(self, path: Path) -> Extension:
---> [49](file:/anaconda3/envs/xyz/lib/python3.9/site-packages/sourcelib/file.py?line=48)     return self.EXTENSIONS[path.suffix]

KeyError: '.qptiff'

Is it because qptiff isn't supported in the WholeSlideDataset as I don't seem them in the extensions.py? Would it be possible for wholeslidedata to support .qptiff? Or is there an alternative way I can approach this issue?

Cucim backend not available

Loading cucim with wsd using

from wholeslidedata.image.backends import get_backend

image_backend = 'cucim'
wsd_image_backend = get_backend(image_backend)

gives the following error:

Traceback (most recent call last):
  File "/home/siemdejong/miniforge3/envs/pathology/lib/python3.11/site-packages/wholeslidedata/image/backends.py", line 31, in get_backend
    return getattr(import_module(module), attribute)
                   ^^^^^^^^^^^^^^^^^^^^^
  File "/home/siemdejong/miniforge3/envs/pathology/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/siemdejong/miniforge3/envs/pathology/lib/python3.11/site-packages/wholeslidedata/interoperability/cucim/backend.py", line 7, in <module>
    class _MixedMeta(type(WholeSlideImageBackend), type(CuImage)):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases type, pybind11_type

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/siemdejong/miniforge3/envs/pathology/lib/python3.11/site-packages/wholeslidedata/image/backends.py", line 33, in get_backend
    raise BackendNotAvailableError(backend)
wholeslidedata.image.backends.BackendNotAvailableError: cucim

Using python 3.11.7.

write docs

Tasks

KeyError: 'classification' in qupath annotation parser

Hi all and thanks for this amazing library. 😊
TL;DR: Solution for handling cases in which the "Classification" key is not present for all the annotations in the GeoJSON from QuPath.

My process:
I am exploring QuPath for different annotation tasks and i am using this package to process it.
One possible scenario involve identifying a ROI in which there might be two different types of cells. Then it is possible to identify the cells and compute some measurements, which will be used to train a classifier.
The results of this operation is typically an object of type Annotation which contains several (hundred/thousands) of object of type Cell .
image
The Annotation usually does not have a "Classification" key, and it is not useful to have it (to my current understanding) since it has an heterogenous class of cells inside it. The Cells instead do have a "Classification" key.

I believe that the current implementation of the QuPath annotation parser assumes that the "Classification" key is always present in the GeoJSON file.

annotation["properties"]["classification"]["name"]

and raise a KeyError if it does not find it.

Proposed solution
I solved it successfully as follow:

        labels = set(
            [
        annotation.get("properties", {}).get("classification", {}).get("name")
        for annotation in opened_annotation
        if annotation.get("properties", {}).get("classification") and annotation.get("properties", {}).get("classification", {}).get("name")
            ]
        )

Does this sound reasonable or am i missing something?
If you find it useful i can open a pull request

Artifacts from batch iterator

When using batch iterator for extracting patches at 8 um/px there are some artifacts in the extracted patches. Few examples of this:

image

image

The user config used:

wholeslidedata:
    default:
        seed: 123
        yaml_source: tigerdatasubset.yml
        
        label_map:
            roi: 0
            invasive tumor: 1
            tumor-associated stroma: 2
            in-situ tumor: 3 
            healthy glands: 4
            necrosis not in-situ: 5
            inflamed stroma: 6
            rest: 7
            
        annotation_parser:
            sample_label_names: ['roi']
            
        batch_shape:
            batch_size: 2
            spacing: 8
            shape: [256, 256, 3]

        point_sampler:
            attribute: RandomPointSampler
            buffer: -128
            

the data subset used :

--- 
training: 
  - 
    wsa: 
      path: /data/wsirois/wsi-level-annotations/annotations-tissue-cells-xmls/100B.xml
    wsi: 
      path: /data/wsirois/wsi-level-annotations/images/100B.tif

To reproduce this the "Tiger-BatchIterator Introduction" notebook can be run with the above settings. Is this a known issue?

Strict sampling with `point_sampler` fails when using data with different level 0 spacings

The PointSampler classes have a 'buffer' argument that allows you specify a margin around the border of your sampling annotations that you shouldn't sample from. If you set buffer equals to half the width/height of the shape of your patches, you effectively enforce 'strict sampling', i.e. only sample patches inside the sampling annotation and nothing outside.

However, the buffer argument is based on the level 0 spacing of whatever image you're sampling. If you have images that have a different level 0 spacing (practical example: I have images scanned at 0.25 um/px and 0.5 um/px and I want to sample at 0.5 um/px), this buffer argument doesn't work.

Proposed solution: make the PointSampler subclasses that use the 'buffer' argument aware of the spacings of the images and convert 'buffer' to level 0 of the image with the smallest spacing. I'm not quite sure whether or not this works though..

AsapAnnotationParser label colors from group

Hi @martvanrijthoven,

Can the AsapAnnotationParser be changed such that the parsed label color is the color of the group, instead of the individual annotation color? I think this behavior would make sense since the parser also takes the label name from the group, instead of the individual annotation name.

I think the simplest way to achieve this would be to pass the root element to the _get_label method of AsapAnnotationParser, and modify the method to:

    def _get_label(self, child, root, labels: Labels, type):
        name = self._get_label_name(child, labels, type)
        if name not in labels.names:
            return None

        label = labels.get_label_by_name(name)
        label = label.todict()
        root.find(f".//Group[@Name='{name}']").get("Color")
        if 'color' not in label or label['color'] is None:
            if color:
                label["color"] = color

        return label

RegistrantNotRegisteredError in Tiger-Hooknet Example

Hi, Thanks a lot for this tool!
I am trying to run the notebook Tiger - HookNet training.
I have set up python 3.8.5 and on RHEL server/Windows machine.

I am encountering this error:

RegistrantNotRegisteredError: 
        Registrant 'openslide' is not found in the register of class 'WholeSlideImageBackend' with an empty register

when I try to create the create_batch_iterator
I have openslide-python installed already.

Could you please help me in fixing this issue? It comes up in RHEL servers, windows machines.

Installing package on local machine

Trying to install the package on my (local) conda environment through

!pip install git+https://github.com/DIAGNijmegen/pathology-whole-slide-data@main

Installation seems successful, yet when I try to use the library on a jupyter notebook, it says that there's no name called 'wholeslidedata'

how to calculate number of samples in one full pass of BatchIterator

Hi, thank you for creating this excellent tool. I am using the BatchIterator as in the example notebook, and I would like to understand how to calculate the number of samples in a single pass through the batch iterator.

I would like to know this for a deep learning application. I am hoping to use this tool to extract tissues and their corresponding annotations and save those to disk. However, I need to know how many samples are present in my dataset.

Copy_data_path freezes upon first trial

When copying data to docker container from a config file using:

dataset:
copy_path: /home/user/data

Initialising the batch_iterator freezes on the first attempt. Waiting for the copying to finish, stopping the running code block and re-running it produces the expected results. The output on the first attempt is below, output on second attempt below that:

Config files + code listed at the bottom of the post.

First attempt:

`Copied from '/data/pathology/projects/pathology-multires-segmentation/data/breastdataset/images/data_lvl1/999.tif'
Copied to: '/home/user/data/T999.tif'
...
Destination path '/home/user/data/T999.tif' already exists

Process ProducerForkProcess-4:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/home/user/.local/lib/python3.8/site-packages/concurrentbuffer/producer.py", line 58, in run
self._producer.build()
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/buffer/batchproducer.py", line 20, in build
build = self._config_builder.build_instances()
File "/home/user/.local/lib/python3.8/site-packages/creationism/configuration/config.py", line 320, in build_instances
build[mode][key] = build[mode][key].build(configurations)
File "/home/user/.local/lib/python3.8/site-packages/creationism/configuration/config.py", line 242, in build
return ConfigObject(_build_object(self, module, attribute))
File "/home/user/.local/lib/python3.8/site-packages/creationism/configuration/config.py", line 350, in _build_object
return attribute(**builds.cast())
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 131, in init
super().init(mode, associations, labels, renamed_labels)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 40, in init
self.data = self._open(self._associations)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 143, in _open
] = self._open_image(wsi_file)

Destination path '/home/user/data/T999.tif' already exists

File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 156, in _open_image
return wsi_file.open()

File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/source/files.py", line 86, in open
return WholeSlideImage(self.path, self._image_backend)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/image/wholeslideimage.py", line 19, in init
self._backend = WholeSlideImageBackend.create(backend, path=self._path)
Process ProducerForkProcess-5:
File "/home/user/.local/lib/python3.8/site-packages/creationism/registration/factory.py", line 89, in create
return cls._create(class_type, *args, **kwargs)
Traceback (most recent call last):
File "/home/user/.local/lib/python3.8/site-packages/creationism/registration/factory.py", line 98, in _create
return class_type(*args, **kwargs)
File "/usr/local/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/home/user/.local/lib/python3.8/site-packages/concurrentbuffer/producer.py", line 58, in run
self._producer.build()
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/image/backend.py", line 150, in init
OpenSlide.init(self, str(path))
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/buffer/batchproducer.py", line 20, in build
build = self._config_builder.build_instances()
File "/home/user/.local/lib/python3.8/site-packages/openslide/init.py", line 160, in init
self._osr = lowlevel.open(filename)
File "/home/user/.local/lib/python3.8/site-packages/creationism/configuration/config.py", line 320, in build_instances
build[mode][key] = build[mode][key].build(configurations)
File "/home/user/.local/lib/python3.8/site-packages/openslide/lowlevel.py", line 128, in _check_open
raise OpenSlideUnsupportedFormatError(
File "/home/user/.local/lib/python3.8/site-packages/creationism/configuration/config.py", line 242, in build
return ConfigObject(_build_object(self, module, attribute))
openslide.lowlevel.OpenSlideUnsupportedFormatError: Unsupported or missing image file
File "/home/user/.local/lib/python3.8/site-packages/creationism/configuration/config.py", line 350, in _build_object
return attribute(**builds.cast())
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 131, in init
super().init(mode, associations, labels, renamed_labels)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 40, in init
self.data = self._open(self._associations)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 143, in _open
] = self._open_image(wsi_file)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/dataset.py", line 156, in _open_image
return wsi_file.open()
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/source/files.py", line 86, in open
return WholeSlideImage(self.path, self._image_backend)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/image/wholeslideimage.py", line 19, in init
self._backend = WholeSlideImageBackend.create(backend, path=self._path)
File "/home/user/.local/lib/python3.8/site-packages/creationism/registration/factory.py", line 89, in create
return cls._create(class_type, *args, **kwargs)
File "/home/user/.local/lib/python3.8/site-packages/creationism/registration/factory.py", line 98, in _create
return class_type(*args, **kwargs)
File "/home/user/.local/lib/python3.8/site-packages/wholeslidedata/image/backend.py", line 150, in init
OpenSlide.init(self, str(path))
File "/home/user/.local/lib/python3.8/site-packages/openslide/init.py", line 160, in init
self._osr = lowlevel.open(filename)
File "/home/user/.local/lib/python3.8/site-packages/openslide/lowlevel.py", line 128, in _check_open
raise OpenSlideUnsupportedFormatError(
openslide.lowlevel.OpenSlideUnsupportedFormatError: Unsupported or missing image file

Copied from '/data/pathology/projects/pathology-proacting/bcts/rumc_dcis_annotations/annotations_lv1_corrected_necrosis_witali_xml/T999.xml'
Copied to: '/home/user/data/T999.xml'
...`

Second attempt:

Destination path '/home/user/data/T999.tif' already exists
Destination path '/home/user/data/T999.xml' already exists
Destination path '/home/user/data/T999.tif' already existsDestination path '/home/user/data/T999.tif' already exists

Destination path '/home/user/data/T998.tif' already exists
Destination path '/home/user/data/T999.xml' already existsDestination path '/home/user/data/T999.xml' already exists

Destination path '/home/user/data/T998.xml' already exists
Destination path '/home/user/data/T998.tif' already existsDestination path '/home/user/data/T998.tif' already exists

Destination path '/home/user/data/T998.xml' already existsDestination path '/home/user/data/T998.xml' already exists

Code to reproduce:

from wholeslidedata.iterators import create_batch_iterator
from plot_utils import init_plot, plot_batch, show_plot

user_config = './
config.yml'
batches = 2 # how many batches that are going to be sampled, batchgenerator will be reset afterwards
repeats = 1
cpus = 2
mode = 'training'

training_batch_generator = create_batch_iterator(user_config=user_config,
batches=batches,
mode=mode,
cpus=cpus)

for r in range(repeats):
fig, axes = init_plot(batches, training_batch_generator.batch_size)
for idx, (x_batch, y_batch) in enumerate(training_batch_generator):
plot_batch(axes, idx, x_batch, y_batch)
show_plot(fig, r)

cuCIM backend not fully supported

After changes introduced in #56 by @siemdejong that fixed #55, new errors occur therefore it seems that the cuCIM backend is not yet fully supported.

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[7], line 3
      1 from wholeslidedata.iterators import create_batch_iterator
----> 3 dataLoader = create_batch_iterator(
      4     user_config=user_config, 
      5     mode='training',
      6     determinstic=True,
      7     cpus=cpus,
      8 )

File /usr/local/lib/python3.11/site-packages/wholeslidedata/iterators/batchiterator.py:159, in create_batch_iterator(user_config, mode, number_of_batches, index, update_samplers, return_info, search_paths, presets, cpus, context, determinstic, extras_shapes, buffer_dtype, iterator_class)
    156 if len(extras_shapes) > 0:
    157     buffer_shapes = buffer_shapes + extras_shapes
--> 159 dataset = build_config(config[mode])["dataset"]
    161 if number_of_batches is not None and number_of_batches > 0:
    162     batch_left = 0

File /usr/local/lib/python3.11/site-packages/dicfg/factory.py:124, in build_config(config)
    114 def build_config(config: dict):
    115     """Builds config
    116 
    117     Args:
   (...)
    121         dict: build config
    122     """
--> 124     return _ObjectFactory(deepcopy(config)).build_config()

File /usr/local/lib/python3.11/site-packages/dicfg/factory.py:26, in _ObjectFactory.build_config(self)
     25 def build_config(self):
---> 26     return self._build(self._configuration)

File /usr/local/lib/python3.11/functools.py:946, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
    944 def _method(*args, **kwargs):
    945     method = self.dispatcher.dispatch(args[0].__class__)
--> 946     return method.__get__(obj, cls)(*args, **kwargs)

File /usr/local/lib/python3.11/site-packages/dicfg/factory.py:38, in _ObjectFactory._build_dict(self, config)
     36     config[key] = value
     37 elif _is_object(value):
---> 38     config[key] = self._build_object(value)
     39 else:
     40     config[key] = self._build(value)

File /usr/local/lib/python3.11/site-packages/dicfg/factory.py:67, in _ObjectFactory._build_object(self, value)
     65 kwargs.update(value.pop("**kwargs", {}))
     66 attribute = self._parse_object_str(object_string)
---> 67 return attribute(*args, **kwargs)

File /usr/local/lib/python3.11/site-packages/wholeslidedata/data/dataset.py:45, in WholeSlideDataSet.__init__(self, mode, associations, labels, load_images, copy_path, spacing)
     43 self._copy_path = copy_path
     44 self._associations = associations
---> 45 self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
     46 self._labels = self._init_labels()
     47 self._sample_references = self._init_samples()

File /usr/local/lib/python3.11/site-packages/wholeslidedata/data/dataset.py:97, in WholeSlideDataSet._open(self, associations, labels)
     95 spacings = []
     96 for wsi_index, wsi_file in enumerate(associated_files[WholeSlideImageFile.IDENTIFIER]):
---> 97     image, spacing = self._open_image(wsi_file)
     98     data[file_key][self.__class__.IMAGES_KEY][
     99         wsi_index
    100     ] = image
    101     spacings.append(spacing)

File /usr/local/lib/python3.11/site-packages/wholeslidedata/data/dataset.py:119, in WholeSlideDataSet._open_image(self, wsi_file)
    116         raise ValueError('Load images is False, but no spacing is set')
    117     return wsi_file, self._spacing
--> 119 wsi = wsi_file.open()
    120 spacing = wsi.spacings[0]
    121 return wsi, spacing

File /usr/local/lib/python3.11/site-packages/wholeslidedata/data/files.py:34, in WholeSlideImageFile.open(self)
     33 def open(self):
---> 34     return WholeSlideImage(self.path, self._image_backend)

File /usr/local/lib/python3.11/site-packages/wholeslidedata/image/wholeslideimage.py:35, in WholeSlideImage.__init__(self, path, backend, auto_resample)
     27 """WholeSlideImage that can open en sample from whole slide images
     28 
     29 Args:
     30     path (Union[Path, str]): path to whole slide image file
     31     backend (Union[WholeSlideImageBackend, str], optional): image backend that opens and extracts regions from the whole slide image. Defaults to 'openslide'.
     32 """
     34 self._path = path
---> 35 self._backend = get_backend(backend)(path=self._path)
     36 self._auto_resample = auto_resample
     37 self._shapes = self._backend._init_shapes()

File /usr/local/lib/python3.11/site-packages/wholeslidedata/interoperability/cucim/backend.py:7, in CucimWholeSlideImageBackend.__init__(self, path)
      6 def __init__(self, path: str) -> None:
----> 7     CuImage.__init__(self, path)
      8     WholeSlideImageBackend.__init__(self, path)

TypeError: __init__(): incompatible constructor arguments. The following argument types are supported:
    1. cucim.clara._cucim.CuImage(path: str)

Invoked with: PosixPath('/data/pathology/archives/breast/camelyon/CAMELYON16/images/tumor_062.tif')

After introducing quick fix - casting PosixPath to str in wholeslidedata/interoperability/cucim/backend.py it works

Iterating over classes in WholeSlideAnnotation objects

Hi @martvanrijthoven,

I was wondering if there is existing code within whole-slide-data to do something similar to what I write below:

wsa = WholeSlideAnnotation('foo.xml')

# Iterate over classes in WSA like with a dict.items()
for label, annos in wsa.annotations_per_label():
    # Do stuff here

I am aware of the existence of sampling annotations, but these don't really fit this use case. I would have to instantiate a separate wsa object with its own sampling_annotation for every class (and I would first have to read these classes if didn't know them a priori).

If something like that doesn't exist, what do you think of making it a property/method in WholeSlideAnnotations? It wouldn't be very hard:

@property
def annotations_per_label(self) -> Dict
    annos_per_label = dict(zip(self.labels.names, [[] for _ in self.labels.names]))
    for anno in self.annotations:
        annos_per_label[anno.label.name].append(anno)
    return annos_per_label

mask to xml/json overhaul

In the current version of WSD there are many bugs in the code to make XMLs from masks.

I made many improvements and rewrote functions. Im not sure though how you would like merge the changes. Im not sure if all these changes will break other code, therefore, I'll make a PR with all changes in a single script that converts masks to xml/json, so you can check everything easily in that single file.

I got confused between branch 'main' and '0.0.16'

When I use your project 'pathology-hooknet', there are many import issuses from wholeslidedata.
For example, if I install wholeslidedata package with branch 'v0.0.16', the notebook in hooknet will report missing 'wholeslidedata/visualization'. But it does exist in branch 'main'. So I install wholeslidedata with branch 'main' instead, and it will report missing some functions in 'wholeslidedata/samplers/utils.py'.
Maybe notebooks in hooknet have been outdate. I don't know how to fix it.

Sliding window with Segmentation Mask Sampling

Hi Mart,
Thanks for this wonderful package. I am facing an issue currently with integrating sliding window with the segmentation mask. I am currently using this yml configuration

wholeslidedata:
    default:
        seed: 35
        yaml_source: test.yml
        
        label_map:
            roi: 0
            invasive tumor: 1
            tumor-associated stroma: 2
            in-situ tumor: 3
            healthy glands: 4
            necrosis not in-situ: 5
            inflamed stroma: 6
            rest: 7
            lymphocytes and plasma cells: 8
            
        annotation_parser:
            sample_label_names: ['roi']
        
        point_sampler:
            attribute: CenterPointSampler

        patch_sampler:
            center: True
        
        annotation_sampler:
            attribute: OrderedAnnotationSampler

However, these are the points that are being sampled:

dx 0 x_shape (256, 256, 3) mask_shape (256, 256) POINT (71516 73734)
idx 1 x_shape (256, 256, 3) mask_shape (256, 256) POINT (90248 33833)
idx 2 x_shape (256, 256, 3) mask_shape (256, 256) POINT (11440 12248)
idx 3 x_shape (256, 256, 3) mask_shape (256, 256) POINT (22092 13028)
idx 4 x_shape (256, 256, 3) mask_shape (256, 256) POINT (35779 7162)
idx 5 x_shape (256, 256, 3) mask_shape (256, 256) POINT (50652 53262)

I tried following the slidingwindow.yml given for tiger, but it uses a different annotation parser which is not valid for my case.

Please do help me out.
Thank you
Vishwesh

Extracting randomly rotated patches from the WSI.

Hi Mart,

I am currently experimenting with data augmentations for training a segmentation model. These include rotating the patches that are retrieved with the batch iterator from this framework. After the rotation there is often a missing region that has to be filled, but this context is available in the WSI. Is it maybe an idea to add an callback for this specifically for training: sample randomly rotated patches.

It could be implemented by extracting a slightly bigger patch (to get all context necessary), rotating it with a random angle between -180, 180 and then center cropping to a desired output, for both the image and the mask.

I think rotation augmentations are nice to have in digital pathology applications and might be best to implement during the patch extraction from the WSI.

P.S. I'm really curious what your experience is with applying data augmentations for the HookNet paper.

Best,

Michel

create_batch_iterator fails when copy_path != None and number_of_batches > 0

Hi,

In the latest wholeslidedata version, calling create_batch_iterator with a copy_path specified in the user_config, and a number_of_batches > 0, causes an error. It seems to be some sort of multiprocessing issue (even though it also occurs when cpus==1), in which one process tries to open an image while another process is still copying the file. I don't know why this is happening, especially with 1 cpu specified, but I think that moving the dataset creation call in create_batch_iterator to before the commander, producer, and buffer_factory are created should fix it. If there are reasons as to why the dataset creation should be afterwards in the case of number_of_batches>0, please let me know.

Example error stacktrace:

Process ProducerForkProcess-4:
Process ProducerForkProcess-11:
Process ProducerForkProcess-5:
Traceback (most recent call last):
Traceback (most recent call last):
Traceback (most recent call last):
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
Process ProducerForkProcess-6:
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/producer.py", line 71, in run
self._producer.build()
Process ProducerForkProcess-10:
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchproducer.py", line 22, in build
builds = build_config(self._config[self._mode])
Process CommanderForkProcess-3:
Traceback (most recent call last):
Process ProducerForkProcess-7:
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/producer.py", line 71, in run
self._producer.build()
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/producer.py", line 71, in run
self._producer.build()
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
Traceback (most recent call last):
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchproducer.py", line 22, in build
builds = build_config(self._config[self._mode])
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchproducer.py", line 22, in build
builds = build_config(self._config[self._mode])
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/local/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/producer.py", line 71, in run
self._producer.build()
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/commander.py", line 66, in run
self._commander.build()
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/producer.py", line 71, in run
self._producer.build()
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/site-packages/concurrentbuffer/producer.py", line 71, in run
self._producer.build()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchproducer.py", line 22, in build
builds = build_config(self._config[self._mode])
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchcommander.py", line 26, in build
builds = build_config(self._config[self._mode])
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchproducer.py", line 22, in build
builds = build_config(self._config[self._mode])
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/buffer/batchproducer.py", line 22, in build
builds = build_config(self._config[self._mode])
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 124, in build_config
return _ObjectFactory(deepcopy(config)).build_config()
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 26, in build_config
return self._build(self._configuration)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
ValueError: cant open image /home/user/tmp/images/0014_R.tif
File "/usr/local/lib/python3.9/functools.py", line 938, in _method
return method.get(obj, cls)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 38, in _build_dict
config[key] = self._build_object(value)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/dicfg/factory.py", line 67, in _build_object
return attribute(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 42, in init
self._data = dict(sorted(self._open(self._associations, labels=labels).items()))
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
ValueError: cant open image /home/user/tmp/images/0014_R.tif
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 94, in _open
image, spacing = self._open_image(wsi_file)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
ValueError: cant open image /home/user/tmp/images/0014_R.tif
ValueError: cant open image /home/user/tmp/images/0014_R.tif
ValueError: cant open image /home/user/tmp/images/0014_R.tif
ValueError: cant open image /home/user/tmp/images/0014_R.tif
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/dataset.py", line 116, in _open_image
wsi = wsi_file.open()
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/data/files.py", line 34, in open
return WholeSlideImage(self.path, self._image_backend)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/image/wholeslideimage.py", line 35, in init
self._backend = get_backend(backend)(path=self._path)
File "/usr/local/lib/python3.9/site-packages/wholeslidedata/interoperability/asap/backend.py", line 15, in init
raise ValueError(f"cant open image {path}")
ValueError: cant open image /home/user/tmp/images/0014_R.tif

read images and annotation directly from s3 bucket

thank you for releasing this super helpful repo! I think it'd be great to be able to read all of the data directly from the s3 bucket, so users don't have to download the data. I've made a notebook available on a forked branch that shows an example:

https://github.com/rj678/pathology-whole-slide-data/blob/test_s3_read/notebooks/s3_image_annotation.ipynb

the good folks at Bayer have released an openslide replacement that is fsspec compatible so we can read images from s3 buckets: https://github.com/bayer-science-for-a-better-life/tiffslide

I've pushed a few changes to the branch test_s3_read on the forked repo where I've added a tiffslide backend, and made a few changes to read annotations from an s3 bucket

please let me know if you think this functionality would be useful to add to the repo, and I can clean up the commits and the code and raise a PR to get your feedback. I plan on making more changes to train a model without having to download any raw data.

thanks again,

Sliding Window configuration

Hi Mart,

I am working with the Sliding Window configuration as shown in: https://github.com/DIAGNijmegen/pathology-whole-slide-data/blob/main/notebooks/tiger/sliding_window/slidingwindowconfig.yml

Is it possible to use a sliding window configuration without the ASAP backend? I can’t install ASAP or use Docker on the server that I am working on currently (working on getting this fixed). But in the meantime I am looking for a workaround.

Let me know whether this is possible.

Thank you,

Michel

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.