a
    Dfk>                     @   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Zddl	m
Z
 ddlmZ g dZd	d
 Zdd Zdd ZG dd d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)Image)TiffFile)
MultiImageImageCollectionconcatenate_imagesimread_collection_wrapperc                 C   s<   dd | D }zt |}W n ty6   tdY n0 |S )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 ).)npZnewaxis).0image r   b/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/skimage/io/collection.py
<listcomp>/       z&concatenate_images.<locals>.<listcomp>zImage dimensions must agree.)r   concatenate
ValueError)ZicZ
all_imagesZ	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   M   r   z$alphanumeric_key.<locals>.<listcomp>z([0-9]+))resplit)skr   r   r   alphanumeric_key7   s    r   c                 C   sP   t | totj| v }t | t }t | t}tdd | D }|pJ|oJ|oJ|}|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>Y   r   z#_is_multipattern.<locals>.<genexpr>)r   r   ospathsepr   all)Zinput_patternZhas_str_ospathsepZnot_a_stringZhas_iterableZhas_stringsZis_multipatternr   r   r   _is_multipatternQ   s    

r$   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.
    **load_func_kwargs : dict
        Any other keyword arguments are passed to `load_func`.

    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 image loading can be customized through
    `load_func`. For an ImageCollection ``ic``, ``ic[5]`` calls
    ``load_func(load_pattern[5])`` to load that image.

    For example, here is an ImageCollection that, for each video provided,
    loads every second frame::

      import imageio.v3 as iio3
      import itertools

      def vidread_step(f, step):
          vid = iio3.imiter(f)
          return list(itertools.islice(vid, None, None, step)

      video_file = 'no_time_for_that_tiny.gif'
      ic = ImageCollection(video_file, load_func=vidread_step, step=2)

      ic  # is an ImageCollection object of length 1 because 1 video is provided

      x = ic[0]
      x[5]  # the 10th frame of the first video

    Alternatively, if `load_func` is provided and `load_pattern` is a
    sequence, an `ImageCollection` of corresponding length will be created,
    and the individual images will be loaded by calling `load_func` with the
    matching element of the `load_pattern` as its first argument. In this
    case, the elements of the sequence do not need to be names of existing
    files (or strings at all). For example, to create an `ImageCollection`
    containing 500 images from a video::

      class FrameReader:
          def __init__ (self, f):
              self.f = f
          def __call__ (self, index):
              return iio3.imread(self.f, index=index)

      ic = ImageCollection(range(500), load_func=FrameReader('movie.mp4'))

      ic  # is an ImageCollection object of length 500

    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 imageio.v3 as iio3
    >>> import skimage.io as io

    # Where your images are located
    >>> data_dir = os.path.join(os.path.dirname(__file__), '../data')

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

    >>> image_col = io.ImageCollection([f'{data_dir}/*.png', '{data_dir}/*.jpg'])

    >>> class MultiReader:
    ...     def __init__ (self, f):
    ...         self.f = f
    ...     def __call__ (self, index):
    ...         return iio3.imread(self.f, index=index)
    ...
    >>> filename = data_dir + '/no_time_for_that_tiny.gif'
    >>> ic = io.ImageCollection(range(24), load_func=MultiReader(filename))
    >>> len(image_col)
    23
    >>> isinstance(ic[0], np.ndarray)
    True
    TNc                 K   s  g | _ t|rPt|tr$|tj}|D ]}| j t| q(t	| j t
d| _ nRt|tr|| j t| t	| j t
d| _ n&t|tr|durt|| _ ntd|du rddlm} || _|  | _n|| _t| j | _d| _|rd}n| j}|| _d| _|| _tj|td| _dS )z'Load and manage a collection of images.)keyNzInvalid pattern as input.   imreaddtype)_filesr$   r   r   r   r!   r"   extendr   sortedr   r   list	TypeError_ior(   	load_func_find_images
_numframeslen_frame_index_conserve_memory_cachedload_func_kwargsr   emptyobjectdata)selfload_patternconserve_memoryr1   r8   patternr(   Zmemory_slotsr   r   r   __init__   s6    

zImageCollection.__init__c                 C   s   | j S r   r+   r<   r   r   r   files   s    zImageCollection.filesc                 C   s   | j S r   )r6   rB   r   r   r   r>      s    zImageCollection.conserve_memoryc              	      s  g }| j D ]   drpt d8}t|}| fddtt|jD 7 }W d    q1 sd0    Y  q
zt }|	d W n t
y   Y q
Y n0 d}z|	| W n ty   Y qY n0 | |f |d7 }qt|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     r   z0ImageCollection._find_images.<locals>.<listcomp>r   r&   fp)r+   lowerendswithopenr   ranger4   Zpagesr   seekOSErrorEOFErrorappendhasattrrI   closer5   )r<   indexfimgZimrF   r   rG   r   r2      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sp j| du r4 j} jr j| \}}|dur||d< z j|fi | j|< W nT ty } z:dt|v r|d=  j|fi | j|< n W Y d}~n
d}~0 0 n 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|_ntjd
td|_n j| |_|S d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   r5   rE   rB   r   r   r   N  r   z/ImageCollection.__getitem__.<locals>.<listcomp>c                    s   g | ]} j | qS r   rY   rE   rB   r   r   r   O  r   c                    s   g | ]} j | qS r   rA   rE   rB   r   r   r   Q  r   r&   r)   )rR   rW   typer   slicer/   _check_imgnumr4   r;   r>   r7   r8   r5   r1   r   rC   rM   r3   r   r+   rT   r   r9   r:   )	r<   nidxkwargsrH   rX   eZfidxZnew_icr   rB   r   __getitem__  sN    



