large-image-source-multi 1.27.5.dev6__py3-none-any.whl → 1.30.7.dev10__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_multi/__init__.py +150 -46
- {large_image_source_multi-1.27.5.dev6.dist-info → large_image_source_multi-1.30.7.dev10.dist-info}/METADATA +20 -6
- large_image_source_multi-1.30.7.dev10.dist-info/RECORD +8 -0
- {large_image_source_multi-1.27.5.dev6.dist-info → large_image_source_multi-1.30.7.dev10.dist-info}/WHEEL +1 -1
- large_image_source_multi-1.27.5.dev6.dist-info/RECORD +0 -8
- {large_image_source_multi-1.27.5.dev6.dist-info → large_image_source_multi-1.30.7.dev10.dist-info}/LICENSE +0 -0
- {large_image_source_multi-1.27.5.dev6.dist-info → large_image_source_multi-1.30.7.dev10.dist-info}/entry_points.txt +0 -0
- {large_image_source_multi-1.27.5.dev6.dist-info → large_image_source_multi-1.30.7.dev10.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,6 @@ from importlib.metadata import PackageNotFoundError
|
|
|
10
10
|
from importlib.metadata import version as _importlib_version
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
|
-
import jsonschema
|
|
14
13
|
import numpy as np
|
|
15
14
|
import yaml
|
|
16
15
|
|
|
@@ -27,6 +26,26 @@ except PackageNotFoundError:
|
|
|
27
26
|
# package is not installed
|
|
28
27
|
pass
|
|
29
28
|
|
|
29
|
+
jsonschema = None
|
|
30
|
+
_validator = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _lazyImport():
|
|
34
|
+
"""
|
|
35
|
+
Import the jsonschema module. This is done when needed rather than in the
|
|
36
|
+
module initialization because it is slow.
|
|
37
|
+
"""
|
|
38
|
+
global jsonschema, _validator
|
|
39
|
+
|
|
40
|
+
if jsonschema is None:
|
|
41
|
+
try:
|
|
42
|
+
import jsonschema
|
|
43
|
+
|
|
44
|
+
_validator = jsonschema.Draft6Validator(MultiSourceSchema)
|
|
45
|
+
except ImportError:
|
|
46
|
+
msg = 'jsonschema module not found.'
|
|
47
|
+
raise TileSourceError(msg)
|
|
48
|
+
|
|
30
49
|
|
|
31
50
|
SourceEntrySchema = {
|
|
32
51
|
'type': 'object',
|
|
@@ -269,10 +288,24 @@ SourceEntrySchema = {
|
|
|
269
288
|
'type': 'array',
|
|
270
289
|
'items': {'type': 'integer'},
|
|
271
290
|
},
|
|
272
|
-
'
|
|
273
|
-
'params': {
|
|
291
|
+
'sampleScale': {
|
|
274
292
|
'description':
|
|
275
|
-
'
|
|
293
|
+
'Each pixel sample values is divided by this scale after any '
|
|
294
|
+
'sampleOffset has been applied',
|
|
295
|
+
'type': 'number',
|
|
296
|
+
},
|
|
297
|
+
'sampleOffset': {
|
|
298
|
+
'description':
|
|
299
|
+
'This is added to each pixel sample value before any '
|
|
300
|
+
'sampleScale is applied',
|
|
301
|
+
'type': 'number',
|
|
302
|
+
},
|
|
303
|
+
'style': {
|
|
304
|
+
'description': 'A style specification to pass to the base tile source',
|
|
305
|
+
'type': 'object',
|
|
306
|
+
},
|
|
307
|
+
'params': {
|
|
308
|
+
'description': 'Additional parameters to pass to the base tile source',
|
|
276
309
|
'type': 'object',
|
|
277
310
|
},
|
|
278
311
|
},
|
|
@@ -333,6 +366,10 @@ MultiSourceSchema = {
|
|
|
333
366
|
'layout and size, assume all sources are so similar',
|
|
334
367
|
'type': 'boolean',
|
|
335
368
|
},
|
|
369
|
+
'dtype': {
|
|
370
|
+
'description': 'If present, a numpy dtype name to use for the data.',
|
|
371
|
+
'type': 'string',
|
|
372
|
+
},
|
|
336
373
|
'singleBand': {
|
|
337
374
|
'description':
|
|
338
375
|
'If true, output only the first band of compositied results',
|
|
@@ -376,6 +413,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
376
413
|
None: SourcePriority.FALLBACK,
|
|
377
414
|
'application/json': SourcePriority.PREFERRED,
|
|
378
415
|
'application/yaml': SourcePriority.PREFERRED,
|
|
416
|
+
'text/yaml': SourcePriority.PREFERRED,
|
|
379
417
|
}
|
|
380
418
|
|
|
381
419
|
_minTileSize = 64
|
|
@@ -383,9 +421,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
383
421
|
_defaultTileSize = 256
|
|
384
422
|
_maxOpenHandles = 6
|
|
385
423
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
def __init__(self, path, **kwargs):
|
|
424
|
+
def __init__(self, path, **kwargs): # noqa
|
|
389
425
|
"""
|
|
390
426
|
Initialize the tile class. See the base class for other available
|
|
391
427
|
parameters.
|
|
@@ -394,11 +430,22 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
394
430
|
"""
|
|
395
431
|
super().__init__(path, **kwargs)
|
|
396
432
|
|
|
433
|
+
_lazyImport()
|
|
434
|
+
self._validator = _validator
|
|
397
435
|
self._largeImagePath = self._getLargeImagePath()
|
|
398
436
|
self._lastOpenSourceLock = threading.RLock()
|
|
399
437
|
# 'c' must be first as channels are special because they can have names
|
|
400
438
|
self._axesList = ['c', 'z', 't', 'xy']
|
|
401
|
-
if
|
|
439
|
+
if isinstance(path, dict) and 'sources' in path:
|
|
440
|
+
self._info = path.copy()
|
|
441
|
+
self._basePath = '.'
|
|
442
|
+
self._largeImagePath = '.'
|
|
443
|
+
try:
|
|
444
|
+
self._validator.validate(self._info)
|
|
445
|
+
except jsonschema.ValidationError:
|
|
446
|
+
msg = 'File cannot be validated via multi-source reader.'
|
|
447
|
+
raise TileSourceError(msg)
|
|
448
|
+
elif not os.path.isfile(self._largeImagePath):
|
|
402
449
|
try:
|
|
403
450
|
possibleYaml = self._largeImagePath.split('multi://', 1)[-1]
|
|
404
451
|
self._info = yaml.safe_load(possibleYaml)
|
|
@@ -410,7 +457,8 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
410
457
|
try:
|
|
411
458
|
with builtins.open(self._largeImagePath) as fptr:
|
|
412
459
|
start = fptr.read(1024).strip()
|
|
413
|
-
if start[:1] not in ('{', '#', '-') and
|
|
460
|
+
if (start[:1] not in ('{', '#', '-') and
|
|
461
|
+
(start[:1] < 'a' or start[:1] > 'z')) or 'FeatureCollection' in start:
|
|
414
462
|
msg = 'File cannot be opened via multi-source reader.'
|
|
415
463
|
raise TileSourceError(msg)
|
|
416
464
|
fptr.seek(0)
|
|
@@ -661,9 +709,15 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
661
709
|
aKey = tuple(self._axisKey(source, frame.get(f'Index{axis.upper()}') or 0, axis)
|
|
662
710
|
for axis in self._axesList)
|
|
663
711
|
channel = channels[cIdx] if cIdx < len(channels) else None
|
|
712
|
+
# We add the channel name to our channel list if the individual
|
|
713
|
+
# source lists the channel name or a set of channels OR the source
|
|
714
|
+
# appends channels to an existing set.
|
|
664
715
|
if channel and channel not in self._channels and (
|
|
665
|
-
'channel' in source or 'channels' in source
|
|
716
|
+
'channel' in source or 'channels' in source or
|
|
717
|
+
len(self._channels) == aKey[0]):
|
|
666
718
|
self._channels.append(channel)
|
|
719
|
+
# Adjust the channel number if the source named the channel; do not
|
|
720
|
+
# do so in other cases
|
|
667
721
|
if (channel and channel in self._channels and
|
|
668
722
|
'c' not in source and 'cValues' not in source):
|
|
669
723
|
aKey = tuple([self._channels.index(channel)] + list(aKey[1:]))
|
|
@@ -759,7 +813,11 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
759
813
|
self.tileWidth = self.tileWidth or ts.tileWidth
|
|
760
814
|
self.tileHeight = self.tileHeight or ts.tileHeight
|
|
761
815
|
if not hasattr(self, '_firstdtype'):
|
|
762
|
-
self._firstdtype =
|
|
816
|
+
self._firstdtype = (
|
|
817
|
+
ts.dtype if not self._info.get('dtype') else
|
|
818
|
+
np.dtype(self._info['dtype']))
|
|
819
|
+
if self._info.get('dtype'):
|
|
820
|
+
self._dtype = np.dtype(self._info['dtype'])
|
|
763
821
|
if not numChecked:
|
|
764
822
|
tsMag = ts.getNativeMagnification()
|
|
765
823
|
for key in self._nativeMagnification:
|
|
@@ -773,7 +831,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
773
831
|
self._bands = {}
|
|
774
832
|
self._bands.update(tsMeta['bands'])
|
|
775
833
|
lastSource = source
|
|
776
|
-
self.
|
|
834
|
+
self._bandCount = 1 if self._info.get('singleBand') else (
|
|
777
835
|
len(self._bands) if hasattr(self, '_bands') else (bandCount or None))
|
|
778
836
|
bbox = self._sourceBoundingBox(source, tsMeta['sizeX'], tsMeta['sizeY'])
|
|
779
837
|
computedWidth = max(computedWidth, int(math.ceil(bbox['right'])))
|
|
@@ -828,7 +886,8 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
828
886
|
with self._lastOpenSourceLock:
|
|
829
887
|
if (hasattr(self, '_lastOpenSource') and
|
|
830
888
|
self._lastOpenSource['source'] == source and
|
|
831
|
-
self._lastOpenSource['params'] == params
|
|
889
|
+
(self._lastOpenSource['params'] == params or (
|
|
890
|
+
params == {} and self._lastOpenSource['params'] is None))):
|
|
832
891
|
return self._lastOpenSource['ts']
|
|
833
892
|
if not len(large_image.tilesource.AvailableTileSources):
|
|
834
893
|
large_image.tilesource.loadTileSources()
|
|
@@ -841,6 +900,22 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
841
900
|
if params is None:
|
|
842
901
|
params = source.get('params', {})
|
|
843
902
|
ts = openFunc(source['path'], **params)
|
|
903
|
+
if (self._dtype and np.dtype(ts.dtype).kind == 'f' and
|
|
904
|
+
(self._dtype == 'check' or np.dtype(self._dtype).kind != 'f') and
|
|
905
|
+
'sampleScale' not in source and 'sampleOffset' not in source):
|
|
906
|
+
minval = maxval = 0
|
|
907
|
+
for f in range(ts.frames):
|
|
908
|
+
ftile = ts.getTile(x=0, y=0, z=0, frame=f, numpyAllowed='always')
|
|
909
|
+
minval = min(minval, np.amin(ftile))
|
|
910
|
+
maxval = max(maxval, np.amax(ftile))
|
|
911
|
+
if minval >= 0 and maxval <= 1:
|
|
912
|
+
source['sampleScale'] = None
|
|
913
|
+
elif minval >= 0:
|
|
914
|
+
source['sampleScale'] = 2 ** math.ceil(math.log2(maxval))
|
|
915
|
+
else:
|
|
916
|
+
source['sampleScale'] = 2 ** math.ceil(math.log2(max(-minval, maxval)) + 1)
|
|
917
|
+
source['sampleOffset'] = source['sampleScale'] / 2
|
|
918
|
+
source['sourceName'] = ts.name
|
|
844
919
|
with self._lastOpenSourceLock:
|
|
845
920
|
self._lastOpenSource = {
|
|
846
921
|
'source': source,
|
|
@@ -860,7 +935,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
860
935
|
None if the associated image doesn't exist.
|
|
861
936
|
"""
|
|
862
937
|
if imageKey not in self._associatedImages:
|
|
863
|
-
return
|
|
938
|
+
return None
|
|
864
939
|
source = self._sources[self._associatedImages[imageKey]['sourcenum']]
|
|
865
940
|
ts = self._openSource(source)
|
|
866
941
|
return ts.getAssociatedImage(self._associatedImages[imageKey]['key'], *args, **kwargs)
|
|
@@ -894,7 +969,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
894
969
|
"""
|
|
895
970
|
Return additional known metadata about the tile source. Data returned
|
|
896
971
|
from this method is not guaranteed to be in any particular format or
|
|
897
|
-
have specific values.
|
|
972
|
+
have specific values. Also, only the first 100 sources are used.
|
|
898
973
|
|
|
899
974
|
:returns: a dictionary of data or None.
|
|
900
975
|
"""
|
|
@@ -903,7 +978,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
903
978
|
'sources': copy.deepcopy(self._sources),
|
|
904
979
|
'sourceFiles': [],
|
|
905
980
|
}
|
|
906
|
-
for path in self._sourcePaths.values():
|
|
981
|
+
for path in list(self._sourcePaths.values())[:100]:
|
|
907
982
|
source = self._sources[min(path['sourcenum'])]
|
|
908
983
|
ts = self._openSource(source)
|
|
909
984
|
result['sourceFiles'].append({
|
|
@@ -937,38 +1012,39 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
937
1012
|
(tile.shape[0] + y - base.shape[0], base.shape[1], base.shape[2]),
|
|
938
1013
|
dtype=base.dtype)
|
|
939
1014
|
if base.shape[2] in {2, 4}:
|
|
940
|
-
vfill[:, :, -1] = fullAlphaValue(
|
|
1015
|
+
vfill[:, :, -1] = fullAlphaValue(base.dtype)
|
|
941
1016
|
base = np.vstack((base, vfill))
|
|
942
1017
|
if base.shape[1] < tile.shape[1] + x:
|
|
943
1018
|
hfill = np.zeros(
|
|
944
1019
|
(base.shape[0], tile.shape[1] + x - base.shape[1], base.shape[2]),
|
|
945
1020
|
dtype=base.dtype)
|
|
946
1021
|
if base.shape[2] in {2, 4}:
|
|
947
|
-
hfill[:, :, -1] = fullAlphaValue(
|
|
1022
|
+
hfill[:, :, -1] = fullAlphaValue(base.dtype)
|
|
948
1023
|
base = np.hstack((base, hfill))
|
|
949
1024
|
if base.flags.writeable is False:
|
|
950
1025
|
base = base.copy()
|
|
951
1026
|
if base.shape[2] in {2, 4}:
|
|
952
1027
|
baseA = base[y:y + tile.shape[0], x:x + tile.shape[1], -1].astype(
|
|
953
|
-
float) / fullAlphaValue(
|
|
954
|
-
tileA = tile[:, :, -1].astype(float) / fullAlphaValue(
|
|
1028
|
+
float) / fullAlphaValue(base.dtype)
|
|
1029
|
+
tileA = tile[:, :, -1].astype(float) / fullAlphaValue(tile.dtype)
|
|
955
1030
|
outA = tileA + baseA * (1 - tileA)
|
|
956
1031
|
base[y:y + tile.shape[0], x:x + tile.shape[1], :-1] = (
|
|
957
|
-
np.where(tileA[..., np.newaxis], tile[:, :, :-1], 0) +
|
|
1032
|
+
np.where(tileA[..., np.newaxis], tile[:, :, :-1] * tileA[..., np.newaxis], 0) +
|
|
958
1033
|
base[y:y + tile.shape[0], x:x + tile.shape[1], :-1] * baseA[..., np.newaxis] *
|
|
959
1034
|
(1 - tileA[..., np.newaxis])
|
|
960
1035
|
) / np.where(outA[..., np.newaxis], outA[..., np.newaxis], 1)
|
|
961
|
-
base[y:y + tile.shape[0], x:x + tile.shape[1], -1] = outA * fullAlphaValue(
|
|
1036
|
+
base[y:y + tile.shape[0], x:x + tile.shape[1], -1] = outA * fullAlphaValue(base.dtype)
|
|
962
1037
|
else:
|
|
963
1038
|
base[y:y + tile.shape[0], x:x + tile.shape[1], :] = tile
|
|
964
1039
|
return base
|
|
965
1040
|
|
|
966
|
-
def _getTransformedTile(self, ts, transform, corners, scale, frame,
|
|
1041
|
+
def _getTransformedTile(self, ts, transform, corners, scale, frame,
|
|
1042
|
+
crop=None, firstMerge=False):
|
|
967
1043
|
"""
|
|
968
1044
|
Determine where the target tile's corners are located on the source.
|
|
969
1045
|
Fetch that so that we have at least sqrt(2) more resolution, then use
|
|
970
|
-
scikit-image warp to transform it. scikit-image does a better
|
|
971
|
-
scipy.ndimage.affine_transform.
|
|
1046
|
+
scikit-image warp to transform it. scikit-image does a better and
|
|
1047
|
+
faster job than scipy.ndimage.affine_transform.
|
|
972
1048
|
|
|
973
1049
|
:param ts: the source of the image to transform.
|
|
974
1050
|
:param transform: a 3x3 affine 2d matrix for transforming the source
|
|
@@ -980,6 +1056,9 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
980
1056
|
:param crop: an optional dictionary to crop the source image in full
|
|
981
1057
|
resolution, untransformed coordinates. This may contain left, top,
|
|
982
1058
|
right, and bottom values in pixels.
|
|
1059
|
+
:param firstMerge: if False and using an alpha channel, transform
|
|
1060
|
+
with nearest neighbor rather than a higher order function to
|
|
1061
|
+
avoid transparency effects.
|
|
983
1062
|
:returns: a numpy array tile or None, x, y coordinates within the
|
|
984
1063
|
target tile for the placement of the numpy tile array.
|
|
985
1064
|
"""
|
|
@@ -1010,7 +1089,7 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
1010
1089
|
# we only need every 1/srcscale pixel.
|
|
1011
1090
|
srcscale = int(2 ** math.log2(max(1, srcscale)))
|
|
1012
1091
|
# Pad to reduce edge effects at tile boundaries
|
|
1013
|
-
border = int(math.ceil(
|
|
1092
|
+
border = int(math.ceil(4 * srcscale))
|
|
1014
1093
|
region = {
|
|
1015
1094
|
'left': int(max(0, minx - border) // srcscale) * srcscale,
|
|
1016
1095
|
'top': int(max(0, miny - border) // srcscale) * srcscale,
|
|
@@ -1057,28 +1136,38 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
1057
1136
|
x, y = int(math.floor(x)), int(math.floor(y))
|
|
1058
1137
|
# Recompute where the source corners will land
|
|
1059
1138
|
destcorners = (np.dot(transform, regioncorners.T).T).tolist()
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1139
|
+
destShape = [
|
|
1140
|
+
max(max(math.ceil(c[1]) for c in destcorners), srcImage.shape[0]),
|
|
1141
|
+
max(max(math.ceil(c[0]) for c in destcorners), srcImage.shape[1]),
|
|
1142
|
+
]
|
|
1143
|
+
if max(0, -x) or max(0, -y):
|
|
1144
|
+
transform[0][2] -= max(0, -x)
|
|
1145
|
+
transform[1][2] -= max(0, -y)
|
|
1146
|
+
destShape[0] -= max(0, -y)
|
|
1147
|
+
destShape[1] -= max(0, -x)
|
|
1148
|
+
x += max(0, -x)
|
|
1149
|
+
y += max(0, -y)
|
|
1150
|
+
destShape = [min(destShape[0], outh - y), min(destShape[1], outw - x)]
|
|
1151
|
+
if destShape[0] <= 0 or destShape[1] <= 0:
|
|
1152
|
+
return None, None, None
|
|
1153
|
+
# Add an alpha band if needed. This has to be done before the
|
|
1154
|
+
# transform if it isn't the first tile, since the unused transformed
|
|
1155
|
+
# areas need to have a zero alpha value
|
|
1063
1156
|
if srcImage.shape[2] in {1, 3}:
|
|
1064
1157
|
_, srcImage = _makeSameChannelDepth(np.zeros((1, 1, srcImage.shape[2] + 1)), srcImage)
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1158
|
+
useNearest = srcImage.shape[2] in {2, 4} and not firstMerge
|
|
1159
|
+
# skimage.transform.warp is faster and has less artifacts than
|
|
1160
|
+
# scipy.ndimage.affine_transform. It is faster than using cupy's
|
|
1161
|
+
# version of scipy's affine_transform when the source and destination
|
|
1162
|
+
# images are converted from numpy to cupy and back in this method.
|
|
1070
1163
|
destImage = skimage.transform.warp(
|
|
1164
|
+
# Although using np.float32 could reduce memory use, it doesn't
|
|
1165
|
+
# provide any speed improvement
|
|
1071
1166
|
srcImage.astype(float),
|
|
1072
|
-
skimage.transform.AffineTransform(np.linalg.inv(
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
x += max(0, -x)
|
|
1077
|
-
y += max(0, -y)
|
|
1078
|
-
if x >= outw or y >= outh:
|
|
1079
|
-
return None, None, None
|
|
1080
|
-
destImage = destImage[:min(destImage.shape[0], outh - y),
|
|
1081
|
-
:min(destImage.shape[1], outw - x), :]
|
|
1167
|
+
skimage.transform.AffineTransform(np.linalg.inv(transform)),
|
|
1168
|
+
order=0 if useNearest else 3,
|
|
1169
|
+
output_shape=(destShape[0], destShape[1], srcImage.shape[2]),
|
|
1170
|
+
).astype(srcImage.dtype)
|
|
1082
1171
|
return destImage, x, y
|
|
1083
1172
|
|
|
1084
1173
|
def _addSourceToTile(self, tile, sourceEntry, corners, scale):
|
|
@@ -1098,12 +1187,12 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
1098
1187
|
:returns: a numpy array of the tile.
|
|
1099
1188
|
"""
|
|
1100
1189
|
source = self._sources[sourceEntry['sourcenum']]
|
|
1101
|
-
ts = self._openSource(source, sourceEntry['kwargs'])
|
|
1102
1190
|
# If tile is outside of bounding box, skip it
|
|
1103
1191
|
bbox = source['bbox']
|
|
1104
1192
|
if (corners[2][0] <= bbox['left'] or corners[0][0] >= bbox['right'] or
|
|
1105
1193
|
corners[2][1] <= bbox['top'] or corners[0][1] >= bbox['bottom']):
|
|
1106
1194
|
return tile
|
|
1195
|
+
ts = self._openSource(source, sourceEntry['kwargs'])
|
|
1107
1196
|
transform = bbox.get('transform')
|
|
1108
1197
|
x = y = 0
|
|
1109
1198
|
# If there is no transform or the diagonals are positive and there is
|
|
@@ -1153,8 +1242,23 @@ class MultiFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
1153
1242
|
else:
|
|
1154
1243
|
sourceTile, x, y = self._getTransformedTile(
|
|
1155
1244
|
ts, transform, corners, scale, sourceEntry.get('frame', 0),
|
|
1156
|
-
source.get('position', {}).get('crop')
|
|
1245
|
+
source.get('position', {}).get('crop'),
|
|
1246
|
+
firstMerge=tile is None)
|
|
1157
1247
|
if sourceTile is not None and all(dim > 0 for dim in sourceTile.shape):
|
|
1248
|
+
targetDtype = np.dtype(self._info.get('dtype', ts.dtype))
|
|
1249
|
+
changeDtype = sourceTile.dtype != targetDtype
|
|
1250
|
+
if source.get('sampleScale') or source.get('sampleOffset'):
|
|
1251
|
+
sourceTile = sourceTile.astype(float)
|
|
1252
|
+
if source.get('sampleOffset'):
|
|
1253
|
+
sourceTile[:, :, :-1] += source['sampleOffset']
|
|
1254
|
+
if source.get('sampleScale') and source.get('sampleScale') != 1:
|
|
1255
|
+
sourceTile[:, :, :-1] /= source['sampleScale']
|
|
1256
|
+
if sourceTile.dtype != targetDtype:
|
|
1257
|
+
if changeDtype:
|
|
1258
|
+
sourceTile = (
|
|
1259
|
+
sourceTile.astype(float) * fullAlphaValue(targetDtype) /
|
|
1260
|
+
fullAlphaValue(sourceTile))
|
|
1261
|
+
sourceTile = sourceTile.astype(targetDtype)
|
|
1158
1262
|
tile = self._mergeTiles(tile, sourceTile, x, y)
|
|
1159
1263
|
return tile
|
|
1160
1264
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: large-image-source-multi
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.30.7.dev10
|
|
4
4
|
Summary: A tilesource for large_image to composite other tile sources
|
|
5
5
|
Home-page: https://github.com/girder/large_image
|
|
6
6
|
Author: Kitware, Inc.
|
|
@@ -15,15 +15,29 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/x-rst
|
|
19
21
|
License-File: LICENSE
|
|
20
22
|
Requires-Dist: jsonschema
|
|
21
|
-
Requires-Dist: large-image
|
|
23
|
+
Requires-Dist: large-image>=1.30.7.dev10
|
|
22
24
|
Requires-Dist: pyyaml
|
|
23
25
|
Provides-Extra: all
|
|
24
|
-
Requires-Dist: scikit-image
|
|
26
|
+
Requires-Dist: scikit-image; extra == "all"
|
|
25
27
|
Provides-Extra: girder
|
|
26
|
-
Requires-Dist: girder-large-image
|
|
28
|
+
Requires-Dist: girder-large-image>=1.30.7.dev10; extra == "girder"
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: keywords
|
|
36
|
+
Dynamic: license
|
|
37
|
+
Dynamic: provides-extra
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
Dynamic: summary
|
|
27
41
|
|
|
28
42
|
A tilesource for large_image to composite other tile sources
|
|
29
43
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
large_image_source_multi/__init__.py,sha256=rUPaj9H32i9v89rCPsjmIfCIEi_N-ZOE9jTiRMrllDc,59131
|
|
2
|
+
large_image_source_multi/girder_source.py,sha256=YOp9hFCv-fzEhOIGAPdRewmyHM1jNu6WLr5Vt6cFtIA,1356
|
|
3
|
+
large_image_source_multi-1.30.7.dev10.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
4
|
+
large_image_source_multi-1.30.7.dev10.dist-info/METADATA,sha256=ovk964Jj7KL1Fyqg1kACs_qKr1W0DGP8sOgJ_lx-ZHM,1482
|
|
5
|
+
large_image_source_multi-1.30.7.dev10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
6
|
+
large_image_source_multi-1.30.7.dev10.dist-info/entry_points.txt,sha256=1ufcPRbofaLVrGNESx1R9QhdUovr4jTzte185wHqpcU,172
|
|
7
|
+
large_image_source_multi-1.30.7.dev10.dist-info/top_level.txt,sha256=v6W6Hkx77lY-DGQ8XqRgbdxYSJRLFv90dCrIJe15d2A,25
|
|
8
|
+
large_image_source_multi-1.30.7.dev10.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
large_image_source_multi/__init__.py,sha256=E4xscgnBb1l0EsUQtaj5LoWpiiBhMqjm5MStHneiaio,54069
|
|
2
|
-
large_image_source_multi/girder_source.py,sha256=YOp9hFCv-fzEhOIGAPdRewmyHM1jNu6WLr5Vt6cFtIA,1356
|
|
3
|
-
large_image_source_multi-1.27.5.dev6.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
4
|
-
large_image_source_multi-1.27.5.dev6.dist-info/METADATA,sha256=cB51hajqTzKi4NdqeSwiOfJawQsmi3YjNpIp1TamqP8,1139
|
|
5
|
-
large_image_source_multi-1.27.5.dev6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
6
|
-
large_image_source_multi-1.27.5.dev6.dist-info/entry_points.txt,sha256=1ufcPRbofaLVrGNESx1R9QhdUovr4jTzte185wHqpcU,172
|
|
7
|
-
large_image_source_multi-1.27.5.dev6.dist-info/top_level.txt,sha256=v6W6Hkx77lY-DGQ8XqRgbdxYSJRLFv90dCrIJe15d2A,25
|
|
8
|
-
large_image_source_multi-1.27.5.dev6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|