33
44import numpy as np
55from pylops import BlockDiag , Gradient
6+ from pylops .utils .backend import get_array_module
67from pylops .utils .typing import NDArray
78
89from 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