
    1-Ph)                     f    d Z ddlZ G d de          Z G d de          Zdddd	Zd
dddZdS )aa  
fisher_vector.py - Implementation of the Fisher vector encoding algorithm

This module contains the source code for Fisher vector computation. The
computation is separated into two distinct steps, which are called separately
by the user, namely:

learn_gmm: Used to estimate the GMM for all vectors/descriptors computed for
           all examples in the dataset (e.g. estimated using all the SIFT
           vectors computed for all images in the dataset, or at least a subset
           of this).

fisher_vector: Used to compute the Fisher vector representation for a
               single set of descriptors/vector (e.g. the SIFT
               descriptors for a single image in your dataset, or
               perhaps a test image).

Reference: Perronnin, F. and Dance, C. Fisher kernels on Visual Vocabularies
           for Image Categorization, IEEE Conference on Computer Vision and
           Pattern Recognition, 2007

Origin Author: Dan Oneata (Author of the original implementation for the Fisher
vector computation using scikit-learn and NumPy. Subsequently ported to
scikit-image (here) by other authors.)
    Nc                       e Zd ZdS )FisherVectorExceptionN__name__
__module____qualname__     ^/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/skimage/feature/_fisher_vector.pyr   r              Dr
   r   c                       e Zd ZdS )DescriptorExceptionNr   r	   r
   r   r   r   "   r   r
   r       )n_modesgm_argsc                   
 	 ddl m} n# t          $ r t          d          w xY wt           t          t
          j        f          st          d           d         }t           t                    r)t          |t
          j                  st          d          t           t                    re d         j        

fd D             }t          |          st          d           fd D             }t          |          st          d	          t          |t                    r|dk    rt          d
          |r#d|v }|d         dk    }|r|rt          d          t           t                    rt          j                    |rd|v }|r |dd|i|}	n |d|dd|}	n ||d          }	|	                                |	S )a	  Estimate a Gaussian mixture model (GMM) given a set of descriptors and
    number of modes (i.e. Gaussians). This function is essentially a wrapper
    around the scikit-learn implementation of GMM, namely the
    :class:`sklearn.mixture.GaussianMixture` class.

    Due to the nature of the Fisher vector, the only enforced parameter of the
    underlying scikit-learn class is the covariance_type, which must be 'diag'.

    There is no simple way to know what value to use for `n_modes` a-priori.
    Typically, the value is usually one of ``{16, 32, 64, 128}``. One may train
    a few GMMs and choose the one that maximises the log probability of the
    GMM, or choose `n_modes` such that the downstream classifier trained on
    the resultant Fisher vectors has maximal performance.

    Parameters
    ----------
    descriptors : np.ndarray (N, M) or list [(N1, M), (N2, M), ...]
        List of NumPy arrays, or a single NumPy array, of the descriptors
        used to estimate the GMM. The reason a list of NumPy arrays is
        permissible is because often when using a Fisher vector encoding,
        descriptors/vectors are computed separately for each sample/image in
        the dataset, such as SIFT vectors for each image. If a list if passed
        in, then each element must be a NumPy array in which the number of
        rows may differ (e.g. different number of SIFT vector for each image),
        but the number of columns for each must be the same (i.e. the
        dimensionality must be the same).
    n_modes : int
        The number of modes/Gaussians to estimate during the GMM estimate.
    gm_args : dict
        Keyword arguments that can be passed into the underlying scikit-learn
        :class:`sklearn.mixture.GaussianMixture` class.

    Returns
    -------
    gmm : :class:`sklearn.mixture.GaussianMixture`
        The estimated GMM object, which contains the necessary parameters
        needed to compute the Fisher vector.

    References
    ----------
    .. [1] https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html

    Examples
    --------
    .. testsetup::
        >>> import pytest; _ = pytest.importorskip('sklearn')

    >>> from skimage.feature import fisher_vector
    >>> rng = np.random.Generator(np.random.PCG64())
    >>> sift_for_images = [rng.standard_normal((10, 128)) for _ in range(10)]
    >>> num_modes = 16
    >>> # Estimate 16-mode GMM with these synthetic SIFT vectors
    >>> gmm = learn_gmm(sift_for_images, n_modes=num_modes)
    r   GaussianMixturemscikit-learn is not installed. Please ensure it is installed in order to use the Fisher vector functionality.zNPlease ensure descriptors are either a NumPy array, or a list of NumPy arrays.z5Please ensure descriptors are a list of NumPy arrays.c                 Z    g | ]'}t          |j                  t                    k    (S r	   )lenshape).0eexpected_shapes     r   
<listcomp>zlearn_gmm.<locals>.<listcomp>t   s.    JJJQW^!4!44JJJr
   zAPlease ensure all elements of your descriptor list are of rank 2.c                 T    g | ]$}|j         d          d         j         d          k    %S )   r   )r   )r   r   descriptorss     r   r   zlearn_gmm.<locals>.<listcomp>y   s0    KKK!
k!n2155KKKr
   z=Please ensure all descriptors are of the same dimensionality.z,Please ensure n_modes is a positive integer.covariance_typediagzCovariance type must be "diag".n_components)r"   r    r	   )sklearn.mixturer   ImportError
