//  [python]
def augment_seqs_ava(raw_frames, num_frame, max_shift, batch_size=2,
                     queue_size=60, num_threads=3, train_height=128,
                     train_width=128, pixel_noise=0.0, mix=True, screen=False,
                     mode='train', to_gray=True):
  """Prepares training sequence batches from AVA dataset.

  Args:
    raw_frames: input video frames from AVA dataset
    num_frame: the number of frames in a sequence
    max_shift: the range each image corner point can move
    batch_size: the size of training or testing batches
    queue_size: the queue size of the shuffle buffer
    num_threads: the number of threads of the shuffle buffer
    train_height: the height of the training/testing images
    train_width: the width of the training/testing images
    pixel_noise: the magnitude of additive noises
    mix: whether mix the magnitude of corner point shifts
    screen: whether remove highly distorted homographies
    mode: 'train' or 'eval', specifying whether preparing images for training or
      testing
    to_gray: whether prepare color or gray scale training images
  Returns:
    a batch of training images and the corresponding ground-truth homographies
  """
  if to_gray:
    output_frames = tf.image.rgb_to_grayscale(raw_frames)
    num_channel = 1
  else:
    output_frames = raw_frames
    num_channel = 3

  frame_height = tf.cast(tf.shape(output_frames)[1], tf.float32)
  frame_width = tf.cast(tf.shape(output_frames)[2], tf.float32)

  if mix:
    p = tf.random_uniform([], minval=0, maxval=1, dtype=tf.float32)
    scale = (tf.cast(tf.greater(p, 0.1), tf.float32) + tf.cast(tf.greater(p, 0.2), tf.float32)
             + tf.cast(tf.greater(p, 0.3), tf.float32)) / 3
  else:
    scale = 1.0
  new_max_shift = max_shift * scale
  rand_shift_base = tf.random_uniform([num_frame, 8], minval=-new_max_shift,
                                      maxval=new_max_shift, dtype=tf.float32)
  crop_width = frame_width - 2 * new_max_shift - 1
  crop_height = frame_height - 2 * new_max_shift - 1
  ref_window = tf.cast(tf.stack([0, 0, 0, crop_height - 1, crop_width - 1,
                                     0, crop_width - 1, crop_height - 1]), tf.float32)
  if screen:
    new_shift_list = []
    flag_list = []
    hmg_list = []
    src_points = tf.reshape(ref_window, [4, 2])
    for i in range(num_frame):
      dst_points = tf.reshape(rand_shift_base[i] + ref_window + new_max_shift,
                              [4, 2])
      hmg = calc_homography_from_points(src_points, dst_points)
      hmg_list.append(hmg)
    for i in range(num_frame - 1):
      hmg = tf.matmul(tf.matrix_inverse(hmg_list[i + 1]), hmg_list[i])
      shift = homography_to_shifts(hmg, crop_width, crop_height)
      angles = calc_homography_distortion(crop_width, crop_height, shift)
      max_angle = tf.reduce_min(angles)
      flag = tf.cast(max_angle >= -0.707, tf.float32)
      flag_list.append(flag)
      if i > 0:
        new_shift = rand_shift_base[i] * flag * flag_list[i - 1]
      else:
        new_shift = rand_shift_base[i] * flag
      new_shift_list.append(new_shift)
    new_shift_list.append(rand_shift_base[num_frame - 1]
                          * flag_list[num_frame - 2])
    rand_shift = tf.stack(new_shift_list)
  else:
    rand_shift = rand_shift_base

  mat_scale = tf.diag(tf.stack([crop_width / train_width,
                                crop_height / train_height, 1.0]))
  inv_mat_scale = tf.matrix_inverse(mat_scale)
  hmg_list = []
  frame_list = []
  for i in range(num_frame):
    src_points = tf.reshape(ref_window, [4, 2])
    dst_points = tf.reshape(rand_shift[i] + ref_window + new_max_shift, [4, 2])
    hmg = calc_homography_from_points(src_points, dst_points)
    hmg_list.append(hmg)
    transform = tf.reshape(hmg, [9]) / hmg[2, 2]
    warped = contrib_image.transform(output_frames[i], transform[:8],
                                     'bilinear')
    crop_window = tf.expand_dims(tf.stack(
        [0, 0, (crop_height - 1) / (frame_height - 1),
         (crop_width - 1) / (frame_width - 1)]), 0)
    resized_base = tf.image.crop_and_resize(
        tf.expand_dims(warped, 0), crop_window, [0],
        [train_height, train_width])
    resized = tf.squeeze(resized_base, [0])

    noise_im = tf.truncated_normal(shape=tf.shape(resized), mean=0.0,
                                   stddev=pixel_noise, dtype=tf.float32)
    noise_frame = normalize_image(tf.cast(resized, tf.float32) + noise_im)
    frame_list.append(noise_frame)
  noise_frames = tf.reshape(
      tf.stack(frame_list, 2),
      (train_height, train_width, num_frame * num_channel))

  label_list = []
  for i in range(num_frame - 1):
    hmg_combine = tf.matmul(tf.matrix_inverse(hmg_list[i + 1]), hmg_list[i])
    hmg_final = tf.matmul(inv_mat_scale, tf.matmul(hmg_combine, mat_scale))
    label = homography_to_shifts(hmg_final, train_width, train_height)
    label_list.append(label)
  labels = tf.reshape(tf.stack(label_list, 0), [(num_frame - 1) * 8])

  if mode == 'train':
    min_after_dequeue = int(queue_size / 3)
  else:
    min_after_dequeue = batch_size * 3
  batch_frames, batch_labels = tf.train.shuffle_batch(
      [noise_frames, labels], batch_size=batch_size,
      num_threads=num_threads, capacity=queue_size,
      min_after_dequeue=min_after_dequeue, enqueue_many=False)

  return tf.cast(batch_frames, tf.float32), tf.cast(batch_labels, tf.float32)