Commit b8fd790a authored by Matthijs's avatar Matthijs
Browse files

added superpixel sparsity proxoperator (untested)

parent 18437633
from numpy import zeros_like, unravel_index, sum
from numpy import zeros_like, unravel_index, sum, max
import numpy as np
from .proxoperators import ProxOperator
from proxtoolbox.Utilities.OrbitalTomog import tile_array, bin_array
class P_Sparsity(ProxOperator):
......@@ -69,9 +70,6 @@ class P_Sparsity_real(P_Sparsity):
order: realness, sparsity
def __init__(self, config):
super(P_Sparsity_real, self).__init__(config)
def work(self, u):
return super(P_Sparsity_real, self).work(u.real)
......@@ -105,9 +103,6 @@ class P_Sparsity_Symmetric_real(P_Sparsity_Symmetric):
order: realness, symmetry, sparsity
def __init__(self, config):
super(P_Sparsity_Symmetric_real, self).__init__(config=config)
def work(self, u):
out = super(P_Sparsity_Symmetric_real, self).work(u.real)
return out
......@@ -165,10 +160,38 @@ class P_Sparsity_Line_Real(P_Sparsity_Line):
Combining P_Sparsity_Line with a realness constraint
def work(self, u):
out = super(P_Sparsity_Line_Real, self).work(u.real)
return out
class P_Sparsity_Superpixel(P_Sparsity):
Apply sparsity on superpixels, i.e. on the binned array
def __init__(self, config):
super(P_Sparsity_Line_Real, self).__init__(config=config)
super(P_Sparsity_Superpixel, self).__init__(config=config)
# Set the superpixel size:
self.superpixel_size = config['superpixel size']
if is not 1: = bin_array(, self.superpixel_size) /= max(
# Assert that the binning+upsampling conserves the array size
test_shape = tile_array(bin_array(config['u_0'], self.superpixel_size, pad_zeros=False),
assert test_shape == config['u_0'].shape, 'Given array size does not allow for binning'
# TODO: allow for padding, then cut of the remainder after tile_array
def work(self, u):
out = super(P_Sparsity_Line_Real, self).work(u.real)
return out
binned = bin_array(u, self.superpixel_size)
constrained = super(P_Sparsity_Superpixel, self).work(binned)
return tile_array(constrained, self.superpixel_size)
class P_Sparsity_Superpixel_real(P_Sparsity_Superpixel):
Apply real-valued sparsity on superpixels, i.e. on the binned array
def work(self, u):
super(P_Sparsity_Superpixel, self).work(u.real)
......@@ -2,8 +2,9 @@ from numpy import roll, ndarray, floor, iscomplexobj, round, any, isnan, nan_to_
from scipy.ndimage.measurements import maximum_position, center_of_mass
from scipy.fftpack import fftn, fftshift, ifftn, ifftshift
from warnings import warn
from numpy.lib.stride_tricks import as_strided
__all__ = ["shift_array", 'roll_to_pos', 'shifted_ifft', 'shifted_fft']
__all__ = ["shift_array", 'roll_to_pos', 'shifted_ifft', 'shifted_fft', 'tile_array']
def shift_array(arr: ndarray, dy: int, dx: int):
......@@ -82,3 +83,35 @@ def shifted_ifft(arr, axes=None):
transformed array
return fftshift(ifftn(ifftshift(arr, axes=axes), axes=axes), axes=axes)
def tile_array(a: ndarray, shape):
Upsample an array by nearest-neighbour interpolation, i.e. [1,2] -> [1,1,2,2]
:param a: numpy array, ndim = [2,3]
:param shape: tile size, single integer for rectangular tiles, tuple for individual axes otherwise
:return: resampled array
if a.ndim == 2:
b0, b1 = shape
except TypeError:
b0 = shape
b1 = shape
r, c = a.shape # number of rows/columns
rs, cs = a.strides # row/column strides
x = as_strided(a, (r, b0, c, b1), (rs, 0, cs, 0)) # view a as larger 4D array
return x.reshape(r * b0, c * b1) # create new 2D array
elif a.ndim == 3:
b0, b1, b2 = shape
except TypeError:
b0 = shape
b1 = shape
b2 = shape
x, y, z = a.shape
xs, ys, zs = a.strides
temp = as_strided(a, (x, b0, y, b1, z, b2), (xs, 0, ys, 0, zs, 0))
return temp.reshape((x * b0, y * b1, z * b2))
raise NotImplementedError("Arrays of dimensions other than 2 and 3 are not implemented yet")
......@@ -3,12 +3,13 @@ import numpy as np
__all__ = ['bin_array']
def bin_array(arr: np.ndarray, new_shape: any, pad_zeros=True) -> np.ndarray:
def bin_array(arr: np.ndarray, new_shape: any, pad_zeros:bool=True) -> np.ndarray:
Reduce the size of an array by binning
:param arr: original
:param new_shape: tuple which must be an integer divisor of the original shape, or integer to bin by that factor
:param pad_zeros: pad array with zeros to enable binning by the given factor
:return: new array
# make tuple with new shape
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment