Usage Examples¶Some examples of using the OCIO API, via both C++ and the Python bindings. For further examples, see the src/apps/ directory in the git repository Applying a basic ColorSpace transform, using the CPU¶This describes what code is used to convert from a specified source ColorSpace to a specified destination ColorSpace. If you are using the OCIO Nuke plugins, the OCIOColorSpace node performs these steps internally.
C++¶#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE;
try
{
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
ConstProcessorRcPtr processor = config->getProcessor(OCIO::ROLE_COMPOSITING_LOG,
OCIO::ROLE_SCENE_LINEAR);
OCIO::PackedImageDesc img(imageData, w, h, 4);
processor->apply(img);
}
catch(OCIO::Exception & exception)
{
std::cerr << "OpenColorIO Error: " << exception.what() << std::endl;
}
Python¶import PyOpenColorIO as OCIO
try:
config = OCIO.GetCurrentConfig()
processor = config.getProcessor(OCIO.Constants.ROLE_COMPOSITING_LOG,
OCIO.Constants.ROLE_SCENE_LINEAR)
# Apply the color transform to the existing RGBA pixel data
img = processor.applyRGBA(img)
except Exception, e:
print "OpenColorIO Error",e
Displaying an image, using the CPU (simple ColorSpace conversion)¶Converting an image for display is similar to a normal color space conversion. The only difference is that one has to first determine the name of the display (destination) ColorSpace by querying the config with the device name and transform name.
C++¶#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE;
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
// If the user hasn't picked a display, use the defaults...
const char * device = config->getDefaultDisplayDeviceName();
const char * transformName = config->getDefaultDisplayTransformName(device);
const char * displayColorSpace = config->getDisplayColorSpaceName(device, transformName);
ConstProcessorRcPtr processor = config->getProcessor(OCIO::ROLE_SCENE_LINEAR,
displayColorSpace);
OCIO::PackedImageDesc img(imageData, w, h, 4);
processor->apply(img);
Python¶import PyOpenColorIO as OCIO
config = OCIO.GetCurrentConfig()
device = config.getDefaultDisplayDeviceName()
transformName = config.getDefaultDisplayTransformName(device)
displayColorSpace = config.getDisplayColorSpaceName(device, transformName)
processor = config.getProcessor(OCIO.Constants.ROLE_SCENE_LINEAR, displayColorSpace)
processor.applyRGB(imageData)
Displaying an image, using the CPU (Full Display Pipeline)¶This alternative version allows for a more complex displayTransform, allowing for all of the controls typically added to real-world viewer interfaces. For example, options are allowed to control which channels (red, green, blue, alpha, luma) are visible, as well as allowing for optional color corrections (such as an exposure offset in scene linear). If you are using the OCIO Nuke plugins, the OCIODisplay node performs these steps internally.
C++¶// Step 1: Get the config
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
// Step 2: Lookup the display ColorSpace
const char * device = config->getDefaultDisplayDeviceName();
const char * transformName = config->getDefaultDisplayTransformName(device);
const char * displayColorSpace = config->getDisplayColorSpaceName(device, transformName);
// Step 3: Create a DisplayTransform, and set the input and display ColorSpaces
// (This example assumes the input is scene linear. Adapt as needed.)
OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
transform->setInputColorSpaceName( OCIO::ROLE_SCENE_LINEAR );
transform->setDisplayColorSpaceName( displayColorSpace );
// Step 4: Add custom transforms for a 'canonical' Display Pipeline
// Add an fstop exposure control (in SCENE_LINEAR)
float gain = powf(2.0f, exposure_in_stops);
const float slope3f[] = { gain, gain, gain };
OCIO::CDLTransformRcPtr cc = OCIO::CDLTransform::Create();
cc->setSlope(slope3f);
transform->setLinearCC(cc);
// Add a Channel view 'swizzle'
// 'channelHot' controls which channels are viewed.
int channelHot[4] = { 1, 1, 1, 1 }; // show rgb
//int channelHot[4] = { 1, 0, 0, 0 }; // show red
//int channelHot[4] = { 0, 0, 0, 1 }; // show alpha
//int channelHot[4] = { 1, 1, 1, 0 }; // show luma
float lumacoef[3];
config.getDefaultLumaCoefs(lumacoef);
float m44[16];
float offset[4];
OCIO::MatrixTransform::View(m44, offset, channelHot, lumacoef);
OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create();
swizzle->setValue(m44, offset);
transform->setChannelView(swizzle);
// And then process the image normally.
OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform);
OCIO::PackedImageDesc img(imageData, w, h, 4);
processor->apply(img);
Python¶import PyOpenColorIO as OCIO
# Step 1: Get the config
config = OCIO.GetCurrentConfig()
# Step 2: Lookup the display ColorSpace
device = config.getDefaultDisplayDeviceName()
transformName = config.getDefaultDisplayTransformName(device)
displayColorSpace = config.getDisplayColorSpaceName(device, transformName)
# Step 3: Create a DisplayTransform, and set the input and display ColorSpaces
# (This example assumes the input is scene linear. Adapt as needed.)
transform = OCIO.DisplayTransform()
transform.setInputColorSpaceName(OCIO.Constants.ROLE_SCENE_LINEAR)
transform.setDisplayColorSpaceName(displayColorSpace)
# Step 4: Add custom transforms for a 'canonical' Display Pipeline
# Add an fstop exposure control (in SCENE_LINEAR)
gain = 2**exposure
slope3f = (gain, gain, gain)
cc = OCIO.CDLTransform()
cc.setSlope(slope3f)
transform.setLinearCC(cc)
# Add a Channel view 'swizzle'
channelHot = (1, 1, 1, 1) # show rgb
# channelHot = (1, 0, 0, 0) # show red
# channelHot = (0, 0, 0, 1) # show alpha
# channelHot = (1, 1, 1, 0) # show luma
lumacoef = config.getDefaultLumaCoefs()
m44, offset = OCIO.MatrixTransform.View(channelHot, lumacoef)
swizzle = OCIO.MatrixTransform()
swizzle.setValue(m44, offset)
transform.setChannelView(swizzle)
# And then process the image normally.
processor = config.getProcessor(transform)
print processor.applyRGB(imageData)
Displaying an image, using the GPU¶Applying OpenColorIO’s color processing using GPU processing is straightforward, provided you have the capability to upload custom shader code and a custom 3D Lookup Table (3DLUT).
C++¶This example is available as a working app in the OCIO source: src/apps/ociodisplay. // Step 0: Get the processor using any of the pipelines mentioned above.
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
const char * device = config->getDefaultDisplayDeviceName();
const char * transformName = config->getDefaultDisplayTransformName(device);
const char * displayColorSpace = config->getDisplayColorSpaceName(device, transformName);
ConstProcessorRcPtr processor = config->getProcessor(OCIO::ROLE_SCENE_LINEAR,
displayColorSpace);
// Step 1: Create a GPU Shader Description
GpuShaderDesc shaderDesc;
shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
shaderDesc.setFunctionName("OCIODisplay");
const int LUT3D_EDGE_SIZE = 32;
shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
// Step 2: Compute and the 3D LUT
// Optional Optimization:
// Only do this the 3D LUT's contents
// are different from the last drawn frame.
// Use getGpuLut3DCacheID to compute the cacheID.
// cheaply.
//
// std::string lut3dCacheID = processor->getGpuLut3DCacheID(shaderDesc);
int num3Dentries = 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
std::vector<float> g_lut3d;
g_lut3d.resize(num3Dentries);
processor->getGpuLut3D(&g_lut3d[0], shaderDesc);
// Load the data into an OpenGL 3D Texture
glGenTextures(1, &g_lut3d_textureID);
glBindTexture(GL_TEXTURE_3D, g_lut3d_textureID);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB,
LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
0, GL_RGB,GL_FLOAT, &g_lut3d[0]);
// Step 3: Query
|