11

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,802
  • 5
  • 24
  • 28
Mael Abgrall
  • 371
  • 2
  • 7
  • 15

3 Answers3

23

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
  • 555
  • 5
  • 14
Jeru Luke
  • 16,909
  • 11
  • 66
  • 79
  • 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
12

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,802
  • 5
  • 24
  • 28
Mick
  • 711
  • 15
  • 30
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,802
  • 5
  • 24
  • 28
  • 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