Study: Artificial Intelligence(AI)/AI: 3D Vision

[Vision] EXR Extended Dynamic Range Image File Format (feat. OpenEXR, ๋ฌด์†์‹ค ๊ณ ํ•ด์ƒ๋„ ๋ฐ์ดํ„ฐ ์ €์žฅ)

DrawingProcess 2024. 4. 19. 17:21
๋ฐ˜์‘ํ˜•
๐Ÿ’ก ๋ณธ ๋ฌธ์„œ๋Š” '[Vision] EXR Extended Dynamic Range Image File Format (feat. OpenEXR)'์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋†“์€ ๊ธ€์ž…๋‹ˆ๋‹ค.
๋ฌด์†์‹ค ๊ณ ํ•ด์ƒ๋„ ๋ฐ์ดํ„ฐ ์ €์žฅ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ํฌ๋ฉง์ธ Extended Dynamic Range(EXR) Image File Format์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์˜€์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

1. What is EXR File format 

Overview of the OpenEXR File Format

Industrial Light + Magic implemented its own extended dynamic range file format in Summer 2000. The existing 8-bit file format used at the time could not accurately reproduce images with extreme contrast between the darkest and brightest regions, or images with very subtle color gradations.

ILM's extended dynamic range file format has been employed successfully in the movies Harry Potter, Men in Black II, and Signs. Several shows currently in production at ILM are using the new format.

Realizing that various other parties are interested in an extended dynamic range file format, ILM decided to polish its new file format a bit, and to publish it. OpenEXR is the result.

Features of OpenEXR

1) high dynamic range

Pixel data are stored as 16-bit or 32-bit floating-point numbers. With 16 bits, the representable dynamic range is significantly higher than the range of most image capture devices: 109 or 30 f-stops without loss of precision, and an additional 10 f-stops at the low end with some loss of precision. Most 8-bit file formats have around 7 to 10 stops.

2) good color resolution

with 16-bit floating-point numbers, color resolution is 1024 steps per f-stop, as opposed to somewhere around 20 to 70 steps per f-stop for most 8-bit file formats. Even after significant processing, for example extensive color correction, images tend to show no noticeable color banding.

3) compatible with graphics hardware

The 16-bit floating-point data format is fully compatible with the 16-bit frame-buffer data format used in some new graphics hardware. Images can be transferred back and forth between an OpenEXR file and a 16-bit floating-point frame buffer without losing data.

4) lossless data compression

The data compression methods currently implemented in OpenEXR are lossless; repeatedly compressing and uncompressing an image does not change the image data. With the current compression methods, photographic images with significant amounts of film grain tend to shrink to somewhere between 35 and 55 percent of their uncompressed size. New lossless and lossy compression schemes can be added in the future.

5) arbitrary image channels

OpenEXR images can contain an arbitrary number and combination of image channels, for example red, green, blue, and alpha, Y, U, and V (luminance, and two sub-sampled chroma channels), depth, surface normal directions, or motion vectors.

6) ability to store additional data

Often it is necessary to annotate images with additional data; for example, color timing information, process tracking data, or camera position and view direction. OpenEXR allows storing of an arbitrary number of extra "attributes", of arbitrary type, in an image file. Software that reads OpenEXR files ignores attributes it does not understand.

7) easy-to-use C++ and C programming interfaces

In order to make writing and reading OpenEXR files easy, the file format was designed together with a C++ programming interface. Two levels of access to image files are provided: a fully general interface for writing and reading files with arbitrary sets of image channels, and a specialized interface for the most common case (red, green, blue, and alpha channels, or some subset of those). Additionally, a C-callable version of the programming interface supports reading and writing OpenEXR files from programs written in C.

8) portability

The OpenEXR file format is hardware and operating system independent. While implementing the C and C++ programming interfaces, an effort was made to use only language features and library functions that comply with the C and C++ ISO standards. The resulting code is known to work on Linux (Intel x86), SGI Irix (Mips), and Mac OSX (PowerPC).

Example EXR File Header

iPhone Depth Image๋ฅผ ๋ฝ‘๋Š” ๊ณผ์ •์—์„œ exr ํ˜•ํƒœ ํŒŒ์ผ์„ ์ œ๊ณตํ•˜์—ฌ, ์ด๋ฅผ ๋ถ„์„ํ•˜๋Š” ๊ณผ์ •์—์„œ Header๋ฅผ ์ถ”์ถœํ•œ ๋‚ด์šฉ์ด๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ํ•ด๋‹น Header ์ •๋ณด์˜ ๊ฒฝ์šฐ ์•„๋ž˜์˜ ์˜ˆ์‹œ์ฝ”๋“œ์— print(exrfile.header()) ๋งŒ ์ถ”๊ฐ€ํ•˜์—ฌ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

