o
    Ni                      @   s   d Z ddlmZ ddlmZ ddlmZ ddlZddlm  mZ	 dd Z
dd	 Zd
d Zde	jfddZedg dZ		dddZdS )z$Provides `image_as_moving_sequence`.    )absolute_import)division)print_functionNc                    sV   t d  fdd}t j||gt jddd}W d   |S 1 s$w   Y  |S )a  Create a moving image sequence from the given image a left padding values.

  Args:
    image: [in_h, in_w, n_channels] uint8 array
    pad_lefts: [sequence_length, 2] int32 array of left padding values
    total_padding: tensor of padding values, (pad_h, pad_w)

  Returns:
    [sequence_length, out_h, out_w, n_channels] uint8 image sequence, where
      out_h = in_h + pad_h, out_w = in_w + out_w
  moving_sequencec                    sN   | \}| }t j||gdd}t jd|jd}t j||gdd}t  |S )Naxis)      dtyper   )tfstackzerosr   concatpad)argspad_left	pad_rightpaddingzimagetotal_padding ]/home/ubuntu/.local/lib/python3.10/site-packages/tensorflow_datasets/video/moving_sequence.pyget_padded_image*   s   z1_create_moving_sequence.<locals>.get_padded_imageF)r   infer_shape	back_propN)r   
name_scopemap_fnuint8)r   	pad_leftsr   r   padded_imagesr   r   r   _create_moving_sequence   s   
r$   c                 C   s   t | } t |}t |}| jjdkrtd|jjdkr#td|jjdkr-tdt j| dd} t j|dd}|t j|dd }| | }|jjdksRJ d	|S )
zConstruct a linear trajectory from x0.

  Args:
    x0: N-D float tensor.
    velocity: N-D float tensor
    t: [sequence_length]-length float tensor

  Returns:
    x: [sequence_length, ndims] float tensor.
  r	   zx0 must be a rank 1 tensorz velocity must be a rank 1 tensorzt must be a rank 1 tensorr   r   r   r
   z-linear_trajectories should be a rank 2 tensor)r   convert_to_tensorshapendims
ValueErrorexpand_dims)x0velocitytdxlinear_trajectoriesr   r   r   _get_linear_trajectory9   s"   


r/   c                 C   s   | d } t jd|  | S )a  Bounce potentially unbounded points to [0, 1].

  Bouncing occurs by exact reflection, i.e. a pre-bound point at 1.1 is moved
  to 0.9, -0.2 -> 0.2. This theoretically can occur multiple times, e.g.
  2.3 -> -0.7 -> 0.3

  Implementation
  points <- points % 2
  return min(2 - points, points)

  Args:
    points: float array

  Returns:
    tensor with same shape/dtype but values in [0, 1].
  r
   )r   mathminimum)pointsr   r   r   _bounce_to_bboxV   s   r3   r
   c                 C   s(   t jj| f|d}|t jj|ddd S )Nr   r   T)r   keepdims)r   randomnormallinalgnorm)r'   r   xr   r   r   _get_random_unit_vectork   s   r:   _MovingSequenceimage_sequence
trajectorystart_positionr+      @   rB   皙?c              	   C   s  d}t | } | jjdkrtdt|  t |}t||kr(td||f t | }|du r<t jj	|ft j
d}n|j|fkrHtd| t j|t j
d}|jjdkr_t|t j
| }n|jjd	krktd
| t j|t j
d}t|||}t|}||dd  }	t  st jj|	d}
t |
g t |	}	W d   n1 sw   Y  t t j|t |	t j
 t j}t| ||	}||g|  | jd g  t||||dS )a  Turn simple static images into sequences of the originals bouncing around.

  Adapted from Srivastava et al.
  http://www.cs.toronto.edu/~nitish/unsupervised_video/

  Example usage:
  ```python
  import tensorflow.compat.v2 as tf
  import tensorflow_datasets as tfds
  from tensorflow_datasets.video import moving_sequence
  tf.enable_v2_behavior()

  def animate(sequence):
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    sequence = np.squeeze(sequence, axis=-1)

    fig = plt.figure()
    plt.axis("off")
    ims = [[plt.imshow(im, cmap="gray", animated=True)] for im in sequence]
    # don't remove `anim =` as linter may suggets
    # weird behaviour, plot will freeze on last frame
    anim = animation.ArtistAnimation(
        fig, ims, interval=50, blit=True, repeat_delay=100)

    plt.show()
    plt.close()


  tf.enable_v2_behavior()
  mnist_ds = tfds.load("mnist", split=tfds.Split.TRAIN, as_supervised=True,
                       shuffle_files=True)
  mnist_ds = mnist_ds.repeat().shuffle(1024)

  def map_fn(image, label):
    sequence = moving_sequence.image_as_moving_sequence(
        image, sequence_length=20)
    return sequence.image_sequence

  moving_mnist_ds = mnist_ds.map(map_fn).batch(2).map(
      lambda x: dict(image_sequence=tf.reduce_max(x, axis=0)))

  # # for comparison with test data provided by original authors
  # moving_mnist_ds = tfds.load("moving_mnist", split=tfds.Split.TEST)

  for seq in moving_mnist_ds:
    animate(seq["image_sequence"].numpy())
  ```

  Args:
    image: [in_h, in_w, n_channels] tensor defining the sub-image to be bouncing
        around.
    sequence_length: int, length of sequence.
    output_size: (out_h, out_w) size returned images.
    velocity: scalar speed or 2D velocity of image. If scalar, the 2D
        velocity is randomly generated with this magnitude. This is the
        normalized distance moved each time step by the sub-image, where
        normalization occurs over the feasible distance the sub-image can move
        e.g if the input image is [10 x 10] and the output image is [60 x 60],
        a speed of 0.1 means the sub-image moves (60 - 10) * 0.1 = 5 pixels per
        time step.
    start_position: 2D float32 normalized initial position of each
        image in [0, 1]. Randomized uniformly if not given.

  Returns:
    `MovingSequence` namedtuple containing:
        `image_sequence`:
          [sequence_length, out_h, out_w, n_channels] image at each time step.
          padded values are all zero. Same dtype as input image.
        `trajectory`: [sequence_length, 2] float32 in [0, 1]
          2D normalized coordinates of the image at every time step.
        `start_position`: 2D float32 initial position in [0, 1].
          2D normalized initial position of image. Same as input if provided,
          otherwise the randomly value generated.
        `velocity`: 2D float32 normalized velocity. Same as input velocity
          if provided as a 2D tensor, otherwise the random velocity generated.
  r
      zimage must be rank 3, got %sz1output_size must have exactly %d elements, got %sNr   zstart_positions must (%d,)r   r	   z)velocity must be rank 0 or rank 1, got %sr   r<   )r   r%   r&   r'   r(   strTensorShapelenr5   uniformfloat32r:   ranger/   r3   executing_eagerlycompatv1assert_greatercontrol_dependenciesidentitycastr0   roundint32r$   	set_shapeas_listMovingSequence)r   sequence_lengthoutput_sizer+   r?   r'   image_shaper,   r>   r   condsequence_pad_leftssequencer   r   r   image_as_moving_sequencet   sR   Q


r]   )r@   rA   rC   N)__doc__
__future__r   r   r   collectionstensorflow.compat.v2rL   v2r   r$   r/   r3   rI   r:   
namedtuplerV   r]   r   r   r   r   <module>   s"   