OpenImageIO
OpenImageIO (OIIO) is a high-performance, open-source library and toolset for reading, writing, and processing images in a wide variety of file formats, using a format-agnostic API. Primarily aimed at visual effects (VFX) and animation applications, it provides robust support for formats like OpenEXR, TIFF, JPEG, PNG, and many more. The library is actively maintained by the Academy Software Foundation, with frequent minor releases within its major versions.
Common errors
-
ModuleNotFoundError: No module named 'OpenImageIO'
cause The Python interpreter cannot find the installed OpenImageIO module. This often happens after building from source or due to incorrect `PYTHONPATH` settings.fixEnsure `pip install openimageio` completed successfully. If building from source, set the `PYTHONPATH` environment variable to include the directory where `OpenImageIO.so` (Linux/macOS) or `OpenImageIO.pyd` (Windows) is located. For macOS, sometimes renaming `OpenImageIO.dylib` to `OpenImageIO.so` is required. -
Python interpreter crashes when reading certain image files.
cause OpenImageIO is a C++ library, and reading malformed or corrupted image files, or files with exotic parameters that expose bugs in the underlying C++ plugins, can lead to a hard crash of the Python interpreter instead of raising a Python exception.fixWrap image reading operations in `try-except` blocks, specifically checking `ImageBuf.has_error` and `ImageBuf.geterror()` after initialization or I/O operations. While this doesn't prevent all C++-level crashes, it helps catch many issues gracefully. Ensure you are using the latest stable version of OpenImageIO and its dependencies, as many such bugs are fixed over time. -
TypeError: argument 'pixels': 'list' object cannot be converted to 'PyArrayObject'
cause Attempting to pass raw Python lists or `array.array` objects as pixel data to OIIO functions (e.g., `ImageBuf.set_pixels()`, `ImageOutput.write_image()`) in OpenImageIO 2.0+.fixConvert pixel data to `numpy.ndarray` objects before passing them to OpenImageIO functions. For example, `pixels_ndarray = np.array(my_list_of_pixels, dtype=np.float32)`.
Warnings
- breaking OpenImageIO 2.0 introduced significant breaking changes in Python bindings, most notably the switch from Python's `array.array` to `numpy.ndarray` for pixel data. Code written for OIIO 1.x that handles pixel buffers will need updates.
- gotcha Installing OpenImageIO via `pip` on certain platforms or for full functionality (especially with specific C++ compiler versions or less common image formats) can sometimes be challenging due to its underlying C++ dependencies. Pre-built wheels aim to simplify this but edge cases exist.
- gotcha When `pip` installing OpenImageIO from source, or if using a custom build, a `ModuleNotFoundError` can occur if the Python interpreter cannot locate the `OpenImageIO` module. This is particularly common on macOS where shared libraries (`.dylib`) might not be found by Python which often expects `.so` extensions.
- gotcha Incorrectly converting a color image (like sRGB JPEG) to grayscale by simply averaging the R, G, B channels will yield visually inaccurate results because human perception of brightness is not uniform across color channels, and sRGB is a non-linear color space.
Install
-
pip install openimageio -
pip install --force-reinstall "openimageio[all]" # For comprehensive format support and to rebuild if issues arise
Imports
- OpenImageIO
import OpenImageIO as oiio
- ImageInput
import ImageInput
from OpenImageIO import ImageInput
- ImageBuf
import ImageBuf
from OpenImageIO import ImageBuf
Quickstart
import OpenImageIO as oiio
import numpy as np
import os
# Create a dummy image (e.g., a red square)
width, height, channels = 256, 256, 3
spec = oiio.ImageSpec(width, height, channels, oiio.TypeDesc('float'))
# Create a NumPy array with red pixels
pixels = np.zeros((height, width, channels), dtype=np.float32)
pixels[:, :, 0] = 1.0 # Red channel to full intensity
# Create an ImageBuf from the spec and pixels
img_buf = oiio.ImageBuf(spec, pixels)
# Define output file path
output_filename = 'red_square.exr'
# Write the image
try:
img_buf.write(output_filename)
print(f"Successfully wrote {output_filename}")
# Read the image back
read_img_buf = oiio.ImageBuf(output_filename)
if read_img_buf.has_error:
raise RuntimeError(f"Error reading {output_filename}: {read_img_buf.geterror()}")
# Get pixel data as a NumPy array
read_pixels = read_img_buf.get_pixels(oiio.TypeDesc('float'))
print(f"Read image with shape: {read_pixels.shape}")
except Exception as e:
print(f"An error occurred: {e}")
finally:
if os.path.exists(output_filename):
os.remove(output_filename) # Clean up the dummy file