large-image-source-openslide 1.30.7.dev35__py3-none-any.whl → 1.33.6a165__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- large_image_source_openslide/__init__.py +48 -6
- large_image_source_openslide/girder_source.py +2 -2
- {large_image_source_openslide-1.30.7.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/METADATA +8 -8
- large_image_source_openslide-1.33.6a165.dist-info/RECORD +8 -0
- {large_image_source_openslide-1.30.7.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/WHEEL +1 -1
- large_image_source_openslide-1.30.7.dev35.dist-info/RECORD +0 -8
- {large_image_source_openslide-1.30.7.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/entry_points.txt +0 -0
- {large_image_source_openslide-1.30.7.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info/licenses}/LICENSE +0 -0
- {large_image_source_openslide-1.30.7.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/top_level.txt +0 -0
|
@@ -20,6 +20,7 @@ import os
|
|
|
20
20
|
from importlib.metadata import PackageNotFoundError
|
|
21
21
|
from importlib.metadata import version as _importlib_version
|
|
22
22
|
|
|
23
|
+
import numpy as np
|
|
23
24
|
import openslide
|
|
24
25
|
import PIL
|
|
25
26
|
import tifftools
|
|
@@ -47,12 +48,13 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
47
48
|
extensions = {
|
|
48
49
|
None: SourcePriority.MEDIUM,
|
|
49
50
|
'bif': SourcePriority.LOW, # Ventana
|
|
50
|
-
'
|
|
51
|
+
'czi': SourcePriority.PREFERRED,
|
|
52
|
+
'dcm': SourcePriority.MEDIUM, # DICOM
|
|
51
53
|
'ini': SourcePriority.LOW, # Part of mrxs
|
|
52
54
|
'mrxs': SourcePriority.PREFERRED, # MIRAX
|
|
53
55
|
'ndpi': SourcePriority.PREFERRED, # Hamamatsu
|
|
54
56
|
'scn': SourcePriority.LOW, # Leica
|
|
55
|
-
'svs': SourcePriority.
|
|
57
|
+
'svs': SourcePriority.HIGH,
|
|
56
58
|
'svslide': SourcePriority.PREFERRED,
|
|
57
59
|
'tif': SourcePriority.MEDIUM,
|
|
58
60
|
'tiff': SourcePriority.MEDIUM,
|
|
@@ -61,6 +63,8 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
61
63
|
}
|
|
62
64
|
mimeTypes = {
|
|
63
65
|
None: SourcePriority.FALLBACK,
|
|
66
|
+
'image/czi': SourcePriority.PREFERRED,
|
|
67
|
+
'application/dicom': SourcePriority.MEDIUM,
|
|
64
68
|
'image/mirax': SourcePriority.PREFERRED, # MIRAX
|
|
65
69
|
'image/tiff': SourcePriority.MEDIUM,
|
|
66
70
|
'image/x-tiff': SourcePriority.MEDIUM,
|
|
@@ -135,19 +139,22 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
135
139
|
# load an appropriate area and scale it to the tile size later.
|
|
136
140
|
maxSize = 16384 # This should probably be based on available memory
|
|
137
141
|
for level in range(self.levels):
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
levelpow = 2 ** (self.levels - 1 - level)
|
|
143
|
+
levelW = max(1, self.sizeX / levelpow)
|
|
144
|
+
levelH = max(1, self.sizeY / levelpow)
|
|
140
145
|
# bestlevel and scale will be the picked svs level and the scale
|
|
141
146
|
# between that level and what we really wanted. We expect scale to
|
|
142
147
|
# always be a positive integer power of two.
|
|
143
148
|
bestlevel = svsAvailableLevels[0]['level']
|
|
144
149
|
scale = 1
|
|
150
|
+
svsscale = 0
|
|
145
151
|
for svslevel in range(len(svsAvailableLevels)):
|
|
146
152
|
if (svsAvailableLevels[svslevel]['width'] < levelW - 1 or
|
|
147
153
|
svsAvailableLevels[svslevel]['height'] < levelH - 1):
|
|
148
154
|
break
|
|
149
155
|
bestlevel = svsAvailableLevels[svslevel]['level']
|
|
150
156
|
scale = int(round(svsAvailableLevels[svslevel]['width'] / levelW))
|
|
157
|
+
svsscale = svsAvailableLevels[svslevel].get('downsample', 0)
|
|
151
158
|
# If there are no tiles at a particular level, we have to read a
|
|
152
159
|
# larger area of a higher resolution level. If such an area would
|
|
153
160
|
# be excessively large, we could have memory issues, so raise an
|
|
@@ -161,6 +168,7 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
161
168
|
self._svslevels.append({
|
|
162
169
|
'svslevel': bestlevel,
|
|
163
170
|
'scale': scale,
|
|
171
|
+
'svsscale': ((svsscale / levelpow) if svsscale else 1) * scale,
|
|
164
172
|
})
|
|
165
173
|
self._bounds = None
|
|
166
174
|
try:
|
|
@@ -186,6 +194,12 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
186
194
|
self._svslevels = self._svslevels[prevlevels - self.levels:]
|
|
187
195
|
except Exception:
|
|
188
196
|
pass
|
|
197
|
+
try:
|
|
198
|
+
self._background = tuple(int(
|
|
199
|
+
self._openslide.properties['openslide.background-color']
|
|
200
|
+
[i * 2:i * 2 + 2], 16) for i in range(3))
|
|
201
|
+
except Exception:
|
|
202
|
+
self._background = None
|
|
189
203
|
self._populatedLevels = len({l['svslevel'] for l in self._svslevels})
|
|
190
204
|
|
|
191
205
|
def _getTileSize(self):
|
|
@@ -235,6 +249,7 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
235
249
|
"""
|
|
236
250
|
levels = []
|
|
237
251
|
svsLevelDimensions = self._openslide.level_dimensions
|
|
252
|
+
|
|
238
253
|
for svslevel in range(len(svsLevelDimensions)):
|
|
239
254
|
try:
|
|
240
255
|
self._openslide.read_region((0, 0), svslevel, (1, 1))
|
|
@@ -243,6 +258,10 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
243
258
|
'width': svsLevelDimensions[svslevel][0],
|
|
244
259
|
'height': svsLevelDimensions[svslevel][1],
|
|
245
260
|
}
|
|
261
|
+
try:
|
|
262
|
+
level['downsample'] = self._openslide.level_downsamples[svslevel]
|
|
263
|
+
except Exception:
|
|
264
|
+
pass
|
|
246
265
|
if level['width'] > 0 and level['height'] > 0:
|
|
247
266
|
# add to the list so that we can sort by resolution and
|
|
248
267
|
# then by earlier entries
|
|
@@ -334,12 +353,31 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
334
353
|
tile, format = self._getTileFromEmptyLevel(x, y, z, **kwargs)
|
|
335
354
|
else:
|
|
336
355
|
retries = 3
|
|
356
|
+
svsTileWidth = self.tileWidth * svslevel['scale']
|
|
357
|
+
svsTileHeight = self.tileHeight * svslevel['scale']
|
|
358
|
+
# Peculiarly, openslide has a "downsample" factor which isn't the
|
|
359
|
+
# power of 2 one would expect. This is computed based on the
|
|
360
|
+
# actual dimensions of levels, but since higher-resolution levels
|
|
361
|
+
# are not fully populated at the right and bottom, this ends up
|
|
362
|
+
# with not the actual downsampling, but some slightly higher number
|
|
363
|
+
# (e.g., 16.0018 rather than 16). Internally, when asking for a
|
|
364
|
+
# region for anything other than the maximum resolution lever, the
|
|
365
|
+
# openslide library is passed coordinates in what _seems_ to be
|
|
366
|
+
# base image coordinates, but is actually inflated by the ratio of
|
|
367
|
+
# their downsample value and the actual downsample value (e.g.,
|
|
368
|
+
# 16.0018 / 16). We multiple our values by this ratio so when
|
|
369
|
+
# openslide misapplies its downsampling we get the region we
|
|
370
|
+
# actually want
|
|
371
|
+
if svslevel['svsscale'] != 1:
|
|
372
|
+
offsetx = int(round(offsetx * svslevel['svsscale']))
|
|
373
|
+
offsety = int(round(offsety * svslevel['svsscale']))
|
|
374
|
+
svsTileWidth = int(round(svsTileWidth * svslevel['svsscale']))
|
|
375
|
+
svsTileHeight = int(round(svsTileHeight * svslevel['svsscale']))
|
|
337
376
|
while retries > 0:
|
|
338
377
|
try:
|
|
339
378
|
tile = self._openslide.read_region(
|
|
340
379
|
(offsetx, offsety), svslevel['svslevel'],
|
|
341
|
-
(
|
|
342
|
-
self.tileHeight * svslevel['scale']))
|
|
380
|
+
(svsTileWidth, svsTileHeight))
|
|
343
381
|
format = TILE_FORMAT_PIL
|
|
344
382
|
break
|
|
345
383
|
except openslide.lowlevel.OpenSlideError as exc:
|
|
@@ -356,6 +394,10 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
356
394
|
retries -= 1
|
|
357
395
|
if retries <= 0:
|
|
358
396
|
raise TileSourceError(msg)
|
|
397
|
+
if tile.mode == 'RGBA' and self._background:
|
|
398
|
+
tile = np.array(tile)
|
|
399
|
+
tile[tile[:, :, -1] == 0, :3] = self._background
|
|
400
|
+
tile = PIL.Image.fromarray(tile, 'RGBA')
|
|
359
401
|
# Always scale to the svs level 0 tile size.
|
|
360
402
|
if svslevel['scale'] != 1:
|
|
361
403
|
tile = tile.resize((self.tileWidth, self.tileHeight),
|
|
@@ -28,5 +28,5 @@ class OpenslideGirderTileSource(OpenslideFileTileSource, GirderTileSource):
|
|
|
28
28
|
cacheName = 'tilesource'
|
|
29
29
|
name = 'openslide'
|
|
30
30
|
|
|
31
|
-
extensionsWithAdjacentFiles = {'mrxs'}
|
|
32
|
-
mimeTypesWithAdjacentFiles = {'image/mirax'}
|
|
31
|
+
extensionsWithAdjacentFiles = {'mrxs', 'dcm', 'dicom'}
|
|
32
|
+
mimeTypesWithAdjacentFiles = {'image/mirax', 'application/dicom'}
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: large-image-source-openslide
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.33.6a165
|
|
4
4
|
Summary: An Openslide tilesource for large_image.
|
|
5
5
|
Home-page: https://github.com/girder/large_image
|
|
6
6
|
Author: Kitware, Inc.
|
|
7
7
|
Author-email: kitware@kitware.com
|
|
8
|
-
License: Apache
|
|
8
|
+
License: Apache-2.0
|
|
9
9
|
Keywords: large_image,tile source
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
-
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Requires-Python: >=3.9
|
|
20
19
|
Description-Content-Type: text/x-rst
|
|
21
20
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: large-image>=1.
|
|
21
|
+
Requires-Dist: large-image>=1.33.6.a165
|
|
23
22
|
Requires-Dist: openslide-python>=1.4.1
|
|
24
23
|
Requires-Dist: openslide-bin; platform_system == "Linux" and platform_machine == "x86_64"
|
|
25
24
|
Requires-Dist: openslide-bin; platform_system == "Linux" and platform_machine == "aarch64"
|
|
@@ -28,7 +27,7 @@ Requires-Dist: openslide-bin; platform_system == "Darwin" and platform_machine =
|
|
|
28
27
|
Requires-Dist: openslide-bin; platform_system == "Darwin" and platform_machine == "x86_64"
|
|
29
28
|
Requires-Dist: tifftools>=1.2.0
|
|
30
29
|
Provides-Extra: girder
|
|
31
|
-
Requires-Dist: girder-large-image>=1.
|
|
30
|
+
Requires-Dist: girder-large-image>=1.33.6.a165; extra == "girder"
|
|
32
31
|
Dynamic: author
|
|
33
32
|
Dynamic: author-email
|
|
34
33
|
Dynamic: classifier
|
|
@@ -37,6 +36,7 @@ Dynamic: description-content-type
|
|
|
37
36
|
Dynamic: home-page
|
|
38
37
|
Dynamic: keywords
|
|
39
38
|
Dynamic: license
|
|
39
|
+
Dynamic: license-file
|
|
40
40
|
Dynamic: provides-extra
|
|
41
41
|
Dynamic: requires-dist
|
|
42
42
|
Dynamic: requires-python
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
large_image_source_openslide/__init__.py,sha256=CEfTufsAco3V87GHdRtJz7KbIuLrgu1vGyc5-dtOXd4,22822
|
|
2
|
+
large_image_source_openslide/girder_source.py,sha256=wPa7xBoJ5-PKHMVy9joUNSUHTN6HCZKyR45lhR0SsRc,1236
|
|
3
|
+
large_image_source_openslide-1.33.6a165.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
4
|
+
large_image_source_openslide-1.33.6a165.dist-info/METADATA,sha256=XApXY6AO8gL5WbeS8nvvWYjrUSQQEgGc9Qe2avit_mM,1797
|
|
5
|
+
large_image_source_openslide-1.33.6a165.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
+
large_image_source_openslide-1.33.6a165.dist-info/entry_points.txt,sha256=4Z5cf63yeesvHxiR9W1dY3rfz5_V4Ck2xYhPUp4A1qA,196
|
|
7
|
+
large_image_source_openslide-1.33.6a165.dist-info/top_level.txt,sha256=wqaQQDWQl9a_l9s6n07tTxfjeEXePtHBhz1np6aUwQE,29
|
|
8
|
+
large_image_source_openslide-1.33.6a165.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
large_image_source_openslide/__init__.py,sha256=O1-E-D7ZdY6Ta_ngId_HV0uqqxAbuY_J9fKTNVOFulE,20495
|
|
2
|
-
large_image_source_openslide/girder_source.py,sha256=ntLgOinO7xcO85wFbjx6XEBmTgEtx5cuPZ_K6wXZzqA,1199
|
|
3
|
-
large_image_source_openslide-1.30.7.dev35.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
4
|
-
large_image_source_openslide-1.30.7.dev35.dist-info/METADATA,sha256=mJwXTkcefJJxNLpCpEAYPsu_nSw1dQVsPKHwaZtXleo,1858
|
|
5
|
-
large_image_source_openslide-1.30.7.dev35.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
6
|
-
large_image_source_openslide-1.30.7.dev35.dist-info/entry_points.txt,sha256=4Z5cf63yeesvHxiR9W1dY3rfz5_V4Ck2xYhPUp4A1qA,196
|
|
7
|
-
large_image_source_openslide-1.30.7.dev35.dist-info/top_level.txt,sha256=wqaQQDWQl9a_l9s6n07tTxfjeEXePtHBhz1np6aUwQE,29
|
|
8
|
-
large_image_source_openslide-1.30.7.dev35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|