Source code for neuralib.widefield.svd

from typing import NamedTuple

import numpy as np
from sklearn.decomposition import TruncatedSVD

__all__ = [
    'SequenceSingularVector',
    'compute_singular_vector'
]


[docs] class SequenceSingularVector(NamedTuple): """A NamedTuple that represents a singular value decomposition result from image sequences `Dimension parameters`: W = image width H = image height F = number of image frame (sequence) C = number of components after SVD reduction """ svd: TruncatedSVD """Dimensionality reduction using truncated SVD""" right_vector: np.ndarray """Temporal structure (right singular vectors). `Array[float, [F, C]]`""" left_vector: np.ndarray """Spatial structure (left singular vectors). `Array[float, [W * H, C]]`""" @property def singular_value(self) -> np.ndarray: """The singular values corresponding to each of the selected components, represent the strength/energy of each component. `Array[float, C]`""" return self.svd.singular_values_
[docs] def compute_singular_vector(sequences: np.ndarray, n_components: int = 128, mean_subtraction: bool = True, **kwargs) -> SequenceSingularVector: """ Performs truncated singular value decomposition (SVD) on a sequence of image frames to extract dominant spatial and temporal components. :param sequences: A numpy array representing a collection of image frames in a sequence. It has a shape of (n_frames, width, height) where 'n_frames' is the number of frames, and 'width' and 'height' are the dimensions of each frame. :param n_components: An integer representing the number of components for Truncated SVD. The default value is 128. :param mean_subtraction: A boolean indicating whether to subtract the mean of each frame :param kwargs: Keyword arguments passed to ``TruncatedSVD()``. :return: A SequenceSingularVector object containing the singular values, the transformed components, and the left singular vectors. """ n_frames, width, height = sequences.shape seq = sequences.reshape(n_frames, height * width).T if mean_subtraction: seq = seq - np.mean(seq, axis=1, keepdims=True) svd = TruncatedSVD(n_components=n_components, **kwargs) Vsv = svd.fit_transform(seq.T) U = seq @ (Vsv / (Vsv ** 2).sum(axis=0) ** 0.5) U /= (U ** 2).sum(axis=0) ** 0.5 return SequenceSingularVector(svd, Vsv, U)