Skip to content

Commit c80fe3c

Browse files
authored
Deprecate moving_window_mean in favor of uniform_filter (#208)
* Deprecate `moving_window_mean` in favor of `uniform_filter` See OPERA-Cal-Val/OPERA_Applications#35 `uniform_filter` seems to run faster for all input/filter sizes. * call `nearest` for mode, now there are not as obvious edge effects
1 parent 2de180f commit c80fe3c

File tree

4 files changed

+9
-96
lines changed

4 files changed

+9
-96
lines changed

src/dolphin/interferogram.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from opera_utils import get_dates
1313
from osgeo import gdal
1414
from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator
15+
from scipy.ndimage import uniform_filter
1516

1617
from dolphin import io, utils
1718
from dolphin._log import get_log
@@ -623,7 +624,7 @@ def estimate_correlation_from_phase(
623624

624625
# Note: the clipping is from possible partial windows producing correlation
625626
# above 1
626-
cor = np.clip(np.abs(utils.moving_window_mean(inp, window_size)), 0, 1)
627+
cor = np.clip(np.abs(uniform_filter(inp, window_size, mode="nearest")), 0, 1)
627628
# Return the input nans to nan
628629
cor[nan_mask] = np.nan
629630
# If the input was 0, the correlation is 0

src/dolphin/utils.py

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -431,55 +431,14 @@ def get_mem(process):
431431
def moving_window_mean(
432432
image: ArrayLike, size: Union[int, tuple[int, int]]
433433
) -> np.ndarray:
434-
"""Calculate the mean of a moving window of size `size`.
434+
"""DEPRECATED: use `scipy.ndimage.uniform_filter` directly.""" # noqa: D401
435+
from scipy.ndimage import uniform_filter
435436

436-
Parameters
437-
----------
438-
image : ndarray
439-
input image
440-
size : int or tuple of int
441-
Window size. If a single int, the window is square.
442-
If a tuple of (row_size, col_size), the window can be rectangular.
443-
444-
Returns
445-
-------
446-
ndarray
447-
image the same size as `image`, where each pixel is the mean
448-
of the corresponding window.
449-
"""
450-
if isinstance(size, int):
451-
size = (size, size)
452-
if len(size) != 2:
453-
msg = "size must be a single int or a tuple of 2 ints"
454-
raise ValueError(msg)
455-
if size[0] % 2 == 0 or size[1] % 2 == 0:
456-
msg = "size must be odd in both dimensions"
457-
raise ValueError(msg)
458-
459-
row_size, col_size = size
460-
row_pad = row_size // 2
461-
col_pad = col_size // 2
462-
463-
# Pad the image with zeros
464-
image_padded = np.pad(
465-
image, ((row_pad + 1, row_pad), (col_pad + 1, col_pad)), mode="constant"
466-
)
467-
468-
# Calculate the cumulative sum of the image
469-
integral_img = np.cumsum(np.cumsum(image_padded, axis=0), axis=1)
470-
if not np.iscomplexobj(integral_img):
471-
integral_img = integral_img.astype(float)
472-
473-
# Calculate the mean of the moving window
474-
# Uses the algorithm from https://en.wikipedia.org/wiki/Summed-area_table
475-
window_mean = (
476-
integral_img[row_size:, col_size:]
477-
- integral_img[:-row_size, col_size:]
478-
- integral_img[row_size:, :-col_size]
479-
+ integral_img[:-row_size, :-col_size]
437+
msg = (
438+
"`moving_window_mean` is deprecated. Please use `scipy.ndimage.uniform_filter`."
480439
)
481-
window_mean /= row_size * col_size
482-
return window_mean
440+
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
441+
return uniform_filter(image, size=size)
483442

484443

485444
def set_num_threads(num_threads: int):

tests/test_interferogram.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,7 @@ def test_manual_indexes(tmp_path, four_slc_files):
253253

254254
@pytest.fixture()
255255
def expected_3x3_cor():
256-
# the edges will be less than 1 because of the windowing
257-
return np.array(
258-
[
259-
[0.44444444, 0.66666667, 0.44444444],
260-
[0.66666667, 1.0, 0.66666667],
261-
[0.44444444, 0.66666667, 0.44444444],
262-
]
263-
)
256+
return np.ones((3, 3))
264257

265258

266259
@pytest.mark.parametrize("window_size", [3, (3, 3)])

tests/test_utils.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import numpy as np
22
import numpy.testing as npt
3-
import pytest
43

54
from dolphin import utils
65

@@ -76,42 +75,3 @@ def test_upsample_nearest():
7675
assert upsampled3d.shape == (3, 4, 4)
7776
for img in upsampled3d:
7877
npt.assert_array_equal(img, upsampled)
79-
80-
81-
def test_moving_window_mean_basic():
82-
image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
83-
result = utils.moving_window_mean(image, 3)
84-
expected = np.array(
85-
[
86-
[1.33333333, 2.33333333, 1.77777778],
87-
[3.0, 5.0, 3.66666667],
88-
[2.66666667, 4.33333333, 3.11111111],
89-
]
90-
)
91-
assert np.allclose(result, expected)
92-
93-
94-
def test_moving_window_mean_single_pixel():
95-
image = np.array([[5]])
96-
result = utils.moving_window_mean(image, 1)
97-
expected = np.array([[5]])
98-
assert np.allclose(result, expected)
99-
100-
101-
def test_moving_window_mean_even_size():
102-
image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
103-
with pytest.raises(ValueError):
104-
utils.moving_window_mean(image, (2, 2))
105-
106-
107-
def test_moving_window_mean_invalid_size_type():
108-
image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
109-
with pytest.raises(ValueError):
110-
utils.moving_window_mean(image, (1, 2, 3))
111-
112-
113-
def test_moving_window_mean_empty_image():
114-
image = np.array([[]])
115-
result = utils.moving_window_mean(image, 1)
116-
expected = np.array([[]])
117-
assert np.allclose(result, expected)

0 commit comments

Comments
 (0)