Git Product home page Git Product logo

wsic's People

Contributors

deepsourcebot avatar dependabot[bot] avatar john-p avatar pre-commit-ci[bot] avatar

Stargazers

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

Watchers

 avatar

wsic's Issues

Trying to create the thumbnail of a converted tiff image times out

  • wsic version: 0.2.0
  • Python version: 3.9
  • Operating System: Debian Bullseye (Docker Container)

Description

I used the wsic tool to convert a jp2 image to tiff. This was a test because I want to use the tool to convert multiple images and upload them to WASABI and the PathLAKE Portal. However, I've noticed that the testing image was not displayed on WASABI. I tried to investigate the issue by reading the image locally and then found out that I was not able to create the thumbnail because it was timing out (taking more than 10misn before crashing). There were no error logs during the conversion of the image, so I expect that it was successful. Also, I managed to convert the image using another tool, therefore the original image is not corrupted and not causing this issue.

I have included all the commands that I have used below. I have also uploaded the original and converted image to OneDrive here. @John-P you should be able to access these images. If you can't please let me know.

What I Did

Command that I used to convert the jp2 image to tiff

wsic convert -i /input/path/image.jp2 -o /output/path/image.tiff -rt 4096 4096 -c jpeg -w 10 --no-ome --overwrite -to 60

Command that I used to read the image using tiatoolbox (Works fine and runs in 0.1s)

wsi = OpenSlideWSIReader(
                input_img='/input/path/to/image.tiff')

wsi_info = wsi.info.as_dict()
# Print one item per line
print(*list(wsi_info.items()), sep='\n')

Command that I used to create and display the thumbnail of the image using tiatoolbox (Times out)

wsi_thumb = wsi.slide_thumbnail()
plt.imshow(wsi_thumb)
plt.axis('off')
plt.show()

Command that I used to read the image using OpenSlide directly (Works fine and runs in 0.1s)

openslide_wsi = openslide.OpenSlide(filename='/input/path/to/image.tiff')

Command that I used to create and display the thumbnail of the image using OpenSlide (Times out)

openslide_thumb = openslide_wsi.get_thumbnail(size=(256, 256))
plt.imshow(openslide_thumb)
plt.axis('off')
plt.show()

note: I think this might be the reason why the image cannot be displayed on WASABI. Link to WASABI collection with the converted images: here. @John-P I have given permissions to your wasabi user for this collection. Let me know if it doesn't work.

DICOM to SVS conversion

  • Python version: 3.9.13
  • Operating System: Ubuntu 18.04

Description

Hello,
I attempted to convert a DICOM wsi to svs using the following command and it failed:

wsic convert -i ANONU3UAJH1JJ_Leica/ -o convert_test/test2.svs  -c jpeg

I manually verified that the DICOM image I was trying to convert was readable on python using wsidicom.

Any ideas on how to do this? Any help would be much appreciated!

Thanks,

Petros

