15

I know that question is really simple, but I didn't find how to bypass the issue:

I'm processing images, the output pixels are float32, and values are in range [-1; 1]. The thing is, when saving using openCV, all negative data and float values are lost (I only get images with 0 or 1 values)

So I need to convert those images to [0; 255] (Int8)

I've tried

  • img * 255, but doing this does not help with negative values.
  • (img + 1) * 255, I'm removing the negative values, but I'm creating an overflow

Is there a (clean) way to do it ?

I'm using Python35, OpenCV2 and Numpy, but I think it's more a math problem than a library thing

Gsk
  • 2,929
  • 5
  • 22
  • 29
Mael Abgrall
  • 441
  • 2
  • 6
  • 16

4 Answers4

28

You can use cv2.normalize()

Consider the following array a:

a = np.array([[-0.12547205, -1.        ],
              [ 0.49696118,  0.91790167],
              [ 0.81638017,  1.        ]])

norm_image = cv2.normalize(image, None, alpha = 0, beta = 255, norm_type = cv2.NORM_MINMAX, dtype = cv2.CV_32F)

norm_image = norm_image.astype(np.uint8)

norm_image returns the following array:

array([[111,   0],
      [190, 244],
      [231, 255]], dtype=uint8)

In this example:

  • -1 will be mapped to 0
  • 1 will be mpped to 255
  • Everything in between will be mapped accordingly (0, 255)

Points to note:

  1. Ensure the array is of type float
  2. The extreme of values are place in alpha and beta respectively.
monzie
  • 565
  • 5
  • 15
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • 1
    Thank you for the answer! I'm marking another response as accepted since it's more general usage (not bound to Opencv). I still appreciate the clear explanation! – Mael Abgrall Jun 21 '18 at 11:21
  • 1
    @MelAbgrall Well enough. I gave this answer since this question was tagged to OpenCV :d – Jeru Luke Jun 21 '18 at 11:26
13

As you have found, img * 255 gives you a resulting range of [-255:255], and (img + 1) * 255 gives you a result of [0:510]. You're on the right track.

What you need is either: int((img + 1) * 255 / 2) or round((img + 1) * 255 / 2). This shifts the input from [-1:1] to [0:2] then multiplies by 127.5 to get [0.0:255.0].

Using int() will actually result in [0:254]

Gsk
  • 2,929
  • 5
  • 22
  • 29
Mick
  • 811
  • 14
  • 31
4

If you simply need to map the range -1, 1 to the range 0, 255 you can simply compare the ranges:

OldMin = -1
OldMax = 1
NewMin = 0
NewMax = 255

OldValue = 0.42

OldRange = (OldMax - OldMin)  
NewRange = (NewMax - NewMin)  
NewValue = int((((OldValue - OldMin) * NewRange) / OldRange) + NewMin)

print NewValue #OUTPUT: 181

see this question for proper mapping

Gsk
  • 2,929
  • 5
  • 22
  • 29
  • Nice ! I had a similar issue with 16Bit images several months ago... OpenCV handle 16 bit images for some operation, So I didn't had to bother... Thank you – Mael Abgrall Jun 21 '18 at 12:26
0

I was able to map an image from float32 [-1.0, 1.0] to integers [0,255] using PIL:

from PIL import Image

# sample a GAN image generator in range [-1.0,1.0]
img = generate_images(generator,1)[0] 

# Map interval [-1.0,1.0] to [0.0, 255.0]
img = ((img+1)/2.0)*255

# Convert image type to [0, 255]
img = Image.fromarray(img.astype('uint8'))
mikeliux
  • 31
  • 4