o
    :ήc8                     @   s   d Z ddlZddlmZ ddlZddlmZ ddlmZ ddlmZ ddl	Z
ddlmZmZ eeedk rDdd	lmZ ed
dd ddlmZ g dZdd Zdd Zdd ZG dd deZdd ZG dd deZdS )zEData structures to hold collections of images, with optional caching.    N)glob)Sequence)copy)version)Image__version__z8.1.2)warnzYour installed pillow version is < 8.1.2. Several security issues (CVE-2021-27921, CVE-2021-25290, CVE-2021-25291, CVE-2021-25293, and more) have been fixed in pillow 8.1.2 or higher. We recommend to upgrade this library.   )
stacklevel)TiffFile)
MultiImageImageCollectionconcatenate_imagesimread_collection_wrapperc                 C   s6   dd | D }zt |}W |S  ty   tdw )au  Concatenate all images in the image collection into an array.

    Parameters
    ----------
    ic : an iterable of images
        The images to be concatenated.

    Returns
    -------
    array_cat : ndarray
        An array having one more dimension than the images in `ic`.

    See Also
    --------
    ImageCollection.concatenate, MultiImage.concatenate

    Raises
    ------
    ValueError
        If images in `ic` don't have identical shapes.

    Notes
    -----
    ``concatenate_images`` receives any iterable object containing images,
    including ImageCollection and MultiImage, and returns a NumPy array.
    c                 S   s   g | ]	}|t jd f qS ).)npnewaxis).0image r   </tmp/pip-target-vg8gfxp4/lib/python/skimage/io/collection.py
<listcomp>:       z&concatenate_images.<locals>.<listcomp>zImage dimensions must agree.)r   concatenate
ValueError)ic
all_images	array_catr   r   r   r      s   r   c                 C   s   dd t d| D }|S )aA  Convert string to list of strings and ints that gives intuitive sorting.

    Parameters
    ----------
    s : string

    Returns
    -------
    k : a list of strings and ints

    Examples
    --------
    >>> alphanumeric_key('z23a')
    ['z', 23, 'a']
    >>> filenames = ['f9.10.png', 'e10.png', 'f9.9.png', 'f10.10.png',
    ...              'f10.9.png']
    >>> sorted(filenames)
    ['e10.png', 'f10.10.png', 'f10.9.png', 'f9.10.png', 'f9.9.png']
    >>> sorted(filenames, key=alphanumeric_key)
    ['e10.png', 'f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png']
    c                 S   s    g | ]}|  rt|n|qS r   )isdigitint)r   cr   r   r   r   X   s     z$alphanumeric_key.<locals>.<listcomp>z([0-9]+))resplit)skr   r   r   alphanumeric_keyB   s   r$   c                 C   sP   t | to	tj| v }t | t }t | t}tdd | D }|p%|o%|o%|}|S )zlHelping function. Returns True if pattern contains a tuple, list, or a
    string separated with os.pathsep.c                 s   s    | ]}t |tV  qd S N)
isinstancestr)r   patr   r   r   	<genexpr>d   s    z#_is_multipattern.<locals>.<genexpr>)r&   r'   ospathsepr   all)input_patternhas_str_ospathsepnot_a_stringhas_iterablehas_stringsis_multipatternr   r   r   _is_multipattern\   s   