zImageCollection.__getitem__c                 C   s>   | j }| |  kr|k r*n n
|| }ntd| d|S )z+Check that the given image number is valid.zThere are only z images in the collection)r3   
IndexError)r<   r]   numr   r   r   r\   _  s
    
zImageCollection._check_imgnumc                 c   s    t t| D ]}| | V  qdS )zIterate over the images.N)rM   r4   )r<   rF   r   r   r   __iter__h  s    zImageCollection.__iter__c                 C   s   | j S )zNumber of images in collection.)r3   rB   r   r   r   __len__m  s    zImageCollection.__len__c                 C   s
   t | jS r   )r   rC   rB   r   r   r   __str__q  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   Z
empty_liker;   )r<   r]   r   r   r   reloadt  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	   rB   r   r   r   r     s    zImageCollection.concatenate)TN)N)__name__
__module____qualname____doc__r@   propertyrC   r>   r2   ra   r\   rd   re   rf   rg   r   r   r   r   r   r   b   s   j
&

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.

        )r>   r1   )r   )r=   r>   r'   r   r   imread_collection  s    z4imread_collection_wrapper.<locals>.imread_collection)Tr   )r(   rm   r   r'   r   r
     s    r
   c                       s.   e Zd ZdZd fdd	Zedd Z  ZS )	r   a   A class containing all frames from multi-frame TIFF 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 the frames of a single
        image. Default is True.

    Notes
    -----
    `MultiImage` returns a list of image-data arrays. In this
    regard, it is very similar to `ImageCollection`, but the two differ in
    their treatment of multi-frame images.

    For a TIFF image containing N frames of size WxH, `MultiImage` stores
    all frames of that image as a single element of shape `(N, W, H)` in the
    list. `ImageCollection` instead creates N elements of shape `(W, H)`.

    For an animated GIF image, `MultiImage` reads only the first frame, while
    `ImageCollection` reads all frames by default.

    Examples
    --------
    # Where your images are located
    >>> data_dir = os.path.join(os.path.dirname(__file__), '../data')

    >>> multipage_tiff = data_dir + '/multipage.tif'
    >>> multi_img = MultiImage(multipage_tiff)
    >>> len(multi_img)  # multi_img contains one element
    1
    >>> multi_img[0].shape  # this element is a two-frame image of shape:
    (2, 15, 10)

    >>> image_col = ImageCollection(multipage_tiff)
    >>> len(image_col)  # image_col contains two elements
    2
    >>> for frame in image_col:
    ...     print(frame.shape)  # each element is a frame of shape (15, 10)
    ...
    (15, 10)
    (15, 10)
    TNc                    s0   ddl m} || _t j||fd|i| dS )zLoad a multi-img.r&   r'   r1   N)r0   r(   	_filenamesuperr@   )r<   filenamer>   r*   Zimread_kwargsr(   	__class__r   r   r@     s    zMultiImage.__init__c                 C   s   | j S r   )rn   rB   r   r   r   rp     s    zMultiImage.filename)TN)rh   ri   rj   rk   r@   rl   rp   __classcell__r   r   rq   r   r     s   .	r   )rk   r!   r   r   collections.abcr   r   numpyr   ZPILr   Ztifffiler   __all__r	   r   r$   r   r
   r   r   r   r   r   <module>   s"   #  4