isinstancelistnpndarrayr   r   allintr   vstackfit)r   r   r   r   d_mat_1ranksdimshas_cov_typecov_type_not_diaggmmr   s   `         @r   	learn_gmmr3   &   s   p
3333333 
 
 
<
 
 	

 kD"*#566 
!)
 
 	

 !nG+t$$ 
Z-L-L 
!C
 
 	
 +t$$ $Q-JJJJkJJJ5zz 	%V   LKKK{KKK4yy 	%O   gs## Tw!||#$RSSS K(G3#$56&@ 	K- 	K'(IJJJ+t$$ -i,, 	L(G3 	!/BBwB'BBCC!/ $f @G CC o7FKKKGGKJs    %Fg      ?)improvedalphac                6   	 ddl m} n# t          $ r t          d          w xY wt          | t          j                  st          d          t          ||          st          d          |r$t          |t                    st          d          t          |           }|j
        }|j        }|j        }|                    |           }	|	                    dd          j        }
|	j                            |           |z  }|	j                            t	          j        | d	                    |z  }|
                                |z
  }||
|z  z
  }|
t	          j        |d	          z  }|
|z  }d	|z  |z  }| |z
  |z   |z   }t	          j        |          }||z  }||d
d
t          j        f         t	          j        |          z  z  }|t	          j        d	          |d
d
t          j        f         z  |z  z  }t	          j        ||                                |                                f          }|r^t	          j        |          t	          j        t	          j        |          |          z  }|t          j                            |          z  }|S )a  Compute the Fisher vector given some descriptors/vectors,
    and an associated estimated GMM.

    Parameters
    ----------
    descriptors : np.ndarray, shape=(n_descriptors, descriptor_length)
        NumPy array of the descriptors for which the Fisher vector
        representation is to be computed.
    gmm : :class:`sklearn.mixture.GaussianMixture`
        An estimated GMM object, which contains the necessary parameters needed
        to compute the Fisher vector.
    improved : bool, default=False
        Flag denoting whether to compute improved Fisher vectors or not.
        Improved Fisher vectors are L2 and power normalized. Power
        normalization is simply f(z) = sign(z) pow(abs(z), alpha) for some
        0 <= alpha <= 1.
    alpha : float, default=0.5
        The parameter for the power normalization step. Ignored if
        improved=False.

    Returns
    -------
    fisher_vector : np.ndarray
        The computation Fisher vector, which is given by a concatenation of the
        gradients of a GMM with respect to its parameters (mixture weights,
        means, and covariance matrices). For D-dimensional input descriptors or
        vectors, and a K-mode GMM, the Fisher vector dimensionality will be
        2KD + K. Thus, its dimensionality is invariant to the number of
        descriptors/vectors.

    References
    ----------
    .. [1] Perronnin, F. and Dance, C. Fisher kernels on Visual Vocabularies
           for Image Categorization, IEEE Conference on Computer Vision and
           Pattern Recognition, 2007
    .. [2] Perronnin, F. and Sanchez, J. and Mensink T. Improving the Fisher
           Kernel for Large-Scale Image Classification, ECCV, 2010

    Examples
    --------
    .. testsetup::
        >>> import pytest; _ = pytest.importorskip('sklearn')

    >>> from skimage.feature import fisher_vector, learn_gmm
    >>> sift_for_images = [np.random.random((10, 128)) for _ in range(10)]
    >>> num_modes = 16
    >>> # Estimate 16-mode GMM with these synthetic SIFT vectors
    >>> gmm = learn_gmm(sift_for_images, n_modes=num_modes)
    >>> test_image_descriptors = np.random.random((25, 128))
    >>> # Compute the Fisher vector
    >>> fv = fisher_vector(test_image_descriptors, gmm)
    r   r   r   z+Please ensure descriptors is a NumPy array.z>Please ensure gmm is a sklearn.mixture.GaussianMixture object.z2Please ensure that the alpha parameter is a float.T)axiskeepdims   N)r#   r   r$   r%   r'   r(   r   r   floatr   weights_means_covariances_predict_probameanTdotpowersqueezesqrtnewaxishstackravelsignabslinalgnorm)r   r2   r4   r5   r   num_descriptorsmixture_weightsmeanscovariancesposterior_probabilitiespp_sumpp_xpp_x_2d_pid_mu
d_sigma_t1
d_sigma_t2
d_sigma_t3d_sigmasqrt_mixture_weightsfisher_vectors                        r   r[   r[      s   j
3333333 
 
 
<
 
 	

 k2:.. Q!"OPPPc?++ 
#L
 
 	
  

5%00 
#@
 
 	
 +&&OlOJE"K!//<< %))q4)@@BF"$((55GD$&**28K+C+CDDVF >>o-D&5. D"(5!,,,J+%JTE!Jg
"Z/*<G 7?33  D BJ/"'+2F2FFFDrwqzz0BJ??+MMG ItTZZ\\7==??CDDM F.."&:O:OQV1W1WW%	}(E(EEs   	 #)__doc__numpyr'   	Exceptionr   r   r3   r[   r	   r
   r   <module>r_      s    4    	 	 	 	 	I 	 	 		 	 	 	 	/ 	 	 	 ')$ r r r r rj 16S n n n n n n nr
   