(
    img1, img2, filter_size, filter_width, power_factors, max_val=255.0)
Computes the MS-SSIM between img1 and img2.

  This function assumes that `img1` and `img2` are image batches, i.e. the last
  three dimensions are [row, col, channels].

  Arguments:
    img1: First RGB image batch.
    img2: Second RGB image batch. Must have the same rank as img1.
    filter_size: An integer, the filter size of the Gaussian kernel used.
    filter_width: A float, the filter width of the Gaussian kernel used.
    power_factors: iterable of weightings for each of the scales. The number of
      scales used is the length of the list. Index 0 is the unscaled
      resolution's weighting and each increasing scale corresponds to the image
      being downsampled by 2.
    max_val: the dynamic range of the images (i.e., the difference between the
      maximum the and minimum allowed values).

  Returns:
    A tensor containing batch-wise MS-SSIM measure. MS-SSIM has range [0, 1].
    The shape is broadcast(img1.shape[:-3], img2.shape[:-3]).
Computes the MS-SSIM between img1 and img2.
Computes the MS - SSIM between img1 and img2 .
def _multiscale_ssim_helper(
    img1, img2, filter_size, filter_width, power_factors, max_val=255.0):
  """Computes the MS-SSIM between img1 and img2.

  This function assumes that `img1` and `img2` are image batches, i.e. the last
  three dimensions are [row, col, channels].

  Arguments:
    img1: First RGB image batch.
    img2: Second RGB image batch. Must have the same rank as img1.
    filter_size: An integer, the filter size of the Gaussian kernel used.
    filter_width: A float, the filter width of the Gaussian kernel used.
    power_factors: iterable of weightings for each of the scales. The number of
      scales used is the length of the list. Index 0 is the unscaled
      resolution's weighting and each increasing scale corresponds to the image
      being downsampled by 2.
    max_val: the dynamic range of the images (i.e., the difference between the
      maximum the and minimum allowed values).

  Returns:
    A tensor containing batch-wise MS-SSIM measure. MS-SSIM has range [0, 1].
    The shape is broadcast(img1.shape[:-3], img2.shape[:-3]).
  """
  # Shape checking.
  shape1 = img1.get_shape().with_rank_at_least(3)
  shape2 = img2.get_shape().with_rank_at_least(3)
  shape1[-3:].merge_with(shape2[-3:])

  with tf.name_scope(None, 'MS-SSIM', [img1, img2]):
    shape1, shape2, checks = verify_compatible_shapes(img1, img2)
    with tf.control_dependencies(checks):
      img1 = tf.identity(img1)

    imgs = [img1, img2]
    shapes = [shape1, shape2]

    # img1 and img2 are assumed to be a (multi-dimensional) batch of
    # 3-dimensional images (height, width, channels). `heads` contain the batch
    # dimensions, and `tails` contain the image dimensions.
    heads = [s[:-3] for s in shapes]
    tails = [s[-3:] for s in shapes]

    divisor = [1, 2, 2, 1]
    divisor_tensor = tf.constant(divisor[1:], dtype=tf.int32)

    def do_pad(images, remainder):  # pylint: disable=invalid-name
      padding = tf.expand_dims(remainder, -1)
      padding = tf.pad(padding, [[1, 0], [1, 0]])
      return [tf.pad(x, padding, mode='SYMMETRIC') for x in images]

    mcs = []
    for k in range(len(power_factors)):
      with tf.name_scope(None, 'Scale%d' % k, imgs):
        if k > 0:
          # Avg pool takes rank 4 tensors. Flatten leading dimensions.
          flat_imgs = [
              tf.reshape(x, tf.concat([[-1], t], 0))
              for x, t in zip(imgs, tails)
          ]

          remainder = tails[0] % divisor_tensor
          need_padding = tf.reduce_any(tf.not_equal(remainder, 0))
          # pylint: disable=cell-var-from-loop
          padded = tf.cond(need_padding,
                           lambda: do_pad(flat_imgs, remainder),
                           lambda: flat_imgs)
          # pylint: enable=cell-var-from-loop

          downscaled = [
              tf.nn.avg_pool(
                  x, ksize=divisor, strides=divisor, padding='VALID')
              for x in padded
          ]
          tails = [x[1:] for x in tf.shape_n(downscaled)]
          imgs = [
              tf.reshape(x, tf.concat([h, t], 0))
              for x, h, t in zip(downscaled, heads, tails)
          ]

        # Overwrite previous ssim value since we only need the last one.
        ssim, cs = _ssim_index_per_channel(
            *imgs,
            filter_size=filter_size, filter_width=filter_width,
            max_val=max_val)
        mcs.append(tf.nn.relu(cs))

    # Remove the cs score for the last scale. In the MS-SSIM calculation,
    # we use the l(p) at the highest scale. l(p) * cs(p) is ssim(p).
    mcs.pop()  # Remove the cs score for the last scale.
    mcs_and_ssim = tf.stack(mcs + [tf.nn.relu(ssim)], axis=-1)
    # Take weighted geometric mean across the scale axis.
    ms_ssim = tf.reduce_prod(tf.pow(mcs_and_ssim, power_factors), [-1])

    ms_ssim = tf.reduce_mean(ms_ssim, [-1])  # Average over color channels.
    return ms_ssim
