
Welcome!¶
Welcome to Imagecat … simple, flexible tools for procedural image editing.
Documentation¶

Installation¶
Imagecat¶
To install the latest stable version of Imagecat and its dependencies, use pip:
$ pip install imagecat
… once it completes, you’ll be able to use all of Imagecat’s core features.
OpenEXR¶
To work with OpenEXR images, you’ll need to have the OpenEXR library, which can’t be installed via pip. If you use Conda (which we strongly recommend), you can install it as follows:
$ conda install -c conda-forge openexr-python
Once you have OpenEXR, you can install Imagecat with the necessary dependencies:
$ pip install imagecat[exr]
Documentation¶
We assume that you’ll normally access this documentation online, but if you want a local copy on your own computer, do the following:
First, you’ll need the pandoc universal document converter, which can’t be installed with pip … if you use Conda (which we strongly recommend), you can install it with the following:
$ conda install pandoc
Once you have pandoc, install Imagecat along with all of the dependencies needed to build the docs:
$ pip install imagecat[doc]
Next, do the following to download a tarball to the current directory containing all of the Imagecat source code, which includes the documentation:
$ pip download imagecat --no-binary=:all: --no-deps
Now, you can extract the tarball contents and build the documentation (adjust the following for the version you downloaded):
$ tar xzvf imagecat-0.6.1.tar.gz
$ cd imagecat-0.6.1/docs
$ make html

Design¶
Images¶
Unsurprisingly, the overwhelming majority of operators in Imagecat either generate, modify, or consume images, making them one of the most important datatypes in the library.
In Imagecat, an image is a container for a set of named layers, and a layer
contains one or more channels. For example, an image loaded by the
imagecat.load
operator might contain a layer named “C” with three
channels of RGB color data, and a layer “A” with a single channel of opacity
information. More sophisticated workflows typical of 3D computer graphics
might involve images containing dozens of layers containing color, depth,
lighting, normal, object identity, velocity information, and more.
To accomodate this, every image in Imagecat is an instance of
imagecat.data.Image
containing a dict of str
layer names as
keys, and instances of imagecat.data.Layer
containing the layer data
as values. Any string is a valid layer name, although some names are more
common by convention, such as “C” for RGB color information and “A” for alpha
channels. Layer data is always stored using Numpy arrays
,
which always have three dimensions, in (row, column, channel) order. Most
layer data contains half-precision floating point values with linear brightness,
instead of the gamma-adjusted unsigned bytes with which you may be familiar.
Note that the third dimension is present even for single-channel layers like
alpha channels and masks, in which case its size will be one. When working
with layers, be careful to keep in mind that (row, column) slicing is the
opposite of the (x, y) ordering normally used in image processing. Finally,
each layer has a imagecat.data.Role
, which defines how the data in
the layer will be used. For example, a layer with three channels might contain
RGB color information, or XYZ coordinates in world space, or XYZ velocity
vectors, or UVW coordinates in texture space. The layer role is what distinguishes
among these cases, which is useful in visualization and I/O.
Graph¶
Imagecat operators are designed to be used with Graphcat,
https://graphcat.readthedocs.io, with which they are organized into
computational graphs that manage executing them at the right time and in the
right order. Imagecat operators are compatible with all
graphcat.graph.Graph
derivatives, which include
graphcat.StaticGraph
,
graphcat.DynamicGraph
, and
graphcat.StreamingGraph
.
Named Inputs¶
Named inputs are the objects that Graphcat uses to pass inputs from one
computational graph task to another; depending on the type of Graph that
you’re using, your Imagecat operators will be called with one of
graphcat.static.NamedInputs
, graphcat.dynamic.NamedInputs
,
or graphcat.streaming.NamedInputs
, which all have compatible APIs.
Note
Since every Graphcat task has the same parameters, the reference documentation for each Imagecat operator lists the named input parameters in a separate “Named Inputs” section.
User Guide¶
The User Guide includes detailed individual subjects covering how to use Imagecat effectively.
Colormap Operator¶
[1]:
import functools
import logging
logging.basicConfig(level=logging.INFO)
import graphcat.notebook
import imagecat.color.brewer
import imagecat.notebook
mapping = functools.partial(imagecat.color.linear_map, palette=imagecat.color.brewer.palette("BlueRed"))
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/load", imagecat.operator.load, path="Wood048_2K_Color.jpg")
imagecat.add_task(graph, "/remap", imagecat.operator.remap, mapping={"Y": {"selection": [("C", 0)], "role": imagecat.data.Role.LUMINANCE}})
imagecat.add_task(graph, "/colormap", imagecat.operator.color.colormap, mapping=mapping)
imagecat.add_links(graph, "/load", ("/remap", "image"))
imagecat.add_links(graph, "/remap", ("/colormap", "image"))
graphcat.notebook.display(graph)
image = graph.output("/remap")
INFO:imagecat.operator:Task /load load:
INFO:imagecat.operator: layers: *
INFO:imagecat.operator: path: Wood048_2K_Color.jpg
INFO:imagecat.operator: output: Image(C: Layer(Role.RGB 2048x2048x3 float16))
INFO:imagecat.operator:Task Y remap:
INFO:imagecat.operator: mapping: {'Y': {'selection': [('C', 0)], 'role': <Role.LUMINANCE: 10>}}
INFO:imagecat.operator: output: Image(Y: Layer(Role.LUMINANCE 2048x2048x1 float16))
[2]:
image.layers["Y"]
[2]:

[3]:
image = graph.output("/colormap")
INFO:imagecat.operator.color:Task /colormap colormap:
INFO:imagecat.operator.color: inlayer: None
INFO:imagecat.operator.color: mapping: functools.partial(<function linear_map at 0x7fd547fd0950>, palette=<imagecat.color.Palette object at 0x7fd546f7c2d0>)
INFO:imagecat.operator.color: outlayer: C
INFO:imagecat.operator.color: output: Image(C: Layer(Role.RGB 2048x2048x3 float64))
[4]:
image.layers["C"]
[4]:

Cryptomatte Decoder¶
[1]:
import logging
logging.basicConfig(level=logging.DEBUG)
import graphcat.notebook
import imagecat
[2]:
mapping = {
"CryptoPreview": {"role": imagecat.data.Role.RGB, "selection": ["uCryptoMaterial.red", "uCryptoMaterial.green", "uCryptoMaterial.blue"]},
}
graph = graphcat.DynamicGraph()
imagecat.add_task(graph, "/load", imagecat.operator.load, path="bunny_CryptoMaterial.exr")
imagecat.add_task(graph, "/preview", imagecat.operator.remap, mapping=mapping)
imagecat.add_links(graph, "/load", ("/preview", "image"))
graphcat.notebook.display(graph)
image = graph.output("/preview")
INFO:imagecat.operator:Task /load load:
INFO:imagecat.operator: layers: *
INFO:imagecat.operator: path: bunny_CryptoMaterial.exr
INFO:imagecat.operator: output: Image(uCryptoMaterial.blue: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial.green: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial.red: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial00.alpha: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial00.blue: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial00.green: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial00.red: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial01.alpha: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial01.blue: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial01.green: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial01.red: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial02.alpha: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial02.blue: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial02.green: Layer(Role.NONE 1280x720x1 float32), uCryptoMaterial02.red: Layer(Role.NONE 1280x720x1 float32))
INFO:imagecat.operator:Task CryptoPreview remap:
INFO:imagecat.operator: mapping: {'CryptoPreview': {'role': <Role.RGB: 1>, 'selection': ['uCryptoMaterial.red', 'uCryptoMaterial.green', 'uCryptoMaterial.blue']}}
INFO:imagecat.operator: output: Image(CryptoPreview: Layer(Role.RGB 1280x720x3 float32))
[3]:
image.layers["CryptoPreview"]
[3]:

