Imread OpenEXR file

Hi,
I have read some HDR images with imread() function but got some negative values in an “OpenEXR” format image. The code is like this:

import os
os.environ["OPENCV_IO_ENABLE_OPENEXR"]="1"
import cv2

exr_neg = cv2.imread('-.exr', cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH | cv2.IMREAD_UNCHANGED)
exr_pos = cv2.imread('+.exr', cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH | cv2.IMREAD_UNCHANGED)
hdr = cv2.imread('0005.hdr', cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)

print('exr_neg: min {} | max {}'.format(exr_neg.min(), exr_neg.max()))
print('exr_pos: min {} | max {}'.format(exr_pos.min(), exr_pos.max()))
print('hdr: min {} | max {}'.format(hdr.min(), hdr.max()))

image

What I am confused about is why the imread() function return numpy matrix with some negative pixels. The HDR image file can be download from here.

Could your please share with me what the problem is or any suggestions? Thank you so much in advance! :smiley: :slightly_smiling_face:

maybe this is correct? what do other EXR tools (imagemagick, …) tell you about the contents of that file?

This is correct for EXR-format with high-dynamic range images. EXR has support for color floating-point depths. You just need to normalize the matrices.

import os

os.environ["OPENCV_IO_ENABLE_OPENEXR"] = "1"

import cv2 as cv

exr_neg = cv.imread('-.exr', cv.IMREAD_UNCHANGED)
exr_pos = cv.imread('+.exr', cv.IMREAD_UNCHANGED)
hdr = cv.imread('0005.hdr', cv.IMREAD_UNCHANGED)

cv.namedWindow('exr_neg',
               cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO | cv.WINDOW_GUI_EXPANDED)
cv.namedWindow('exr_pos',
               cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO | cv.WINDOW_GUI_EXPANDED)
cv.namedWindow('hdr',
               cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO | cv.WINDOW_GUI_EXPANDED)

exr_neg = cv.normalize(exr_neg, None, 0, 255, cv.NORM_MINMAX, cv.CV_8U)
exr_pos = cv.normalize(exr_pos, None, 0, 255, cv.NORM_MINMAX, cv.CV_8U)
hdr = cv.normalize(hdr, None, 0, 255, cv.NORM_MINMAX, cv.CV_8U)

print('exr_neg: min {} | max {}'.format(exr_neg.min(), exr_neg.max()))
print('exr_pos: min {} | max {}'.format(exr_pos.min(), exr_pos.max()))
print('hdr: min {} | max {}'.format(hdr.min(), hdr.max()))

cv.imshow('exr_neg', exr_neg)
cv.imshow('exr_pos', exr_pos)
cv.imshow('hdr', hdr)

cv.waitKey(0)
cv.destroyAllWindows()

or

cv.normalize(mat, None, 0, 1, cv.NORM_MINMAX, cv.CV_64F)

numerical inaccuracies. always expect them. your negative numbers (-0.001) are close to 0 anyway, so…

what color space does that file have natively? OpenCV likes to convert to RGB/BGR, while some pictures have some type of yuv space, or lab, or who knows what. that can be a source of numerical errors.

Hi crackwitz,
I print the information of -.exr:

$ identify -verbose -.exr                          
Image: -.exr
  Format: EXR (High Dynamic-range (HDR))
  Class: DirectClass
  Geometry: 4288x2412+0+0
  Units: Undefined
  Colorspace: RGB
  Type: TrueColorAlpha
  Base type: Undefined
  Endianess: Undefined
  Depth: 16-bit
  Channel depth:
    red: 16-bit
    green: 16-bit
    blue: 16-bit
    alpha: 1-bit
  Channel statistics:
    Pixels: 10342656
    Red:
      min: 0  (0)
      max: 65535 (1)
      mean: 27428.7 (0.418535)
      standard deviation: 20484.1 (0.312568)
      kurtosis: -0.721404
      skewness: 0.894195
      entropy: 0.82117
    Green:
      min: 0  (0)
      max: 65535 (1)
      mean: 34510.8 (0.526601)
      standard deviation: 20908 (0.319035)
      kurtosis: -1.19547
      skewness: 0.471033
      entropy: 0.70769
    Blue:
      min: 71  (0.00108339)
      max: 65535 (1)
      mean: 45589.1 (0.695645)
      standard deviation: 18410 (0.280919)
      kurtosis: 0.000131018
      skewness: -0.788791
      entropy: 0.623624
    Alpha:
      min: 65535  (1)
      max: 65535 (1)
      mean: 65535 (1)
      standard deviation: -nan (-nan)
      kurtosis: -1.61532e+58
      skewness: 1.32891e+41
      entropy: 0
  Image statistics:
    Overall:
      min: 0  (0)
      max: 65535 (1)
      mean: 43265.9 (0.660195)
      standard deviation: -nan (-nan)
      kurtosis: -1.4721
      skewness: -0.341945
      entropy: 0.538121
  Rendering intent: Undefined
  Gamma: 1
  Background color: rgba(255,255,255,1)
  Border color: rgba(223,223,223,1)
  Matte color: rgba(189,189,189,1)
  Transparent color: rgba(0,0,0,0)
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 4288x2412+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: Undefined
  Orientation: Undefined
  Properties:
    date:create: 2022-09-21T19:08:26+08:00
    date:modify: 2022-09-21T19:08:26+08:00
    signature: dff017f48502e894aadb188b9ada4fe1cc5316858de1eb3e7b41c2688f6253a4
  Artifacts:
    filename: -.exr
    verbose: true
  Tainted: False
  Filesize: 32.2277MiB
  Number pixels: 10.3427M
  Pixels per second: 44.9681MB
  User time: 0.230u
  Elapsed time: 0:01.230
  Version: ImageMagick 6.9.10-23 Q16 x86_64 20190101 https://imagemagick.org

It seems that the image statistics don’t contain negative values :face_with_monocle:

1 Like

fascinating.

your file seems to contain uint16, not floats, yet you get floats, even with IMREAD_UNCHANGED!

does OpenEXR even support uint16? wikipedia says it supports 16 bit floats, and 32 bit unsigned integers.

the identify suggests that you actually have uint16, not just “half floats” reinterpreted as uint16, because if that were the case, I wouldn’t expect to see 0xFFFF (65535) as a maximum, which is a NaN value.

is this perhaps an artefact of using imagemagick? is this what imagemagick works with after decoding the file? your imagemagick is the Q16 variant, so it’s using more than 8 bits internally… but I don’t know if identify should report decoded data or the data that’s actually in the file.

perhaps browse the issues on the github and if you can’t find your situation, make a bug report? that is, if you’re sure your file can’t contain negative values.

1 Like

Thank you Saracen24. But I have no idea what the negative number in EXP means, does it means the pixel is blacker than black? :thinking: