tensorflow: how to rotate an image for data augmentation?

后端 未结 7 2023
遇见更好的自我
遇见更好的自我 2020-12-09 05:27

In tensorflow, I would like to rotate an image from a random angle, for data augmentation. But I don\'t find this transformation in the tf.image module.

相关标签:
7条回答
  • 2020-12-09 05:48

    Here's the @zimmermc answer updated to Tensorflow v0.12

    Changes:

    • pack() is now stack()
    • order of split parameters reversed

      def rotate_image_tensor(image, angle, mode='white'):
          """
          Rotates a 3D tensor (HWD), which represents an image by given radian angle.
      
          New image has the same size as the input image.
      
          mode controls what happens to border pixels.
          mode = 'black' results in black bars (value 0 in unknown areas)
          mode = 'white' results in value 255 in unknown areas
          mode = 'ones' results in value 1 in unknown areas
          mode = 'repeat' keeps repeating the closest pixel known
          """
          s = image.get_shape().as_list()
          assert len(s) == 3, "Input needs to be 3D."
          assert (mode == 'repeat') or (mode == 'black') or (mode == 'white') or (mode == 'ones'), "Unknown boundary mode."
          image_center = [np.floor(x/2) for x in s]
      
          # Coordinates of new image
          coord1 = tf.range(s[0])
          coord2 = tf.range(s[1])
      
          # Create vectors of those coordinates in order to vectorize the image
          coord1_vec = tf.tile(coord1, [s[1]])
      
          coord2_vec_unordered = tf.tile(coord2, [s[0]])
          coord2_vec_unordered = tf.reshape(coord2_vec_unordered, [s[0], s[1]])
          coord2_vec = tf.reshape(tf.transpose(coord2_vec_unordered, [1, 0]), [-1])
      
          # center coordinates since rotation center is supposed to be in the image center
          coord1_vec_centered = coord1_vec - image_center[0]
          coord2_vec_centered = coord2_vec - image_center[1]
      
          coord_new_centered = tf.cast(tf.stack([coord1_vec_centered, coord2_vec_centered]), tf.float32)
      
          # Perform backward transformation of the image coordinates
          rot_mat_inv = tf.dynamic_stitch([[0], [1], [2], [3]], [tf.cos(angle), tf.sin(angle), -tf.sin(angle), tf.cos(angle)])
          rot_mat_inv = tf.reshape(rot_mat_inv, shape=[2, 2])
          coord_old_centered = tf.matmul(rot_mat_inv, coord_new_centered)
      
          # Find nearest neighbor in old image
          coord1_old_nn = tf.cast(tf.round(coord_old_centered[0, :] + image_center[0]), tf.int32)
          coord2_old_nn = tf.cast(tf.round(coord_old_centered[1, :] + image_center[1]), tf.int32)
      
          # Clip values to stay inside image coordinates
          if mode == 'repeat':
              coord_old1_clipped = tf.minimum(tf.maximum(coord1_old_nn, 0), s[0]-1)
              coord_old2_clipped = tf.minimum(tf.maximum(coord2_old_nn, 0), s[1]-1)
          else:
              outside_ind1 = tf.logical_or(tf.greater(coord1_old_nn, s[0]-1), tf.less(coord1_old_nn, 0))
              outside_ind2 = tf.logical_or(tf.greater(coord2_old_nn, s[1]-1), tf.less(coord2_old_nn, 0))
              outside_ind = tf.logical_or(outside_ind1, outside_ind2)
      
              coord_old1_clipped = tf.boolean_mask(coord1_old_nn, tf.logical_not(outside_ind))
              coord_old2_clipped = tf.boolean_mask(coord2_old_nn, tf.logical_not(outside_ind))
      
              coord1_vec = tf.boolean_mask(coord1_vec, tf.logical_not(outside_ind))
              coord2_vec = tf.boolean_mask(coord2_vec, tf.logical_not(outside_ind))
      
          coord_old_clipped = tf.cast(tf.transpose(tf.stack([coord_old1_clipped, coord_old2_clipped]), [1, 0]), tf.int32)
      
          # Coordinates of the new image
          coord_new = tf.transpose(tf.cast(tf.stack([coord1_vec, coord2_vec]), tf.int32), [1, 0])
      
          image_channel_list = tf.split(image, s[2], 2)
      
          image_rotated_channel_list = list()
          for image_channel in image_channel_list:
              image_chan_new_values = tf.gather_nd(tf.squeeze(image_channel), coord_old_clipped)
      
              if (mode == 'black') or (mode == 'repeat'):
                  background_color = 0
              elif mode == 'ones':
                  background_color = 1
              elif mode == 'white':
                  background_color = 255
      
              image_rotated_channel_list.append(tf.sparse_to_dense(coord_new, [s[0], s[1]], image_chan_new_values,
                                                                   background_color, validate_indices=False))
      
          image_rotated = tf.transpose(tf.stack(image_rotated_channel_list), [1, 2, 0])
      
          return image_rotated
      
    0 讨论(0)
提交回复
热议问题