dsa-helpers 0.2__tar.gz → 0.3.dev0__tar.gz
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.
- {dsa_helpers-0.2/dsa_helpers.egg-info → dsa_helpers-0.3.dev0}/PKG-INFO +3 -1
- dsa_helpers-0.3.dev0/dsa_helpers/__init__.py +7 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/dsa_helpers/girder_utils.py +8 -12
- dsa_helpers-0.3.dev0/dsa_helpers/image_utils.py +65 -0
- dsa_helpers-0.3.dev0/dsa_helpers/imread.py +32 -0
- dsa_helpers-0.3.dev0/dsa_helpers/imwrite.py +37 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/dsa_helpers/login.py +0 -6
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0/dsa_helpers.egg-info}/PKG-INFO +3 -1
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/dsa_helpers.egg-info/SOURCES.txt +4 -2
- dsa_helpers-0.3.dev0/dsa_helpers.egg-info/requires.txt +5 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/pyproject.toml +4 -2
- dsa_helpers-0.2/dsa_helpers.egg-info/requires.txt → dsa_helpers-0.3.dev0/requirements.txt +3 -1
- dsa_helpers-0.2/dsa_helpers/__init__.py +0 -5
- dsa_helpers-0.2/requirements.txt +0 -3
- dsa_helpers-0.2/tests/general-tests.py +0 -11
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/.gitignore +0 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/LICENSE +0 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/README.md +0 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/dsa_helpers.egg-info/dependency_links.txt +0 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/dsa_helpers.egg-info/top_level.txt +0 -0
- {dsa_helpers-0.2 → dsa_helpers-0.3.dev0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dsa_helpers
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.dev0
|
|
4
4
|
Summary: Utility functions for working with the DSA girder client.
|
|
5
5
|
Author-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
|
|
6
6
|
Maintainer-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
|
|
@@ -14,6 +14,8 @@ License-File: LICENSE
|
|
|
14
14
|
Requires-Dist: girder-client==3.2.3
|
|
15
15
|
Requires-Dist: numpy==2.0.0
|
|
16
16
|
Requires-Dist: setuptools==71.0.3
|
|
17
|
+
Requires-Dist: opencv-python==4.10.0.84
|
|
18
|
+
Requires-Dist: pandas==2.2.2
|
|
17
19
|
|
|
18
20
|
# Digital Slide Archive (DSA) Helpers
|
|
19
21
|
Digital Slide Archive Python utility library.
|
|
@@ -43,18 +43,14 @@ def get_thumbnail(
|
|
|
43
43
|
Returns:
|
|
44
44
|
np.ndarray: The thumbnail image.
|
|
45
45
|
|
|
46
|
-
Raises:
|
|
47
|
-
ValueError: If neither mag, width, nor height is provided.
|
|
48
|
-
|
|
49
46
|
"""
|
|
50
|
-
|
|
51
|
-
raise ValueError("Either mag, width, or height must be provided.")
|
|
47
|
+
get_url = f"item/{item_id}/tiles/"
|
|
52
48
|
|
|
53
49
|
if mag is not None:
|
|
54
|
-
get_url
|
|
50
|
+
get_url += f"region?magnification={mag}&encoding=pickle"
|
|
55
51
|
else:
|
|
56
52
|
# Instead use width and height.
|
|
57
|
-
|
|
53
|
+
params = ["encoding=pickle"]
|
|
58
54
|
|
|
59
55
|
if width is not None and height is not None:
|
|
60
56
|
if isinstance(fill, (tuple, list)):
|
|
@@ -63,13 +59,13 @@ def get_thumbnail(
|
|
|
63
59
|
elif len(fill) == 4:
|
|
64
60
|
fill = f"rgba({fill[0]},{fill[1]},{fill[2]},{fill[3]})"
|
|
65
61
|
|
|
66
|
-
|
|
62
|
+
params.extend([f"width={width}", f"height={height}", f"fill={fill}"])
|
|
67
63
|
elif width is not None:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
params.append(f"width={width}")
|
|
65
|
+
elif height is not None:
|
|
66
|
+
params.append(f"height={height}")
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
get_url += "thumbnail?" + "&".join(params)
|
|
73
69
|
|
|
74
70
|
response = gc.get(get_url, jsonResp=False)
|
|
75
71
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Functions for working images.
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import cv2 as cv
|
|
6
|
+
from . import imwrite
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def tile_image(
|
|
10
|
+
img: np.ndarray,
|
|
11
|
+
save_loc: str,
|
|
12
|
+
tile_size: int,
|
|
13
|
+
stride: int | None = None,
|
|
14
|
+
fill: int | tuple = (255, 255, 255),
|
|
15
|
+
prepend_name: str = "",
|
|
16
|
+
) -> pd.DataFrame:
|
|
17
|
+
"""Tile an image into smaller images.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
img (np.ndarray): The image to tile.
|
|
21
|
+
save_loc (str): The location to save the tiles.
|
|
22
|
+
tile_size (int): The size of the tiles.
|
|
23
|
+
stride (int | None, optional): The stride for the tiles. Defaults to None,
|
|
24
|
+
in which case it is set equal to tile_size.
|
|
25
|
+
fill (int | tuple, optional): The fill value for tiles over the edges.
|
|
26
|
+
Defaults to (255, 255, 255).
|
|
27
|
+
prepend_name (str, optional): A string to prepend to the tile names.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
pandas.DataFrame: A DataFrame with the tile locations.
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
h, w = img.shape[:2]
|
|
34
|
+
|
|
35
|
+
img = cv.copyMakeBorder(
|
|
36
|
+
img, 0, tile_size, 0, tile_size, cv.BORDER_CONSTANT, value=fill
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Pad the image to avoid tiles not of the right size.
|
|
40
|
+
save_loc = Path(save_loc)
|
|
41
|
+
|
|
42
|
+
if not save_loc.exists():
|
|
43
|
+
save_loc.mkdir(parents=True)
|
|
44
|
+
|
|
45
|
+
if stride is None:
|
|
46
|
+
stride = tile_size
|
|
47
|
+
|
|
48
|
+
df_data = []
|
|
49
|
+
|
|
50
|
+
xys = [(x, y) for x in range(0, w, stride) for y in range(0, h, stride)]
|
|
51
|
+
|
|
52
|
+
for xy in xys:
|
|
53
|
+
x, y = xy
|
|
54
|
+
# Get the tile from the image.
|
|
55
|
+
tile_img = img[x : x + tile_size, y : y + tile_size]
|
|
56
|
+
|
|
57
|
+
save_fp = str(save_loc.joinpath(f"{prepend_name}x-{x}y-{y}.png"))
|
|
58
|
+
|
|
59
|
+
imwrite(save_fp, tile_img)
|
|
60
|
+
|
|
61
|
+
df_data.append([save_fp, x, y])
|
|
62
|
+
|
|
63
|
+
df = pd.DataFrame(df_data, columns=["fp", "x", "y"])
|
|
64
|
+
|
|
65
|
+
return df
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Function to read image from disk.
|
|
2
|
+
import cv2 as cv
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def imread(fp: str, grayscale: bool = False) -> np.ndarray:
|
|
7
|
+
"""Read image from disk. Currently does not support reading RGBA images.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
fp (str): The file path to save the image.
|
|
11
|
+
grayscale (bool, optional): If True, the image will be read as grayscale.
|
|
12
|
+
Defaults to False.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
np.ndarray: The image read from disk.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
if grayscale:
|
|
19
|
+
img = cv.imread(fp, cv.IMREAD_GRAYSCALE)
|
|
20
|
+
else:
|
|
21
|
+
img = cv.imread(fp, cv.IMREAD_UNCHANGED)
|
|
22
|
+
|
|
23
|
+
# Convert the image from OpenCV's BGR to RGB.
|
|
24
|
+
shape = img.shape
|
|
25
|
+
|
|
26
|
+
if len(shape) == 3:
|
|
27
|
+
if shape[2] == 3:
|
|
28
|
+
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
|
|
29
|
+
elif shape[2] == 4:
|
|
30
|
+
img = cv.cvtColor(img, cv.COLOR_RGBA2BGRA)
|
|
31
|
+
|
|
32
|
+
return img
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Function to save image to disk.
|
|
2
|
+
import cv2 as cv
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def imwrite(fp: str, img: np.ndarray, grayscale: bool = False) -> None:
|
|
7
|
+
"""Save an image to disk.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
img (np.ndarray): The image to save.
|
|
11
|
+
fp (str): The file path to save the image.
|
|
12
|
+
grayscale (bool, optional): Whether to save the image as grayscale.
|
|
13
|
+
Defaults to False.
|
|
14
|
+
|
|
15
|
+
Raises:
|
|
16
|
+
ValueError: The image must be grayscale, RGB, or RGBA.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
if grayscale:
|
|
20
|
+
if len(img.shape) == 2:
|
|
21
|
+
_ = cv.imwrite(fp, img)
|
|
22
|
+
else:
|
|
23
|
+
_ = cv.imwrite(fp, cv.cvtColor(img, cv.COLOR_RGB2GRAY))
|
|
24
|
+
else:
|
|
25
|
+
shape = img.shape
|
|
26
|
+
|
|
27
|
+
if len(shape) == 2:
|
|
28
|
+
_ = cv.imwrite(fp)
|
|
29
|
+
elif len(shape) == 3:
|
|
30
|
+
if shape[2] == 3:
|
|
31
|
+
_ = cv.imwrite(fp, cv.cvtColor(img, cv.COLOR_RGB2BGR))
|
|
32
|
+
elif shape[2] == 4:
|
|
33
|
+
_ = cv.imwrite(fp, cv.cvtColor(img, cv.COLOR_RGBA2BGRA))
|
|
34
|
+
else:
|
|
35
|
+
raise ValueError("The image must be grayscale, RGB, or RGBA.")
|
|
36
|
+
else:
|
|
37
|
+
raise ValueError("The image must be grayscale, RGB, or RGBA.")
|
|
@@ -20,13 +20,7 @@ def login(
|
|
|
20
20
|
Returns:
|
|
21
21
|
girder_client.GirderClient: The authenticated girder client.
|
|
22
22
|
|
|
23
|
-
Raises:
|
|
24
|
-
ValueError: If neither login_or_email nor api_key is provided.
|
|
25
|
-
|
|
26
23
|
"""
|
|
27
|
-
if login_or_email is None and api_key is None:
|
|
28
|
-
raise ValueError("Either login_or_email or api_key must be provided.")
|
|
29
|
-
|
|
30
24
|
gc = GirderClient(apiUrl=api_url)
|
|
31
25
|
|
|
32
26
|
if api_key is None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dsa_helpers
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.dev0
|
|
4
4
|
Summary: Utility functions for working with the DSA girder client.
|
|
5
5
|
Author-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
|
|
6
6
|
Maintainer-email: "Juan C. Vizcarra" <jvizcar@emory.edu>
|
|
@@ -14,6 +14,8 @@ License-File: LICENSE
|
|
|
14
14
|
Requires-Dist: girder-client==3.2.3
|
|
15
15
|
Requires-Dist: numpy==2.0.0
|
|
16
16
|
Requires-Dist: setuptools==71.0.3
|
|
17
|
+
Requires-Dist: opencv-python==4.10.0.84
|
|
18
|
+
Requires-Dist: pandas==2.2.2
|
|
17
19
|
|
|
18
20
|
# Digital Slide Archive (DSA) Helpers
|
|
19
21
|
Digital Slide Archive Python utility library.
|
|
@@ -5,10 +5,12 @@ pyproject.toml
|
|
|
5
5
|
requirements.txt
|
|
6
6
|
dsa_helpers/__init__.py
|
|
7
7
|
dsa_helpers/girder_utils.py
|
|
8
|
+
dsa_helpers/image_utils.py
|
|
9
|
+
dsa_helpers/imread.py
|
|
10
|
+
dsa_helpers/imwrite.py
|
|
8
11
|
dsa_helpers/login.py
|
|
9
12
|
dsa_helpers.egg-info/PKG-INFO
|
|
10
13
|
dsa_helpers.egg-info/SOURCES.txt
|
|
11
14
|
dsa_helpers.egg-info/dependency_links.txt
|
|
12
15
|
dsa_helpers.egg-info/requires.txt
|
|
13
|
-
dsa_helpers.egg-info/top_level.txt
|
|
14
|
-
tests/general-tests.py
|
|
16
|
+
dsa_helpers.egg-info/top_level.txt
|
|
@@ -6,7 +6,9 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
dependencies = [
|
|
7
7
|
'girder-client==3.2.3',
|
|
8
8
|
'numpy==2.0.0',
|
|
9
|
-
'setuptools==71.0.3'
|
|
9
|
+
'setuptools==71.0.3',
|
|
10
|
+
'opencv-python==4.10.0.84',
|
|
11
|
+
'pandas==2.2.2'
|
|
10
12
|
]
|
|
11
13
|
name = "dsa_helpers"
|
|
12
14
|
authors = [
|
|
@@ -23,7 +25,7 @@ classifiers = [
|
|
|
23
25
|
"License :: OSI Approved :: MIT License",
|
|
24
26
|
]
|
|
25
27
|
keywords = ["dsa", "girder", "girder_client"]
|
|
26
|
-
version = "v0.
|
|
28
|
+
version = "v0.3dev"
|
|
27
29
|
|
|
28
30
|
[project.urls]
|
|
29
31
|
Repository = "https://github.com/Gutman-Lab/dsa-python-utils"
|
dsa_helpers-0.2/requirements.txt
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|