def _multiscale_ssim_helper ( img1 , img2 , filter_size , filter_width , power_factors , max_val = 255.0 ) : # Shape checking. shape1 = img1 . get_shape ( ) . with_rank_at_least ( 3 ) shape2 = img2 . get_shape ( ) . with_rank_at_least ( 3 ) shape1 [ - 3 : ] . merge_with ( shape2 [ - 3 : ] ) with tf . name_scope ( None , 'MS-SSIM' , [ img1 , img2 ] ) : shape1 , shape2 , checks = verify_compatible_shapes ( img1 , img2 ) with tf . control_dependencies ( checks ) : img1 = tf . identity ( img1 ) imgs = [ img1 , img2 ] shapes = [ shape1 , shape2 ] # img1 and img2 are assumed to be a (multi-dimensional) batch of # 3-dimensional images (height, width, channels). `heads` contain the batch # dimensions, and `tails` contain the image dimensions. heads = [ s [ : - 3 ] for s in shapes ] tails = [ s [ - 3 : ] for s in shapes ] divisor = [ 1 , 2 , 2 , 1 ] divisor_tensor = tf . constant ( divisor [ 1 : ] , dtype = tf . int32 ) def do_pad ( images , remainder ) : # pylint: disable=invalid-name padding = tf . expand_dims ( remainder , - 1 ) padding = tf . pad ( padding , [ [ 1 , 0 ] , [ 1 , 0 ] ] ) return [ tf . pad ( x , padding , mode = 'SYMMETRIC' ) for x in images ] mcs = [ ] for k in range ( len ( power_factors ) ) : with tf . name_scope ( None , 'Scale%d' % k , imgs ) : if k > 0 : # Avg pool takes rank 4 tensors. Flatten leading dimensions. flat_imgs = [ tf . reshape ( x , tf . concat ( [ [ - 1 ] , t ] , 0 ) ) for x , t in zip ( imgs , tails ) ] remainder = tails [ 0 ] % divisor_tensor need_padding = tf . reduce_any ( tf . not_equal ( remainder , 0 ) ) # pylint: disable=cell-var-from-loop padded = tf . cond ( need_padding , lambda : do_pad ( flat_imgs , remainder ) , lambda : flat_imgs ) # pylint: enable=cell-var-from-loop downscaled = [ tf . nn . avg_pool ( x , ksize = divisor , strides = divisor , padding = 'VALID' ) for x in padded ] tails = [ x [ 1 : ] for x in tf . shape_n ( downscaled ) ] imgs = [ tf . reshape ( x , tf . concat ( [ h , t ] , 0 ) ) for x , h , t in zip ( downscaled , heads , tails ) ] # Overwrite previous ssim value since we only need the last one. ssim , cs = _ssim_index_per_channel ( * imgs , filter_size = filter_size , filter_width = filter_width , max_val = max_val ) mcs . append ( tf . nn . relu ( cs ) ) # Remove the cs score for the last scale. In the MS-SSIM calculation, # we use the l(p) at the highest scale. l(p) * cs(p) is ssim(p). mcs . pop ( ) # Remove the cs score for the last scale. mcs_and_ssim = tf . stack ( mcs + [ tf . nn . relu ( ssim ) ] , axis = - 1 ) # Take weighted geometric mean across the scale axis. ms_ssim = tf . reduce_prod ( tf . pow ( mcs_and_ssim , power_factors ) , [ - 1 ] ) ms_ssim = tf . reduce_mean ( ms_ssim , [ - 1 ] ) # Average over color channels. return ms_ssim