Reading:   0%|                                                                                                                                                                   | 0/28272 [00:00<?, ?it/s$
data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/wsic/readers.py:385: UserWarning: Failed to get next tile after 100 attempts. Dumping debug information.       | 0/113088 [00:00<?, ?it/s$
  warnings.warn(                                                                                                                                                                                           
Reader Shape (58258, 126761, 3)                                                                                                                                                                            
Read Tile Size (512, 512)                                                                                                                                                                                  
Yield Tile Size (256, 256)                                                                                                                                                                                 
Read Mosaic Shape (114, 248)                                                                                                                                                                               
Yield Mosaic Shape (228, 496)                                                                                                                                                                              
Read Index (0, 0)                                                                                                                                                                                          
Yield Index (0, 0)                                                                                                                                                                                         
Remaining Reads (:10) [(0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11), (0, 12)]                                                                                                  
Enqueued {(0, 1), (0, 2), (0, 0)}                                                                                                                                                                          
Reordering Dict (keys) dict_keys([])                                                                                                                                                                       
Queue Size 0                                                                                                                                                                                               
Intermediate Read slices (slice(0, 256, None), slice(0, 256, None))                                                                                                                                        
Reading:   0%|                                                                                                                                                                   | 0/28272 [00:10<?, ?it/s$
Writing:   0%|                                                                                                                                                                  | 0/113088 [00:11<?, ?it/s$
Traceback (most recent call last):                                                                                                                                                                         
  File "/data/home/pliako/anaconda3/envs/wsic/bin/wsic", line 8, in <module>                                                                                                                               
    sys.exit(main())                                                                                                                                                                                       
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1128, in __call__                                                                                           
    return self.main(*args, **kwargs)                                                                                                                                                                      
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1053, in main                                                                                               
    rv = self.invoke(ctx)                                                                                                                                                                                  
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1659, in invoke                                                                                             
    return _process_result(sub_ctx.command.invoke(sub_ctx))                                                                                                                                                
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1395, in invoke                                                                                             
    return ctx.invoke(self.callback, **ctx.params)                                                                                                                                                         
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 754, in invoke                                                                                              
    return __callback(*args, **kwargs)
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/wsic/cli.py", line 223, in convert
    writer.copy_from_reader(
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/wsic/writers.py", line 942, in copy_from_reader
    tif.write(
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/tifffile/tifffile.py", line 2556, in write
    chunk = next(dataiter)
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/tqdm/std.py", line 1195, in __iter__
    for obj in iterable:
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/wsic/readers.py", line 406, in __next__
    raise IOError(f"Tile read timed out at index {self.yield_index}")
OSError: Tile read timed out at index (0, 0)
Exception ignored in: <function MultiProcessTileIterator.__del__ at 0x7f179e266f70>
Traceback (most recent call last):
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/wsic/readers.py", line 509, in __del__
    self.close()
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/site-packages/wsic/readers.py", line 501, in close
    executor.map(lambda p: p.join(1), self.processes)
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/concurrent/futures/_base.py", line 598, in map
    fs = [self.submit(fn, *args) for args in zip(*iterables)]
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/concurrent/futures/_base.py", line 598, in <listcomp>
    fs = [self.submit(fn, *args) for args in zip(*iterables)]
  File "/data/home/pliako/anaconda3/envs/wsic/lib/python3.9/concurrent/futures/thread.py", line 169, in submit
    raise RuntimeError('cannot schedule new futures after '
RuntimeError: cannot schedule new futures after interpreter shutdown

BUG: WSIC fails to read the first tile from a jp2 image

1st Machine

  • wsic version: 0.2.0
  • Python version: 3.9.11
  • Operating System: Ubuntu 18.04.4 LTS

2nd Machine

  • wsic version: 0.2.0
  • Python version: 3.9.11
  • Operating System: Debian Bullseye Slim (through a Docker container based on Python3.9-Bullseye Slim)

Description

I was trying to convert a JP2 image (size: 71.3Mb) to tiff. I tested the same command on two different machines

What I Did

wsic convert -i ${input} -o ${output} -rt 4096 4096 -w 4 --overwrite --no-ome -to 600
/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/wsic/readers.py:265: UserWarning: Failed to get next tile after 100 attempts. Dumping debug information.
  warnings.warn(
Reader Shape (161864, 88832, 3)
Read Tile Size (4096, 4096)
Yield Tile Size (256, 256)
Read Mosaic Shape (40, 22)
Yield Mosaic Shape (633, 347)
Read Index (0, 0)
Yield Index (0, 0)
Remaining Reads (:10) [(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), (0, 11)]
Enqueued {(0, 1), (0, 0)}
Reordering Dict (keys) dict_keys([])
Queue Size 0
Intermediate Read slices (slice(0, 256, None), slice(0, 256, None))
Traceback (most recent call last):
  File "/home/giorgos-tia/.conda/envs/wsic/bin/wsic", line 8, in <module>
    sys.exit(main())
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/wsic/cli.py", line 126, in convert
    writer.copy_from_reader(reader, read_tile_size=read_tile_size, num_workers=workers)
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/wsic/writers.py", line 513, in copy_from_reader
    tif.write(
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/tifffile/tifffile.py", line 2660, in write
    for tileindex, chunk in enumerate(
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/tifffile/tifffile.py", line 16817, in encode_tiles
    tile = next(tileiter)
  File "/home/giorgos-tia/.conda/envs/wsic/lib/python3.9/site-packages/wsic/readers.py", line 284, in __next__
    raise Exception(f"Failed to yield tile {self.yield_index}")
Exception: Failed to yield tile (0, 0)

MPP data missing from OpenSlideReader

  • wsic version: 0.7
  • Python version: 3.10.9
  • Operating System: ArchLinux

Description

When trying to create a pyramid TIFF image from a single-level tiff image, MPP got lost in the output TIFF file.

What I Did

wsic convert -i in.tiff -o test_out.tiff -rt 4096 4096 -w 20 --no-ome --overwrite -to 180 -c jpeg -d 2 -d 4 -d 8

Note

I debugged a bit and found out this function call caused the error. Inside ppu2mpp function, the actual unit passed was "centimeter" instead of "cm" according to openslide standard. After adding "centimeter": 1e4, to L238, the output got corrected.

Convert SVS to NDPI

Description

As a user I would like to convert a WSI in Aperio SVS format to Hamamatsu NDPI file. Is this possible?

Incorrect MPP resolution handling from JP2 image

  • wsic version: v0.6.1
  • Python version: 3.10
  • Operating System: Ubuntu 20.04

Description

By inspecting the jp2 metadata I see the Capture X Resolution is 36364 and the unit is cm. The corresponding MPP is 0.275
ๅ›พ็‰‡
However, In the code, the resolution box reads 3636400 and an MPP of approx. 0.00275.
image2
image3

What I Did

wsic convert -i in.jp2 -o out.tiff -rt 4096 4096 -w 2 --no-ome --overwrite -to 180 -c jpeg -cl 95 -d 2 -d 4 -d 8

BUG: Queues Python library fails on MacOS

  • wsic version: 0.2.0 (installed from wheel)
  • Python version: 3.9.11 (Conda Environment)
  • Operating System: MacOS Monterey Version 12.1

Description

I was trying to convert a JP2 image (size: 71.3Mb) to tiff. The wsic library failed because the Queues library threw a NotImplementedError. The creators of the library are aware of this issue since the code that throws the error has this comment

    def qsize(self):
        # Raises NotImplementedError on Mac OSX because of broken sem_getvalue()
        return self._maxsize - self._sem._semlock._get_value()

What I Did

Command

wsic convert -i ./<input_path>.jp2 -o ./1.tiff -rt 4096 4096 -w 1 --overwrite --no-ome -to 600

Error

Traceback (most recent call last):
  File "/opt/miniconda3/envs/wsic/bin/wsic", line 8, in <module>
    sys.exit(main())
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/wsic/cli.py", line 139, in convert
    writer.copy_from_reader(
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/wsic/writers.py", line 527, in copy_from_reader
    tif.write(
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/tifffile/tifffile.py", line 2660, in write
    for tileindex, chunk in enumerate(
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/tifffile/tifffile.py", line 16817, in encode_tiles
    tile = next(tileiter)
  File "/opt/miniconda3/envs/wsic/lib/python3.9/site-packages/wsic/readers.py", line 281, in __next__
    print(f"Queue Size {self.queue.qsize()}")
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/queues.py", line 126, in qsize
    return self._maxsize - self._sem._semlock._get_value()
NotImplementedError

The code keeps running after this error is thrown. When I stop it with ctrl + c, it throws this error

Traceback (most recent call last):
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/popen_fork.py", line 27, in poll
Process Process-1:
    pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
Traceback (most recent call last):
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/process.py", line 318, in _bootstrap
    util._exit_function()
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/util.py", line 360, in _exit_function
    _run_finalizers()
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/util.py", line 300, in _run_finalizers
    finalizer()
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/util.py", line 224, in __call__
    res = self._callback(*self._args, **self._kwargs)
  File "/opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/queues.py", line 201, in _finalize_join
    thread.join()
  File "/opt/miniconda3/envs/wsic/lib/python3.9/threading.py", line 1053, in join
    self._wait_for_tstate_lock()
  File "/opt/miniconda3/envs/wsic/lib/python3.9/threading.py", line 1073, in _wait_for_tstate_lock
    if lock.acquire(block, timeout):
KeyboardInterrupt
(wsic) ghadjigeorgiou@192 jp2tiff % /opt/miniconda3/envs/wsic/lib/python3.9/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown
  warnings.warn('resource_tracker: There appear to be %d '

Tile read timed out when converting images

  • wsic version: 0.6.1
  • Python version: 3.9
  • Operating System: Debian GNU/Linux 11

Description

When converting an image, the program created a crashdump and exited.

What I Did

/usr/local/bin/python /usr/local/bin/wsic convert -i /xxx.jp2 -o /xxx.tiff -rt 4096 4096 -w 30 -mpp 0.5 0.5 --no-ome --overwrite -to 180 -c jpeg -cl 90 -d 2 -d 4 -d 8

Reading:   1%|          | 10/828 [00:23<31:10,  2.29s/it] 
Writing:   0%|          | 106/204840 [00:23<12:07:59,  4.69it/s]
                                                                /usr/local/lib/python3.9/site-packages/wsic/readers.py:385: UserWarning: Failed to get next tile after 100 attempts. Dumping debug information.9,  4.69it/s]
  warnings.warn(
Reading:   1%|          | 10/828 [03:23<4:37:56, 20.39s/it]
Writing:   0%|          | 160/204840 [03:23<72:26:45,  1.27s/it]
Traceback (most recent call last):
  File "/usr/local/bin/wsic", line 8, in <module>
Reader Shape (145456, 92000, 3)
Read Tile Size (4096, 4096)
Yield Tile Size (256, 256)
    sys.exit(main())
  File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1130, in __call__
Read Mosaic Shape (36, 23)
Yield Mosaic Shape (569, 360)
Read Index (0, 10)
Yield Index (0, 160)
Remaining Reads (:10) [(1, 17), (1, 18), (1, 19), (1, 20), (1, 21), (1, 22), (2, 0), (2, 1), (2, 2), (2, 3)]
Enqueued {(1, 0), (1, 6), (0, 14), (1, 3), (1, 9), (0, 11), (0, 17), (1, 12), (0, 20), (1, 15), (1, 2), (0, 10), (0, 16), (1, 5), (1, 11), (0, 13), (0, 19), (1, 8), (1, 14), (0, 22), (1, 1), (1, 4), (0, 12), (1, 7), (1, 13), (0, 15), (0, 21), (1, 10), (1, 16), (0, 18)}
Reordering Dict (keys) dict_keys([(0, 22), (0, 21), (0, 18), (0, 15), (1, 1), (0, 14), (0, 11), (1, 4), (0, 13), (1, 5), (1, 3), (0, 12), (0, 17), (0, 19), (1, 0), (1, 6), (1, 8), (1, 10), (1, 7), (1, 13), (1, 14), (1, 15), (1, 12), (1, 16), (1, 9), (1, 11)])
Queue Size 0
Intermediate Read slices (slice(0, 256, None), slice(40960, 41216, None))
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.9/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/wsic/cli.py", line 223, in convert
    writer.copy_from_reader(
  File "/usr/local/lib/python3.9/site-packages/wsic/writers.py", line 593, in copy_from_reader
    tif.write(
  File "/usr/local/lib/python3.9/site-packages/tifffile/tifffile.py", line 3116, in write
    for tileindex, chunk in enumerate(
  File "/usr/local/lib/python3.9/site-packages/tifffile/tifffile.py", line 20438, in encode_tiles
    tile = next(tileiter)
  File "/usr/local/lib/python3.9/site-packages/tifffile/tifffile.py", line 21536, in newiter
    yield from iterator
  File "/usr/local/lib/python3.9/site-packages/tqdm/std.py", line 1195, in __iter__
    for obj in iterable:
  File "/usr/local/lib/python3.9/site-packages/wsic/readers.py", line 406, in __next__
    raise IOError(f"Tile read timed out at index {self.yield_index}")
OSError: Tile read timed out at index (0, 160)
Exception ignored in: <function MultiProcessTileIterator.__del__ at 0x7f3a53e61160>
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/wsic/readers.py", line 509, in __del__
    self.close()
  File "/usr/local/lib/python3.9/site-packages/wsic/readers.py", line 501, in close
    executor.map(lambda p: p.join(1), self.processes)
  File "/usr/local/lib/python3.9/concurrent/futures/_base.py", line 598, in map
    fs = [self.submit(fn, *args) for args in zip(*iterables)]
  File "/usr/local/lib/python3.9/concurrent/futures/_base.py", line 598, in <listcomp>
    fs = [self.submit(fn, *args) for args in zip(*iterables)]
  File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 169, in submit
    raise RuntimeError('cannot schedule new futures after '
RuntimeError: cannot schedule new futures after interpreter shutdown

There is no other I/O intensive job while running the task.

Support for DICOM multi level

Introduction

Dear @John-P,

First of all, thank you very much for your excellent work.

Setup

  • wsic version:
    • 0.9.0
  • Python version:
    • 3.11.3
  • Operating System:
    • WSL Ubuntu 22.04

Description

I have tried to add a DICOM writer that supports multi-level whole slide images.
Example image: https://drive.google.com/file/d/1hd3EVYNL_1bpHJfMZu6JO3FqC3xNhCOS/view?usp=sharing

What I Did

from codecs import Codec
from ctypes.wintypes import HCOLORSPACE
from functools import partial
from math import floor
import multiprocessing
from os import PathLike
from pathlib import Path
from typing import Generator, List, Optional, Tuple

import numpy as np
import wsic

from wsic.utils import warn_unused, mosaic_shape
from wsic.readers import Reader
from wsic.writers import ZarrIntermediate, ColorSpace, DICOMWSIWriter, get_level_tile
from wsic.enums import ColorSpace

class DICOMWSIWriterMultiLevel(DICOMWSIWriter):
    """Writer for DICOM WSI images using wsidicom and supports multiple levels.

    Notes:
        - Supports JPEG and JPEG2000 compression.
        - DICOM Whole Slide Imaging:  https://dicom.nema.org/Dicom/DICOMWSI/
    """

    def __init__(
        self,
        path: PathLike,
        shape: Tuple[int, int],
        tile_size: Tuple[int, int] = (256, 256),
        dtype: np.dtype = np.uint8,
        color_space: Optional[HCOLORSPACE] = None,
        codec: Optional[Codec] = None,
        compression_level: int = 0,
        microns_per_pixel: Tuple[float, float] = None,
        pyramid_downsamples: Optional[List[int]] = None,
        overwrite: bool = False,
        verbose: bool = False,
        **kwargs,
    ) -> None:
        if color_space != "rgb":
            warn_unused(color_space)
        warn_unused(codec)
        warn_unused(compression_level, ignore_falsey=True)
        warn_unused(microns_per_pixel)

        for key, value in kwargs.items():
            warn_unused(key, value)
        super().__init__(
            path=path,
            shape=shape,
            tile_size=tile_size,
            dtype=dtype,
            color_space=color_space,
            codec=codec,
            compression_level=compression_level,
            microns_per_pixel=microns_per_pixel,
            pyramid_downsamples=pyramid_downsamples,
            overwrite=overwrite,
            verbose=verbose,
        )


    def copy_from_reader(
        self,
        reader: Reader,
        num_workers: int = 2,
        read_tile_size: Tuple[int, int] = None,
        timeout: float = 10,
        downsample_method: Optional[str] = None,
    ) -> None:
        from pydicom import FileDataset, dcmwrite

        from wsic.dicom import append_frames, create_vl_wsi_dataset

        width = self.shape[1]
        height = self.shape[0]
        photometric_interpretation = (
            ColorSpace.YCBCR.to_dicom_photometric_interpretation((4, 2, 2))
        )
        mpp: Tuple[float, float] = (
            self.microns_per_pixel or reader.microns_per_pixel or (1.0, 1.0)
        )
        self.validate_write_args(microns_per_pixel=mpp)

        meta, dataset = create_vl_wsi_dataset(
            size=(width, height),
            tile_size=self.tile_size,
            microns_per_pixel=mpp,
            photometric_interpretation=photometric_interpretation,
        )

        file_dataset = FileDataset(
            str(self.path),
            dataset=dataset,
            preamble=b"\0" * 128,
            file_meta=meta,
            is_implicit_VR=False,
            is_little_endian=True,
        )

        level_path = str(self.path.parent / f"{self.path.stem}_{0}.dcm")
        dcmwrite(
            dataset=file_dataset,
            filename=level_path,
            write_like_original=False,
        )

        with ZarrIntermediate(
            None, reader.shape, zero_after_read=False
        ) as intermediate:
            reader_tile_iterator = self.reader_tile_iterator(
                reader=reader,
                num_workers=num_workers,
                intermediate=intermediate,
                read_tile_size=read_tile_size or self.tile_size,
                timeout=timeout,
            )

            def jpeg_generator(tile_iterator) -> Generator[bytes, None, None]:
                """Encodes arrays to JPEG bytes."""
                import imagecodecs

                for tile in tile_iterator:
                    yield imagecodecs.jpeg_encode(
                        tile,
                        level=self.compression_level,
                        colorspace=self.color_space,
                        outcolorspace=ColorSpace.YCBCR,
                    )


            tile_iterator = iter(
                self.level_progress(
                    jpeg_generator(reader_tile_iterator),
                    total=len(reader_tile_iterator),
                )
            )
            append_frames(level_path, tile_iterator, len(reader_tile_iterator))

            # Write pyramid resolutions
            with multiprocessing.Pool(1) as pool:  # num_workers
                for level, downsample in self.pyramid_progress(
                    enumerate(self.pyramid_downsamples),
                    total=len(self.pyramid_downsamples),
                ):
                    level += 1
                    level_shape = tuple(
                        floor(s / downsample) for s in reader.shape[:2]
                    ) + (reader.shape[-1],)

                    level_tiles_shape = mosaic_shape(
                        level_shape,
                        self.tile_size,
                    )

                    l_meta, l_dataset = create_vl_wsi_dataset(
                        size=level_shape[:2],
                        tile_size=self.tile_size,
                        microns_per_pixel=[mpp[0] * downsample, mpp[1] * downsample],
                        photometric_interpretation=photometric_interpretation,
                    )
                    l_dataset.InstanceNumber = f"{level + 1}"
                    l_dataset.StudyInstanceUID = dataset.StudyInstanceUID
                    l_dataset.SeriesInstanceUID = dataset.SeriesInstanceUID
                    l_dataset.FrameOfReferenceUID = dataset.FrameOfReferenceUID

                    level_path = str(self.path.parent / f"{self.path.stem}_{level}.dcm")
                    file_dataset = FileDataset(
                        level_path,
                        dataset=l_dataset,
                        preamble=b"\0" * 128,
                        file_meta=l_meta,
                        is_implicit_VR=False,
                        is_little_endian=True,
                    )

                    dcmwrite(
                        dataset=file_dataset,
                        filename=level_path,
                        write_like_original=False,
                    )

                    func = partial(
                        get_level_tile,
                        tile_size=self.tile_size,
                        downsample=downsample,
                        read_intermediate_path=intermediate.path,
                        downsample_method=downsample_method,
                    )

                    tile_generator = pool.imap(
                        func=func,
                        iterable=np.ndindex(level_tiles_shape),
                    )

                    tile_generator = self.level_progress(
                        tile_generator,
                        total=int(np.product(level_tiles_shape)),
                        desc=f"Level {level + 1}",
                        leave=False,
                    )

                    tile_iterator = iter(
                        self.level_progress(
                            jpeg_generator(tile_generator),
                            total=len(tile_generator),
                        )
                    )
                    append_frames(level_path, tile_iterator, len(tile_generator))

def main():


    root_folder = Path("M01KBB05R-1315")

    result_file = root_folder /  "Test"

    reader = wsic.readers.DICOMWSIReader(root_folder) 
    #writer = wsic.writers.DICOMWSIWriter(path=result_file,         
    writer = DICOMWSIWriterMultiLevel(path=result_file,                           
                                                shape=reader.original_shape[:2], 
                                                pyramid_downsamples=[2,4,8,16,32], #[2,4,8,16,32]
                                                verbose=True,
                                                compression_level=80,
                                                app_mag=40.) #   , microns_per_pixel=0.241
    writer.copy_from_reader(reader, num_workers=10, timeout=120)  #num_workers=10,

if __name__ == "__main__":
    main()

What happens

The dcm files are created and can be opened, but each row's last tile looks wrong.

This is how the last tile in a row looks in a DICOM viewer:
image

And this is in a whole slide image viewer.
image

It only affects my implementation. The implementation from level 0 is correct.

Do you know where I made a calculation or implementation error?

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.