r3   c                   @   st   e Zd ZdZdddZedd Zedd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd ZdddZdd ZdS )r   a  Load and manage a collection of image files.

    Parameters
    ----------
    load_pattern : str or list of str
        Pattern string or list of strings to load. The filename path can be
        absolute or relative.
    conserve_memory : bool, optional
        If True, `ImageCollection` does not keep more than one in memory at a
        specific time. Otherwise, images will be cached once they are loaded.

    Other parameters
    ----------------
    load_func : callable
        ``imread`` by default. See notes below.

    Attributes
    ----------
    files : list of str
        If a pattern string is given for `load_pattern`, this attribute
        stores the expanded file list. Otherwise, this is equal to
        `load_pattern`.

    Notes
    -----
    Note that files are always returned in alphanumerical order. Also note
    that slicing returns a new ImageCollection, *not* a view into the data.

    ImageCollection can be modified to load images from an arbitrary
    source by specifying a combination of `load_pattern` and
    `load_func`.  For an ImageCollection ``ic``, ``ic[5]`` uses
    ``load_func(load_pattern[5])`` to load the image.

    Imagine, for example, an ImageCollection that loads every third
    frame from a video file::

      video_file = 'no_time_for_that_tiny.gif'

      def vidread_step(f, step):
          vid = imageio.get_reader(f)
          seq = [v for v in vid.iter_data()]
          return seq[::step]

      ic = ImageCollection(video_file, load_func=vidread_step, step=3)

      ic  # is an ImageCollection object of length 1 because there is 1 file

      x = ic[0]  # calls vidread_step(video_file, step=3)
      x[5]  # is the sixth element of a list of length 8 (24 / 3)

    Another use of ``load_func`` would be to convert all images to ``uint8``::

      def imread_convert(f):
          return imread(f).astype(np.uint8)

      ic = ImageCollection('/tmp/*.png', load_func=imread_convert)

    Examples
    --------
    >>> import skimage.io as io
    >>> from skimage import data_dir

    >>> coll = io.ImageCollection(data_dir + '/chess*.png')
    >>> len(coll)
    2
    >>> coll[0].shape
    (200, 200)

    >>> ic = io.ImageCollection(['/tmp/work/*.png', '/tmp/other/*.jpg'])
    TNc                 K   s   g | _ t|r t|tr|tj}|D ]
}| j t| qnt|tr.| j t| nt	dt
| j td| _ |du rMddlm} || _|  | _n|| _t| j | _d| _|r^d}n| j}|| _d| _|| _tj|td| _dS )z'Load and manage a collection of images.zInvalid pattern as input.)keyN   imreaddtype)_filesr3   r&   r'   r!   r*   r+   extendr   	TypeErrorsortedr$   _ior7   	load_func_find_images
_numframeslen_frame_index_conserve_memory_cachedload_func_kwargsr   emptyobjectdata)selfload_patternconserve_memoryr?   rF   patternr7   memory_slotsr   r   r   __init__   s2   

zImageCollection.__init__c                 C      | j S r%   r:   rJ   r   r   r   files      zImageCollection.filesc                 C   rP   r%   )rD   rR   r   r   r   rL      rT   zImageCollection.conserve_memoryc              
      s
  g }| j D ]x   dr8t d}t|}| fddtt|jD 7 }W d    n1 s2w   Y  qzt }|	d W n t
tfyO   Y qw d}	 z|	| W n	 tyc   Y nw | |f |d7 }qSt|dr}|jr}|j  q|| _t|S )	N)z.tiffz.tifrbc                    s   g | ]} |fqS r   r   r   ifnamer   r   r      s    z0ImageCollection._find_images.<locals>.<listcomp>r   Tr5   fp)r:   lowerendswithopenr   rangerB   pagesr   seekIOErrorOSErrorEOFErrorappendhasattrrZ   closerC   )rJ   indexfimgimrW   r   rX   r   r@      s:   
"

zImageCollection._find_imagesc           	   
      s  t |dr	| }t|ttfvrtdt|tu r |}|t j } j	r/| j
ks6 j| du r j} jr j| \}}|durK||d< z j|fi | j|< W n8 ty } zdt|v rw|d=  j|fi | j|< n W Y d}~nd}~ww  j j| fi | j|< | _
 j| S t j| }t } jr fdd|D |_ fdd|D |_n
 fd	d|D |_t||_ j	r j
|v r| j
|_
t j|_|S tjd
td|_|S  j| |_|S )a  Return selected image(s) in the collection.

        Loading is done on demand.

        Parameters
        ----------
        n : int or slice
            The image number to be returned, or a slice selecting the images
            and ordering to be returned in a new ImageCollection.

        Returns
        -------
        img : ndarray or ImageCollection.
            The `n`-th image in the collection, or a new ImageCollection with
            the selected images.
        	__index__z+slicing must be with an int or slice objectNimg_numz%unexpected keyword argument 'img_num'c                    s   g | ]	} j | d  qS )r   rC   rV   rR   r   r   r   3  r   z/ImageCollection.__getitem__.<locals>.<listcomp>c                       g | ]} j | qS r   rm   rV   rR   r   r   r   4      c                    rn   r   rQ   rV   rR   r   r   r   6  ro   r5   r8   )re   rk   typer   slicer<   _check_imgnumrB   rI   rL   rE   rF   rC   r?   r'   rS   r^   rA   r   r:   rg   r   rG   rH   )	rJ   nidxkwargsrY   rl   efidxnew_icr   rR   r   __getitem__   sX   