[4]:
graph.output("/load").metadata
[4]:
{'CameraFilmApertureHorizontal': 1.0,
'CameraFilmApertureVertical': 0.5625,
'CameraFocalLength': 0.9890166521072388,
'arnold/AA_samples': 10,
'arnold/auto_transparency_depth': 10,
'arnold/diffuse_depth': 1,
'arnold/diffuse_samples': 0,
'arnold/glossy_depth': 1,
'arnold/glossy_samples': 0,
'arnold/host/hw': '2 x Intel(R) Xeon(R) CPU E5645 @ 2.40GHz (12 cores, 24 logical) with 24567MB',
'arnold/host/name': 'NYMRNDR108',
'arnold/host/os': 'Windows 7 Professional Service Pack 1 (version 6.1, build 7601)',
'arnold/reflection_depth': 2,
'arnold/refraction_depth': 2,
'arnold/refraction_samples': 0,
'arnold/sss_samples': 3,
'arnold/stats/date': 'Tue Mar 01 19:29:05 2016',
'arnold/stats/geo/curve_segments': 1095000.0,
'arnold/stats/geo/triangles': 125766.0,
'arnold/stats/memory/peak': 8468.72265625,
'arnold/stats/memory/start': 367.5078125,
'arnold/stats/rays/all/pixel': 1062.9029541015625,
'arnold/stats/rays/all/total': 1043855808.0,
'arnold/stats/rays/camera/pixel': 96.8963851928711,
'arnold/stats/rays/camera/total': 95160000.0,
'arnold/stats/time/render': 591.790771484375,
'arnold/stats/time/setup': 6.202756881713867,
'arnold/texture_max_memory_MB': 999999.0,
'arnold/threads': 24,
'arnold/total_depth': 10,
'arnold/version': 'Arnold 4.2.11.1 windows icc-14.0.2 oiio-1.5.20 rlm-11.3.1 2015/11/18 13:42:29',
'arnold/volume_depth': 0,
'arnold/volume_samples': 0,
'capDate': '2016:03:01 19:29:05',
'channels': {'uCryptoMaterial.blue': ['FLOAT', 1, 1],
'uCryptoMaterial.green': ['FLOAT', 1, 1],
'uCryptoMaterial.red': ['FLOAT', 1, 1],
'uCryptoMaterial00.alpha': ['FLOAT', 1, 1],
'uCryptoMaterial00.blue': ['FLOAT', 1, 1],
'uCryptoMaterial00.green': ['FLOAT', 1, 1],
'uCryptoMaterial00.red': ['FLOAT', 1, 1],
'uCryptoMaterial01.alpha': ['FLOAT', 1, 1],
'uCryptoMaterial01.blue': ['FLOAT', 1, 1],
'uCryptoMaterial01.green': ['FLOAT', 1, 1],
'uCryptoMaterial01.red': ['FLOAT', 1, 1],
'uCryptoMaterial02.alpha': ['FLOAT', 1, 1],
'uCryptoMaterial02.blue': ['FLOAT', 1, 1],
'uCryptoMaterial02.green': ['FLOAT', 1, 1],
'uCryptoMaterial02.red': ['FLOAT', 1, 1]},
'compression': 'ZIPS_COMPRESSION',
'compressionName': 'Zip (1 scanline)',
'cryptomatte/xc7bccc/conversion': 'uint32_to_float32',
'cryptomatte/xc7bccc/hash': 'MurmurHash3_32',
'cryptomatte/xc7bccc/manifest': '{"Material10":"83ae4666","Material11":"8131354e","Material12":"758b1edb","Material7":"b5c7aeb6","Material8":"dd5dc347","Material9":"d1d42e32","ai_bad_shader":"b3e5341b","bunny_porcelain_mat":"b24b26d4","flowerA_petal":"4f6ba831","flowerB_petal":"be02d5cc","flowerStem_mat":"7f0f6696","grass_mat":"41c3eaf9","ground_mat":"ee25e74e","smallLeaf_mat":"c607dc0c","smallStalk_mat":"7ec9f550"}',
'cryptomatte/xc7bccc/name': 'uCryptoMaterial',
'dataWindow': [0, 0, 1279, 719],
'displayWindow': [0, 0, 1279, 719],
'lineOrder': 'INCREASING_Y',
'nuke/full_layer_names': 0,
'nuke/node_hash': '52b1af4c323e1b16',
'nuke/version': '10.0v5',
'pixelAspectRatio': 1.0,
'screenWindowCenter': [0.0, 0.0],
'screenWindowWidth': 1.0,
'type': 'scanlineimage',
'version': 1,
'worldToCamera': None,
'worldToNDC': None}
[5]:
imagecat.add_task(graph, "/cryptomatte", imagecat.operator.cryptomatte.decoder, clown=False, mattes=["bunny_porcelain_mat"])
imagecat.add_links(graph, "/load", ("/cryptomatte", "image"))
graphcat.notebook.display(graph)
image = graph.output("/cryptomatte")
INFO:imagecat.operator.cryptomatte:Task /cryptomatte cryptomatte.decode:
INFO:imagecat.operator.cryptomatte: clown: False
INFO:imagecat.operator.cryptomatte: cryptomatte: None
INFO:imagecat.operator.cryptomatte: layer: M
INFO:imagecat.operator.cryptomatte: mattes: ['bunny_porcelain_mat']
INFO:imagecat.operator.cryptomatte: output: Image(M: Layer(Role.MATTE 1280x720x1 float32))
[6]:
image.layers["M"]
[6]:

[7]:
graph.set_task("/cryptomatte/mattes", graphcat.constant(["flowerA_petal", "flowerB_petal"]))
image = graph.output("/cryptomatte")
INFO:imagecat.operator.cryptomatte:Task /cryptomatte cryptomatte.decode:
INFO:imagecat.operator.cryptomatte: clown: False
INFO:imagecat.operator.cryptomatte: cryptomatte: None
INFO:imagecat.operator.cryptomatte: layer: M
INFO:imagecat.operator.cryptomatte: mattes: ['flowerA_petal', 'flowerB_petal']
INFO:imagecat.operator.cryptomatte: output: Image(M: Layer(Role.MATTE 1280x720x1 float32))
[8]:
image.layers["M"]
[8]:

[9]:
graph.set_task("/cryptomatte/clown", graphcat.constant(True))
graph.set_task("/cryptomatte/mattes", graphcat.constant(["bunny_porcelain_mat","flowerA_petal","flowerB_petal","flowerStem_mat","grass_mat","ground_mat","smallLeaf_mat","smallStalk_mat"]))
image = graph.output("/cryptomatte")
INFO:imagecat.operator.cryptomatte:Task /cryptomatte cryptomatte.decode:
INFO:imagecat.operator.cryptomatte: clown: True
INFO:imagecat.operator.cryptomatte: cryptomatte: None
INFO:imagecat.operator.cryptomatte: layer: M
INFO:imagecat.operator.cryptomatte: mattes: ['bunny_porcelain_mat', 'flowerA_petal', 'flowerB_petal', 'flowerStem_mat', 'grass_mat', 'ground_mat', 'smallLeaf_mat', 'smallStalk_mat']
INFO:imagecat.operator.cryptomatte: output: Image(M: Layer(Role.RGB 1280x720x3 float32))
[10]:
image.layers["M"]
[10]:

Dot Operator¶
[1]:
import logging
logging.basicConfig(level=logging.INFO)
import graphcat.notebook
import imagecat.notebook
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/load", imagecat.operator.load, path="Wood048_2K_Color.jpg")
imagecat.add_task(graph, "/dot", imagecat.operator.color.dot, matrix=[[0.6], [0.6], [0.1]])
imagecat.add_links(graph, "/load", ("/dot", "image"))
graphcat.notebook.display(graph)
image = graph.output("/load")
INFO:imagecat.operator:Task /load load:
INFO:imagecat.operator: layers: *
INFO:imagecat.operator: path: Wood048_2K_Color.jpg
INFO:imagecat.operator: output: Image(C: Layer(Role.RGB 2048x2048x3 float16))
[2]:
image.layers["C"]
[2]:

[3]:
image = graph.output("/dot")
INFO:imagecat.operator.color:Task /dot dot:
INFO:imagecat.operator.color: inlayer: None
INFO:imagecat.operator.color: matrix: [[0.6]
[0.6]
[0.1]]
INFO:imagecat.operator.color: outdtype: float16
INFO:imagecat.operator.color: outlayer: Y
INFO:imagecat.operator.color: outrole: Role.LUMINANCE
INFO:imagecat.operator.color: output: Image(Y: Layer(Role.LUMINANCE 2048x2048x1 float16))
[4]:
image.layers["Y"]
[4]:

Fill Operator¶
[1]:
import logging
logging.basicConfig(level=logging.INFO)
import graphcat
import imagecat
# Create a color fill.
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/fill", imagecat.operator.color.fill, values=[1, 0.5, 0])
image = graph.output("/fill")
INFO:imagecat.operator.color:Task /fill fill:
INFO:imagecat.operator.color: layer: C
INFO:imagecat.operator.color: res: [256 256]
INFO:imagecat.operator.color: role: Role.RGB
INFO:imagecat.operator.color: values: [1. 0.5 0. ]
INFO:imagecat.operator.color: output: Image(C: Layer(Role.RGB 256x256x3 float16))
[2]:
image.layers["C"]
[2]:

[3]:
# Create a grayscale fill.
imagecat.add_task(graph, "/fill2", imagecat.operator.color.fill, layer="A", values=[0], role=imagecat.data.Role.ALPHA)
image = graph.output("/fill2")
INFO:imagecat.operator.color:Task /fill2 fill:
INFO:imagecat.operator.color: layer: A
INFO:imagecat.operator.color: res: [256 256]
INFO:imagecat.operator.color: role: Role.ALPHA
INFO:imagecat.operator.color: values: [0]
INFO:imagecat.operator.color: output: Image(A: Layer(Role.ALPHA 256x256x1 float16))
[4]:
image.layers["A"]
[4]:

Gaussian Operator¶
[1]:
import logging
logging.basicConfig(level=logging.INFO)
import graphcat.notebook
import imagecat.notebook
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/text", imagecat.operator.render.text, string="Blur!")
imagecat.add_task(graph, "/gaussian", imagecat.operator.blur.gaussian, radius=["5px", "5px"])
imagecat.set_links(graph, "/text", ("/gaussian", "image"))
graphcat.notebook.display(graph)
image = graph.output("/gaussian")
INFO:imagecat.operator.render:Task /text text:
INFO:imagecat.operator.render: anchor: mm
INFO:imagecat.operator.render: fontindex: 0
INFO:imagecat.operator.render: fontname: /Users/tshead/src/imagecat/imagecat/LeagueSpartan-SemiBold.ttf
INFO:imagecat.operator.render: fontsize: 0.33h
INFO:imagecat.operator.render: layer: A
INFO:imagecat.operator.render: position: ('0.5w', '0.5h')
INFO:imagecat.operator.render: res: [256 256]
INFO:imagecat.operator.render: string: Blur!
INFO:imagecat.operator.render: output: Image(A: Layer(Role.ALPHA 256x256x1 float16))
INFO:imagecat.operator.blur:Task /gaussian gaussian:
INFO:imagecat.operator.blur: layer: None
INFO:imagecat.operator.blur: radius: ['5px', '5px']
INFO:imagecat.operator.blur: output: Image(A: Layer(Role.ALPHA 256x256x1 float16))
[2]:
image.layers["A"]
[2]:

Offset Operator¶
[1]:
import logging
logging.basicConfig(level=logging.INFO)
import graphcat.notebook
import imagecat.notebook
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/text", imagecat.operator.render.text, string="Offset!")
imagecat.add_task(graph, "/offset", imagecat.operator.transform.offset, offset=("0.5w", 0))
imagecat.set_links(graph, "/text", ("/offset", "image"))
graphcat.notebook.display(graph)
image = graph.output("/offset")
INFO:imagecat.operator.render:Task /text text:
INFO:imagecat.operator.render: anchor: mm
INFO:imagecat.operator.render: fontindex: 0
INFO:imagecat.operator.render: fontname: /Users/tshead/src/imagecat/imagecat/LeagueSpartan-SemiBold.ttf
INFO:imagecat.operator.render: fontsize: 0.33h
INFO:imagecat.operator.render: layer: A
INFO:imagecat.operator.render: position: ('0.5w', '0.5h')
INFO:imagecat.operator.render: res: [256 256]
INFO:imagecat.operator.render: string: Offset!
INFO:imagecat.operator.render: output: Image(A: Layer(Role.ALPHA 256x256x1 float16))
INFO:imagecat.operator.transform:Task /offset offset:
INFO:imagecat.operator.transform: layers: *
INFO:imagecat.operator.transform: offset: ('0.5w', 0)
INFO:imagecat.operator.transform: output: Image(A: Layer(Role.ALPHA 256x256x1 float16))
[2]:
image.layers["A"]
[2]:

Text Operator¶
[1]:
import logging
logging.basicConfig(level=logging.INFO)
import graphcat
import imagecat
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/text", imagecat.operator.render.text)
image = graph.output("/text")
INFO:imagecat.operator.render:Task /text text:
INFO:imagecat.operator.render: anchor: mm
INFO:imagecat.operator.render: fontindex: 0
INFO:imagecat.operator.render: fontname: /Users/tshead/src/imagecat/imagecat/LeagueSpartan-SemiBold.ttf
INFO:imagecat.operator.render: fontsize: 0.33h
INFO:imagecat.operator.render: layer: A
INFO:imagecat.operator.render: position: ('0.5w', '0.5h')
INFO:imagecat.operator.render: res: [256 256]
INFO:imagecat.operator.render: string: Text!
INFO:imagecat.operator.render: output: Image(A: Layer(Role.ALPHA 256x256x1 float16))
[2]:
image.layers["A"]
[2]:

Uniform Noise Operator¶
[1]:
import logging
logging.basicConfig(level=logging.INFO)
import graphcat
import imagecat
# Create grayscale noise.
graph = graphcat.StaticGraph()
imagecat.add_task(graph, "/uniform", imagecat.operator.noise.uniform)
image = graph.output("/uniform")
INFO:imagecat.operator.noise:Task /uniform uniform:
INFO:imagecat.operator.noise: high: 1.0
INFO:imagecat.operator.noise: layer: Y
INFO:imagecat.operator.noise: low: 0.0
INFO:imagecat.operator.noise: res: [256 256]
INFO:imagecat.operator.noise: role: Role.LUMINANCE
INFO:imagecat.operator.noise: seed: 1234
INFO:imagecat.operator.noise: output: Image(Y: Layer(Role.LUMINANCE 256x256x1 float16))
[2]:
image.layers["Y"]
[2]:

[3]:
# Create color noise.
imagecat.add_task(graph, "/uniform2", imagecat.operator.noise.uniform, layer="C", role=imagecat.data.Role.RGB)
image = graph.output("/uniform2")
INFO:imagecat.operator.noise:Task /uniform2 uniform:
INFO:imagecat.operator.noise: high: 1.0
INFO:imagecat.operator.noise: layer: C
INFO:imagecat.operator.noise: low: 0.0
INFO:imagecat.operator.noise: res: [256 256]
INFO:imagecat.operator.noise: role: Role.RGB
INFO:imagecat.operator.noise: seed: 1234
INFO:imagecat.operator.noise: output: Image(C: Layer(Role.RGB 256x256x3 float16))
[4]:
image.layers["C"]
[4]:


Development¶
Getting Started¶
If you haven’t already, you’ll want to get familiar with the Imagecat repository at http://github.com/shead-custom-design/imagecat … there, you’ll find the Imagecat source code, issue tracker, discussions, and wiki.
You’ll need to install Graphviz and pandoc, neither of which can be installed via pip. If you use Conda (which we strongly recommend), you can install them as follows:
$ conda install graphviz pandoc
You’ll also need OpenEXR which also can’t be installed via pip. With Conda (again - strongly recommended), do the following:
$ conda install -c conda-forge openexr-python
Next, you’ll need to install all of the extra dependencies needed for Imagecat development:
$ pip install imagecat[all]
Then, you’ll be ready to obtain Imagecat’s source code and install it using “editable mode”. Editable mode is a feature provided by pip that links the Imagecat source code into the install directory instead of copying it … that way you can edit the source code in your git sandbox, and you don’t have to keep re-installing it to test your changes:
$ git clone https://github.com/shead-custom-design/imagecat.git
$ cd imagecat
$ pip install --editable .
Versioning¶
Imagecat version numbers follow the Semantic Versioning standard.
Coding Style¶
The Imagecat source code follows the PEP-8 Style Guide for Python Code.
Running Regression Tests¶
To run the Imagecat test suite, simply run regression.py from the top-level source directory:
$ cd imagecat
$ python regression.py
The tests will run, providing feedback on successes / failures.
Test Coverage¶
When you run the test suite with regression.py, it also automatically generates code coverage statistics. To see the coverage results, open .cover/index.html in a web browser.
Building the Documentation¶
To build the documentation, run:
$ cd imagecat/docs
$ make html
Once the documentation is built, you can view it by opening docs/_build/html/index.html in a web browser.

API Reference¶
Contents:
imagecat module¶
Image processing functionality based on Graphcat computational graphs, http://graphcat.readthedocs.io.
- imagecat.add_links(graph, *args, **kwargs)[source]¶
Add links between tasks in a
graphcat.Graph
.This function calls-through to
graphcat.Graph.add_links()
, and is provided for symmetry withadd_task()
.
- imagecat.add_task(graph, name, fn, **parameters)[source]¶
Simplify setting-up graphcat tasks with parameters.
Virtually all non-trivial Imagecat operations have parameters that affect their operation. Because individually creating parameter tasks and linking them with the main task is tiresome and verbose, use this function instead.
- Parameters
graph (
graphcat.Graph
, required) – The Graphcat graph where the new task will be created.name (
str
, required) – The name of the new task.fn (callable, required) – The Imagecat operation to use for the new task.
parameters (additional keyword arguments, optional) – Each extra keyword argument will be turned into a parameter task and linked with the main task. Each parameter name is created by concatenating name with the keyword name, separated by a slash “/”.
- Returns
name – Name of the newly-created operation, which may be different than name.
- Return type
- imagecat.set_expression(graph, name, expression, locals={})[source]¶
Setup an expression task in a
graphcat.Graph
.This function calls-through to
graphcat.Graph.set_expression()
, but provides a library of Imagecat-specific functionality that can be used by expressions.
- imagecat.set_links(graph, *args, **kwargs)[source]¶
Set links between tasks in a
graphcat.Graph
.This function calls-through to
graphcat.Graph.set_links()
, and is provided for symmetry withadd_task()
.
imagecat.color module¶
Functionality for color mapping and colorspace conversion.
- class imagecat.color.Palette(colors, reverse=False)[source]¶
Bases:
object
Storage for an ordered collection of colors.
A palette is an ordered collection of colors. Typically, palettes are used to define color mappings.
See also
srgb_to_linear()
Useful for converting colors from other sources into linear space.
- Parameters
colors (
numpy.ndarray
, required) – \(M \times N\) matrix containing \(M\) colors with \(N\) channels each. Note that while three channels for colors is typical, any number of channels is allowed. The color channels must be in linear space, not sRGB.reverse (boolean, optional) – If True, reverse the order of colors.
- property colors¶
Color data stored by this palette.
- Returns
\(M \times N\) matrix containing \(M\) colors with \(N\) channels each.
- Return type
- imagecat.color.categorical_map(data, palette)[source]¶
Convert scalar data to color data using a categorical map.
Integer input values will be used to lookup colors in palette. Modulo arithmetic ensures that colors are repeated for negative or out-of-bound colors. Floating point values are truncated using “floor” prior to lookup.
- Parameters
data (
numpy.ndarray
, required) – The data to be mapped.palette (
Palette
, required) – The palette of colors to use for the categorical mapping.
- Returns
mapped – Mapped data with the same shape as data, but an extra dimension added.
- Return type
- imagecat.color.linear_map(data, palette, min=None, max=None)[source]¶
Convert scalar data to color data using a linear map.
Input values between min and max will be linearly mapped to the colors in palette. If min or max are
None
, the corresponding value will be computed from the data.- Parameters
data (
numpy.ndarray
, required) – The data to be mapped.palette (
Palette
, required) – The palette of colors to use for the linear mapping.min (number, optional) – If
None
(the default) uses the minimum value in data.max (number, optional) – If
None
(the default) uses the maximum value in data.
- Returns
mapped – Mapped data with the same shape as data, but an extra dimension added.
- Return type
- imagecat.color.linear_to_srgb(data)[source]¶
Convert linear color data to sRGB.
Acessed from https://entropymine.com/imageworsener/srgbformula
- Parameters
data (
numpy.ndarray
, required) – Array of any shape containing linear data to be converted to sRGB.- Returns
converted – Array with the same shape as data containing values in sRGB space.
- Return type
- imagecat.color.srgb_to_linear(data)[source]¶
Convert sRGB data to linear color.
Acessed from https://entropymine.com/imageworsener/srgbformula
- Parameters
data (
numpy.ndarray
, required) – Array of any shape containing sRGB data to be converted to linear.- Returns
converted – Array with the same shape as data containing values in linear space.
- Return type
imagecat.color.basic module¶
Functionality for working with high quality color maps.
- imagecat.color.basic.palette(name, reverse=False)[source]¶
Factory for
imagecat.color.Palette
instances based on a set of high quality color palettes.Currently, the palettes “Blockbody”, “ExtendedBlackbody”, “Kindlmann”, and “ExtendedKindlemann” are supported.
- Parameters
- Returns
palette – Palette with the requested colors.
- Return type
imagecat.color.brewer module¶
Functionality for working with Color Brewer color maps, https://colorbrewer2.org.
- imagecat.color.brewer.linear_map(name, count=None, reverse=False)[source]¶
Warning
function ‘imagecat.color.brewer.linear_map’ undocumented
- imagecat.color.brewer.palette(name, count=None, reverse=False)[source]¶
Factory for
imagecat.color.Palette
instances using Color Brewer 2 palettes.- Parameters
- Returns
palette – Palette with the given color brewer colors.
- Return type
imagecat.data module¶
Functionality for manipulating images and related data structures.
- class imagecat.data.Image(layers=None, metadata=None)[source]¶
Bases:
object
Storage for a multi-layer bitmap image.
An Imagecat
Image
is composed of zero-to-many layers, which are instances ofLayer
. Each layer is named, and all layer names must be unique.- Parameters
layers (
dict
, optional) – Dictionary mappingstr
layer names toLayer
instances that contain the data for each layer. IfNone
(the default), creates an empty (no layers) image.metadata (
dict
, optional) – Arbitrary user-defined metadata for the image. This could be populated by image loaders, modified in operators, and subsets saved by writers. An example of real-world metadata is Cryptomatte information loaded from an EXR file.
See also
- Images
For an in-depth discussion of how images are stored in Imagecat.
- copy(layers=None, metadata=None)[source]¶
return a shallow copy of the image, with optional modifications.
Returns a new instance of
Image
that can be altered without modifying the original. Note that the new image will references the same layers as the original, unless a new set of layers are supplied as an argument.
- match_layer_names(patterns)[source]¶
Return layer names in this image that match the given patterns.
See
match_layer_names()
for a description of the pattern syntax.
- class imagecat.data.Layer(*, data, role=None)[source]¶
Bases:
object
Storage for one layer in a bitmap image.
An Imagecat
Layer
contains the data and metadata that describe a single layer in an ImagecatImage
. This includes the raw data itself, plus an enumerated role that describes the semantic purpose of the layer.- Parameters
data (
numpy.ndarray
, required) – A three dimensional \(M \times N \times C\) array containing the layer data, organized into \(M\) rows in top-to-bottom order, \(N\) columns in left-to-right order, and \(C\) channels. The array dtype should be numpy.float16 for most data, with numpy.float32 and numpy.int32 reserved for special cases such as depth maps and object id maps, respectively.role (
Role
, optional) – Semantic purpose of the layer. IfNone
(the default), the role will default toRole.NONE
.
See also
- Images
For an in-depth discussion of how images are stored in Imagecat.
- copy(data=None, role=None)[source]¶
Return a shallow copy of the layer, with optional modifications.
This method returns a new instance of
Layer
that can be altered without modifying the original. Note that the new layer still references the same data as the original, unless a new data array is supplied as an argument.- Parameters
data (
numpy.ndarray
, optional) – Replaces the existing data array in the new layer, if notNone
(the default).role (
Role
, optional) – Replaces the existing role in the new layer, if notNone
(the default).
- Returns
layer – The new layer instance with modifications.
- Return type
- class imagecat.data.Role(value)[source]¶
Bases:
Enum
Semantic description of how
Layer
data should be interpreted.Because Imagecat allows an image to contain an arbitrary number of layers with arbitray names, and a layer can contain one of many different types of data - not just color information -
Role
is used to indicate how the data in a given layer will be used. The layer role can influence many operations in Imagecat, including visualization and file IO.See also
- Images
For an in-depth discussion of how images are stored in Imagecat.
- ALPHA = 8¶
Layer with one channel of alpha (opacity) information.
- BLUE = 7¶
Layer with one channel of blue color information.
- DEPTH = 11¶
Layer with one channel of depth (distance from viewer) information.
- GREEN = 6¶
Layer with one channel of green color information.
- GREENBLUE = 3¶
Layer with two channels of green-blue color information.
- LUMINANCE = 10¶
Layer with one channel of luminance (intensity) information.
- MATTE = 9¶
Layer with one channel of matte (selection / mask) information.
- NONE = 0¶
General purpose layer with an unknown role and any number of channels.
- NORMAL = 16¶
Layer with three channels of normal vector information.
- RED = 5¶
Layer with one channel of red color information.
- REDBLUE = 4¶
Layer with two channels of red-blue color information.
- REDGREEN = 2¶
Layer with two channels of red-green color information.
- RGB = 1¶
Layer with three channels of red-green-blue color information.
- RGBA = 12¶
Layer with three channels of red-green-blue color and one channel of alpha (opacity) information.
- UV = 13¶
Layer with two channels of texture coordinate information.
- VELOCITY = 15¶
Layer with three channels of velocity information.
- XYZ = 14¶
Layer with three channels of position information.
- imagecat.data.default_font()[source]¶
Path to a default font file included with Imagecat.
- Returns
path – Absolute path to the default Imagecat font.
- Return type
- imagecat.data.from_array(data, role=None, name=None)[source]¶
Warning
function ‘imagecat.data.from_array’ undocumented
- imagecat.data.match_layer_names(names, patterns)[source]¶
Match image layer names against a pattern.
Use this function to implement operators that operate on multiple image layers. patterns is a
str
that can contain multiple whitespace delimited patterns. Patterns can include"*"
which matches everything,"?"
to match a single character,"[seq]"
to match any character in seq, and"[!seq]"
to match any character not in seq.
imagecat.expression module¶
Helper functions providing Imagecat-specific functionality for expression tasks.
The following builtin functions can be used in Imagecat expression tasks:
- imagecat.expression.graph()¶
- imagecat.expression.out(name)¶
- imagecat.expression.res(name)¶
- imagecat.expression.shape(name)¶
- imagecat.expression.builtins(graph)[source]¶
Return a dict containing functions that can be used in expressions.
- Parameters
graph (
graphcat.Graph
, required) – Graph that will contain the expression task to be executed.- Returns
builtins – Dict containing functions that can be used in expressions.
- Return type
imagecat.io module¶
Helpers for implementing Imagecat I/O.
- imagecat.io.loaders = [<function pickle_loader>, <function pil_loader>]¶
List of available loader plugins. In-house plugins may be prepended to this list for use with
imagecat.operator.load()
.
- imagecat.io.openexr_loader(task, path, layers)[source]¶
Image loader plugin for OpenEXR (.exr) files.
Implemented using https://www.excamera.com/sphinx/articles-openexr.html
Use
imagecat.operator.load()
to load images in an Imagecat workflow.
- imagecat.io.openexr_saver(task, image, layers, path)[source]¶
Image saver plugin for OpenEXR (.exr) files.
Implemented using https://www.excamera.com/sphinx/articles-openexr.html
Use
imagecat.operator.save()
to save images in an Imagecat workflow.
- imagecat.io.pickle_loader(task, path, layers)[source]¶
Image loader plugin for Imagecat Pickle (.icp) files.
The .icp format serializes an Imagecat image as a gzip2-compressed Python pickle object. It is primarily used in testing, and is not recommended for general use.
Use
imagecat.operator.load()
to load images in an Imagecat workflow.
- imagecat.io.pickle_saver(task, image, layers, path)[source]¶
Image saver plugin for Imagecat Pickle (.icp) files.
The .icp format serializes an Imagecat image as a gzip2-compressed Python pickle object. It is primarily used in testing, and is not recommended for general use.
Use
imagecat.operator.save()
to save images in an Imagecat workflow.
- imagecat.io.pil_loader(task, path, layers)[source]¶
Image loader plugin that uses Pillow for file I/O.
Loads any file format supported by Pillow, https://pillow.readthedocs.io.
Use
imagecat.operator.load()
to load images in an Imagecat workflow.
- imagecat.io.pil_saver(task, image, layers, path)[source]¶
Image saver plugin that uses Pillow for file I/O.
Saves any file format supported by Pillow, https://pillow.readthedocs.io.
Use
imagecat.operator.save()
to save images in an Imagecat workflow.
- imagecat.io.savers = [<function pickle_saver>, <function pil_saver>]¶
List of available saver plugins. In-house plugins may be prepended to this list for use with
imagecat.operator.save()
.
imagecat.notebook module¶
Integration with Jupyter notebooks, https://jupyter.org
imagecat.operator module¶
Functions that produce, consume, and modify Imagecat images.
- imagecat.operator.delete(graph, name, inputs)[source]¶
Delete layers from an image.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image with layers to be deleted.layers (
str
, optional) – Pattern matching the image layers are deleted. Default: “*”, which deletes all layers.
- Returns
image – A copy of the input image with some layers deleted.
- Return type
- imagecat.operator.load(graph, name, inputs)[source]¶
Load an image from a file.
The file loader plugins in
imagecat.io
are used to load specific file formats. See that module for details, and to write loaders of your own.- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
path (
str
, required) – Filesystem path of the file to be loaded.- Returns
image – Image loaded from the file.
- Return type
- imagecat.operator.merge(graph, name, inputs)[source]¶
Merge multiple images into one.
This operator merges the layers from multiple images into a single image. The images must all have the same resolution. Upstream inputs are merged in order, sorted by input name. Later image layers with duplicate names will overwrite earlier layers. Callers can prevent this by renaming layers upstream with the
rename()
operator.See also
imagecat.operator.transform.composite()
Composites one image over another using a mask.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
every input (
imagecat.data.Image
, optional) – Images to be merged.- Returns
image – New image containing the union of all input layers.
- Return type
- imagecat.operator.remap(graph, name, inputs)[source]¶
Merge and split layers from an image.
- Parameters
graph (Graph, required) – Graphcat graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image containing image layers and channels to be mapped.mapping (
dict
, optional) – Maps existing layers and channels to the output. Default: {}, which returns an empty image.
- Returns
image – A new image containing only the mapped layers and channels.
- Return type
- imagecat.operator.rename(graph, name, inputs)[source]¶
Rename layers within an image.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image containing layers to be renamed.changes (
dict
, optional) – Maps existing names to new names. Default: {}, which does nothing.
- Returns
image – A copy of the input image with some layers renamed.
- Return type
- imagecat.operator.save(graph, name, inputs)[source]¶
Save an image to a file.
The file saver plugins in
imagecat.io
are used to save specific file formats. See that module for details, and to write savers of your own.- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this function, including:
- Named Inputs
image (
imagecat.data.Image
, required) – Image to be saved.path (
str
, required) – Filesystem path of the file to be saved.layers (
str
, optional) – Pattern matching the layers to be saved. Default: ‘*’, which saves all layers.
imagecat.optional module¶
Helpers for implementing optional functionality.
imagecat.operator.blur module¶
Operators for blurring images.
- imagecat.operator.blur.gaussian(graph, name, inputs)[source]¶
Blur an image using a Gaussian kernel.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image containing layer to be blurred.layer (
str
, optional) – Name of the layer to be blurred. Default:None
.sigma ((x, y) tuple, required) – Width of the gaussian kernel in pixels along each dimension.
- Returns
image – A copy of the input image with some layers blurred.
- Return type
imagecat.operator.color module¶
Functions that generate and alter image color.
- imagecat.operator.color.colormap(graph, name, inputs)[source]¶
Convert single-channel layers to RGB layers using a colormap.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image with layer to be color mapped.inlayer (
str
, optional) – image layer to be color mapped. Default:None
.outlayer (
str
, optional) – Name of the output image layer. Default:"C"
.mapping (Python callable, optional) – Mapping function that accepts a shape (rows, columns, 1) array as input and produces an RGB (rows, columns, 3) shaped array as output. If
None
(the default), a linear map with a Color Brewer 2 Blue-Red palette will be used.
- Returns
image – A copy of the input image with some layers mapped.
- Return type
- imagecat.operator.color.dot(graph, name, inputs)[source]¶
Compute the dot product of a
image.data.Layer
and a matrix.This is most commonly used to convert an RGB layer to grayscale, but the operator is capable of converting any depth \(M\) layer to depth \(N\) using an \(M \times N\) matrix. The values in each output channel will be a weighted sum of the input channels, using weights stored in the corresponding matrix column.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image containing layer to be converted.inlayer (
str
, optional) – Layer to be converted. Default: None.outlayer (
str
, optional) – Output layer. Default: “Y”.outrole (
imagecat.data.Role
, optional) – Role for the new layer. Defaults toimagecat.data.role.LUMINANCE
.matrix (\(M \times N\)
numpy.ndarray
matrix, optional) – Matrix controlling how much each input channel contributes to each output channel. Defaults to an RGB-to-grayscale matrix. \(M\) must match the depth of the input layer, and \(N\) must match the expected depth of the output role.
- Returns
image – Image containing the new layer.
- Return type
- imagecat.operator.color.fill(graph, name, inputs)[source]¶
Generate an image with a single solid-color layer.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
layer (
str
, optional) – New layer name. Default: “C”.res ((width, height) tuple, optional) – Resolution of the new image. Default: (256, 256).
role (
imagecat.data.Role
, optional) – Semantic role of the new layer. Default:imagecat.data.Role.RGB
.values (sequence of values, optional) – Values for the new layer. The number of values must be appropriate for role. Default: [1, 1, 1].
- Returns
image – New image with a single solid-color layer.
- Return type
imagecat.operator.cryptomatte module¶
Functionality for working with Cryptomattes, see https://github.com/Psyop/Cryptomatte.
- imagecat.operator.cryptomatte.decoder(graph, name, inputs)[source]¶
Extract matte(s) from an image containing Cryptomatte data.
- Parameters
graph (Graph, required) – Graphcat graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
clown (
bool
, optional) – IfTrue
, extract a clown matte containing a unique color for the ID that has the greatest coverage in a given pixel. Default:False
image (
imagecat.data.Image
, required) – Image containing Cryptomatte data to be decoded.layer (
str
, optional) – Output matte layer name. Default: “M”.mattes (
list
ofstr
, optional) – List of mattes to extract. The output will contain the union of all the given mattes. Default: [], which returns an empty matte.cryptomatte (
str
, optional) – Name of the Cryptomatte to extract. Use this parameter to control which Cryptomatte to use, for images that contain multiple Cryptomattes. Default:None
, which will match one Cryptomatte or raise an exception if there is more than one.
- Returns
matte – The extracted matte.
- Return type
imagecat.operator.noise module¶
Operators that generate images containing noise.
- imagecat.operator.noise.uniform(graph, name, inputs)[source]¶
Generate an image containing random values drawn from a uniform distribution.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
high (number, optional) – Highest value in the generated noise. Default: 1.
layer (
str
, optional) – Name of the layer to be created. Default: ‘Y’.low (number, optional) – Lowest value for the generated noise. Default: 0.
role (
imagecat.data.Role
, optional) – Role for the layer to be created. Default:imagecat.data.Role.LUMINANCE
.seed (
int
, optional) – Random seed for the random noise function. Default: 1234.res ((width, height) tuple, optional) – Resolution of the new image along each dimension. Default: [256, 256].
- Returns
image – New image with one layer containing uniform noise.
- Return type
imagecat.operator.render module¶
Functions that generate new image data.
- imagecat.operator.render.text(graph, name, inputs)[source]¶
Generate an image containing text.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
anchor (
str
, optional) – Anchor point for text placement, defined at https://pillow.readthedocs.io/en/latest/handbook/text-anchors.html#text-anchors. Defaults to “mm”.fontindex (integer, optional) – Index of the font to use within a multi-font file. Defaults to 0.
fontname (
str
, optional) – Path to a font file. Defaults toimagecat.data.default_font()
.fontsize (Size of the rendered font, optional) – Default: “0.33h”, which is one-third the height of the output image.
layer (
str
, optional) – Name of the generated layer. Default: [“A”].position ((x, y) tuple, optional) – Position of the text anchor relative to the output image. Default: [“0.5w”, “0.5h”], which is centered vertically and horizontally.
res ((width, height) tuple, optional) – Resolution of the output image. Default: [256, 256].
string (
str
, optional) – String to be rendered. Default: “Text”.
- Returns
image – New image containing rendered text.
- Return type
imagecat.operator.transform module¶
Operators that modify images by transforming content.
- imagecat.operator.transform.composite(graph, name, inputs)[source]¶
Composite foreground and background layers using a mask and optional transformation.
- Parameters
graph (Graph, required) – Graph that owns this task.
name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
background (
imagecat.data.Image
, required) – Image containing the background layer.bglayer (
str
, optional) – Name of the background layer. Defaults toNone
.fglayer (
str
, optional) – Name of the foreground layer. Defaults toNone
.foreground (
imagecat.data.Image
, required) – Image containing the foreground layer.layer (
str
, optional) – Name of the output image layer. Defaults to the value of bglayer.mask (
imagecat.data.Image
, optional) – Image containing the foreground layer mask. If omitted, the foreground layer is assumed to be 100% opaque.masklayer (
str
, optional) – Name of the mask layer. Defaults toNone
.orientation (number, optional) – Rotation of the foreground layer for the composition. Default: 0.
pivot ((x, y) tuple, optional) – Position of the foreground pivot point. All rotation and positioning is relative to this point. Default: [“0.5w”, “0.5h”], which is centered on the foreground.
position ((x, y) tuple, optional) – Position of the foreground layer over the background layer. All rotation and positioning is relative to the pivot point. Default: [“0.5w”, “0.5h”], which is centered on the background.
- Returns
image – New image with a single solid-color layer.
- Return type
- imagecat.operator.transform.offset(graph, name, inputs)[source]¶
Offset layers in an image.
- Parameters
graph (
graphcat.Graph
, required) – Graph that owns this task.name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image containing layers to be offset.layers (
str
, optional) – Pattern matching the layers to be offset. Default: ‘*’, which offsets all layers.offset ((x, y) tuple, required) – Distance to offset layers along each dimension.
- Returns
image – A copy of the input image with some layers offset.
- Return type
- imagecat.operator.transform.resize(graph, name, inputs)[source]¶
Resize an image to a new resolution.
- Parameters
graph (
graphcat.Graph
, required) – Graph that owns this task.name (hashable object, required) – Name of the task executing this function.
inputs (Named Inputs, required) – Inputs for this operator.
- Named Inputs
image (
imagecat.data.Image
, required) – Image to be resized.order (
int
, optional) – Resampling filter order. Default: ‘3’ for bicubic resampling.res ((width, height) tuple, optional) – New resolution of the image along each dimension.
- Returns
image – A copy of the input image that has been resized.
- Return type
imagecat.operator.util module¶
Functions that produce, consume, and modify Imagecat images.
- imagecat.operator.util.array(ndim=None, shape=None, dtype=None)[source]¶
Factory for parameter converters that return arrays.
- Parameters
ndim (integer, optional) – Raise exceptions if the number of value dimensions don’t match.
shape (integer or tuple of integers, optional) – Raise exceptions if the value shape doesn’t match.
dtype (
numpy.dtype
, optional) – If specified, the returned array will be coerced to the given dtype.
- Returns
converter – Callable that takes a single value as input and produces a
numpy.ndarray
as output.- Return type
callable
- imagecat.operator.util.log_result(log, name, operation, output, **parameters)[source]¶
Standard logging output for operators when they’re executed.
- imagecat.operator.util.optional_image(name, inputs, input)[source]¶
Extract an optional image from task inputs.
- Parameters
name (hashable object, required) – The name of the task being executed.
inputs (Named Inputs, required) – Named inputs containing task function arguments.
input (hashable object, required) – Name of the optional input image.
- Raises
RuntimeError – If inputs contains input, but it isn’t a
imagecat.data.Image
.- Returns
image – The optional image from inputs.
- Return type
class:imagecat.data.Image or
None
- imagecat.operator.util.optional_input(name, inputs, input, *, type=None, default=None)[source]¶
Extract an optional parameter from task inputs.
- Parameters
name (hashable object, required) – The name of the task being executed.
inputs (Named Inputs, required) – Named inputs containing task function arguments.
input (hashable object, required) – Name of the input parameter.
type (callable, optional) – Function for testing / converting the parameter value.
default (Any python object, optional) – Default value that will be returned if inputs doesn’t contain input.
- Returns
parameter – The optional parameter from inputs, or the default value.
- Return type
Any python object.
- imagecat.operator.util.optional_layer(name, inputs, input, *, layer=None, role=None, depth=None, dtype=None)[source]¶
Extract an optional layer from task inputs.
- Parameters
name (hashable object, required) – The name of the task being executed.
inputs (Named Inputs, required) – Named inputs containing task function arguments.
input (hashable object, required) – Name of the optional input image.
layer (
str
, optional) – The name of the optional layer. IfNone
(the default) and the image only contains one layer, use it.role (
imagecat.data.Role
, optional) – If specified, the layer must have a matching role.depth (int, optional) – If specified, the layer must have a matching depth (number of channels).
dtype (
numpy.dtype
, optional) – If specified, the layer must have a matching dtype.
- Returns
layer (
imagecat.data.Layer
orNone
) – The matching layer.
- imagecat.operator.util.require_image(name, inputs, input)[source]¶
Extract an image from task inputs.
- Parameters
name (hashable object, required) – The name of the task being executed.
inputs (Named Inputs, required) – Named inputs containing task function arguments.
input (hashable object, required) – Name of the required input image.
- Raises
RuntimeError – If inputs doesn’t contain the required input.
- Returns
image – The required image from inputs.
- Return type
class:imagecat.data.Image
- imagecat.operator.util.require_input(name, inputs, input, *, type=None)[source]¶
Extract a parameter from task inputs.
- Parameters
name (hashable object, required) – The name of the task being executed.
inputs (Named Inputs, required) – Named inputs containing task function arguments.
input (hashable object, required) – Name of the required input parameter.
type (callable, optional) – Function for testing / converting the type of the input parameter value.
- Raises
RuntimeError – If inputs doesn’t contain the required input.
- Returns
parameter – The required parameter from inputs.
- Return type
Any python object.
- imagecat.operator.util.require_layer(name, inputs, input, *, layer=None, role=None, depth=None, dtype=None)[source]¶
Extract a layer from task inputs.
- Parameters
name (hashable object, required) – The name of the task being executed.
inputs (Named Inputs, required) – Named inputs containing task function arguments.
input (hashable object, required) – Name of the required input image.
layer (
str
, optional) – The name of the required layer. IfNone
(the default) and the image only contains one layer, use it.role (
imagecat.data.Role
, optional) – If specified, the layer must have a matching role.depth (int, optional) – If specified, the layer must have a matching depth (number of channels).
dtype (
numpy.dtype
, optional) – If specified, the layer must have a matching dtype.
- Raises
RuntimeError – If a layer matching all of the criteria can’t be found.
- Returns
layername (
str
) – The name of the matching layer.layer (
imagecat.data.Layer
) – The matching layer.
- imagecat.operator.util.transform(source, target_shape, *, pivot, position, orientation, scale, order)[source]¶
Transform an image using an affine transformation.
- Parameters
source (
numpy.ndarray
, required) – Image to be transformed.target_shape (2-tuple of integers, required) – Desired output image size, as a
(rows, cols)
tuple. Note that this does not have to match the size of the source image. By default, the source image will be centered in the output, cropped if necessary.pivot (2-tuple of numbers, required) – Location of the point on the source image around which scaling and rotation takes place.
orientation (number, required) – Rotation of the source around its pivot point, in degrees. Positive angles lead to counter-clockwise rotation.
position (2-tuple of numbers, required) – Position of the image pivot point relative to target_shape.
scale (2-tuple of numbers, required) – Scale of the source image around its pivot point.
- Returns
rowoffset (integer) – Vertical offset of the returned array relative to the upper-left corner of target_shape
coloffset (integer) – Horizontal offset of the returned array relative to the upper-left corner of target_shape
image (
numpy.ndarray
) – The transformed image.
imagecat.require module¶
Functionality for testing preconditions and assertions.
- imagecat.require.loaded_module(modules)[source]¶
Function decorator that tests whether module(s) have already been loaded.
- Parameters
modules (
str
or sequence ofstr
, required) – Names of the modules that must already be loaded for the wrapped function to execute.- Raises
RuntimeError – If any module in modules isn’t already loaded.
imagecat.units module¶
Functionality for performing unit conversions.
- imagecat.units.length(value, size, default='px')[source]¶
Convert a length value to pixels.
Supported unit abbreviations include:
- “px”, “pixel”, “pixels”
absolute length in pixels
- “w”, “width”
relative length, as a fraction of the width of an image
- “h”, “height”
relative length, as a fraction of the height of an image
- “min”
relative length, as a fraction of the smaller of width and height
- “max”
relative length, as a fraction of the larger of width and height
Relative lengths will be relative to some reference that is context-specific and documented. For example: the text operator fontsize is relative to the size of the output image.
- Parameters
value (number,
str
or (number,str
) tuple, required) – Value to be converted. The value may be a number (in which case the default parameter will specify the unit of measure), astr
containing a number and unit abbreviation, or a (value, units) tuple.size ((width, height) tuple, required) – Reference width and height for use when the caller specifies a relative unit of measure. Note that width and height must be specified in pixels.
default (
str
, optional) – Default unit of measure to use when value is a plain number.
- Returns
value – value converted to pixel units. Note that the result is a floating-point number, so callers may need to convert to an int if they are intend to e.g. specifying the resolution of an image.
- Return type
number

Compatibility¶
A quick disclaimer on backwards-compatibility for Imagecat users:
Imagecat follows the Semantic Versioning standard for assigning version numbers in a way that has specific meaning. As of this writing Imagecat releases are still in the 0.y.z development phase, which means (among other things) that the API may change at any time. We try not to be abusive about it, but you should be prepared for the occasional bump on the road to the 1.0 release.

Release Notes¶
Imagecat 0.7.0 - November 21, 2022¶
Make it easier to manage optional functionality.
Simplify creating images from numpy arrays.
Switch to pyproject.toml for packaging and flit for builds.
Cleanup and organize documentation.
Imagecat 0.6.1 - October 21, 2021¶
Make it easier to display single-layer images in Jupyter notebooks.
Updated the way we collect code coverage data.
Switched from Zulip to Github Discussions for support.
Imagecat 0.6.0 - October 13, 2021¶
PIL reader didn’t handle luma-only images correctly.
Incorporate platform-specific regression test reference images.
Reorganize and streamline the documentation.
Switch from Travis-CI to GitHub Actions for continuous integration.
Clarify where named inputs are documented.
Imagecat 0.5.0 - March 19, 2021¶
Cryptomatte operator works with a wider range of files, and better matches the behavior of other implementations.
Added an option to extract clown mattes from the Cryptomatte operator, with caller control over which mattes to include.
Missing dependencies cause failures at run time instead of import time.
Replaced the rgb2gray operator with dot, which can created weighted combinations of layers with any depth.
Added new layer roles for RGBA, matte, luminance, depth, UV, position, velocity, and normal data, and subsets of RGB channels.
Substantial reorganization and cleanup of the documentation.
Imagecat 0.4.0 - December 9, 2020¶
Initial support for storing image metadata.
OpenEXR loader imports metadata.
imagecat.notebook.display() dynamically renders image layers using IPython widgets.
Added new imagecat.data.Role enumerations for varying subsets of RGB, alpha, matte, luminance, and depth data.
Added imagecat.operator.remap() for creating new images from arbitrary combinations of existing layers and components.
Added support for Cryptomatte decoding.
imagecat.data.Layer supports Jupyter rich output.
Expanded / cleaned-up the documentation.
Substantial reorganization of operators into separate modules.
Removed support for explicit layer component names.
Imagecat 0.3.0 - December 4, 2020¶
Add support for categorical color maps.
Added optional parameters to control the output range of imagecat.operator.uniform().
Updated the implementation for compatibility with graphcat >= 0.10.0.
Dramatically improved performance for imagecat.operator.composite().
OpenEXR loader generates simplified output.
Imagecat 0.2.0 - November 23, 2020¶
Move functionality for image conversion to the imagecat.data module.
Add scaling support to imagecat.operator.composite().
Add control over the reconstruction kernel in imagecat.operator.composite().
Made the mask input optional for imagecat.operator.composite().
Imagecat 0.1.0 - November 13, 2020¶
Initial Release.

Support¶
The Imagecat documentation:
Visit our GitHub repository for access to source code, test results, issue tracker, and the wiki:
Our coverage statistics are updated automatically when modifications are committed:
For Imagecat questions, comments, or suggestions, get in touch with the team at:
Otherwise, you can contact Tim directly:
Timothy M. Shead - tim@shead-custom-design

Credits¶
Included in Imagecat¶
Cynthia A. Brewer, “ColorBrewer: Color Advice for Maps,” http://colorbrewer2.org, accessed October, 2014.
Tyler Finck, “League Spartan” TrueType font https://github.com/theleagueof/league-spartan:
Copyright (c) 2016-2020, Tyler Finck <hi@tylerfinck.com>
Copyright (c) 2014, Micah Rich <micah@micahrich.com>,
with Reserved Font Name: "League Spartan".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
Version 1.1 - 26 February 2007
Jason Summers, “A close look at the sRGB formula” https://entropymine.com/imageworsener/srgbformula, accessed November, 2020.