{ 
    'channels': {'R': HALF (1,1)}, 
    'compression': ZIP_COMPRESSION, 
    'dataWindow': (0,0) - (191,255), 
    'displayWindow': (0,0) - (191,255), 
    'lineOrder': INCREASING_Y, 
    'pixelAspectRatio': 1.0, 
    'screenWindowCenter': (0.0,0.0), 
    'screenWindowWidth': 1.0
}
  • channels: 'R'์€ Red Intensity ์ด๋ฉฐ, Depth ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜์˜ ์ฑ„๋„์„ ์‚ฌ์šฉํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž„
    • HALF: The IEEE-754 16-bit floating-point data type. Same as Nvidia’s 16-bit floating-point format (fp16 / half). The range of representable numbers is roughly 6.0×10^-8 ~ 6.5×10^4
  • compression: ๋ฐ์ดํ„ฐ ์••์ถ• ๋ฐฉ์‹
  • dataWindow, displayWindow: dataWindow๋Š” ๋ฐ์ดํ„ฐ ์ž์ฒด์˜ ํฌ๊ธฐ๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, displayWindow๋Š” ์ด๋ฅผ ์ด๋ฏธ์ง€ ์ƒ์— ๋ณด์—ฌ์ค„ ๋•Œ ์‚ฌ์ด์ฆˆ
  • lineOrder: ์ด๋ฏธ์ง€ ์ €์žฅ ๋ฐฉ์‹์œผ๋กœ, INCREASING_Y๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋ฏธ์ง€ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋™์ผํ•˜๊ฒŒ ์ขŒ์ƒ๋‹จ (0,0)์œผ๋กœ ์‹œ์ž‘
  • pixelAspectRatio: Width divided by height of a pixel when the image is displayed with the correct aspect ratio. 
  • screenWindowCenter, screenWindowWidth: Those programs(OpenEXR) should set screenWindowWidth to 1, and screenWindowCenter to (0, 0).
  • [์ฐธ๊ณ ] OpenEXR File Header: https://openexr.com/en/latest/TechnicalIntroduction.html#header

2. How to Use an EXR File

How to Open an EXR File

1) Commercial Tools

2) using OpenEXR

def read_depth_exr_file(filepath):
    # exrfile = exr.InputFile(filepath.as_posix())
    exrfile = exr.InputFile(filename)
    raw_bytes = exrfile.channel('R', Imath.PixelType(Imath.PixelType.FLOAT))
    depth_vector = np.frombuffer(raw_bytes, dtype=np.float32)
    height = exrfile.header()['displayWindow'].max.y + 1 - exrfile.header()['displayWindow'].min.y
    width = exrfile.header()['displayWindow'].max.x + 1 - exrfile.header()['displayWindow'].min.x
    depth_map = np.reshape(depth_vector, (height, width))
    return depth_map
import numpy as np
import OpenEXR as exr
import Imath

from matplotlib import pyplot as plt

def readEXR(filename):
    """Read color + depth data from EXR image file.
    
    Parameters
    ----------
    filename : str
        File path.
        
    Returns
    -------
    img : RGB or RGBA image in float32 format. Each color channel
          lies within the interval [0, 1].
          Color conversion from linear RGB to standard RGB is performed
          internally. See https://en.wikipedia.org/wiki/SRGB#The_forward_transformation_(CIE_XYZ_to_sRGB)
          for more information.
          
    Z : Depth buffer in float32 format or None if the EXR file has no Z channel.
    """
    
    exrfile = exr.InputFile(filename)
    header = exrfile.header()
    
    dw = header['dataWindow']
    isize = (dw.max.y - dw.min.y + 1, dw.max.x - dw.min.x + 1)
    
    channelData = dict()
    
    # convert all channels in the image to numpy arrays
    for c in header['channels']:
        C = exrfile.channel(c, Imath.PixelType(Imath.PixelType.FLOAT))
        C = np.fromstring(C, dtype=np.float32)
        C = np.reshape(C, isize)
        
        channelData[c] = C

    # Read EXR RGBD Format
    colorChannels = ['R', 'G', 'B', 'A'] if 'A' in header['channels'] else ['R', 'G', 'B']
    img = np.concatenate([channelData[c][...,np.newaxis] for c in colorChannels], axis=2)
    
    # linear to standard RGB
    img[..., :3] = np.where(img[..., :3] <= 0.0031308,
                            12.92 * img[..., :3],
                            1.055 * np.power(img[..., :3], 1 / 2.4) - 0.055)
    
    # sanitize image to be in range [0, 1]
    img = np.where(img < 0.0, 0.0, np.where(img > 1.0, 1, img))
    
    # Read EXR D Format
    Z = None if 'Z' not in header['channels'] else channelData['Z']
    
    return img, Z

if __name__ == "__main__":
    filename = "./nerf_custom/lab_record3d/EXR_RGBD/depth/0.exr"
    img, Z = readEXR(filename)
    Z = readEXR(filename)

    plt.imshow(Z)
    plt.imsave("depth.jpg", Z)

depth_read_exr.py
0.00MB

How to Convert an EXR File

AConvert.com is an example of an online tool that supports this format. It can save your file to JPG, PNG, TIFF, GIF, and many other formats. This website can also resize it before the conversion.

You might also be able to convert an EXR file using one of the programs from above that can open the file, but a dedicated file converter is much quicker and doesn't need to be installed to your computer before you use it.

์ฐธ๊ณ 

๋ฐ˜์‘ํ˜•