zImageCollection.__getitem__c                 C   s8   | j }| |  kr|k rn n|| }|S td| )z+Check that the given image number is valid.z*There are only %s images in the collection)rA   
IndexError)rJ   rs   numr   r   r   rr   D  s   zImageCollection._check_imgnumc                 c   s"    t t| D ]}| | V  qdS )zIterate over the images.N)r^   rB   )rJ   rW   r   r   r   __iter__N  s   zImageCollection.__iter__c                 C   rP   )zNumber of images in collection.)rA   rR   r   r   r   __len__S  rT   zImageCollection.__len__c                 C   s
   t | jS r%   )r'   rS   rR   r   r   r   __str__W  s   
zImageCollection.__str__c                 C   s   t | j| _dS )zClear the image cache.

        Parameters
        ----------
        n : None or int
            Clear the cache for this image only. By default, the
            entire cache is erased.

        N)r   
empty_likerI   )rJ   rs   r   r   r   reloadZ  s   
zImageCollection.reloadc                 C   s   t | S )a  Concatenate all images in the collection into an array.

        Returns
        -------
        ar : np.ndarray
            An array having one more dimension than the images in `self`.

        See Also
        --------
        concatenate_images

        Raises
        ------
        ValueError
            If images in the `ImageCollection` don't have identical shapes.
        )r   rR   r   r   r   r   f  s   zImageCollection.concatenateTNr%   )__name__
__module____qualname____doc__rO   propertyrS   rL   r@   ry   rr   r|   r}   r~   r   r   r   r   r   r   r   m   s    
F$

J

r   c                    s   d fdd	}|S )NTc                    s   t | | dS )a  Return an `ImageCollection` from files matching the given pattern.

        Note that files are always stored in alphabetical order. Also note that
        slicing returns a new ImageCollection, *not* a view into the data.

        See `skimage.io.ImageCollection` for details.

        Parameters
        ----------
        load_pattern : str or list
            Pattern glob or filenames to load. The path can be absolute or
            relative.  Multiple patterns should be separated by a colon,
            e.g. ``/tmp/work/*.png:/tmp/other/*.jpg``.  Also see
            implementation notes below.
        conserve_memory : bool, optional
            If True, never keep more than one in memory at a specific
            time.  Otherwise, images will be cached once they are loaded.

        )rL   r?   )r   )rK   rL   r6   r   r   imread_collection{  s   z4imread_collection_wrapper.<locals>.imread_collection)Tr   )r7   r   r   r6   r   r   z  s   r   c                       s.   e Zd ZdZd fdd	Zedd Z  ZS )	r   aq  A class containing all frames from multi-frame images.

    Parameters
    ----------
    load_pattern : str or list of str
        Pattern glob or filenames to load. The path can be absolute or
        relative.
    conserve_memory : bool, optional
        Whether to conserve memory by only caching a single frame. Default is
        True.

    Other parameters
    ----------------
    load_func : callable
        ``imread`` by default.  See notes below.

    Notes
    -----
    If ``conserve_memory=True`` the memory footprint can be reduced, however
    the performance can be affected because frames have to be read from file
    more often.

    The last accessed frame is cached, all other frames will have to be read
    from file.

    The current implementation makes use of ``tifffile`` for Tiff files and
    PIL otherwise.

    Examples
    --------
    >>> from skimage import data_dir

    >>> img = MultiImage(data_dir + '/multipage.tif') # doctest: +SKIP
    >>> len(img) # doctest: +SKIP
    2
    >>> for frame in img: # doctest: +SKIP
    ...     print(frame.shape) # doctest: +SKIP
    (15, 10)
    (15, 10)

    TNc                    s4   ddl m} || _tt| j||fd|i| dS )zLoad a multi-img.r5   r6   r?   N)r>   r7   	_filenamesuperr   rO   )rJ   filenamerL   r9   imread_kwargsr7   	__class__r   r   rO     s   
zMultiImage.__init__c                 C   rP   r%   )r   rR   r   r   r   r     rT   zMultiImage.filenamer   )r   r   r   r   rO   r   r   __classcell__r   r   r   r   r     s
    *	r   )r   r*   r   r    collections.abcr   r   	packagingr   numpyr   PILr   r   pil_versionparsewarningsr   tifffiler   __all__r   r$   r3   rH   r   r   r   r   r   r   r   <module>   s0    #  