code: def smooth_with_noise(image, bits):
      
      
      rr = np.random.RandomState()
      rr.seed(0)
      r = rr.normal(size=image.shape)
      delta = pow(2.0,-bits)
      image_copy = np.clip(image, delta, 1)
      result = np.exp2(np.log2(image_copy + delta) * r + 
                       (1-r) * np.log2(image_copy))
      result[result>1] = 1
      result[result<0] = 0
      return result
docs: Smooth the image with a per-pixel random multiplier
      
      image - the image to perturb
      bits - the noise is this many bits below the pixel value
      
      The noise is random with normal distribution, so the individual pixels
      get either multiplied or divided by a normally distributed # of bits