[deprecated] A practical scripter's color management toolkit.
 
 
 
 
Go to file
Sofus Albert Høgsbro Rose b58a8f0374 openlut is working. 3D LUTs do not work, numpy optimization can certainly be done. 2016-08-22 20:42:50 -04:00
code_tests openlut is working. 3D LUTs do not work, numpy optimization can certainly be done. 2016-08-22 20:42:50 -04:00
testpath openlut is working. 3D LUTs do not work, numpy optimization can certainly be done. 2016-08-22 20:42:50 -04:00
README.md openlut is working. 3D LUTs do not work, numpy optimization can certainly be done. 2016-08-22 20:42:50 -04:00
openlut.py openlut is working. 3D LUTs do not work, numpy optimization can certainly be done. 2016-08-22 20:42:50 -04:00

README.md

openlut

Open-source tools for practical color management.

=====

What is it?

openlut is, at its core, a color management library, accessible from Python 3.5+. It's built on my own color pipeline needs, which includes managing Lookup Tables, Gamma/Gamut functions/matrices, applying color transformations, etc. .

openlut is also a tool. Included soon will be a command line utility letting you perform complex color transformations from the comfort of your console. In all cases, interactive usage from a Python console is easy.

I wanted it to cover this niche simply and consistently, something color management often isn't! Take a look; hopefully you'll agree :) !

What About OpenColorIO? Why does this exist?

OpenColorIO is a wonderful library, but seems geared towards managing the complexity of many larger applications in a greater pipeline. openlut is more simple; it doesn't care about the big picture - you simply read in images, transform them, then output them. openlut also focuses greatly on the "how" of these transformations with tools that eg. create or resize LUTs, things missing in OCIO.

Since it's a library, though, it's perfectly feasable (if not easy) to build such a greater pipeline based on openlut's simple color transformations.

Installation

I'll put it on pip eventually (when I figure out how!). For now, just download the repository.

To run openlut.py, first make sure you have the Dependencies. To run the test code at the bottom (make sure openlut is in the same directory as testpath; it needs to load test.exr), you can then run:

python3 openlut.py -t

To use in your code, simply import the module at the top of your file.

Dependencies

There are some dependencies that you must get. Keep in mind that it's Python 3.X only; all dependencies must be their 3.X versions.

Getting python3 and pip3

If you're on a Mac, run this to get python3 and pip3: brew install python3; curl https://bootstrap.pypa.io/get-pip.py | python3 If you're on Linux, you should already have python3 and pip3 - otherwise see your distribution repositories.

Dependency Installation

Run this to get all deps: sudo pip3 install numpy wand numba scipy

Basic Library Usage

To represent images, use a ColMap object. This handles IO to/from all ImageMagick supported formats (including EXR and DPX), as well as storing the image data.

Use any child of the Transform class to do a color transform on a ColMap, using ColMap's apply(Transform) method.

The Transform objects themselves have plenty of features - like LUT, with open(), save(), and resize() methods, or TransMat with auto-combining input matrices, or automatic spline-based interpolation of very small 1D LUTs - to make them helpful in and of themselves!

The best way to demonstrate from here, I think, is to show some test code: (run python3 openlut.py -t to see it work)

#Open any format image. Try it with exr/dpx/anything!
img = ColMap.open('testpath/test.exr') #Opens a test image 'test.exr', creating a ColMap object, automatically using the best image backend available to load the image at the correct bit depth.

'''
Gamma has gamma functions like Gamma.sRGB, called by value like Gamma.sRGB(val). All take one argument, the value (x), and returns the transformed value. Color doesn't matter for gamma.
TransMat has matrices, in 3x3 numpy array form. All are relative to ACES, with direction aptly named. So, TransMat.XYZ is a matrix from ACES --> XYZ, while TransMat.XYZinv goes from XYZ --> ACES. All use/are converted to the D65 illuminant, for consistency sake.
'''

#Gamma Functions: sRGB --> Linear.
gFunc = Gamma(Gamma.sRGBinv) #A Gamma Transform object using the sRGB-->Linear gamma formula. Apply to ColMaps!
gFuncManualsRGB = Gamma(lambda val: ((val + 0.055) / 1.055) ** 2.4 if val > 0.04045 else val / 12.92) #It's generic - specify any gamma function, even inline with a lambda!

#LUT from Function: sRGB --> Linear
oLut = LUT.lutFunc(Gamma.sRGBinv) #A LUT Transform object, created from a gamma function. Size is 16384 by default. LUTs are faster!
oLut.save('testpath/sRGB-->Lin.cube') #Saves the LUT to a format inferred from the extension. cube only for now!

#Opening LUTs from .cube files.
lut = LUT.open('testpath/sRGB-->Lin.cube') #Opens the lut we just made into a different LUT object.
lut.resized(17).save('testpath/sRGB-->Lin_tiny.cube') #Resizes the LUT, then saves it again to a much smaller file!

#Matrix Transformations
simpleMat = TransMat(TransMat.sRGBinv) #A Matrix Transform (TransMat) object, created from a color transform matrix for gamut transformations! This one is sRGB --> ACES.
mat = TransMat(TransMat.sRGBinv, TransMat.XYZ, TransMat.XYZinv, TransMat.aRGB) * TransMat.aRGBinv
#Indeed, specify many matrices which auto-multiply into a single one! You can also combine them after, with simple multiplication.

#Applying and saving.
img.apply(gFunc).save('testpath/openlut_gammafunc.png') #save saves an image using the appropriate image backend, based on the extension.
img.apply(lut).save('testpath/openlut_lut-lin-16384.png') #apply applies any color transformation object that inherits from Transform - LUT, Gamma, TransMat, etc., or make your own! It's easy ;) .
img.apply(lut.resized(17)).save('testpath/openlut_lut-lin-17.png') #Why so small? Because spline interpolation automatically turns on. It's identical to the larger LUT!
img.apply(mat).save('testpath/openlut_mat.png') #Applies the gamut transformation.

#As a proof of concept, here's a long list of transformations that should, in sum, do nothing :) :

img.apply(lut).apply(LUT.lutFunc(Gamma.sRGB)).apply(mat).apply(~mat).save('testpath/openlut_noop.png') #~mat is the inverse of mat. Easily undo the gamut operation!

#Format Test: All output images are in Linear ACES.
tImg = img.apply(mat)
tImg.save('testpath/output.exr')
tImg.save('testpath/output.dpx')
tImg.save('testpath/output.png')
tImg.save('testpath/output.jpg')
tImg.save('testpath/output.tif') #All sorts of formats work! Bit depth is 16, unless you say something else.

#Compression is impossible right now - wand is being difficult.
#Keep in mind, values are clipped from 0 to 1 when done. Scary transforms can make this an issue!

#Color management of openlut itself is simple: openlut doesn't touch your data, unless you tell it to with a Transform. So, the data that goes in, goes out, unless a Transform was applied.