Search code examples
pythonopencvpython-imageiohdr

How to read a hdr image quickly in the RGBE format in Python?


I would like to know how to read a HDR image (.hdr) by obtaining pixel values in the RGBE format quickly and efficiently in Python.

These are somethings I tried:

    import imageio
    img = imageio.imread(hdr_path, format="HDR-FI")

alternatively:

    import cv2
    img = cv2.imread(hdr_path, flags=cv2.IMREAD_ANYDEPTH)

This read the image, but gave the values in a RGB format.

How do you obtain the 4rth channel, the "E" channel for every pixel, without altered RGB values? I would prefer a solution involving only imageio, as i am restricted to use only that module.


Solution

  • If you prefer the RGBE representation over the float representation you can convert between the two

    def float_to_rgbe(image, *, channel_axis=-1):
    
        # ensure channel-last
        image = np.moveaxis(image, channel_axis, -1)
    
        max_float = np.max(image, axis=-1)
        
        scale, exponent = np.frexp(max_float)
        scale *= 256.0/max_float
    
        image_rgbe = np.empty((*image.shape[:-1], 4)
        image_rgbe[..., :3] = image * scale
        image_rgbe[..., -1] = exponent + 128
    
        image_rgbe[scale < 1e-32, :] = 0
        
        # restore original axis order
        image_rgbe = np.moveaxis(image_rgbe, -1, channel_axis)
    
        return image_rgbe
    

    (Note: this is based on the RGBE reference implementation (found here) and can be further optimized if it actually is the bottleneck.)

    In your comment, you mention "If i parse the numpy array manually and split the channels into an E channel, it takes too much time...", but it is hard to tell why that is the case without seeing the code. The above is O(height*width), which seems reasonable for a pixel-level image processing method.