Skip to content

Commit 933ef4b

Browse files
committed
feat: added optional tau/mu to Segment
1 parent 0fd8797 commit 933ef4b

1 file changed

Lines changed: 27 additions & 9 deletions

File tree

‎pyproximal/optimization/segmentation.py‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import numpy as np
55
from pylops import BlockDiag, Gradient
6+
from pylops.utils.backend import get_array_module
67
from pylops.utils.typing import NDArray
78

89
from pyproximal import L21, Simplex, VStack
@@ -14,6 +15,8 @@ def Segment(
1415
cl: NDArray,
1516
sigma: float,
1617
alpha: float,
18+
tau: float | None = 1.0,
19+
mu: float | None = None,
1720
clsigmas: NDArray | None = None,
1821
z: NDArray | None = None,
1922
niter: int = 10,
@@ -37,6 +40,14 @@ def Segment(
3740
Positive scalar weight of the misfit term
3841
alpha : :obj:`float`
3942
Positive scalar weight of the regularization term
43+
tau : :obj:`float`, optional
44+
Stepsize of subgradient of segmentation term.
45+
If ``None``, it is set from ``mu`` and the
46+
Lipschitz constant of the gradient operator.
47+
mu : :obj:`float`, optional
48+
Stepsize of subgradient of regularization term.
49+
If ``None``, it is set from ``tau`` and the
50+
Lipschitz constant of the gradient operator.
4051
clsigmas : :obj:`numpy.ndarray`, optional
4152
Classes standard deviations
4253
z : :obj:`numpy.ndarray`, optional
@@ -64,6 +75,11 @@ def Segment(
6475
Estimated classes. This is a vector of the same size of the input data
6576
``y`` with the selected classes at each pixel.
6677
78+
Raises
79+
------
80+
ValueError
81+
If both ``tau`` and ``mu`` are ``None``
82+
6783
Notes
6884
-----
6985
This solver performs image segmentation over :math:`N_{cl}` classes solving
@@ -90,6 +106,11 @@ def Segment(
90106
Imaging and Vision, 40, 8pp. 120–145. 2011.
91107
92108
"""
109+
if tau is None and mu is None:
110+
msg = "Either tau or mu must be provided."
111+
raise ValueError(msg)
112+
113+
ncp = get_array_module(y)
93114
kwargs_simplex = {} if kwargs_simplex is None else kwargs_simplex
94115

95116
dims = y.shape
@@ -104,10 +125,7 @@ def Segment(
104125
g = g.ravel()
105126

106127
# Gradient operator
107-
sampling = 1.0
108-
Gop = Gradient(
109-
dims=dims, sampling=sampling, edge=False, kind="forward", dtype="float64"
110-
)
128+
Gop = Gradient(dims=dims, sampling=1.0, edge=False, kind="forward", dtype="float64")
111129
Gop = BlockDiag([Gop] * ncl)
112130

113131
# Simplex and L21 proximal operators
@@ -119,9 +137,9 @@ def Segment(
119137
)
120138

121139
# Steps
122-
L = 8.0 / sampling**2
123-
tau = 1.0
124-
mu = 1.0 / (tau * L)
140+
L = 4 * ndims
141+
tau = 1.0 / (mu * L) if tau is None else tau
142+
mu = 1.0 / (tau * L) if mu is None else mu
125143

126144
# Inversion
127145
x: NDArray = PrimalDual(
@@ -132,14 +150,14 @@ def Segment(
132150
mu=mu,
133151
z=g if z is None else g + z,
134152
theta=1.0,
135-
x0=np.zeros_like(g) if x0 is None else x0,
153+
x0=ncp.zeros_like(g) if x0 is None else x0,
136154
niter=niter,
137155
callback=callback,
138156
show=show,
139157
returny=False,
140158
)
141159
x = x.reshape(ncl, dimsprod).T
142-
cl = np.argmax(x, axis=1)
160+
cl = ncp.argmax(x, axis=1)
143161
cl = cl.reshape(dims)
144162

145163
return x, cl

0 commit comments

Comments
 (0)