o
    hk>                     @   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   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   P/var/www/html/scripts/venv/lib/python3.10/site-packages/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   M   s     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 }|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>Y   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_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|r(t|tr|tj}|D ]
}| j t| qt	| j t
d| _ n)t|tr>| j t| t	| j t
d| _ nt|trM|durMt|| _ ntd|du rdddlm} || _|  | _n|| _t| j | _d| _|rud}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_ior2   	load_func_find_images
_numframeslen_frame_index_conserve_memory_cachedload_func_kwargsr   emptyobjectdata)selfload_patternconserve_memoryr;   rB   patternr2   memory_slotsr   r   r   __init__   s6   

zImageCollection.__init__c                 C      | j S r    r5   rF   r   r   r   files      zImageCollection.filesc                 C   rL   r    )r@   rN   r   r   r   rH      rP   zImageCollection.conserve_memoryc              	      s  g }| j D ]v   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
yM   Y qw d}	 z|	| W n	 tya   Y nw | |f |d7 }qQt|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   Tr0   fp)r5   lowerendswithopenr   ranger>   pagesr   seekOSErrorEOFErrorappendhasattrrV   closer?   )rF   indexfimgimrS   r   rT   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   r?   rR   rN   r   r   r   N  r   z/ImageCollection.__getitem__.<locals>.<listcomp>c                       g | ]} j | qS r   rh   rR   rN   r   r   r   O      c                    ri   r   rM   rR   rN   r   r   r   Q  rj   r0   r3   )r`   rf   typer   slicer9   _check_imgnumr>   rE   rH   rA   rB   r?   r;   r"   rO   rZ   r=   r   r5   rb   r   rC   rD   )	rF   nidxkwargsrU   rg   efidxnew_icr   rN   r   __getitem__  sV   




zImageCollection.__getitem__c                 C   s<   | j }| |  kr|k rn n|| }|S td| d)z+Check that the given image number is valid.zThere are only z images in the collection)r=   
IndexError)rF   rn   numr   r   r   rm   _  s
   zImageCollection._check_imgnumc                 c   s"    t t| D ]}| | V  qdS )zIterate over the images.N)rZ   r>   )rF   rS   r   r   r   __iter__h  s   zImageCollection.__iter__c                 C   rL   )zNumber of images in collection.)r=   rN   r   r   r   __len__m  rP   zImageCollection.__len__c                 C   s
   t | jS r    )r"   rO   rN   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   
empty_likerE   )rF   rn   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	   rN   r   r   r   r     s   zImageCollection.concatenateTNr    )__name__
__module____qualname____doc__rK   propertyrO   rH   r<   rt   rm   rw   rx   ry   r{   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.

        )rH   r;   )r   )rG   rH   r1   r   r   imread_collection  s   z4imread_collection_wrapper.<locals>.imread_collection)Tr   )r2   r   r   r1   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.r0   r1   r;   N)r:   r2   	_filenamesuperrK   )rF   filenamerH   r4   imread_kwargsr2   	__class__r   r   rK     s   
zMultiImage.__init__c                 C   rL   r    )r   rN   r   r   r   r     rP   zMultiImage.filenamer|   )r}   r~   r   r   rK   r   r   __classcell__r   r   r   r   r     s
    .	r   )r   r%   r   r   collections.abcr   r   numpyr   PILr   tifffiler   __all__r	   r   r.   r   r
   r   r   r   r   r   <module>   s$    #  4