spyrit.core.meas.DynamicLinearSplit
- class spyrit.core.meas.DynamicLinearSplit(H: tensor, time_dim: int, meas_shape: int | Size | Iterable[int] = None, meas_dims: int | Size | Iterable[int] = None, img_shape: int | Size | Iterable[int] = None, *, noise_model: Module = Identity(), white_acq: tensor = None, dtype: dtype = torch.float32, device: device = device(type='cpu'))[source]
Bases:
DynamicLinearSimulates linear measurements of a moving scene by splitting an acquisition matrix \(H \in \mathbb{R}^{M \times N}\) that contains negative values. In practice, only positive values can be implemented using a DMD. Therefore, we acquire
\[y = \mathcal{N}\left(\text{diag}(A x_{t=1,..., 2M})\right),\]where \(A \colon\, \mathbb{R}_+^{2M\times N}\) is the acquisition matrix that contains positive DMD patterns, \(x_{t=1,..., 2M} \in \mathbb{R}^{N \times 2M}\) is the temporal signal of interest, \(2M\) is both the number of DMD patterns (positives and negatives) and the number of frames, \(N\) is the dimension of the signal within the field of view, \(\text{diag}\colon\, \mathbb{R}^{2M \times 2M} \to \mathbb{R}^{2M}\) extracts the diagonal of its input, and \(\mathcal{N} \colon\, \mathbb{R}^{2M} \to \mathbb{R}^{2M}\) represents a noise operator (e.g., Gaussian).
Given a matrix \(H\), we define the positive DMD patterns \(A\) from the positive and negative components \(H\). In practice, the even rows of \(A\) contain the positive components of \(H\), while odd rows of \(A\) contain the negative components of \(H\).
\[\begin{split}\begin{cases} A[0::2, :] = H_{+}, \text{ with } H_{+} = \max(0,H),\\ A[1::2, :] = H_{-}, \text{ with } H_{-} = \max(0,-H). \end{cases}\end{split}\]Note
\(H_{+}\) and \(H_{-}\) are such that \(H_{+} - H_{-} = H\).
Warning
For each call, there must be exactly twice as many images in \(x\) as there are measurements in the linear operator \(H\).
- Args:
H(torch.tensor): measurement matrix (linear operator) with shape \((M, N)\). Only real values are supported.time_dim(int): dimension index in the input tensor \(x\) that corresponds to time (i.e., the frames dimension).meas_shape(tuple, optional): Shape of the measurement patterns. Must be a tuple of two integers representing the height and width of the patterns. If not specified, the shape is suppposed to be a square image. If not, an error is raised. Defaults to None.meas_dims(tuple, optional): Dimensions of \(x_{t=1, ..., M}\) the acquisition matrix applies to. Must be a tuple with the same length asmeas_shape. If not, an error is raised. Defaults to the last dimensions of the multi-dimensional array \(x_{t=1, ..., M}\) (e.g., (-2,-1) when len(meas_shape)=2).img_shape(tuple, optional): Shape of the image. Must be a tuple of two integers representing the height and width of the image. If not specified, the shape is taken as equal to meas_shape. Setting this value is particularly useful when using an extended field of view [Maitre2024_2].noise_model(seespyrit.core.noise): Noise model \(\mathcal{N}\). Defaults to torch.nn.Identity().white_acq(torch.tensor, optional): Eventual spatial gain resulting from detector inhomogeneities and used for dynamic flat-field correction. It can be determined from a “white acquisition” without any object. If None, no correction is applied. Must haveself.meas_shapeshape.dtype(torch.dtype, optional): Data type of the measurement matrix. Defaults to torch.float32.device(torch.device, optional): Device of the measurement matrix. Defaults to torch.device(“cpu”).- Attributes:
M(int): Number of (pos, neg) measurements.N(int): Number of pixels in the field of view.L(int): Number of pixels in the extended field of view.meas_shape(tuple): Shape of the underlying multi-dimensional array \(x\) over the field of view.img_shape(tuple): Shape of the underlying multi-dimensional array \(x\) over the extended field of view.H(torch.tensor): Static measurement matrix of shape \((M, N)\) initialized as \(H\).A(torch.tensor): Splitted static measurement matrix of shape \((2M, N)\) initialized as \(A\).H_dyn(torch.tensor): Differential dynamic measurement matrix \(H_{\rm{dyn}}\) of shape. \((M, L)\). Must be set using thebuild_dynamic_forward()method before being accessed.A_dyn(torch.tensor): Splitted dynamic measurement matrix \(A_{\rm{dyn}}\) of shape. \((2M, L)\). Must be set using thebuild_dynamic_forward()method before being accessed.- Example:
>>> import torch >>> from spyrit.core.meas import DynamicLinearSplit >>> >>> x = torch.rand([1, 2*400, 3, 50, 50]) # dummy RGB video with 800 frames of size 50x50 >>> H = torch.rand([400, 40*40]) # dummy static measurement matrix >>> meas_op = DynamicLinearSplit(H, time_dim=1, meas_shape=(40, 40), img_shape=(50, 50)) >>> print(meas_op) DynamicLinearSplit( (noise_model): Identity() )
- References:
[Maitre2024_2] Maitre, T., Bretin, E., Phan, R., Ducros, N., & Sdika, M. (2024, October). Dynamic single-pixel imaging on an extended field of view without warping the patterns. In International Conference on Medical Image Computing and Computer-Assisted Intervention (pp. 275-284). Cham: Springer Nature Switzerland. DOI: 10.1007/978-3-031-72104-5_27
[Maitre2026] (Submitted to TIP) Maitre, T., Bretin, E., Mahieu-Williame, L., Phan, R., Sdika, M., & Ducros, N. (2025). Dual-arm motion-compensated single-pixel imaging. HAL Id: hal-05068181
Methods
adjoint(y[, unvectorize])Apply adjoint of matrix \(A_{\rm{dyn}}\).
adjoint_H_dyn(m[, unvectorize])Apply adjoint of matrix \(H_{\rm{dyn}}\).
build_dynamic_forward(motion[, mode, ...])Builds the dynamic forward operator \(A_{\rm{dyn}}\).
forward(x)Simulates noisy dynamic measurements from matrix A.
Simulates noisy dynamic measurements with the splitted dynamic matrix
forward_H(x)Simulates noisy dynamic measurements from matrix H.
Simulates noisy dynamic measurements with the dynamic matrix
measure(x)Simulates noiseless dynamic measurements from matrix A.
Simulates noiseless dynamic measurements with the splitted dynamic matrix
measure_H(x)Simulates noiseless dynamic measurements from matrix H.
Simulates noiseless dynamic measurements with the dynamic matrix
set_matrix_to_inverse(matrix_name)unvectorize(input)Unflatten the measured dimensions.
vectorize(input)Flatten the measured dimensions.