microssim 0.0.1__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.
- microssim/__init__.py +11 -0
- microssim/conftest.py +39 -0
- microssim/image_processing/__init__.py +13 -0
- microssim/image_processing/background.py +52 -0
- microssim/image_processing/care_normalization.py +124 -0
- microssim/image_processing/linearize.py +21 -0
- microssim/image_processing/micro_ssim_normalization.py +84 -0
- microssim/micro_ms3im.py +200 -0
- microssim/micro_ssim.py +437 -0
- microssim/ri_factor/__init__.py +6 -0
- microssim/ri_factor/mse_ri_factor.py +61 -0
- microssim/ri_factor/ri_factor.py +200 -0
- microssim/ssim/__init__.py +10 -0
- microssim/ssim/ssim_utils.py +397 -0
- microssim-0.0.1.dist-info/METADATA +120 -0
- microssim-0.0.1.dist-info/RECORD +18 -0
- microssim-0.0.1.dist-info/WHEEL +4 -0
- microssim-0.0.1.dist-info/licenses/LICENSE +21 -0
microssim/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""MicroSSIM and MicroMS3IM metrics to compare images."""
|
|
2
|
+
|
|
3
|
+
from .micro_ms3im import MicroMS3IM, micro_multiscale_structural_similarity
|
|
4
|
+
from .micro_ssim import MicroSSIM, micro_structural_similarity
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"MicroSSIM",
|
|
8
|
+
"micro_structural_similarity",
|
|
9
|
+
"MicroMS3IM",
|
|
10
|
+
"micro_multiscale_structural_similarity",
|
|
11
|
+
]
|
microssim/conftest.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""File used to discover python modules and run doctest.
|
|
2
|
+
|
|
3
|
+
See https://sybil.readthedocs.io/en/latest/use.html#pytest
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from pytest import TempPathFactory
|
|
10
|
+
from sybil import Sybil
|
|
11
|
+
from sybil.parsers.codeblock import PythonCodeBlockParser
|
|
12
|
+
from sybil.parsers.doctest import DocTestParser
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture(scope="module")
|
|
16
|
+
def my_path(tmpdir_factory: TempPathFactory) -> Path:
|
|
17
|
+
"""Fixture used in doctest to create a temporary directory.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
tmpdir_factory : TempPathFactory
|
|
22
|
+
Temporary path factory from pytest.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
Path
|
|
27
|
+
Temporary directory path.
|
|
28
|
+
"""
|
|
29
|
+
return tmpdir_factory.mktemp("my_path")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
pytest_collect_file = Sybil(
|
|
33
|
+
parsers=[
|
|
34
|
+
DocTestParser(),
|
|
35
|
+
PythonCodeBlockParser(future_imports=["print_function"]),
|
|
36
|
+
],
|
|
37
|
+
pattern="*.py",
|
|
38
|
+
fixtures=["my_path"],
|
|
39
|
+
).pytest()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Image processing utilities."""
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"get_background",
|
|
5
|
+
"remove_background",
|
|
6
|
+
"linearize_list",
|
|
7
|
+
"normalize_min_max",
|
|
8
|
+
"compute_norm_parameters",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
from .background import get_background, remove_background
|
|
12
|
+
from .linearize import linearize_list
|
|
13
|
+
from .micro_ssim_normalization import compute_norm_parameters, normalize_min_max
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Background calculation and removal functions."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_background(x: NDArray, percentage: float = 3) -> float:
|
|
8
|
+
"""
|
|
9
|
+
Compute the value of the background based on the percentile.
|
|
10
|
+
|
|
11
|
+
This method simply run `np.percentile` on the input image.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
x : numpy.ndarray
|
|
16
|
+
The input image.
|
|
17
|
+
percentage : float, default=3
|
|
18
|
+
Percentage for the percentile.
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
float
|
|
23
|
+
The value of the background.
|
|
24
|
+
"""
|
|
25
|
+
return np.percentile(x, percentage, keepdims=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def remove_background(
|
|
29
|
+
x: NDArray, percentage: float = 3, dtype: type = np.float32
|
|
30
|
+
) -> NDArray:
|
|
31
|
+
"""
|
|
32
|
+
Remove the background from an image.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
x : NDArray
|
|
37
|
+
The input image.
|
|
38
|
+
percentage : float, default=3
|
|
39
|
+
Percentage for the percentile.
|
|
40
|
+
dtype : type, default=np.float32
|
|
41
|
+
Data type for the output image.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
NDArray
|
|
46
|
+
The image with the background removed.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# get percentile
|
|
50
|
+
perc_val = get_background(x, percentage).astype(dtype, copy=False)
|
|
51
|
+
|
|
52
|
+
return x.astype(dtype, copy=False) - perc_val
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Normalization as done in the CSBDEEP library and CARE approach.
|
|
2
|
+
|
|
3
|
+
Code adapted from https://github.com/CSBDeep/CSBDeep under BSD-3-Clause license.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def normalize_care(
|
|
13
|
+
x: NDArray,
|
|
14
|
+
pmin: float = 3,
|
|
15
|
+
pmax: float = 99.8,
|
|
16
|
+
axis: Optional[int] = None,
|
|
17
|
+
eps: float = 1e-20,
|
|
18
|
+
dtype: type = np.float32,
|
|
19
|
+
) -> NDArray:
|
|
20
|
+
"""
|
|
21
|
+
Normalize input image using min and max percentiles.
|
|
22
|
+
|
|
23
|
+
This approach was used in the CARE method.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
x : NDArray
|
|
28
|
+
Input image.
|
|
29
|
+
pmin : float, default=3
|
|
30
|
+
Lower percentile.
|
|
31
|
+
pmax : float, default=99.8
|
|
32
|
+
Upper percentile.
|
|
33
|
+
axis : int or None, default=None
|
|
34
|
+
Axis or axes along which to compute the percentiles. The default `None` is to
|
|
35
|
+
compute the percentile(s) over a flattened version of the array.
|
|
36
|
+
eps : float, default=1e-20
|
|
37
|
+
Small value to avoid division by zero.
|
|
38
|
+
dtype : type, default=np.float32
|
|
39
|
+
Data type of the output.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
NDArray
|
|
44
|
+
Normalized image.
|
|
45
|
+
"""
|
|
46
|
+
# Compute percentiles
|
|
47
|
+
mi = np.percentile(x, pmin, axis=axis, keepdims=True)
|
|
48
|
+
ma = np.percentile(x, pmax, axis=axis, keepdims=True)
|
|
49
|
+
|
|
50
|
+
return normalize_min_max(x, mi, ma, eps=eps, dtype=dtype)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def normalize_min_max(
|
|
54
|
+
x: NDArray,
|
|
55
|
+
min_val: float,
|
|
56
|
+
max_val: float,
|
|
57
|
+
eps: float = 1e-20,
|
|
58
|
+
dtype: type = np.float32,
|
|
59
|
+
) -> NDArray:
|
|
60
|
+
"""
|
|
61
|
+
Normalize input image using absolute min and max values.
|
|
62
|
+
|
|
63
|
+
This approach was used in the CARE method.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
x : NDArray
|
|
68
|
+
Input image.
|
|
69
|
+
min_val : float
|
|
70
|
+
Lower value.
|
|
71
|
+
max_val : float
|
|
72
|
+
Upper value.
|
|
73
|
+
eps : float, default=1e-20
|
|
74
|
+
Small value to avoid division by zero.
|
|
75
|
+
dtype : type, default=np.float32
|
|
76
|
+
Data type of the output.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
NDArray
|
|
81
|
+
Normalized image.
|
|
82
|
+
"""
|
|
83
|
+
# change types
|
|
84
|
+
x = x.astype(dtype, copy=False)
|
|
85
|
+
min_val = (
|
|
86
|
+
dtype(min_val) if np.isscalar(min_val) else min_val.astype(dtype, copy=False)
|
|
87
|
+
)
|
|
88
|
+
max_val = (
|
|
89
|
+
dtype(max_val) if np.isscalar(max_val) else max_val.astype(dtype, copy=False)
|
|
90
|
+
)
|
|
91
|
+
eps = dtype(eps)
|
|
92
|
+
|
|
93
|
+
return (x - min_val) / (max_val - min_val + eps)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def normalize_min_mse(x: NDArray, target: NDArray) -> NDArray:
|
|
97
|
+
"""
|
|
98
|
+
Normalize input image to a target image using minimum mean square error.
|
|
99
|
+
|
|
100
|
+
This method performs an affine rescaling of x, such that the mean squared error to
|
|
101
|
+
target is minimal.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
x : NDArray
|
|
106
|
+
Input image.
|
|
107
|
+
target : NDArray
|
|
108
|
+
Target image.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
NDArray
|
|
113
|
+
Normalized input image.
|
|
114
|
+
"""
|
|
115
|
+
# compute covariance
|
|
116
|
+
cov = np.cov(x.flatten(), target.flatten())
|
|
117
|
+
|
|
118
|
+
# scaling factor
|
|
119
|
+
alpha = cov[0, 1] / (cov[0, 0] + 1e-10)
|
|
120
|
+
|
|
121
|
+
# offset
|
|
122
|
+
beta = target.mean() - alpha * x.mean()
|
|
123
|
+
|
|
124
|
+
return alpha * x + beta
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Linearize list of images."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def linearize_list(images: list[NDArray]) -> NDArray:
|
|
8
|
+
"""
|
|
9
|
+
Linearize and concatenate a list of images, avoiding copying the arrays.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
images : list of numpy.ndarray
|
|
14
|
+
Input images.
|
|
15
|
+
|
|
16
|
+
Returns
|
|
17
|
+
-------
|
|
18
|
+
np.ndarray
|
|
19
|
+
Lineatized and concatenated images.
|
|
20
|
+
"""
|
|
21
|
+
return np.concatenate([np.ravel(x) for x in images])
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""MicroSSIM normalization functions."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Union
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# TODO add tests
|
|
10
|
+
def normalize_min_max(
|
|
11
|
+
images: Union[list[NDArray], NDArray], min_val: float, max_val: float
|
|
12
|
+
) -> Union[list[NDArray], NDArray]:
|
|
13
|
+
"""
|
|
14
|
+
Normalize the images using provided minimum and maximum values.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
images : numpy.ndarray or list of numpy.ndarray
|
|
19
|
+
Image or list of images to normalize.
|
|
20
|
+
min_val : float
|
|
21
|
+
Minimum value used in normalization.
|
|
22
|
+
max_val : float
|
|
23
|
+
Maximum value used in normalization.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
numpy.ndarray or list of numpy.ndarray
|
|
28
|
+
Normalized image or list of normalized images.
|
|
29
|
+
"""
|
|
30
|
+
if isinstance(images, list):
|
|
31
|
+
return [normalize_min_max(x, min_val, max_val) for x in images]
|
|
32
|
+
|
|
33
|
+
return (images - min_val) / max_val
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def compute_norm_parameters(
|
|
37
|
+
gt: NDArray,
|
|
38
|
+
pred: NDArray,
|
|
39
|
+
bg_percentile: float = 3.0,
|
|
40
|
+
offset_gt: Optional[float] = None,
|
|
41
|
+
offset_pred: Optional[float] = None,
|
|
42
|
+
max_val: Optional[float] = None,
|
|
43
|
+
) -> tuple[float, float, float]:
|
|
44
|
+
"""
|
|
45
|
+
Compute the parameters used to normalize the images for MicroSSIM.
|
|
46
|
+
|
|
47
|
+
If the offsets are provided, they are simply returned. Otherwise, they are
|
|
48
|
+
estimated from the images using the background percentile value.
|
|
49
|
+
|
|
50
|
+
If the maximum value is provided, it is simply returned. Otherwise, it is
|
|
51
|
+
estimated from the ground truth image by checking the maximum value after
|
|
52
|
+
background subtraction.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
gt : NDArray
|
|
57
|
+
Reference image.
|
|
58
|
+
pred : NDArray
|
|
59
|
+
Image being compared to the reference.
|
|
60
|
+
bg_percentile : float, default=3
|
|
61
|
+
Percentile of the image considered as background.
|
|
62
|
+
offset_gt : float or None, default=None
|
|
63
|
+
Estimate of background pixel intensity in the reference image.
|
|
64
|
+
offset_pred : float or None, default=None
|
|
65
|
+
Estimate of background pixel intensity in the second image.
|
|
66
|
+
max_val : float or None, default=None
|
|
67
|
+
Maximum value used in normalization.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
(float, float, float)
|
|
72
|
+
A tuple containing the ground-truth offset, the prediction offset and the
|
|
73
|
+
maximum value.
|
|
74
|
+
"""
|
|
75
|
+
if offset_gt is None:
|
|
76
|
+
offset_gt = np.percentile(gt, bg_percentile, keepdims=False)
|
|
77
|
+
|
|
78
|
+
if offset_pred is None:
|
|
79
|
+
offset_pred = np.percentile(pred, bg_percentile, keepdims=False)
|
|
80
|
+
|
|
81
|
+
if max_val is None:
|
|
82
|
+
max_val = (gt - offset_gt).max()
|
|
83
|
+
|
|
84
|
+
return offset_gt, offset_pred, max_val
|
microssim/micro_ms3im.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""MicroMS3IM metrics."""
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from typing import Optional, Union
|
|
5
|
+
|
|
6
|
+
import torch
|
|
7
|
+
from numpy.typing import NDArray
|
|
8
|
+
from torch import Tensor
|
|
9
|
+
from torchmetrics.image import MultiScaleStructuralSimilarityIndexMeasure
|
|
10
|
+
|
|
11
|
+
from microssim.image_processing import normalize_min_max
|
|
12
|
+
from microssim.micro_ssim import MicroSSIM
|
|
13
|
+
|
|
14
|
+
# TODO implement it in numpy?
|
|
15
|
+
# TODO return types are torch.Tensor
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def micro_multiscale_structural_similarity(
|
|
19
|
+
gt: Union[NDArray, list[NDArray]],
|
|
20
|
+
pred: Union[NDArray, list[NDArray]],
|
|
21
|
+
*,
|
|
22
|
+
bg_percentile: int = 3,
|
|
23
|
+
offset_gt: Optional[float] = None,
|
|
24
|
+
offset_pred: Optional[float] = None,
|
|
25
|
+
max_val: Optional[float] = None,
|
|
26
|
+
ri_factor: Optional[float] = None,
|
|
27
|
+
) -> Union[float, list[float]]:
|
|
28
|
+
"""
|
|
29
|
+
Compute the mean MicroMS3IM metric between two images.
|
|
30
|
+
|
|
31
|
+
MicroSSIM computes a scaled version of the multiscale structural similarity index
|
|
32
|
+
(MS3IM), in which images are first normalized using an offset and maximum value. A
|
|
33
|
+
range-invariant factor is then estimated by maximizing a scaled MS3IM metrics
|
|
34
|
+
between the normalized images.
|
|
35
|
+
|
|
36
|
+
If the offsets are not provided, they are estimated from the images using the
|
|
37
|
+
background percentile value.
|
|
38
|
+
|
|
39
|
+
If the maximum value is not provided, it is estimated from the ground truth image
|
|
40
|
+
by checking the maximum value after background subtraction.
|
|
41
|
+
|
|
42
|
+
If the range-invariant factor is not provided, it is estimated from the normalized
|
|
43
|
+
images.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
gt : numpy.ndarray or list of numpy.ndarray
|
|
48
|
+
Reference image.
|
|
49
|
+
pred : numpy.ndarray or list of numpy.ndarray
|
|
50
|
+
Image being compared to the reference.
|
|
51
|
+
bg_percentile : int, default=3
|
|
52
|
+
Percentile of the image considered as background.
|
|
53
|
+
offset_gt : float or None, default=None
|
|
54
|
+
Estimate of background pixel intensity in the reference image.
|
|
55
|
+
offset_pred : float or None, default=None
|
|
56
|
+
Estimate of background pixel intensity in the second image.
|
|
57
|
+
max_val : float or None, default=None
|
|
58
|
+
Maximum value used in normalization.
|
|
59
|
+
ri_factor : float or None, default=None
|
|
60
|
+
Range-invariant factor.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
float or list of float
|
|
65
|
+
Mean MicroSSIM metric between the images, either as a list if the input are
|
|
66
|
+
lists or array with more than 2 dimensions.
|
|
67
|
+
|
|
68
|
+
Examples
|
|
69
|
+
--------
|
|
70
|
+
>>> import numpy as np
|
|
71
|
+
>>> from microssim import micro_multiscale_structural_similarity
|
|
72
|
+
>>> rng = np.random.default_rng(42)
|
|
73
|
+
>>> gt = 150 + rng.integers(0, data_range, (100, 100))
|
|
74
|
+
>>> pred = rng.poisson(gt) / 10. - 100
|
|
75
|
+
>>> micro_multiscale_structural_similarity(gt, pred)
|
|
76
|
+
"""
|
|
77
|
+
# generate parameters for the metrics computation
|
|
78
|
+
micro_ssim = MicroMS3IM(
|
|
79
|
+
bg_percentile=bg_percentile,
|
|
80
|
+
offset_gt=offset_gt,
|
|
81
|
+
offset_pred=offset_pred,
|
|
82
|
+
max_val=max_val,
|
|
83
|
+
ri_factor=ri_factor,
|
|
84
|
+
)
|
|
85
|
+
micro_ssim.fit(gt, pred)
|
|
86
|
+
|
|
87
|
+
# compute the MicroMS3IM metric
|
|
88
|
+
if isinstance(gt, list) or gt.ndim > 2:
|
|
89
|
+
return [
|
|
90
|
+
micro_ssim.score(
|
|
91
|
+
gt_i,
|
|
92
|
+
pred_i,
|
|
93
|
+
)
|
|
94
|
+
for gt_i, pred_i in zip(gt, pred)
|
|
95
|
+
]
|
|
96
|
+
else:
|
|
97
|
+
return micro_ssim.score(
|
|
98
|
+
gt,
|
|
99
|
+
pred,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class MicroMS3IM(MicroSSIM):
|
|
104
|
+
"""
|
|
105
|
+
A class computing the MicroMS3IM metric between images.
|
|
106
|
+
|
|
107
|
+
In addition to computing the metrics, this class allows to inspect the parameters
|
|
108
|
+
estimated along the way, such as the offsets, the max value and the range-invariant
|
|
109
|
+
factor.
|
|
110
|
+
|
|
111
|
+
Attributes
|
|
112
|
+
----------
|
|
113
|
+
_bg_percentile : int
|
|
114
|
+
Percentile of the image considered as background.
|
|
115
|
+
_offset_pred : float
|
|
116
|
+
Estimate of background pixel intensity in the prediction image.
|
|
117
|
+
_offset_gt : float
|
|
118
|
+
Estimate of background pixel intensity in the ground truth image.
|
|
119
|
+
_max_val : float
|
|
120
|
+
Maximum value used in normalization.
|
|
121
|
+
_ri_factor : float
|
|
122
|
+
MicroSSIM scaling factor.
|
|
123
|
+
_initialized : bool
|
|
124
|
+
Whether the class has been initialized and can compute scores between images.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
def score(
|
|
128
|
+
self,
|
|
129
|
+
gt: NDArray,
|
|
130
|
+
pred: NDArray,
|
|
131
|
+
return_individual_components: bool = False,
|
|
132
|
+
**ms_ssim_kwargs,
|
|
133
|
+
) -> float:
|
|
134
|
+
"""Compute the metrics between two arrays.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
gt : numpy.ndarray
|
|
139
|
+
Reference array.
|
|
140
|
+
pred : NDArray
|
|
141
|
+
Array to be compared to the reference array.
|
|
142
|
+
return_individual_components : bool, default=False
|
|
143
|
+
Unused argument.
|
|
144
|
+
**ms_ssim_kwargs : dict
|
|
145
|
+
Additional keyword arguments to be passed to the
|
|
146
|
+
`torchmetrics.image.MultiScaleStructuralSimilarityIndexMeasure` class.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
float or ScaledSSIM
|
|
151
|
+
MicroSSIM metric between the arrays.
|
|
152
|
+
|
|
153
|
+
Raises
|
|
154
|
+
------
|
|
155
|
+
ValueError
|
|
156
|
+
If the `fit` method has not been called before calling this method.
|
|
157
|
+
ValueError
|
|
158
|
+
If the groundtruth and prediction arrays have different shapes.
|
|
159
|
+
ValueError
|
|
160
|
+
If the arrays are not 2D.
|
|
161
|
+
"""
|
|
162
|
+
if return_individual_components:
|
|
163
|
+
warnings.warn(
|
|
164
|
+
"The `return_individual_components` argument is not supported for "
|
|
165
|
+
"the MS-SSIM metric. Ignoring it."
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if not self._initialized:
|
|
169
|
+
raise ValueError(
|
|
170
|
+
"MicroSSIM was not initialized, call the `fit` method first. It is "
|
|
171
|
+
"advised to run the `fit` method on entire datasets rather than on "
|
|
172
|
+
"pairs of images."
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if gt.shape != pred.shape:
|
|
176
|
+
raise ValueError("Groundtruth and prediction must have the same shape.")
|
|
177
|
+
|
|
178
|
+
if gt.ndim != 2:
|
|
179
|
+
raise ValueError("Only 2D images are supported.")
|
|
180
|
+
|
|
181
|
+
if ms_ssim_kwargs is None:
|
|
182
|
+
ms_ssim_kwargs = {}
|
|
183
|
+
|
|
184
|
+
# normalize the images
|
|
185
|
+
gt_norm = normalize_min_max(gt, self._offset_gt, self._max_val)
|
|
186
|
+
pred_norm = normalize_min_max(pred, self._offset_pred, self._max_val)
|
|
187
|
+
|
|
188
|
+
# convert to torch tensors
|
|
189
|
+
gt_torch = torch.Tensor(gt_norm[None, None])
|
|
190
|
+
pred_torch = torch.Tensor(pred_norm[None, None])
|
|
191
|
+
|
|
192
|
+
# rescale
|
|
193
|
+
pred_torch = pred_torch * self._ri_factor
|
|
194
|
+
|
|
195
|
+
# compute the MS-SSIM
|
|
196
|
+
ms_ssim = MultiScaleStructuralSimilarityIndexMeasure(
|
|
197
|
+
data_range=gt_norm.max() - gt_norm.min(), **ms_ssim_kwargs
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return ms_ssim(pred_torch, gt_torch)
|