ImageBufAlgo: Image Processing#
ImageBufAlgo is a set of image processing functions that operate on
ImageBuf’s. The functions are declared in the header file
OpenImageIO/imagebufalgo.h
and are declared in the
namespace ImageBufAlgo
.
ImageBufAlgo common principles#
This section explains the general rules common to all ImageBufAlgo functions. Only exceptions to these rules will be explained in the subsequent listings of all the individual ImageBufAlgo functions.
Return values and error messages#
Most ImageBufAlgo functions that produce image data come in two forms:
Return an ImageBuf.
The return value is a new ImageBuf containing the result image. In this case, an entirely new image will be created to hold the result. In case of error, the result image returned can have any error conditions checked with
has_error()
andgeterror()
.// Method 1: Return an image result ImageBuf dst = ImageBufAlgo::over (fg, bg); if (dst.has_error()) std::cout << "error: " << dst.geterror() << "\n";
# Method 1: Return an image result dst = ImageBufAlgo.over(fg, bg) if dst.has_error: print("error:", dst.geterror())
Pass a destination ImageBuf reference as the first parameter.
The function is passed a destination ImageBuf where the results will be stored, and the return value is a
bool
that istrue
if the function succeeds orfalse
if the function fails. Upon failure, the destination ImageBuf (the one that is being altered) will have an error message set.// Method 2: Write into an existing image ImageBuf dst; // will be the output image bool ok = ImageBufAlgo::over (dst, fg, bg); if (! ok) std::cout << "error: " << dst.geterror() << "\n";
# Method 2: Write into an existing image dst = ImageBuf() # will be the output image ok = ImageBufAlgo.over(dst, fg, bg) if not ok: print("error:", dst.geterror())
The first option (return an ImageBuf directly) is a more compact and
intuitive notation that is natural for most simple uses. But the second
option (pass an ImageBuf&
referring to an existing destination) offers
additional flexibility, including more careful control over allocations, the
ability to partially overwrite regions of an existing image, and the ability
for the destination image to also be one of the input images (for example,
add(A,A,B)
adds B into existing image A, with no third image allocated at
all).
For a small minority of ImageBufAlgo functions, there are only input images,
and no image outputs (e.g., isMonochrome()
). In such cases, the error
message should be retrieved from the first input image.
Region of interest#
Most ImageBufAlgo functions take an optional ROI parameter that restricts
the operation to a range in x, y, z, and channels. The default-constructed
ROI (also known as ROI::All()
) means no region restriction – the whole
image will be copied or altered.
For ImageBufAlgo functions that write into a destination ImageBuf parameter and it is already initialized (i.e. allocated with a particular size and data type), the operation will be performed on the pixels in the destination that overlap the ROI, leaving pixels in the destination which are outside the ROI unaltered.
For ImageBufAlgo functions that return an ImageBuf directly, or if their
dst
parameter is an uninitialized ImageBuf, the ROI (if set) determines
the size of the result image. If the ROI is the default All
, the result
image size will be the union of the pixel data windows of the input images
and have a data type determined by the data types of the input images.
Most ImageBufAlgo functions also respect the chbegin
and chend
members
of the ROI, thus restricting the channel range on which the operation is
performed. The default ROI constructor sets up the ROI to specify that the
operation should be performed on all channels of the input image(s).
Constant and per-channel values#
Many ImageBufAlgo functions take per-channel constant-valued arguments (for
example, a fill color). These parameters are passed as cspan<float>
. These
are generally expected to have length equal to the number of channels. But
you may also pass a single float which will be used as the value for all
channels. (More generally, what is happening is that the last value supplied
is replicated for any missing channel.)
Some ImageBufAlgo functions have parameters of type Image_or_Const
, which
may take either an ImageBuf reference, or a per-channel constant, or a
single constant to be used for all channels.
Multithreading#
All ImageBufAlgo functions take an optional nthreads
parameter that
signifies the maximum number of threads to use to parallelize the
operation. The default value for nthreads
is 0, which signifies
that the number of thread should be the OIIO global default set by
OIIO::attribute()
(see Section Global Attributes), which
itself defaults to be the detected level of hardware concurrency (number
of cores available).
Generally you can ignore this parameter (or pass 0), meaning to use all the cores available in order to perform the computation as quickly as possible. The main reason to explicitly pass a different number (generally 1) is if the application is multithreaded at a high level, and the thread calling the ImageBufAlgo function just wants to continue doing the computation without spawning additional threads, which might tend to crowd out the other application threads.
Pattern generation#
For the ImageBufAlgo functions in this section, there is no “source” image.
Therefore, either an initialized dst
must be supplied (to give a pre-
allocated size and data type of the image), or else it is strictly necessary
to supply an ROI parameter to specify the size of the new image (the data
type in this case will always be float
). It is an error if one of the
pattern generation ImageBufAlgo functions is neither supplied a
pre-allocated dst
nor a non-default ROI.
zero() – create a black image#
-
ImageBuf OIIO::ImageBufAlgo::zero(ROI roi, int nthreads = 0)#
Create an all-black
float
image of size and channels as described by the ROI.
Result-as-parameter version:
Examples:
// Create a new 3-channel, 512x512 float image filled with 0.0 values. ImageBuf zero = ImageBufAlgo::zero (ROI(0,512,0,512,0,1,0,3)); // Zero out an existing buffer, keeping it the same size and data type ImageBufAlgo::zero (A); // Zero out just the green channel, leave everything else the same ROI roi = B.roi (); roi.chbegin = 1; // green roi.chend = 2; // one past the end of the channel region ImageBufAlgo::zero (B, roi); // Zero out a rectangular region of an existing buffer ImageBufAlgo::zero (C, ROI (0, 100, 0, 100));# Create a new 3-channel, 512x512 float image filled with 0.0 values. zero = ImageBufAlgo.zero(ROI(0, 512, 0, 512, 0, 1, 0, 3)) # Zero out an existing buffer, keeping it the same size and data type ImageBufAlgo.zero(A) # Zero out just the green channel, leave everything else the same roi = B.roi roi.chbegin = 1 # green roi.chend = 2 # one past the end of the channel region ImageBufAlgo.zero(B, roi) # Zero out a rectangular region of an existing buffer ImageBufAlgo.zero(C, ROI(0, 100, 0, 100))# Create a new 3-channel, 512x512 float image filled with 0.0 values. oiiotool --create 512x512 3 -d float -o out.exr # Zero out an existing image, keeping it the same size and data type. # For simplicity, just scale all values by 0.0 oiiotool in.exr --mulc 0.0 -o out.exr # Zero out just the green channel, leave everything else the same. # Again, rely on --mulc to scale the channels oiiotool in.exr --mulc 1,0,1 -o out.exr # Zero out a rectangular region of an existing image oiiotool in.exr --fill:color=0,0,0 100x100+0+0 -o out.exr
fill() – fill a region with a solid color or gradient#
- group fill
Fill an image region with given channel values, either returning a new image or altering the existing
dst
image within the ROI. Note that the values arrays start with channel 0, even if the ROI indicates that a later channel is the first to be changed.Three varieties of fill() exist: (a) a single set of channel values that will apply to the whole ROI, (b) two sets of values that will create a linearly interpolated gradient from top to bottom of the ROI, (c) four sets of values that will be bilinearly interpolated across all four corners of the ROI.
Examples:
// Create a new 640x480 RGB image, with a top-to-bottom gradient // from red to pink float pink[3] = { 1, 0.7, 0.7 }; float red[3] = { 1, 0, 0 }; ImageBuf A = ImageBufAlgo::fill(red, cspan<float>(pink), ROI(0, 640, 0, 480, 0, 1, 0, 3)); // Draw a filled red rectangle overtop existing image A. ImageBufAlgo::fill (A, cspan<float>(red), ROI(50, 100, 75, 175));# Create a new 640x480 RGB image, with a top-to-bottom gradient # from red to pink pink = (1, 0.7, 0.7) red = (1, 0, 0) A = ImageBufAlgo.fill(top=red, bottom=pink, roi=ROI(0, 640, 0, 480, 0, 1, 0, 3)) # Draw a filled red rectangle overtop existing image A. ImageBufAlgo.fill(A, red, ROI(50, 100, 75, 175))# Create a new 640x480 RGB image, with a top-to-bottom gradient # from red to pink oiiotool --pattern fill:top=1,0.7,0.7:bottom=1,0,0 640x480 3 -o A.exr # Draw a filled red rectangle overtop existing image A.exr oiiotool A.exr --pattern fill:color=1,0,0 25x75 3 --paste +50+100 -o A.exr
checker() – make a checker pattern#
-
ImageBuf OIIO::ImageBufAlgo::checker(int width, int height, int depth, cspan<float> color1, cspan<float> color2, int xoffset, int yoffset, int zoffset, ROI roi, int nthreads = 0)#
Create a checkerboard pattern of size given by
roi
, with origin given by theoffset
values, checker size given by thewidth
,height
,depth
values, and alternating betweencolor1[]
andcolor2[]
. The pattern is defined in abstract “image space” independently of the pixel data window ofdst
or the ROI.
Result-as-parameter version:
Examples:
// Create a new 640x480 RGB image, fill it with a two-toned gray // checkerboard, the checkers being 64x64 pixels each. ImageBuf A(ImageSpec(640, 480, 3, TypeDesc::FLOAT)); float dark[3] = { 0.1, 0.1, 0.1 }; float light[3] = { 0.4, 0.4, 0.4 }; ImageBufAlgo::checker(A, 64, 64, 1, cspan<float>(dark), cspan<float>(light), 0, 0, 0);# Create a new 640x480 RGB image, fill it with a two-toned gray # checkerboard, the checkers being 64x64 pixels each. A = ImageBuf(ImageSpec(640, 480, 3, "float")) dark = (0.1, 0.1, 0.1) light = (0.4, 0.4, 0.4) A = ImageBufAlgo.checker(64, 64, 1, dark, light, roi=ROI(0, 640, 0, 480, 0, 1, 0, 3))# Create a new 640x480 RGB image, fill it with a two-toned gray # checkerboard, the checkers being 64x64 pixels each. oiiotool --pattern checker:width=64:color1=0.1,0.1,0.1:color2=0.4,0.4,0.4 640x480 3 -o A.exr
Noise patterns#
-
ImageBuf OIIO::ImageBufAlgo::noise(string_view noisetype, float A = 0.0f, float B = 0.1f, bool mono = false, int seed = 0, ROI roi = {}, int nthreads = 0)#
Return an image of “noise” in every pixel and channel specified by the roi. There are several noise types to choose from, and each behaves differently and has a different interpretation of the
A
andB
parameters:“gaussian” adds Gaussian (normal distribution) noise values with mean value A and standard deviation B.
”white” adds independent uniformly distributed values on range [A,B).
”uniform” (synonym for “white”)
”blue” adds “blue noise” uniformly distributed on range [A,B) but not independent; rather, they are chosen for good spectral properties for sampling and dither.
”salt” changes to value A a portion of pixels given by B.
If the
mono
flag is true, a single noise value will be applied to all channels specified byroi
, but ifmono
is false, a separate noise value will be computed for each channel in the region.The random number generator is actually driven by a hash on the “image
space” coordinates and channel, independently of the pixel data window of
dst
or the ROI. Choosing different seed values will result in a different pattern, but for the same seed value, the noise at a given pixel coordinate (x,y,z) channel c will is completely deterministic and repeatable.
Result-as-parameter version:
Examples:
// Create a new 256x256 field of grayscale white noise on [0,1) ImageBuf A = ImageBufAlgo::noise ("uniform", 0.0f /*min*/, 1.0f /*max*/, true /*mono*/, 1 /*seed*/, ROI(0,256,0,256,0,1,0,3)); // Create a new 256x256 field of grayscale white noise on [0,1) ImageBuf B = ImageBufAlgo::noise ("blue", 0.0f /*min*/, 1.0f /*max*/, true /*mono*/, 1 /*seed*/, ROI(0,256,0,256,0,1,0,3)); // Add color Gaussian noise to an existing image ImageBuf C ("tahoe.tif"); ImageBufAlgo::noise (C, "gaussian", 0.0f /*mean*/, 0.1f /*stddev*/, false /*mono*/, 1 /*seed*/); // Use salt and pepper noise to make occasional random dropouts ImageBuf D ("tahoe.tif"); ImageBufAlgo::noise (D, "salt", 0.0f /*value*/, 0.01f /*portion*/, true /*mono*/, 1 /*seed*/);# Create a new 256x256 field of grayscale white noise on [0,1) A = ImageBufAlgo.noise("uniform", A=0.0, B=1.0, mono=True, seed=1, roi=ROI(0, 256, 0, 256, 0, 1, 0, 3)) # Create a new 256x256 field of grayscale blue noise on [0,1) B = ImageBufAlgo.noise("blue", A=0.0, B=1.0, mono=True, seed=1, roi=ROI(0, 256, 0, 256, 0, 1, 0, 3)) # Add color Gaussian noise to an existing image C = ImageBuf("tahoe.tif") ImageBufAlgo.noise(C, "gaussian", A=0.0, B=0.1, mono=False, seed=1) # Use salt and pepper noise to make occasional random dropouts D = ImageBuf("tahoe.tif") ImageBufAlgo.noise(D, "salt", A=0.0, B=0.01, mono=True, seed=1)# Create a new 256x256 field of grayscale white noise on [0,1) oiiotool --pattern noise:type=uniform:mono=1:seed=1 256x256 3 -o A.exr # Create a new 256x256 field of grayscale blue noise on [0,1) oiiotool --pattern noise:type=blue:mono=1:seed=1 256x256 3 -o B.exr # Add color Gaussian noise to an existing image oiiotool tahoe.jpg --noise:type=gaussian:stddev=0.1 -o C.exr # Use salt and pepper noise to make occasional random dropouts oiiotool tahoe.jpg --noise:type=salt:value=0:portion=0.01:mono=1 -o D.exr
-
const ImageBuf &OIIO::ImageBufAlgo::bluenoise_image()#
Return a const reference to a periodic bluenoise texture with float data in 4 channels that are uncorrelated to each other. Note that unlike most other ImageBufAlgo functions, it does not return an ImageBuf by value, but by const reference.
Example:
const ImageBuf& A = ImageBufAlgo::bluenoise_image();A = ImageBufAlgo.bluenoise_image()
Drawing shapes: points, lines, boxes#
-
bool OIIO::ImageBufAlgo::render_point(ImageBuf &dst, int x, int y, cspan<float> color = 1.0f, ROI roi = {}, int nthreads = 0)#
Render a single point at (x,y) of the given color “over” the existing image
dst
. If there is no alpha channel, the color will be written unconditionally (as if the alpha is 1.0).
Examples:
ImageBuf A (ImageSpec (640, 480, 4, TypeDesc::FLOAT)); float red[4] = { 1, 0, 0, 1 }; ImageBufAlgo::render_point (A, 50, 100, red);A = ImageBuf(ImageSpec(640, 480, 4, "float")) red = (1, 0, 0, 1) ImageBufAlgo.render_point(A, 50, 100, red)oiiotool A.exr -point:color=1,0,0,1 50,100 -o out.exr
-
bool OIIO::ImageBufAlgo::render_line(ImageBuf &dst, int x1, int y1, int x2, int y2, cspan<float> color = 1.0f, bool skip_first_point = false, ROI roi = {}, int nthreads = 0)#
Render a line from pixel (
x1
,y1
) to (x2
,y2
) intodst
, doing an “over” of the color (if it includes an alpha channel) onto the existing data indst
. Thecolor
should include as many values asroi.chend-1
. The ROI can be used to limit the pixel area or channels that are modified, and default to the entirety ofdst
. Ifskip_first_point
istrue
, the first point (x1
,y1
) will not be drawn (this can be helpful when drawing poly-lines, to avoid double-rendering of the vertex positions).
Examples:
ImageBuf A (ImageSpec (640, 480, 4, TypeDesc::FLOAT)); float red[4] = { 1, 0, 0, 1 }; ImageBufAlgo::render_line (A, 10, 60, 250, 20, red); ImageBufAlgo::render_line (A, 250, 20, 100, 190, red, true);A = ImageBuf(ImageSpec(640, 480, 4, "float")) red = (1, 0, 0, 1) ImageBufAlgo.render_line(A, 10, 60, 250, 20, red) ImageBufAlgo.render_line(A, 250, 20, 100, 190, red, True)oiiotool A.exr -line:color=1,0,0,1 10,60,20,100 -o out.exr
-
bool OIIO::ImageBufAlgo::render_box(ImageBuf &dst, int x1, int y1, int x2, int y2, cspan<float> color = 1.0f, bool fill = false, ROI roi = {}, int nthreads = 0)#
Render a filled or unfilled box with corners at pixels (
x1
,y1
) and (x2
,y2
) intodst
, doing an “over” of the color (if it includes an alpha channel) onto the existing data indst
. Thecolor
must include as many values asroi.chend-1
. The ROI can be used to limit the pixel area or channels that are modified, and default to the entirety ofdst
. Iffill
istrue
, the box will be completely filled in, otherwise only its outlien will be drawn.
Examples:
ImageBuf A (ImageSpec (640, 480, 4, TypeDesc::FLOAT)); float cyan[4] = { 0, 1, 1, 1 }; float yellow_transparent[4] = { 0.5, 0.5, 0, 0.5 }; ImageBufAlgo::render_box (A, 150, 100, 240, 180, cyan); ImageBufAlgo::render_box (A, 100, 50, 180, 140, yellow_transparent, true);A = ImageBuf(ImageSpec(640, 480, 4, "float")) cyan = (0, 1, 1, 1) yellow_transparent = (0.5, 0.5, 0, 0.5) ImageBufAlgo.render_box(A, 150, 100, 240, 180, cyan) ImageBufAlgo.render_box(A, 100, 50, 180, 140, yellow_transparent, fill=True)oiiotool A.exr -box:color=0,1,1,1 150,100,240,180 \ -box:color=0.5,0.5,0,0.5 100,50,180,140 -o out.exr
Drawing text#
-
bool OIIO::ImageBufAlgo::render_text(ImageBuf &dst, int x, int y, string_view text, int fontsize = 16, string_view fontname = "", cspan<float> textcolor = 1.0f, TextAlignX alignx = TextAlignX::Left, TextAlignY aligny = TextAlignY::Baseline, int shadow = 0, ROI roi = {}, int nthreads = 0)#
Render a text string (encoded as UTF-8) into image
dst
. If thedst
image is not yet initialized, it will be initialized to be a black background exactly large enough to contain the rasterized text. Ifdst
is already initialized, the text will be rendered into the existing image by essentially doing an “over” of the character into the existing pixel data.Note that any named fonts (if not a full pathname) will search for the fonts in the following places: (a) any directories named in the global “font_searchpath” attribute or the
$OPENIMAGEIO_FONTS
environment variable; (b) any font-related subdirectories (fonts
,Fonts
,share/fonts
, orLibrary/Fonts
) underneath the directories in environment variables$HOME
,$SystemRoot
,$OpenImageIO_ROOT
; (c) a number of common system font areas, including/usr/share/fonts
,/Library/fonts
, andC:/Windows/fonts
; (d) in fonts directories one level up from the place where the currently running binary lives.- Parameters:
dst – Destination ImageBuf — text is rendered into this image.
x/y – The position to place the text.
text – The text to draw. Linefeed (
\n
) characters are respected as indications that the text spans multiple rows.fontsize/fontname – Size and name of the font. If the name is not a full pathname to a font file, it will search for a matching font, defaulting to some reasonable system font if not supplied at all), and with a nominal height of fontsize (in pixels).
textcolor – Color for drawing the text, defaulting to opaque white (1.0,1.0,…) in all channels if not supplied. If provided, it is expected to point to a float array of length at least equal to
R.spec().nchannels
, or defaults will be chosen for you).alignx/aligny – The default behavior is to align the left edge of the character baseline to (
x
,y
). Optionally,alignx
andaligny
can override the alignment behavior, with horizontal alignment choices of TextAlignX::Left, Right, and Center, and vertical alignment choices of Baseline, Top, Bottom, or Center.shadow – If nonzero, a “drop shadow” of this radius will be used to make the text look more clear by dilating the alpha channel of the composite (makes a black halo around the characters).
Examples:
ImageBufAlgo::render_text(ImgA, 50, 100, "Hello, world"); float red[] = { 1, 0, 0, 1 }; ImageBufAlgo::render_text(ImgA, 100, 200, "Go Big Red!", 60, "" /*font name*/, cspan<float>(red)); float white[] = { 1, 1, 1, 1 }; ImageBufAlgo::render_text(ImgB, 320, 240, "Centered", 60, "" /*font name*/, cspan<float>(white), ImageBufAlgo::TextAlignX::Center, ImageBufAlgo::TextAlignY::Center);ImageBufAlgo.render_text(ImgA, 50, 100, "Hello, world") red = (1, 0, 0, 1) ImageBufAlgo.render_text(ImgA, 100, 200, "Go Big Red!", fontsize=60, fontname="", textcolor=red) white = (1, 1, 1, 1) ImageBufAlgo.render_text(ImgB, 320, 240, "Centered", fontsize=60, fontname="", textcolor=white, alignx="center", aligny="center")oiiotool ImgA.exr --text:x=50:y=100 "Hello, world" \ --text:x=100:y=200:fontsize=60:fontname="Arial Bold":color=1,0,0,1 "Go Big Red!" \ -o out.exr oiiotool ImgB.exr \ --text:x=320:y=240:fontsize=60:fontname="Arial Bold":color=1,1,1,1:alignx=center:aligny=center "Centered" \ -o out.exr
-
ROI OIIO::ImageBufAlgo::text_size(string_view text, int fontsize = 16, string_view fontname = "")#
The helper function
text_size()
merely computes the dimensions of the text, returning it as an ROI relative to the left side of the baseline of the first character. Only thex
andy
dimensions of the ROI will be used. The x dimension runs from left to right, and y runs from top to bottom (image coordinates). For a failure (such as an invalid font name), the ROI will returnfalse
if you call itsdefined()
method. Thetext
may contain linefeed characters to designate multiple lines of text.
Examples:
// Render text centered in the image, using text_size to find out // the size we will need and adjusting the coordinates. ImageBuf A (ImageSpec (640, 480, 4, TypeDesc::FLOAT)); ROI Aroi = A.roi(); ROI size = ImageBufAlgo::text_size("Centered", 48, "Courier New"); if (size.defined()) { int x = Aroi.xbegin + Aroi.width()/2 - (size.xbegin + size.width()/2); int y = Aroi.ybegin + Aroi.height()/2 - (size.ybegin + size.height()/2); ImageBufAlgo::render_text(A, x, y, "Centered", 48, "Courier New"); }# Render text centered in the image, using text_size to find out # the size we will need and adjusting the coordinates. A = ImageBuf(ImageSpec(640, 480, 4, "float")) Aroi = A.roi size = ImageBufAlgo.text_size("Centered", 48, "Courier New") if size.defined: x = Aroi.xbegin + Aroi.width//2 - (size.xbegin + size.width//2) y = Aroi.ybegin + Aroi.height//2 - (size.ybegin + size.height//2) ImageBufAlgo.render_text(A, x, y, "Centered", 48, "Courier New")
Image transformations and data movement#
Shuffling channels#
-
ImageBuf OIIO::ImageBufAlgo::channels(const ImageBuf &src, int nchannels, cspan<int> channelorder, cspan<float> channelvalues = {}, cspan<std::string> newchannelnames = {}, bool shuffle_channel_names = false, int nthreads = 0)#
Generic channel shuffling: return (or store in
dst
) a copy ofsrc
, but with channels in the orderchannelorder[0..nchannels-1]
(or set to a constant value, designated bychannelorder[i] = -1
and having the fill value inchannelvalues[i]
. In-place operation is allowed (i.e.,dst
andsrc
the same image, but an extra copy will occur).- Parameters:
nchannels – The total number of channels that will be set up in the
dst
image.channelorder – For each channel in
dst
, the index of thesrc
channel from which to copy. Anychannelorder[i]
< 0 indicates that the channeli
should be filled with constant valuechannelvalues[i]
rather than copy any channel fromsrc
. Ifchannelorder
itself is empty, the implied channel order will be{0, 1, ..., nchannels-1}
, meaning that it’s only renaming, truncating, or extending channels, not reordering the channels that are already present.channelvalues – Fill values for color channels in which
channelorder[i]
< 0. This can be empty if no channels are to be filled with constant values.newchannelnames – An array of new channel names. Channels for which this specifies an empty string will have their name taken from the
src
channel that was copied. Ifnewchannelnames
is entirely empty, all channel names will simply be copied fromsrc
.shuffle_channel_names – If true, the channel names will be taken from the corresponding channels of the source image — be careful with this, shuffling both channel ordering and their names could result in no semantic change at all, if you catch the drift. If false (the default), the resulting
dst
image will have default channel names in the usual order (“R”, “G”, etc.).
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::channels(ImageBuf &dst, const ImageBuf &src, int nchannels, cspan<int> channelorder, cspan<float> channelvalues = {}, cspan<std::string> newchannelnames = {}, bool shuffle_channel_names = false, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
// Copy the first 3 channels of an RGBA, drop the alpha ImageBuf RGB = ImageBufAlgo::channels(RGBA, 3, {} /*default ordering*/); // Copy just the alpha channel, making a 1-channel image ImageBuf Alpha = ImageBufAlgo::channels(RGBA, 1, 3 /*alpha_channel*/); // Swap the R and B channels ImageBuf BRGA; bool success = ImageBufAlgo::channels(BRGA, RGBA, 4, { 2, 1, 0, 3 }, {}, { "R", "G", "B", "A" }); // Add an alpha channel with value 1.0 everywhere to an RGB image, // keep the other channels with their old ordering, values, and // names. RGBA = ImageBufAlgo::channels(RGB, 4, { 0, 1, 2, -1 }, { 0 /*ignore*/, 0 /*ignore*/, 0 /*ignore*/, 1.0 }, { "", "", "", "A" });# Copy the first 3 channels of an RGBA, drop the alpha RGB = ImageBufAlgo.channels(RGBA, (0, 1, 2)) # Copy just the alpha channel, making a 1-channel image Alpha = ImageBufAlgo.channels(RGBA, ("A",)) # Swap the R and B channels success = ImageBufAlgo.channels(BRGA, RGBA, channelorder=(2, 1, 0, 3), newchannelnames=("R", "G", "B", "A")) # Add an alpha channel with value 1.0 everywhere to an RGB image, # keep the other channels with their old ordering, values, and # names. RGBA = ImageBufAlgo.channels(RGB, channelorder=(0, 1, 2, 1.0), newchannelnames=("", "", "", "A"))# Copy the first 3 channels of an RGBA, drop the alpha oiiotool RGBA.exr -ch R,G,B -o RGB.exr # Copy just the alpha channel, making a 1-channel image oiiotool RGBA.exr -ch A -o A.exr # Swap the R and B channels oiiotool RGBA.exr -ch R=B,G,B=R,A -o BGRA.exr # Add an alpha channel with value 1.0 everywhere to an RGB image, # keep the other channels with their old ordering, values, and # names. oiiotool RGB.exr -ch 0,1,2,1.0 -o RGBA.exr
-
ImageBuf OIIO::ImageBufAlgo::channel_append(const ImageBuf &A, const ImageBuf &B, ROI roi = {}, int nthreads = 0)#
Append the channels of
A
andB
together intodst
over the region of interest. If the region passed is uninitialized (the default), it will be interpreted as being the union of the pixel windows ofA
andB
(and all channels of both images). Ifdst
is not already initialized, it will be resized to be big enough for the region.
Result-as-parameter version:
Examples:
ImageBuf RGBA("grid.exr"); ImageBuf RGBAZ = ImageBufAlgo::channel_append(RGBA, Z);RGBA = ImageBuf("grid.exr") RGBAZ = ImageBufAlgo.channel_append(RGBA, Z)oiiotool rgba.exr z.exr --chappend -o rgbaz.exr
-
ImageBuf OIIO::ImageBufAlgo::copy(const ImageBuf &src, TypeDesc convert = TypeUnknown, ROI roi = {}, int nthreads = 0)#
Return the specified region of pixels of
src
as specified byroi
(which will default to the whole ofsrc
, optionally with the pixel type overridden by convert (if it is notTypeUnknown
).
Result-as-parameter version:
Examples:
// Set B to be a copy of A, but converted to float ImageBuf A("grid.exr"); ImageBuf B = ImageBufAlgo::copy(A, TypeDesc::FLOAT);# Set B to be a copy of A, but converted to float A = ImageBuf("grid.exr") B = ImageBufAlgo.copy(A, convert="float")# Convert A to float pixels oiiotool A.exr -d float -o B.exr
-
ImageBuf OIIO::ImageBufAlgo::crop(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Return the specified region of
src
as an image, without altering its position in the image plane.Pixels from
src
which are outsideroi
will not be copied, and new black pixels will be added for regions ofroi
which were outside the data window ofsrc
.Note that the
crop
operation does not actually move the pixels on the image plane or adjust the full/display window; it merely restricts which pixels are copied fromsrc
todst
. (Note the difference compared tocut()
).
Result-as-parameter version:
Examples:
// Set B to be a 200x100 region of A starting at (50,50), trimming // the exterior away but leaving that region in its original position. ImageBuf A("grid.exr"); ImageBuf B = ImageBufAlgo::crop(A, ROI(50, 250, 50, 150));# Set B to be a 200x100 region of A starting at (50,50), trimming # the exterior away but leaving that region in its original position. A = ImageBuf("grid.exr") B = ImageBufAlgo.crop(A, ROI(50, 250, 50, 150))# Set B to be a 200x100 region of A starting at (50,50), trimming # the exterior away but leaving that region in its original position. oiiotool A.exr --crop 200x100+50+50 -o B.exr
-
ImageBuf OIIO::ImageBufAlgo::cut(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Return the designated region of
src
, but repositioned to the image origin and with the full/display window set to exactly cover the new pixel data window. (Note the difference compared tocrop()
).
Result-as-parameter version:
Examples:
// Set B to be a 200x100 region of A starting at (50,50), but // moved to the upper left corner so its new origin is (0,0). ImageBuf A("grid.exr"); ImageBuf B = ImageBufAlgo::cut(A, ROI(50, 250, 50, 150));# Set B to be a 200x100 region of A starting at (50,50), but # moved to the upper left corner so its new origin is (0,0). A = ImageBuf("grid.exr") B = ImageBufAlgo.cut(A, ROI(50, 250, 50, 150))# Set B to be a 200x100 region of A starting at (50,50), but # moved to the upper left corner so its new origin is (0,0). oiiotool A.exr --cut 200x100+50+50 -o B.exr
-
bool OIIO::ImageBufAlgo::paste(ImageBuf &dst, int xbegin, int ybegin, int zbegin, int chbegin, const ImageBuf &src, ROI srcroi = {}, int nthreads = 0)#
Copy
src
pixels withinsrcroi
into thedst
image, offset so that source location (0,0,0) will be copied to destination location (xbegin
,ybegin
,zbegin
). If thesrcroi
isROI::All()
, the entirety of the data window ofsrc
will be used. It will copy intochannels[chbegin...]
, as many channels as are described by srcroi. Pixels or channels ofsrc
insidesrcroi
will replace the corresponding destination pixels entirely, whereassrc
pixels outside ofsrcroi
will not be copied and the corresponding offset pixels ofdst
will not be altered.
Examples:
// Paste Fg on top of Bg, offset by (100,100) ImageBuf Bg("grid.exr"); ImageBuf Fg("tahoe.tif"); ImageBufAlgo::paste(Bg, 100, 100, 0, 0, Fg);# Paste Fg on top of Bg, offset by (100,100) Bg = ImageBuf("grid.exr") Fg = ImageBuf("tahoe.tif") ImageBufAlgo.paste(Bg, 100, 100, 0, 0, Fg)# Paste fg.exr on top of bg.exr, offset by (100,100) oiiotool bg.exr fg.exr --paste +100+100 -o bg.exr
- group rotateN
Return (or copy into
dst
) a rotated copy of the image pixels ofsrc
, in 90 degree increments. Pictorially:rotate90 rotate180 rotate270 ----------- ----------- ----------- AB --> CA AB --> DC AB --> BD CD DB CD BA CD AC
Functions
-
ImageBuf rotate90(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate180(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate270(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool rotate90(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool rotate180(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool rotate270(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate90(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Examples:
ImageBuf A("grid.exr"); ImageBuf R90 = ImageBufAlgo::rotate90(A); ImageBuf R180 = ImageBufAlgo::rotate180(A); ImageBuf R270 = ImageBufAlgo::rotate270(A);A = ImageBuf("grid.exr") R90 = ImageBufAlgo.rotate90(A) R180 = ImageBufAlgo.rotate180(A) R270 = ImageBufAlgo.rotate270(A)oiiotool grid.jpg -rotate 90 -o R90.jpg oiiotool grid.jpg -rotate 180 -o R180.jpg oiiotool grid.jpg -rotate 270 -o R270.jpg
- group flip-flop-transpose
Return (or copy into
dst
) a subregion ofsrc
, but with the scanlines exchanged vertically (flip), or columns exchanged horizontally (flop), or transposed across the diagonal by swapping rows for columns (transpose) within the display/full window. In other words,flip flop transpose ----------- ----------- ----------- AB --> CD AB --> BA AB --> AC CD AB CD DC CD BD
Functions
-
ImageBuf flip(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf flop(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf transpose(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool flip(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool flop(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool transpose(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf flip(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Examples:
ImageBuf A("grid.exr"); ImageBuf B1 = ImageBufAlgo::flip(A); ImageBuf B2 = ImageBufAlgo::flop(A); ImageBuf B3 = ImageBufAlgo::transpose(A);A = ImageBuf("grid.exr") B1 = ImageBufAlgo.flip(A) B2 = ImageBufAlgo.flop(A) B3 = ImageBufAlgo.transpose(A)oiiotool grid.jpg --flip -o flip.jpg oiiotool grid.jpg --flop -o flop.jpg oiiotool grid.jpg --transpose -o transpose.jpg
-
ImageBuf OIIO::ImageBufAlgo::reorient(const ImageBuf &src, int nthreads = 0)#
Return (or store into
dst
) a copy ofsrc
, but with whatever seties of rotations, flips, or flops are necessary to transform the pixels into the configuration suggested by the “Orientation” metadata of the image (and the “Orientation” metadata is then set to 1, ordinary orientation).
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::reorient(ImageBuf &dst, const ImageBuf &src, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
ImageBuf A("grid-vertical.exr"); A = ImageBufAlgo::reorient(A);A = ImageBuf("grid-vertical.exr") A = ImageBufAlgo.reorient(A)oiiotool tahoe.jpg --reorient -o out.jpg
-
ImageBuf OIIO::ImageBufAlgo::circular_shift(const ImageBuf &src, int xshift, int yshift, int zshift = 0, ROI roi = {}, int nthreads = 0)#
Return a subregion of
src
, but circularly shifting by the given amount. To clarify, the circular shift of [0,1,2,3,4,5] by +2 is [4,5,0,1,2,3].
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::circular_shift(ImageBuf &dst, const ImageBuf &src, int xshift, int yshift, int zshift = 0, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
ImageBuf A("grid.exr"); ImageBuf B = ImageBufAlgo::circular_shift(A, 70, 30);A = ImageBuf("grid.exr") B = ImageBufAlgo.circular_shift(A, 70, 30)oiiotool tahoe.jpg --cshift +70+30 -o out.jpg
- group rotate
Rotate the
src
image by theangle
(in radians, with positive angles clockwise). Whencenter_x
andcenter_y
are supplied, they denote the center of rotation, in pixel coordinates; in their absence, the rotation will be about the center of the image’s display window.Only the pixels (and channels) of
dst
that are specified byroi
will be copied from the rotatedsrc
; the defaultroi
is to alter all the pixels indst
. Ifdst
is uninitialized, it will be resized to be an ImageBuf large enough to hold the rotated image if recompute_roi is true, or will have the same ROI assrc
ifrecompute_roi
isfalse
. It is an error to pass both an uninitializeddst
and an undefinedroi
.The filter is used to weight the
src
pixels falling underneath it for eachdst
pixel. The caller may specify a reconstruction filter by name and width (expressed in pixels units of thedst
image), orrotate()
will choose a reasonable default high-quality default filter (lanczos3) if the empty string is passed, and a reasonable filter width iffilterwidth
is 0. (Note that some filter choices only make sense with particular width, in which case this filterwidth parameter may be ignored.)Functions
-
ImageBuf rotate(const ImageBuf &src, float angle, string_view filtername = string_view(), float filterwidth = 0.0f, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate(const ImageBuf &src, float angle, Filter2D *filter, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate(const ImageBuf &src, float angle, float center_x, float center_y, string_view filtername = string_view(), float filterwidth = 0.0f, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate(const ImageBuf &src, float angle, float center_x, float center_y, Filter2D *filter, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
bool rotate(ImageBuf &dst, const ImageBuf &src, float angle, string_view filtername = string_view(), float filterwidth = 0.0f, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
bool rotate(ImageBuf &dst, const ImageBuf &src, float angle, Filter2D *filter, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
bool rotate(ImageBuf &dst, const ImageBuf &src, float angle, float center_x, float center_y, string_view filtername = string_view(), float filterwidth = 0.0f, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
bool rotate(ImageBuf &dst, const ImageBuf &src, float angle, float center_x, float center_y, Filter2D *filter, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rotate(const ImageBuf &src, float angle, string_view filtername = string_view(), float filterwidth = 0.0f, bool recompute_roi = false, ROI roi = {}, int nthreads = 0)#
Examples:
ImageBuf Src ("grid.exr"); ImageBuf Dst = ImageBufAlgo::rotate (Src, 45.0);Src = ImageBuf("grid.exr") Dst = ImageBufAlgo.rotate(Src, 45.0)oiiotool tahoe.exr --rotate 45.0 -o out.exr
- group resize
Set
dst
, over the region of interest, to be a resized version of the corresponding portion ofsrc
(mapping such that the “full” image window of each correspond to each other, regardless of resolution). Ifdst
is not yet initialized, it will be sized according toroi
.The
options
list contains optional ParamValue’s that control the resizing behavior. The following options are recognized:“filtername” : string (default: “”)
The type of reconstruction filter used to weight the
src
pixels falling underneath it for eachdst
pixel. If the value is the empty string or not supplied, a reasonable high-quality filter will be chosen automatically (blackman-harris when upsizing, lanczos3 when downsizing).”filterwidth” : float (default: 0)
The width of the reconstruction filter, expressed in pixel units of the
dst
image. If 0 or not supplied, the default width of the named filter will be used.”filterptr” : pointer to a Filter2D (default: nullptr)
Advanced use: It is also possible to pass a custom reconstruction filter as a
Filter2D*
, overriding any filtername and filterwidth that may also be passed. The easiest way to pass it is as:make_pv("filterptr", raw_filter_ptr)
. Use with caution!
The caller may either (a) explicitly pass a reconstruction
filter
, or (b) specify one byfiltername
andfilterwidth
. Iffilter
isnullptr
or iffiltername
is the empty stringresize()
will choose a reasonable high-quality default (blackman-harris when upsizing, lanczos3 when downsizing). The filter is used to weight thesrc
pixels falling underneath it for eachdst
pixel; the filter’s size is expressed in pixel units of thedst
image.
Examples:
// Resize the image to 640x480, using the default filter ImageBuf Src("grid.exr"); ROI roi(0, 320, 0, 240, 0, 1, /*chans:*/ 0, Src.nchannels()); ImageBuf Dst = ImageBufAlgo::resize(Src, {}, roi);# Resize the image to 640x480, using the default filter Src = ImageBuf("grid.exr") roi = ROI(0, 320, 0, 240, 0, 1, 0, Src.nchannels) Dst = ImageBufAlgo.resize(Src, roi=roi)# Resize the image to 640x480, using the default filter oiiotool grid.exr --resize 640x480 -o out.exr
-
ImageBuf OIIO::ImageBufAlgo::resample(const ImageBuf &src, bool interpolate = true, ROI roi = {}, int nthreads = 0)#
Set
dst
, over the region of interest, to be a resized version of the corresponding portion ofsrc
(mapping such that the “full” image window of each correspond to each other, regardless of resolution). Ifdst
is not yet initialized, it will be sized according toroi
.Unlike
ImageBufAlgo::resize()
,resample()
does not take a filter; it just samples either with a bilinear interpolation (ifinterpolate
istrue
, the default) or uses the single “closest” pixel (ifinterpolate
isfalse
). This makes it a lot faster than a properresize()
, though obviously with lower quality (aliasing when downsizing, pixel replication when upsizing).For “deep” images, this function returns copies the closest source pixel needed, rather than attempting to interpolate deep pixels (regardless of the value of
interpolate
).See also
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::resample(ImageBuf &dst, const ImageBuf &src, bool interpolate = true, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
// Resample quickly to 320x240, with default interpolation ImageBuf Src("grid.exr"); ROI roi(0, 320, 0, 240, 0, 1, /*chans:*/ 0, Src.nchannels()); ImageBuf Dst = ImageBufAlgo::resample(Src, true, roi);# Resample quickly to 320x240, with default interpolation Src = ImageBuf("grid.exr") roi = ROI(0, 320, 0, 240, 0, 1, 0, Src.nchannels) Dst = ImageBufAlgo.resample(Src, roi=roi)# Resample quickly to 320x240, with default interpolation oiiotool tahoe.exr --resample 320x240 -o out.exr
- group fit
Resize
src
to fit intodst
(to a size specified byroi
, ifdst
is not initialized), preserving its original aspect ratio. Thus, it will resize to be the largest size with the same aspect ratio that can fit inside the region, but will not necessarily completely fill it in both dimensions if the source and destination image buffers do not have the same aspect ratio.The
options
list contains optional ParamValue’s that control the resizing behavior. The following options are recognized:“filtername” : string (default: “”)
The type of reconstruction filter used to weight the
src
pixels falling underneath it for eachdst
pixel. If the value is the empty string or not supplied, a reasonable high-quality filter will be chosen automatically (blackman-harris when upsizing, lanczos3 when downsizing).”filterwidth” : float (default: 0)
The width of the reconstruction filter, expressed in pixel units of the
dst
image. If 0 or not supplied, the default width of the named filter will be used.”filterptr” : pointer to a Filter2D (default: nullptr)
Advanced use: It is also possible to pass a custom reconstruction filter as a
Filter2D*
, overriding any filtername and filterwidth that may also be passed. The easiest way to pass it is as:make_pv("filterptr", raw_filter_ptr)
. Use with caution!”fillmode” : string (default: “letterbox”)
The
fillmode
determines which of several methods will be used to determine how the image will fill the new frame, if its aspect ratio does not precisely match the original source aspect ratio:”width” exactly fills the width of the new frame, either cropping or letterboxing the height if it isn’t precisely the right size to preserve the original aspect ratio.
”height” exactly fills the height of the new frame, either cropping or letterboxing the width if it isn’t precisely the right size to preserve the original aspect ratio.
”letterbox” (the default) chooses whichever of “width” or “height” will maximally fill the new frame with no image data lost (it will only letterbox, never crop).
”exact” : int (default: 0)
If nonzero, will result in an exact match on aspect ratio and centering (partial pixel shift if necessary), whereas exact=false will only preserve aspect ratio and centering to the precision of a whole pixel.
Examples:
// Resize to fit into a max of 640x480, preserving the aspect ratio ImageBuf Src("grid.exr"); ROI roi(0, 320, 0, 240, 0, 1, /*chans:*/ 0, Src.nchannels()); ImageBuf Dst = ImageBufAlgo::fit(Src, {}, roi);# Resize to fit into a max of 640x480, preserving the aspect ratio Src = ImageBuf("grid.exr") roi = ROI(0, 320, 0, 240, 0, 1, 0, Src.nchannels) Dst = ImageBufAlgo.fit(Src, "", roi=roi)# Resize to fit into a max of 640x480, preserving the aspect ratio oiiotool grid.exr --fit 640x480 -o out.exr
- group warp
Warp the
src
image using the supplied 3x3 transformation matrix.Only the pixels (and channels) of
dst
that are specified byroi
will be copied from the warpedsrc
; the default is to alter all the pixels indst
. Ifdst
is uninitialized, it will be sized to be an ImageBuf large enough to hold the warped image if recompute_roi is true, or will have the same ROI as src if recompute_roi is false. It is an error to pass both an uninitializeddst
and an undefinedroi
.The
options
list contains optional ParamValue’s that may control the filtering and reconstruction. The following options are recognized:“filtername” : string (default: “”)
The type of reconstruction filter used to weight the
src
pixels falling underneath it for eachdst
pixel. If the value is the empty string or not supplied, a reasonable high-quality filter will be chosen automatically.”filterwidth” : float (default: 0)
The width of the reconstruction filter, expressed in pixel units of the
dst
image. If 0 or not supplied, the default width of the named filter will be used.”wrap” : string (default: “black”)
The wrap mode controlling the value of pixel lookups that need to occur beyond the boundary of the
src
image. (Could be one of: black, clamp, periodic, mirror.)”edgeclamp” : int (default: 0)
If nonzero, will enable special edge clamp behavior to reduce artifacts at the image edges (experimental).
”recompute_roi” : int (default: 0)
If nonzero and
dst
is not yet initialized, the result image will be sized to be large enough to hold the warped image. If zero (the default), thedst
image will have the same ROI assrc
. If thedst
image already is initialized, its size will not be changed and this option will be ignored.”filterptr” : pointer to a Filter2D (default: nullptr)
Advanced use: It is also possible to pass a custom reconstruction filter as a
Filter2D*
, overriding any filtername and filterwidth that may also be passed. The easiest way to pass it is as:make_pv("filterptr", raw_filter_ptr)
. Use with caution!
- param dst:
The output ImageBuf. If not already initialized, it will be sized based on
roi
(which itself will default to the size ofsrc
, if not specified).- param src:
The source ImageBuf.
- param M:
A 3x3 matrix describing the desired spatial transformation of destination pixel coordinates to source pixel coordinates.
- param roi:
The region of
dst
that will receive transformed pixels. If not specified, it will be all the pixels ofdst
.- param options:
Optional ParamValue’s that may control the filtering and reconstruction.
Examples:
Imath::M33f M( 0.7071068, 0.7071068, 0, -0.7071068, 0.7071068, 0, 20, -8.284271, 1); ImageBuf Src("grid.exr"); ImageBuf Dst = ImageBufAlgo::warp(Src, M, { { "filtername", "lanczos3" } });M = (0.7071068, 0.7071068, 0, -0.7071068, 0.7071068, 0, 20, -8.284271, 1) Src = ImageBuf("grid.exr") Dst = ImageBufAlgo.warp(Src, M, filtername="lanczos3")oiiotool grid.exr --warp 0.7071068,0.7071068,0,-0.7071068,0.7071068,0,20,-8.284271,1 -o out.exr
- group st_warp
Warp the
src
image using “st” coordinates from a secondarystbuf
image.Each pixel in the
stbuf
image is used as a normalized image-space coordinate in thesrc
image, which is then sampled at that position using the given reconstruction filter to produce an output pixel.The transform is only defined over the area of the
stbuf
image, and thus the givenroi
argument will be intersected with its geometry.NOTE: The current behavior of this transform is modeled to match Nuke’s STMap node.
- param dst:
The output ImageBuf. If an initialized buffer is provided, its full-size dimensions must match those of
stbuf
.- param src:
The source ImageBuf to warp.
- param stbuf:
The ImageBuf holding the st coordinates. This must be holding a floating-point pixel data type.
- param chan_s:
The index of the “s” channel in the
stbuf
image. This defaults to its first channel.- param chan_t:
The index of the “t” channel in the
stbuf
image. This defaults to its second channel.- param flip_s:
Whether to mirror the “s” coordinate along the horizontal axis when computing source pixel positions. This is useful if the coordinates are defined in terms of a different image origin than OpenImageIO’s.
- param flip_t:
Whether to mirror the “t” coordinate along the vertical axis when computing source pixel positions. This is useful if the coordinates are defined in terms of a different image origin than OpenImageIO’s.
Functions
-
ImageBuf st_warp(const ImageBuf &src, const ImageBuf &stbuf, string_view filtername = string_view(), float filterwidth = 0.0f, int chan_s = 0, int chan_t = 1, bool flip_s = false, bool flip_t = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf st_warp(const ImageBuf &src, const ImageBuf &stbuf, const Filter2D *filter, int chan_s = 0, int chan_t = 1, bool flip_s = false, bool flip_t = false, ROI roi = {}, int nthreads = 0)#
-
bool st_warp(ImageBuf &dst, const ImageBuf &src, const ImageBuf &stbuf, string_view filtername = string_view(), float filterwidth = 0.0f, int chan_s = 0, int chan_t = 1, bool flip_s = false, bool flip_t = false, ROI roi = {}, int nthreads = 0)#
-
bool st_warp(ImageBuf &dst, const ImageBuf &src, const ImageBuf &stbuf, const Filter2D *filter, int chan_s = 0, int chan_t = 1, bool flip_s = false, bool flip_t = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf OIIO::ImageBufAlgo::demosaic(const ImageBuf &src, KWArgs options = {}, ROI roi = {}, int nthreads = 0)#
Performs demosaicing of a raw digital camera image. Expects the
src
to be a single channel image. Returns a three channel RGB image with the color channels reconstructed using the selected algorithm.The
options
list contains optional ParamValue’s that may control the reconstruction. The following options are recognized:“pattern” : string (default: “bayer”)
The type of image sensor color filter array. Currently suported patterns:
bayer
- Bayer-pattern image.xtrans
- X-Trans-pattern image.
”algorithm” : string (default: “linear”)
The demosaicing algorithm, pattern-specific. The following algorithms are supported for Bayer-pattern images:
linear
- simple bilinear demosaicing. Fast, but can produce artefacts along sharp edges.MHC
- Malvar-He-Cutler linear demosaicing algorithm. Slower thanlinear
, but produces significantly better results.
The following algorithms are supported for X-Trans-pattern images:
linear
- simple linear demosaicing. Fast, but can produce artefacts along sharp edges.
”layout” : string (default: “RGGB” for Bayer, “GRBGBR BGGRGG RGGBGG GBRGRB RGGBGG BGGRGG” for X-Trans)
The order the color filter array elements are arranged in, pattern-specific.
”white-balance” : float[3] or float[4], (default: {1.0, 1.0, 1.0, 1.0})
Optional white-balancing weights. Can contain either three (R,G,B), or four (R,G1,B,G2) values. The order of the white balance multipliers does not depend on the matrix layout.
- Parameters:
options – Optional ParamValue’s that may control the reconstruction.
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::demosaic(ImageBuf &dst, const ImageBuf &src, KWArgs options = {}, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
ImageBuf Src("bayer.png"); float WB[3] = {2.0, 1.0, 1.5}; ParamValue options[] = { { "layout", "BGGR" }, ParamValue("white_balance", TypeFloat, 3, WB) }; ImageBuf Dst = ImageBufAlgo::demosaic(Src, options);Src = ImageBuf("bayer.png") WB_RGBG = (2.0, 1.0, 1.5, 1.0) Dst = ImageBufAlgo.demosaic(Src, layout="BGGR", white_balance = WB_RGBG)oiiotool -iconfig raw:Demosaic none -i test.cr3 --demosaic:layout=GRBG:white_balance=2.0,0.8,1.2,1.5 -o out.exr
Image arithmetic#
-
ImageBuf OIIO::ImageBufAlgo::add(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel sum
A + B
, returning the result image.A
andB
may each either be anImageBuf&
, or acspan<float>
giving a per- channel constant, or a single constant used for all channels. (But at least one must be an image.)
Result-as-parameter version:
Examples:
// Add images A and B ImageBuf A ("A.exr"); ImageBuf B ("B.exr"); ImageBuf Sum = ImageBufAlgo::add(A, B); // Add 0.2 to channels 0-2, but not to channel 3 ImageBuf SumCspan = ImageBufAlgo::add(A, { 0.2f, 0.2f, 0.2f, 0.0f });# Add images A and B A = ImageBuf("A.exr") B = ImageBuf("B.exr") Sum = ImageBufAlgo.add (A, B) # Add 0.2 to channels 0-2, but not to channel 3 Sum_cspan = ImageBufAlgo.add (A, (0.2, 0.2, 0.2, 0.0))# Add images A and B oiiotool a.exr b.exr --add -o sum.exr # Add 0.2 to channels 0-2, but not to channel 3 oiiotool a.exr --addc 0.2,0.2,0.2,0.0 -o sum.exr
-
ImageBuf OIIO::ImageBufAlgo::sub(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel signed difference
A - B
, returning the result image.A
andB
may each either be anImageBuf&
, or acspan<float>
giving a per-channel constant, or a single constant used for all channels. (But at least one must be an image.)
Result-as-parameter version:
Examples:
ImageBuf A ("A.exr"); ImageBuf B ("B.exr"); ImageBuf Diff = ImageBufAlgo::sub(A, B);A = ImageBuf("A.exr") B = ImageBuf("B.exr") Diff = ImageBufAlgo.sub (A, B)oiiotool a.exr b.exr --sub -o diff.exr
-
ImageBuf OIIO::ImageBufAlgo::absdiff(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel absolute difference
abs(A - B)
, returning the result image.A
andB
may each either be anImageBuf&
, or acspan<float>
giving a per- channel constant, or a single constant used for all channels. (But at least one must be an image.)
Result-as-parameter version:
Examples:
ImageBuf A ("A.exr"); ImageBuf B ("B.exr"); ImageBuf Diff = ImageBufAlgo::absdiff (A, B);A = ImageBuf("A.exr") B = ImageBuf("B.exr") Diff = ImageBufAlgo.absdiff (A, B)oiiotool a.exr b.exr --absdiff -o diff.exr
-
ImageBuf OIIO::ImageBufAlgo::abs(const ImageBuf &A, ROI roi = {}, int nthreads = 0)#
Compute per-pixel absolute value
abs(A)
, returning the result image.
Result-as-parameter version:
Examples:
ImageBuf A("grid.exr"); ImageBuf Abs = ImageBufAlgo::abs(A);A = ImageBuf("grid.exr") Abs = ImageBufAlgo.abs (A)oiiotool a.exr --abs -o abs.exr
-
ImageBuf OIIO::ImageBufAlgo::scale(const ImageBuf &A, const ImageBuf &B, KWArgs options = {}, ROI roi = {}, int nthreads = 0)#
Compute per-pixel product
A * B
, returning the result image. At least one ofA
andB
must be a single channel image, whose value is used to scale all channels of the other image.- Parameters:
options – Optional ParamValue’s that may control the reconstruction. (Reserved for future expansion.)
Result-as-parameter version:
Examples:
// Pixel-by-pixel multiplication of all channels of A by the single channel of B ImageBuf A("A.exr"); ImageBuf B("mono.exr"); ImageBuf Product = ImageBufAlgo::scale(A, B);# Pixel-by-pixel multiplication of all channels of one image A by the single channel of the other image A = ImageBuf("A.exr") B = ImageBuf("mono.exr") Product = ImageBufAlgo.scale (A, B)# Pixel-by-pixel multiplication of all channels of one image by the only channel of another image oiiotool a.exr mono.exr --scale -o scale.exr
-
ImageBuf OIIO::ImageBufAlgo::mul(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel product
A * B
, returning the result image.Either both
A
andB
are images, or one is an image and the other is acspan<float>
giving a per-channel constant or a single constant used for all channels.
Result-as-parameter version:
Examples:
// Pixel-by-pixel, channel-by-channel multiplication of A and B ImageBuf A ("A.exr"); ImageBuf B ("B.exr"); ImageBuf Product = ImageBufAlgo::mul (A, B); // In-place reduce intensity of A's channels 0-2 by 50% ImageBufAlgo::mul (A, A, { 0.5f, 0.5f, 0.5f, 1.0f });# Pixel-by-pixel, channel-by-channel multiplication of A and B A = ImageBuf("A.exr") B = ImageBuf("B.exr") Product = ImageBufAlgo.mul (A, B) # In-place reduce intensity of A's channels 0-2 by 50% ImageBufAlgo.mul (A, A, (0.5, 0.5, 0.5, 1.0))# Pixel-by-pixel, channel-by-channel multiplication of A and B oiiotol a.exr b.exr --mul -o product.exr # In-place reduce intensity of A's channels 0-2 by 50% oiiotool a.exr --mulc 0.5,0.5,0.5,1.0 -o a.exr
-
ImageBuf OIIO::ImageBufAlgo::div(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel division
A / B
, returning the result image. Division by zero is defined to result in zero.A
is always an image, andB
is either an image or acspan<float>
giving a per-channel constant or a single constant used for all channels.
Result-as-parameter version:
Examples:
// Pixel-by-pixel, channel-by-channel division of A by B ImageBuf A ("A.exr"); ImageBuf B ("B.exr"); ImageBuf Ratio = ImageBufAlgo::div (A, B); // In-place reduce intensity of A's channels 0-2 by 50% ImageBufAlgo::div (A, A, { 2.0f, 2.0f, 2.0f, 1.0f });# Pixel-by-pixel, channel-by-channel division of A by B A = ImageBuf("A.exr") B = ImageBuf("B.exr") Ratio = ImageBufAlgo.div (A, B) # In-place reduce intensity of A's channels 0-2 by 50% ImageBufAlgo.div (A, A, (2.0, 2.0, 2.0, 1.0))# Pixel-by-pixel, channel-by-channel division of A by B oiiotol a.exr b.exr --div -o ratio.exr # In-place reduce intensity of A's channels 0-2 by 50% oiiotool a.exr --divc 2,2,2,1 -o a.exr
-
ImageBuf OIIO::ImageBufAlgo::mad(Image_or_Const A, Image_or_Const B, Image_or_Const C, ROI roi = {}, int nthreads = 0)#
Compute per-pixel multiply-and-add
A * B + C
, returning the result image.A
,B
, andC
are each either an image, or acspan<float>
giving a per-channel constant or a single constant used for all channels. (Note: at least one must be an image.)
Result-as-parameter version:
Examples:
// Pixel-by-pixel, channel-by-channel A * B + C ImageBuf A ("a.exr"); ImageBuf B ("b.exr"); ImageBuf C ("c.exr"); ImageBuf Result = ImageBufAlgo::mad (A, B, C); // Compute the "inverse" A, which is 1.0-A, as A*(-1) + 1 // Do this in-place, and only for the first 3 channels (leave any // alpha channel, if present, as it is). ImageBuf Ainv = ImageBufAlgo::mad (A, { -1.0, -1.0, -1.0, 1.0 }, { 1.0, 1.0, 1.0, 0.0 });# Pixel-by-pixel, channel-by-channel A * B + C A = ImageBuf("a.exr") B = ImageBuf("b.exr") C = ImageBuf("c.exr") Result = ImageBufAlgo.mad (A, B, C) # Compute the "inverse" A, which is 1.0-A, as A*(-1) + 1 # Do this in-place, and only for the first 3 channels (leave any # alpha channel, if present, as it is). Ainv = ImageBufAlgo.mad (A, (-1.0, -1.0, -1.0, 1.0), (1.0, 1.0, 1.0, 0.0))# Pixel-by-pixel, channel-by-channel A * B + C oiiotol a.exr b.exr c.exr --mad -o result.exr
-
ImageBuf OIIO::ImageBufAlgo::over(const ImageBuf &A, const ImageBuf &B, ROI roi = {}, int nthreads = 0)#
Return the composite of
A
overB
using the Porter/Duff definition of “over”, returning true upon success and false for any of a variety of failures (as described below).A
andB
(and dst, if already defined/allocated) must have valid alpha channels identified by their ImageSpecalpha_channel
field. IfA
orB
do not have alpha channels (as determined by those rules) or if the number of non-alpha channels do not match betweenA
andB
,over()
will fail, returning false.If
dst
is not already an initialized ImageBuf, it will be sized to encompass the minimal rectangular pixel region containing the union of the defined pixels ofA
andB
, and with a number of channels equal to the number of non-alpha channels ofA
andB
, plus an alpha channel. However, ifdst
is already initialized, it will not be resized, and the “over” operation will apply to its existing pixel data window. In this case, dst must have an alpha channel designated and must have the same number of non-alpha channels asA
andB
, otherwise it will fail, returning false.A
,B
, anddst
need not perfectly overlap in their pixel data windows; pixel values ofA
orB
that are outside their respective pixel data window will be treated as having “zero” (0,0,0…) value.
Result-as-parameter version:
Examples:
ImageBuf A ("a.exr"); ImageBuf B ("b.exr"); ImageBuf Composite = ImageBufAlgo::over (A, B);A = ImageBuf("a.exr") B = ImageBuf("b.exr") Composite = ImageBufAlgo.over (A, B)oiiotool a.exr b.exr --over -o composite.exr
-
ImageBuf OIIO::ImageBufAlgo::zover(const ImageBuf &A, const ImageBuf &B, bool z_zeroisinf = false, ROI roi = {}, int nthreads = 0)#
Just like
ImageBufAlgo::over()
, but inputsA
andB
must have designated ‘z’ channels, and on a pixel-by-pixel basis, the z values will determine which ofA
orB
will be considered the foreground or background (lower z is foreground). Ifz_zeroisinf
is true, then z=0 values will be treated as if they are infinitely far away.
Result-as-parameter version:
Examples:
ImageBuf A ("a.exr"); ImageBuf B ("b.exr"); ImageBuf Composite = ImageBufAlgo::zover (A, B);A = ImageBuf("a.exr") B = ImageBuf("b.exr") Composite = ImageBufAlgo.zover (A, B)oiiotool a.exr b.exr --zover -o composite.exr
-
ImageBuf OIIO::ImageBufAlgo::invert(const ImageBuf &A, ROI roi = {}, int nthreads = 0)#
Compute per-pixel value inverse
1.0 - A
(which you can think of as roughly meaning switching white and black), returning the result image.Tips for callers: (1) You probably want to set
roi
to restrict the operation to only the color channels, and not accidentally include alpha, z, or others. (2) There may be situations where you want tounpremult()
before the invert, thenpremult()
the result, so that you are computing the inverse of the unmasked color.
Result-as-parameter version:
Examples:
// Invert all channels of A ImageBuf A ("a.exr"); ImageBuf Inverse = ImageBufAlgo::invert (Inverse, A); // In this example, we are careful to deal with alpha in an RGBA image. // First we copy A to Inverse, un-premultiply the color values by alpha, // invert just the color channels in-place, and then re-premultiply the // colors by alpha. roi = A.roi(); roi.chend = 3; // Restrict roi to only R,G,B ImageBuf Inverse = ImageBufAlgo::unpremult (A); ImageBufAlgo::invert (Inverse, Inverse, roi); ImageBufAlgo::repremult (Inverse, Inverse);# Invert all channels of A A = ImageBuf("a.exr") Inverse = ImageBufAlgo.invert (Inverse, A) # In this example, we are careful to deal with alpha in an RGBA image. # First we copy A to Inverse, un-premultiply the color values by alpha, # invert just the color channels in-place, and then re-premultiply the # colors by alpha. roi = A.roi.copy() roi.chend = 3 # Restrict roi to only R,G,B Inverse = ImageBufAlgo.unpremult (A) ImageBufAlgo.invert (Inverse, Inverse, roi) ImageBufAlgo.repremult (Inverse, Inverse)# Invert all channels of A, including alpha. # Because oiiotool --invert by default includes only the first # 3 channels, we have to use optional modifiers to include alpha. oiiotool a.exr --invert:chbegin=0:chend=3 -o inverse.exr # In this example, invert only the RGB channels (which is the default # behavior of oiiotool --invert) and also we un-premultiply the color # values by alpha, invert, and then re-premultiply the colors by alpha. oiiotool a.exr --unpremult --invert --repremult -o inverse.exr
-
ImageBuf OIIO::ImageBufAlgo::pow(const ImageBuf &A, cspan<float> B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel raise-to-power
A ^ B
. returning the result image. It is permitted fordst
andA
to be the same image.A
is always an image, andB
is either an image or acspan<float>
giving a per-channel constant or a single constant used for all channels.
Result-as-parameter version:
Examples:
// Gamma-correct by 2.2 channels 0-2 of the image, in-place ImageBuf A ("a.exr"); const float g = 1.0f / 2.2f; ImageBufAlgo::pow (A, A, { g, g, g, 1.0f });# Gamma-correct by 2.2 channels 0-2 of the image, in-place A = ImageBuf("a.exr") g = 1.0 / 2.2 ImageBufAlgo.pow (A, A, (g, g, g, 1))# Gamma-correct by 2.2 channels 0-2 of the image, in-place oiiotool a.exr --powc 0.4545,0.4545,0.4545,1.0 -o a.exr
-
ImageBuf OIIO::ImageBufAlgo::channel_sum(const ImageBuf &src, cspan<float> weights = 1.0f, ROI roi = {}, int nthreads = 0)#
Converts a multi-channel image into a one-channel image via a weighted sum of channels:
returning the resulting one-channel image. The(channel[0]*weight[0] + channel[1]*weight[1] + ...)
weights
, if not supplied, default to{ 1, 1, 1, ... }
).
Result-as-parameter version:
Examples:
Compute luminance via a weighted sum of R,G,B (assuming Rec709 primaries and a linear scale):
// Compute luminance via a weighted sum of R,G,B // (assuming Rec709 primaries and a linear scale) float luma_weights[3] = { .2126, .7152, .0722, 0.0 }; ImageBuf A ("a.exr"); ImageBuf lum = ImageBufAlgo::channel_sum (A, luma_weights);# Compute luminance via a weighted sum of R,G,B # (assuming Rec709 primaries and a linear scale) A = ImageBuf("a.exr") lum = ImageBufAlgo.channel_sum (A, (.2126, .7152, .0722, 0.0))# Compute luminance via a weighted sum of R,G,B # (assuming Rec709 primaries and a linear scale) oiiotool a.exr --chsum 0.2126,0.7152,0.0722,0.0 -o lum.exr
Max, min, clamp
- group maxminclamp
max()
andmin()
take the pixel-by-pixel, channel-by-channel maximum and minimum of two images, or of an image and a constant.clamp()
restricts values of an image to the range between per-channel minimum and maximum constant values.Functions
-
ImageBuf max(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel
max(A, B)
, returning the result image.Either both
A
andB
are images, or one is an image and the other is acspan<float>
giving a per-channel constant or a single constant used for all channels.
-
bool max(ImageBuf &dst, Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).
-
ImageBuf min(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Compute per-pixel
min(A, B)
, returning the result image.Either both
A
andB
are images, or one is an image and the other is acspan<float>
giving a per-channel constant or a single constant used for all channels.
-
bool min(ImageBuf &dst, Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).
-
ImageBuf clamp(const ImageBuf &src, cspan<float> min = -std::numeric_limits<float>::max(), cspan<float> max = std::numeric_limits<float>::max(), bool clampalpha01 = false, ROI roi = {}, int nthreads = 0)#
Return pixels of
src
with pixel values clamped as follows:- Parameters:
min – The minimum clamp value for each channel. If
min
is empty, no minimum clamping is performed.max – The maximum clamp value for each channel. If
max
is empty, no maximum clamping is performed.clampalpha01 – If true, then additionally any alpha channel is clamped to the 0-1 range.
-
ImageBuf max(Image_or_Const A, Image_or_Const B, ROI roi = {}, int nthreads = 0)#
Examples:
// min of images A and B, assign to MinImage ImageBuf A ("a.exr"); ImageBuf B ("b.exr"); ImageBuf MinImage = ImageBufAlgo::min (Sum, A, B); // Squash negative values in A by taking max(A, 0.0) for all channels ImageBuf A ("a.exr"); ImageBufAlgo::max (A, A, 0.0f); // Clamp image buffer A in-place to the [0,1] range for all pixels. ImageBufAlgo::clamp (A, A, 0.0f, 1.0f); // Just clamp alpha to [0,1] in-place ImageBufAlgo::clamp (A, A, -std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), true); // Clamp R & G to [0,0.5], leave other channels alone std::vector<float> min (A.nchannels(), -std::numeric_limits<float>::max()); std::vector<float> max (A.nchannels(), std::numeric_limits<float>::max()); min[0] = 0.0f; max[0] = 0.5f; min[1] = 0.0f; max[1] = 0.5f; ImageBufAlgo::clamp (A, A, &min[0], &max[0], false);# min of images A and B, assign to MinImage A = ImageBuf("a.exr") B = ImageBuf("b.exr") MinImage = ImageBufAlgo.min (Sum, A, B) # Squash negative values in A by taking max(A, 0.0) for all channels A = ImageBuf("a.exr") ImageBufAlgo.max (A, A, 0.0) # Clamp image buffer A in-place to the [0,1] range for all pixels. ImageBufAlgo.clamp (A, A, 0.0, 1.0) # Just clamp alpha to [0,1] in-place ImageBufAlgo.clamp (A, A, -1.0e30, 1.0e30, True) # Clamp R & G to [0,0.5], leave other channels alone ImageBufAlgo.clamp (A, A, (0, 0, -1.0e30, -1.0e30), (0.5, 0.5, 1.0e30, 1.0e30), False)# min of images A and B, assign to MinImage oiiotool a.exr b.exr --min -o minimage.exr # Squash negative values in A by taking max(A, 0.0) for all channels oiiotool.exr a.exr --maxc 0 -o a.exr # Clamp image buffer A in-place to the [0,1] range for all pixels. oiiotool.exr a.exr --clamp:min=0:max=1 -o a.exr # Just clamp alpha to [0,1] in-place oiiotool.exr a.exr --clamp:min=,,,0:max=,,,1 -o a.exr # Clamp R & G to [0,0.5], leave other channels alone oiiotool.exr a.exr --clamp:min=0,0,,,:max=1,1,,, -o a.exr
- group maxminchan
maxchan()
computes a one-channel image that for each pixel, contains the maximum value of all channels of corresponding pixel of the source image.minchan()
similarly computes the minimum value of all channels.- Version
2.3.10
Functions
-
ImageBuf maxchan(const ImageBuf &A, ROI roi = {}, int nthreads = 0)#
-
bool maxchan(ImageBuf &dst, const ImageBuf &A, ROI roi = {}, int nthreads = 0)#
-
ImageBuf minchan(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool minchan(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Examples:
// Computes the maximum of R, G, B. ImageBuf A ("rgb.exr"); ImageBuf B = ImageBufAlgo::maxchan (A);# Computes the maximum of R, G, B. A = ImageBuf("a.exr") B = ImageBufAlgo.maxchan (A)# Computes the maximum of R, G, B. oiiotool a.exr -maxchan -o b.exr
-
ImageBuf OIIO::ImageBufAlgo::contrast_remap(const ImageBuf &src, cspan<float> black = 0.0f, cspan<float> white = 1.0f, cspan<float> min = 0.0f, cspan<float> max = 1.0f, cspan<float> scontrast = 1.0f, cspan<float> sthresh = 0.5f, ROI = {}, int nthreads = 0)#
Return pixel values that are a contrast-remap of the corresponding values of the
src
image, transforming pixel value domain [black, white] to range [min, max], either linearly or with optional application of a smooth sigmoidal remapping (ifscontrast
!= 1.0).The following steps are performed, in order:
Linearly rescale values [
black
,white
] to [0, 1].If
scontrast
!= 1, apply a sigmoidal remapping where a largerscontrast
value makes a steeper slope, and the steepest part is at valuesthresh
(relative to the new remapped value after steps 1 & 2; the default is 0.5).Rescale the range of that result: 0.0 ->
min
and 1.0 ->max
.
Values outside of the [black,white] range will be extrapolated to outside [min,max], so it may be prudent to apply a clamp() to the results.
The black, white, min, max, scontrast, sthresh parameters may each either be a single float value for all channels, or a span giving per-channel values.
You can use this function for a simple linear contrast remapping of [black, white] to [min, max] if you use the default values for sthresh. Or just a simple sigmoidal contrast stretch within the [0,1] range if you leave all other parameters at their defaults, or a combination of these effects. Note that if
black
==white
, the result will be a simple binary thresholding where values <black
map tomin
and values >=black
map tomax
.
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::contrast_remap(ImageBuf &dst, const ImageBuf &src, cspan<float> black = 0.0f, cspan<float> white = 1.0f, cspan<float> min = 0.0f, cspan<float> max = 1.0f, cspan<float> scontrast = 1.0f, cspan<float> sthresh = 0.5f, ROI = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
ImageBuf A ("tahoe.tif"); // Simple linear remap that stretches input 0.1 to black, and input // 0.75 to white. ImageBuf linstretch = ImageBufAlgo::contrast_remap (A, 0.1f, 0.75f); // Remapping 0->1 and 1->0 inverts the colors of the image, // equivalent to ImageBufAlgo::invert(). ImageBuf inverse = ImageBufAlgo::contrast_remap (A, 1.0f, 0.0f); // Use a sigmoid curve to add contrast but without any hard cutoffs. // Use a contrast parameter of 5.0. ImageBuf sigmoid = ImageBufAlgo::contrast_remap (A, 0.0f, 1.0f, 0.0f, 1.0f, 5.0f);A = ImageBuf("tahoe.tif") # Simple linear remap that stretches input 0.1 to black, and input # 0.75 to white. linstretch = ImageBufAlgo.contrast_remap (A, 0.1, 0.75) # Remapping 0->1 and 1->0 inverts the colors of the image, # equivalent to ImageBufAlgo::invert(). inverse = ImageBufAlgo.contrast_remap (A, 1.0, 0.0) # Use a sigmoid curve to add contrast but without any hard cutoffs. # Use a contrast parameter of 5.0. sigmoid = ImageBufAlgo.contrast_remap (A, 0.0, 1.0, 0.0, 1.0, 5.0)# Simple linear remap that stretches input 0.1 to black, and input # 0.75 to white. oiiotool tahoe.exr --contrast:black=0.1:white=0.75 -o linstretch.exr # Remapping 0->1 and 1->0 inverts the colors of the image, # equivalent to ImageBufAlgo::invert(). oiiotool tahoe.tif --contrast:black=1.0:white=0.0:clamp=0 -o inverse.tif # Use a sigmoid curve to add contrast but without any hard cutoffs. # Use a contrast parameter of 5.0. oiiotool tahoe.tif --contrast:scontrast=5 -o sigmoid.tif
- group saturate
Increase or decrease color saturation of the image.
The
saturate
operation returns (or copies intodst
) the pixels ofsrc
within the ROI, and in the process adjusts the color saturation of the three consecutive channels starting withfirstchannel
based on thescale
parameter: 0.0 fully desaturates to a greyscale image of percaptually equivalent luminance, 1.0 leaves the colors unchanged,scale
values inside this range interpolate between them, andscale
> 1 would increase apparent color saturation.Channels that are within the range of
roi.chbegin
toroi.chend-1
, but outside the range offirstchannel
tofirstchannel+2
are simply copied unaltered. Only three channels at a time can be desaturated, by default the first three channels, thoughfirstchannel
may be used to specify a different subset of channels. It is allowed forsrc
anddst
to be the same image.- Version
2.4+
Examples:
ImageBuf img("tahoe.exr"); ImageBuf grey = ImageBufAlgo::saturate (img, 0.0f); ImageBuf colorful = ImageBufAlgo::saturate (img, 2.0f);img = ImageBuf("tahoe.exr") grey = ImageBufAlgo.saturate (img, 0.0) colorful = ImageBufAlgo.saturate (img, 2.0)oiiotool tahoe.exr -saturate 0.0 -o grey.exr oiiotool tahoe.exr -saturate 2.0 -o colorful.exr
- group color_map
Remap value range by spline or name
Return (or copy into
dst
) pixel values determined by looking up a color map using values of the source image, using either the channel specified bysrcchannel
, or the luminance ofsrc
’s RGB ifsrcchannel
is -1. This happens for all pixels within the ROI (which defaults to all ofsrc
), and ifdst
is not already initialized, it will be initialized to the ROI and with color channels equal tochannels
.In the variant that takes a
knots
parameter, this specifies the values of a linearly-interpolated color map given byknots[nknots*channels]
. An input value of 0.0 is mapped toknots[0..channels-1]
(one value for each color channel), and an input value of 1.0 is mapped toknots[(nknots-1)*channels..knots.size()-1]
.In the variant that takes a
mapname
parameter, this is the name of a color map. Recognized map names include: “inferno”, “viridis”, “magma”, “plasma”, all of which are perceptually uniform, strictly increasing in luminance, look good when converted to grayscale, and work for people with all types of colorblindness. Also “turbo” has most of these properties (except for being strictly increasing in luminance) and is a nice rainbow-like pattern. Also supported are the following color maps that do not have those desirable qualities (and are thus not recommended, but are present for back-compatibility or for use by clueless people): “blue-red”, “spectrum”, and “heat”. In all cases, the impliedchannels
is 3.Functions
-
ImageBuf color_map(const ImageBuf &src, int srcchannel, int nknots, int channels, cspan<float> knots, ROI roi = {}, int nthreads = 0)#
-
ImageBuf color_map(const ImageBuf &src, int srcchannel, string_view mapname, ROI roi = {}, int nthreads = 0)#
-
bool color_map(ImageBuf &dst, const ImageBuf &src, int srcchannel, int nknots, int channels, cspan<float> knots, ROI roi = {}, int nthreads = 0)#
-
bool color_map(ImageBuf &dst, const ImageBuf &src, int srcchannel, string_view mapname, ROI roi = {}, int nthreads = 0)#
-
ImageBuf color_map(const ImageBuf &src, int srcchannel, int nknots, int channels, cspan<float> knots, ROI roi = {}, int nthreads = 0)#
Examples:
// Use luminance of a.exr (assuming Rec709 primaries and a linear // scale) and map to a spectrum-like palette: ImageBuf A ("a.exr"); ImageBuf B = ImageBufAlgo::color_map (A, -1, "turbo"); // Use a custom color map float mymap[] = { 0.25, 0.25, 0.25, 0, 0.5, 0, 1, 0, 0 }; B = ImageBufAlgo::color_map (A, -1 /* use luminance */, 3 /* num knots */, 3 /* channels */, mymap);# Use luminance of a.exr (assuming Rec709 primaries and a linear # scale) and map to a spectrum-like palette: A = ImageBuf("a.exr") B = ImageBufAlgo.color_map (A, -1, "turbo") # Use a custom color map B = ImageBufAlgo.color_map (A, -1, (0.25, 0.25, 0.25, 0, 0.5, 0, 1, 0, 0))# Use luminance of a.exr (assuming Rec709 primaries and a linear # scale) and map to a spectrum-like palette: oiiotool a.exr --colormap turbo -o b.exr # Use a custom color map oiiotool a.exr --colormap turbo 0.25,0.25,0.25,0,0.5,0,1,0,0 -o b.exr
- group range
Nonlinear range remapping for contrast preservation
rangecompress()
returns (or copy intodst
) all pixels and color channels ofsrc
within regionroi
(defaulting to all the defined pixels ofdst
), rescaling their range with a logarithmic transformation. Alpha and z channels are not transformed.rangeexpand()
performs the inverse transformation (logarithmic back into linear).If
useluma
is true, the luma of channels [roi.chbegin..roi.chbegin+2] (presumed to be R, G, and B) are used to compute a single scale factor for all color channels, rather than scaling all channels individually (which could result in a color shift).The purpose of these function is as follows: Some image operations (such as resizing with a “good” filter that contains negative lobes) can have objectionable artifacts when applied to images with very high-contrast regions involving extra bright pixels (such as highlights in HDR captured or rendered images). By compressing the range pixel values, then performing the operation, then expanding the range of the result again, the result can be much more pleasing (even if not exactly correct).
Functions
-
ImageBuf rangecompress(const ImageBuf &src, bool useluma = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rangeexpand(const ImageBuf &src, bool useluma = false, ROI roi = {}, int nthreads = 0)#
-
bool rangecompress(ImageBuf &dst, const ImageBuf &src, bool useluma = false, ROI roi = {}, int nthreads = 0)#
-
bool rangeexpand(ImageBuf &dst, const ImageBuf &src, bool useluma = false, ROI roi = {}, int nthreads = 0)#
-
ImageBuf rangecompress(const ImageBuf &src, bool useluma = false, ROI roi = {}, int nthreads = 0)#
Examples:
In this example, we resize the image to 640x480, using a Lanczos3 filter, which has negative lobes. To prevent those negative lobes from producing ringing or negative pixel values for HDR data, do range compression, then resize, then re-expand the range.
// 1. Read the original image ImageBuf Src ("tahoeHDR.exr"); // 2. Range compress to a logarithmic scale ImageBuf Compressed = ImageBufAlgo::rangecompress (Src); // 3. Now do the resize ImageBuf Dst = ImageBufAlgo::resize (Compressed, { { "filtername", "lanczos3" } { "filterwidth", 6.0f } }, ROI(0, 640, 0, 480)); // 4. Expand range to be linear again (operate in-place) ImageBufAlgo::rangeexpand (Dst, Dst);# 1. Read the original image Src = ImageBuf("tahoeHDR.exr") # 2. Range compress to a logarithmic scale Compressed = ImageBufAlgo.rangecompress (Src) # 3. Now do the resize Dst = ImageBufAlgo.resize (Compressed, filtername="lanczos3", filterwidth=6.0, ROI(0, 640, 0, 480)) # 4. Expand range to be linear again (operate in-place) ImageBufAlgo.rangeexpand (Dst, Dst)oiiotool tahoeHDR.exr --rangecompress --resize 640x480 --rangeexpand -o out.exr # Alternately, the --resize command has an option to do the # range compression/expansion on its own: oiiotool tahoeHDR.exr --resize:highlightcomp=1 640x480 -o out.exr
Image comparison and statistics#
-
PixelStats OIIO::ImageBufAlgo::computePixelStats(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Compute statistics about the ROI of the
src
image, returning a PixelStats structure. Upon success, the returned vectors in the result structure will have size == src.nchannels(). If there is a failure, the vector sizes will be 0 and an error will be set in src.
The PixelStats structure is defined as follows in C++:
struct PixelStats { std::vector<float> min; std::vector<float> max; std::vector<float> avg; std::vector<float> stddev; std::vector<imagesize_t> nancount; std::vector<imagesize_t> infcount; std::vector<imagesize_t> finitecount; };Examples:
ImageBuf A ("a.exr"); auto stats = ImageBufAlgo::computePixelStats(A); if (stats.min.size() == 0) return; // empty vectors means we could not get the stats for (int c = 0; c < A.nchannels(); ++c) { std::cout << "Channel " << c << ":\n"; std::cout << " min = " << stats.min[c] << "\n"; std::cout << " max = " << stats.max[c] << "\n"; std::cout << " average = " << stats.avg[c] << "\n"; std::cout << " standard deviation = " << stats.stddev[c] << "\n"; std::cout << " # NaN values = " << stats.nancount[c] << "\n"; std::cout << " # Inf values = " << stats.infcount[c] << "\n"; std::cout << " # finite values = " << stats.finitecount[c] << "\n"; }A = ImageBuf("a.exr") stats = ImageBufAlgo.computePixelStats(A) if stats is None : return for c in A.channels : print ("Channel", c, ":") print (" min =", stats.min[c]) print (" max =", stats.max[c]) print (" average =", stats.avg[c]) print (" standard deviation =", stats.stddev[c]) print (" # NaN values =", stats.nancount[c]) print (" # Inf values =", stats.infcount[c]) print (" # finite values =", stats.finitecount[c])oiiotool -stats -v a.exr
-
CompareResults OIIO::ImageBufAlgo::compare(const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, ROI roi = {}, int nthreads = 0)#
Numerically compare two images. The difference threshold (for any individual color channel in any pixel) for a “failure” is failthresh, and for a “warning” is warnthresh. The results are stored in result. If roi is defined, pixels will be compared for the pixel and channel range that is specified. If roi is not defined, the comparison will be for all channels, on the union of the defined pixel windows of the two images (for either image, undefined pixels will be assumed to be black).
The CompareResults structure is defined in C++ as follows:
struct CompareResults { double meanerror, rms_error, PSNR, maxerror; int maxx, maxy, maxz, maxc; imagesize_t nwarn, nfail; bool error; };Examples:
ImageBuf A ("a.exr"); ImageBuf B ("b.exr"); auto comp = ImageBufAlgo::compare(A, B, 1.0f/255.0f, 0.0f); if (comp.nwarn == 0 && comp.nfail == 0) { std::cout << "Images match within tolerance\n"; } else { std::cout << "Image differed: " << comp.nfail << " failures, " << comp.nwarn << " warnings.\n"; std::cout << "Average error was " << comp.meanerror << "\n"; std::cout << "RMS error was " << comp.rms_error << "\n"; std::cout << "PSNR was " << comp.PSNR << "\n"; std::cout << "largest error was " << comp.maxerror << " on pixel (" << comp.maxx << "," << comp.maxy << "," << comp.maxz << "), channel " << comp.maxc << "\n"; }A = ImageBuf("a.exr") B = ImageBuf("b.exr") comp = ImageBufAlgo.compare(A, B, 1.0f/255.0f, 0.0f) if comp.nwarn == 0 and comp.nfail == 0 : print("Images match within tolerance" else : print("Image differed:", comp.nfail, "failures,", comp.nwarn, "warnings.") print("Average error was", comp.meanerror) print("RMS error was", comp.rms_error) print("PSNR was", comp.PSNR) print("largest error was", comp.maxerror, "on pixel (", comp.maxx, ",", comp.maxy, ",", comp.maxz, "), channel", comp.maxc)oiiotool a.exr b.exr --diff
-
int OIIO::ImageBufAlgo::compare_Yee(const ImageBuf &A, const ImageBuf &B, CompareResults &result, float luminance = 100, float fov = 45, ROI roi = {}, int nthreads = 0)#
Compare two images using Hector Yee’s perceptual metric, returning the number of pixels that fail the comparison. Only the first three channels (or first three channels specified by
roi
) are compared. Free parameters are the ambient luminance in the room and the field of view of the image display; our defaults are probably reasonable guesses for an office environment. The ‘result’ structure will store the maxerror, and the maxx, maxy, maxz of the pixel that failed most severely. (The other fields of the CompareResults are not used for Yee comparison.)Works for all pixel types. But it’s basically meaningless if the first three channels aren’t RGB in a linear color space that sort of resembles AdobeRGB.
Return true on success, false on error.
-
bool OIIO::ImageBufAlgo::isConstantColor(const ImageBuf &src, float threshold = 0.0f, span<float> color = {}, ROI roi = {}, int nthreads = 0)#
Do all pixels within the ROI have the same values for channels
[roi.chbegin..roi.chend-1]
, within a tolerance of +/-threshold
? If so, returntrue
and store that color incolor[chbegin...chend-1]
(ifcolor
is not empty); otherwise returnfalse
. Ifroi
is not defined (the default), it will be understood to be all of the defined pixels and channels of source.
Examples:
ImageBuf A ("a.exr"); std::vector<float> color (A.nchannels()); if (ImageBufAlgo::isConstantColor (A, color)) { std::cout << "The image has the same value in all pixels: "; for (int c = 0; c < A.nchannels(); ++c) std::cout << (c ? " " : "") << color[c]; std::cout << "\n"; } else { std::cout << "The image is not a solid color.\n"; }A = ImageBuf ("a.exr") color = ImageBufAlgo.isConstantColor (A, color) if color is not None : print ("The image has the same value in all pixels: ", color) else : print ("The image is not a solid color.")
-
bool OIIO::ImageBufAlgo::isConstantChannel(const ImageBuf &src, int channel, float val, float threshold = 0.0f, ROI roi = {}, int nthreads = 0)#
Does the requested channel have a given value (within a tolerance of +/-
threshold
) for every channel within the ROI? (For this function, the ROI’s chbegin/chend are ignored.) Returntrue
if so, otherwise returnfalse
. Ifroi
is not defined (the default), it will be understood to be all of the defined pixels and channels of source.
Examples:
ImageBuf A ("a.exr"); int alpha = A.spec().alpha_channel; if (alpha < 0) std::cout << "The image does not have an alpha channel\n"; else if (ImageBufAlgo::isConstantChannel (A, alpha, 1.0f)) std::cout << "The image has alpha = 1.0 everywhere\n"; else std::cout << "The image has alpha != 1 in at least one pixel\n";A = ImageBuf ("a.exr") alpha = A.spec.alpha_channel if alpha < 0 : print ("The image does not have an alpha channel") else if ImageBufAlgo.isConstantChannel (A, alpha, 1.0f) : print ("The image has alpha = 1.0 everywhere") else print ("The image has alpha != 1 in at least one pixel")
-
bool OIIO::ImageBufAlgo::isMonochrome(const ImageBuf &src, float threshold = 0.0f, ROI roi = {}, int nthreads = 0)#
Is the image monochrome within the ROI, i.e., for every pixel within the region, do all channels [roi.chbegin, roi.chend) have the same value (within a tolerance of +/- threshold)? If roi is not defined (the default), it will be understood to be all of the defined pixels and channels of source.
Examples:
ImageBuf A ("a.exr"); ROI roi = get_roi (A.spec()); roi.chend = std::min (3, roi.chend); // only test RGB, not alpha if (ImageBufAlgo::isMonochrome (A, roi)) std::cout << "a.exr is really grayscale\n";A = ImageBuf("a.exr") roi = A.roi.copy() roi.chend = min(3, roi.chend) if ImageBufAlgo.isMonochrome(A, roi) : print("a.exr is really grayscale")
-
bool OIIO::ImageBufAlgo::color_count(const ImageBuf &src, imagesize_t *count, int ncolors, cspan<float> color, cspan<float> eps = 0.001f, ROI roi = {}, int nthreads = 0)#
Count how many pixels in the ROI match a list of colors. The colors to match are in:
and so on, a total ofcolors[0 ... nchans-1] colors[nchans ... 2*nchans-1] ... colors[(ncolors-1)*nchans ... (ncolors*nchans)-1]
ncolors
consecutively stored colors ofnchans
channels each (nchans
is the number of channels in the image, itself, it is not passed as a parameter).eps[0..nchans-1]
are the error tolerances for a match, for each channel. Settingeps[c]
=numeric_limits<float>max()
will effectively make it ignore the channel. The defaulteps
is 0.001 for all channels (this value is chosen because it requires exact matches for 8 bit images, but allows a wee bit of imprecision for float images.Upon success, return
true
and store the number of pixels that matched each colorcount[0..ncolors-1]
. If there is an error, returnsfalse
and sets an appropriate error message set insrc
.
Examples:
ImageBuf A ("a.exr"); int n = A.nchannels(); // Try to match two colors: pure red and green std::vector<float> colors (2*n, numeric_limits<float>::max()); colors[0] = 1.0f; colors[1] = 0.0f; colors[2] = 0.0f; colors[n+0] = 0.0f; colors[n+1] = 1.0f; colors[n+2] = 0.0f; const int ncolors = 2; imagesize_t count[ncolors]; ImageBufAlgo::color_count (A, count, ncolors); std::cout << "Number of red pixels : " << count[0] << "\n"; std::cout << "Number of green pixels : " << count[1] << "\n";oiiotool a.exr --colorcount "1,0,0;0,1,0"
-
bool OIIO::ImageBufAlgo::color_range_check(const ImageBuf &src, imagesize_t *lowcount, imagesize_t *highcount, imagesize_t *inrangecount, cspan<float> low, cspan<float> high, ROI roi = {}, int nthreads = 0)#
Count how many pixels in the image (within the ROI) are outside the value range described by
low[roi.chbegin..roi.chend-1]
andhigh[roi.chbegin..roi.chend-1]
as the low and high acceptable values for each color channel.The number of pixels containing values that fall below the lower bound will be stored in
*lowcount
, the number of pixels containing values that fall above the upper bound will be stored in*highcount
, and the number of pixels for which all channels fell within the bounds will be stored in*inrangecount
. Any of these may be NULL, which simply means that the counts need not be collected or stored.
ImageBuf A ("a.exr"); ROI roi = get_roi (A.spec()); roi.chend = std::min (roi.chend, 4); // only compare RGBA float low[] = {0, 0, 0, 0}; float high[] = {1, 1, 1, 1}; imagesize_t lowcount, highcount, inrangecount; ImageBufAlgo::color_range_check (A, &lowcount, &highcount, &inrangecount, low, high, roi); std::cout << lowcount << " pixels had components < 0\n"; std::cout << highcount << " pixels had components > 1\n"; std::cout << inrangecount << " pixels were fully within [0,1] range\n";A = ImageBuf("a.exr") roi = A.roi.copy() roi.chend = min (roi.chend, 4) # only compare RGBA low = (0, 0, 0, 0) high = (1, 1, 1, 1) lowcount, highcount, inrangecount = ImageBufAlgo.color_range_check (A, low, high, roi) print(lowcount, "pixels had components < 0") print(highcount, "pixels had components > 1") print(inrangecount, "pixels were fully within [0,1] range")oiiotool a.exr --rangecheck "0,0,0,0;1,1,1,1"
-
ROI OIIO::ImageBufAlgo::nonzero_region(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Find the minimal rectangular region within
roi
(which defaults to the entire pixel data window ofsrc
) that consists of nonzero pixel values. In other words, gives the region that is a “shrink-wraps” ofsrc
to exclude black border pixels. Note that if the entire image was black, the ROI returned will contain no pixels.For “deep” images, this function returns the smallest ROI that contains all pixels that contain depth samples, and excludes the border pixels that contain no depth samples at all.
Examples:
ImageBuf A ("a.exr"); ROI shrunk = ImageBufAlgo::nonzero_region (A); if (shrunk.undefined()) std::cout << "All pixels were empty\n"; else std::cout << "Non-empty region was " << shrunk << "\n";A = ImageBuf("a.exr") shrunk = ImageBufAlgo.nonzero_region (A) if not shrunk.defined : print ("All pixels were empty") else : print ("Non-empty region was", shrunk)
-
std::string OIIO::ImageBufAlgo::computePixelHashSHA1(const ImageBuf &src, string_view extrainfo = "", ROI roi = {}, int blocksize = 0, int nthreads = 0)#
Compute the SHA-1 byte hash for all the pixels in the specified region of the image. If
blocksize
> 0, the function will compute separate SHA-1 hashes of eachblocksize
batch of scanlines, then return a hash of the individual hashes. This is just as strong a hash, but will NOT match a single hash of the entire image (blocksize==0
). But by breaking up the hash into independent blocks, we can parallelize across multiple threads, given bynthreads
(ifnthreads
is 0, it will use the global OIIO thread count). Theextrainfo
provides additional text that will be incorporated into the hash.
Examples:
ImageBuf A ("a.exr"); std::string hash; hash = ImageBufAlgo::computePixelHashSHA1 (A, "", ROI::All(), 64);A = ImageBuf("a.exr") hash = ImageBufAlgo.computePixelHashSHA1 (A, blocksize=64)
-
std::vector<imagesize_t> OIIO::ImageBufAlgo::histogram(const ImageBuf &src, int channel = 0, int bins = 256, float min = 0.0f, float max = 1.0f, bool ignore_empty = false, ROI roi = {}, int nthreads = 0)#
Compute a histogram of
src
, for the given channel and ROI. Return a vector of lengthbins
that contains the counts of how many pixel values were in each ofbins
equally spaced bins covering the range of values[min,max]
. Values <min
count for bin 0, values >max
count for binnbins-1
. Ifignore_empty
istrue
, no counts will be incremented for any pixels whose value is 0 in all channels.If there was an error, the returned vector will be empty, and an error message will be retrievable from src.geterror().
Examples:
ImageBuf Src ("tahoe.exr"); const int bins = 4; auto hist = ImageBufAlgo::histogram (Src, 0, bins, 0.0f, 1.0f); std::cout << "Channel 0 of the image had:\n"; float binsize = (max-min)/nbins; for (int i = 0; i < nbins; ++i) hist[i] << " pixels that are >= " << (min+i*binsize) << " and " << (i == nbins-1 ? " <= " : " < ") << (min+(i+1)*binsize) << "\n";Src = ImageBuf("tahoe.exr") bins = 4 hist = ImageBufAlgo.histogram (Src, channel=0, bins=4, min=0.0, max=1.0) print ("Channel 0 of the image had:") binsize = (max-min)/nbins for i in range(nbins) : print (hist[i], "pixels that are >=", (min+i*binsize), "and", ("<=" if i == nbins-1 else "<"), (min+(i+1)*binsize))
Convolutions and frequency-space algorithms#
-
ImageBuf OIIO::ImageBufAlgo::make_kernel(string_view name, float width, float height, float depth = 1.0f, bool normalize = true)#
Make a 1-channel
float
image of the named kernel. The size of the image will be big enough to contain the kernel given its size (width
xheight
) and rounded up to odd resolution so that the center of the kernel can be at the center of the middle pixel. If width and height are 0, the natural size of the named filter will be chosen. The kernel image will be offset so that its center is at the (0,0) coordinate. Ifnormalize
is true, the values will be normalized so that they sum to 1.0. Ifdepth
> 1, a volumetric kernel will be created. Use with caution!Kernel names can be: “gaussian”, “sharp-gaussian”, “box”, “triangle”, “blackman-harris”, “mitchell”, “b-spline”, “catmull-rom”, “lanczos3”, “disk”, “binomial”, “laplacian”.
Note that “catmull-rom” and “lanczos3” are fixed-size kernels that don’t scale with the width, and are therefore probably less useful in most cases.
The ImageBuf that is returned indicates if there was an error, in which case return.has_error() will be true and return.geterror() can be used to retrieve an error message.
Examples:
ImageBuf K = ImageBufAlgo::make_kernel ("gaussian", 5.0f, 5.0f);K = ImageBufAlgo.make_kernel ("gaussian", 5.0, 5.0)oiiotool --makekernel gaussian 5x5 -o kernel.exr
-
ImageBuf OIIO::ImageBufAlgo::convolve(const ImageBuf &src, const ImageBuf &kernel, bool normalize = true, ROI roi = {}, int nthreads = 0)#
Return the convolution of
src
and akernel
. Ifroi
is not defined, it defaults to the full sizesrc
. Ifnormalized
is true, the kernel will be normalized for the convolution, otherwise the original values will be used.
Result-as-parameter version:
- bool OIIO::ImageBufAlgo::convolve(ImageBuf &dst, const ImageBuf &src, const ImageBuf &kernel, bool normalize = true, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized). Ifroi
is not defined, it defaults to the full size ofdst
(orsrc
, ifdst
was uninitialized). Ifdst
is uninitialized, it will be allocated to be the size specified byroi
.Examples:
// Blur an image with a 5x5 Gaussian kernel ImageBuf Src ("tahoe.exr"); ImageBuf K = ImageBufAlgo::make_kernel ("gaussian", 5.0f, 5.0f); ImageBuf Blurred = ImageBufAlgo::convolve (Src, K);Src = ImageBuf("tahoe.exr") K = ImageBufAlgo.make_kernel ("gaussian", 5.0, 5.0) Blurred = ImageBufAlgo.convolve (Src, K)oiiotool tahoe.exr --makekernel gaussian 5x5 --convolve -o blurred.exr
-
ImageBuf OIIO::ImageBufAlgo::laplacian(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Return the Laplacian of the corresponding region of
src
. The Laplacian is the generalized second derivative of the image\[ \frac{\partial^2 s}{\partial x^2} + \frac{\partial^2 s}{\partial y^2} \][ 0 1 0 ] [ 1 -4 1 ] [ 0 1 0 ]
Result-as-parameter version:
Examples:
ImageBuf src ("tahoe.exr"); ImageBuf lap = ImageBufAlgo::laplacian (src);src = ImageBuf("tahoe.exr") lap = ImageBufAlgo.laplacian (src)oiiotool tahoe.exr --laplacian -o laplacian.exr
- group fft-ifft
Fast Fourier Transform and inverse
Return (or copy into
dst
) the discrete Fourier transform (DFT), or its inverse, of the section ofsrc
denoted by roi, If roi is not defined, it will be all ofsrc
’s pixels.fft()
takes the discrete Fourier transform (DFT) of the section ofsrc
denoted byroi
, returning it or storing it indst
. Ifroi
is not defined, it will be all ofsrc
’s pixels. Only one channel ofsrc
may be transformed at a time, so it will be the first channel described byroi
(or, again, channel 0 ifroi
is undefined). If not already in the correct format,dst
will be re-allocated to be a 2-channelfloat
buffer of sizeroi.width()
xroi.height
, with channel 0 being the “real” part and channel 1 being the the “imaginary” part. The values returned are actually the unitary DFT, meaning that it is scaled by 1/sqrt(npixels).ifft()
takes the inverse discrete Fourier transform, transforming a 2-channel complex (real and imaginary) frequency domain image and into a single-channel spatial domain image.src
must be a 2-channel float image, and is assumed to be a complex frequency-domain signal with the “real” component in channel 0 and the “imaginary” component in channel 1.dst
will end up being a float image of one channel (the real component is kept, the imaginary component of the spatial-domain will be discarded). Just as withfft()
, theifft()
function is dealing with the unitary DFT, so it is scaled by 1/sqrt(npixels).Functions
-
ImageBuf fft(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf ifft(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool fft(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool ifft(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf fft(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Examples:
ImageBuf Src ("tahoe.exr"); // Take the DFT of the first channel of Src ImageBuf Freq = ImageBufAlgo::fft (Src); // At this point, Freq is a 2-channel float image (real, imag) // Convert it back from frequency domain to a spatial image ImageBuf Spatial = ImageBufAlgo::ifft (Freq);src = ImageBuf("tahoe.exr") # Take the DFT of the first channel of Src Freq = ImageBufAlgo.fft (Src) # At this point, Freq is a 2-channel float image (real, imag) # Convert it back from frequency domain to a spatial image Spatial = ImageBufAlgo.ifft (Freq)oiiotool tahoe.exr --fft -o freq.exr oiiotool freq.exr --ifft -o spatial.exr
- group complex-polar
Converting complex to polar and back
The
polar_to_complex()
function transforms a 2-channel image whose channels are interpreted as complex values (real and imaginary components) into the equivalent values expressed in polar form of amplitude and phase (with phase between 0 and \( 2\pi \).The
complex_to_polar()
function performs the reverse transformation, converting from polar values (amplitude and phase) to complex (real and imaginary).In either case, the section of
src
denoted byroi
is transformed, storing the result indst
. Ifroi
is not defined, it will be all ofsrc
’s pixels. Only the first two channels ofsrc
will be transformed.The transformation between the two representations are:
real = amplitude * cos(phase); imag = amplitude * sin(phase); amplitude = hypot (real, imag); phase = atan2 (imag, real);
Functions
-
ImageBuf complex_to_polar(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool complex_to_polar(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf polar_to_complex(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool polar_to_complex(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf complex_to_polar(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Examples:
// Suppose we have an FFT in frequency space values expressed as // complex values (real, imaginary) ImageBuf fft ("fft.exr"); // Convert to polar values (amplitude, phase) ImageBuf Polar = ImageBufAlgo::complex_to_polar (fft); // Convert from polar back to (real, imag) ImageBuf Freq = ImageBufAlgo::polar_to_complex (Polar);# Suppose we have an FFT in frequency space values expressed as # complex values (real, imaginary) fft = ImageBuf("fft.exr") # Convert to polar values (amplitude, phase) Polar = ImageBufAlgo.complex_to_polar (fft) # Convert from polar back to (real, imag) Freq = ImageBufAlgo.polar_to_complex (Polar)# Suppose we have an FFT in frequency space values expressed as # complex values (real, imaginary). # Convert to polar values (amplitude, phase) oiiotool fft.exr --polar -o polar.exr # Convert from polar back to (real, imag) oiiotool polar.exr --unpolar -o freq.exr
Image Enhancement / Restoration#
-
ImageBuf OIIO::ImageBufAlgo::fixNonFinite(const ImageBuf &src, NonFiniteFixMode mode = NONFINITE_BOX3, int *pixelsFixed = nullptr, ROI roi = {}, int nthreads = 0)#
fixNonFinite()
returns an image containing the values ofsrc
(within the ROI), while repairing any non-finite (NaN/Inf) pixels. IfpixelsFixed
is not nullptr, store in it the number of pixels that contained non-finite value. It is permissible to operate in-place (withsrc
anddst
referring to the same image).How the non-finite values are repaired is specified by one of the
mode
parameter, which is an enum ofNonFiniteFixMode
.This function works on all pixel data types, though it’s just a copy for images with pixel data types that cannot represent NaN or Inf values.
- Result-as-parameter version:
Examples:
ImageBuf Src ("with_nans.tif"); int pixelsFixed = 0; ImageBufAlgo::fixNonFinite (Src, Src, ImageBufAlgo::NONFINITE_BOX3, &pixelsFixed); std::cout << "Repaired " << pixelsFixed << " non-finite pixels\n";Src = ImageBuf("with_nans.tif") ImageBufAlgo.fixNonFinite (Src, Src, oiio.NONFINITE_BOX3)oiiotool with_nans.tif --fixnan box3 -o with_nans_fixed.tif
-
ImageBuf OIIO::ImageBufAlgo::fillholes_pushpull(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Copy the specified ROI of
src
and fill any holes (pixels where alpha < 1) with plausible values using a push-pull technique. Thesrc
image must have an alpha channel. Thedst
image will end up with a copy ofsrc
, but will have an alpha of 1.0 everywhere withinroi
, and any place where the alpha ofsrc
was < 1,dst
will have a pixel color that is a plausible “filling” of the original alpha hole.
- Result-as-parameter version:
Examples:
ImageBuf Src ("checker_with_alpha.exr"); ImageBuf Filled = ImageBufAlgo::fillholes_pushpull (Src);Src = ImageBuf("checker_with_alpha.exr") Filled = ImageBufAlgo.fillholes_pushpull(Src)oiiotool checker_with_alpha.exr --fillholes -o checker_with_alpha_filled.exr
-
ImageBuf OIIO::ImageBufAlgo::median_filter(const ImageBuf &src, int width = 3, int height = -1, ROI roi = {}, int nthreads = 0)#
Return a median-filtered version of the corresponding region of
src
. The median filter replaces each pixel with the median value underneath thewidth
xheight
window surrounding it. Ifheight
<= 0, it will be set towidth
, making a square window.Median filters are good for removing high-frequency detail smaller than the window size (including noise), without blurring edges that are larger than the window size.
- Result-as-parameter version:
Examples:
ImageBuf Noisy ("tahoe.tif"); ImageBuf Clean = ImageBufAlgo::median_filter (Noisy, 3, 3);Noisy = ImageBuf("tahoe.tif") Clean = ImageBufAlgo.median_filter (Noisy, 3, 3)oiiotool tahoe.tif --median 3x3 -o tahoe_median_filter.tif
-
ImageBuf OIIO::ImageBufAlgo::unsharp_mask(const ImageBuf &src, string_view kernel = "gaussian", float width = 3.0f, float contrast = 1.0f, float threshold = 0.0f, ROI roi = {}, int nthreads = 0)#
Return a sharpened version of the corresponding region of
src
using the “unsharp mask” technique. Unsharp masking basically works by first blurring the image (low pass filter), subtracting this from the original image, then adding the residual back to the original to emphasize the edges. Roughly speaking,The specific blur can be selected by kernel name and width (for example, “gaussian” is typical). As a special case, “median” is also accepted as the kernel name, in which case a median filter is performed rather than a blurring convolution (Gaussian and other blurs sometimes over-sharpen edges, whereas using the median filter will sharpen compact high-frequency details while not over-sharpening long edges).dst = src + contrast * thresh(src - blur(src))
The
contrast
is a multiplier on the overall sharpening effect. The thresholding step causes all differences less thanthreshold
to be squashed to zero, which can be useful for suppressing sharpening of low-contrast details (like noise) but allow sharpening of higher-contrast edges.
- Result-as-parameter version:
Examples:
ImageBuf Blurry ("tahoe.tif"); ImageBuf Sharp = ImageBufAlgo::unsharp_mask (Blurry, "gaussian", 5.0f);Blurry = ImageBuf("tahoe.tif") Sharp = ImageBufAlgo.unsharp_mask (Blurry, "gaussian", 5.0)oiiotool tahoe.tif --unsharp:kernel=gaussian:width=5 -o tahoe_unsharp_mask.tif
Morphological filters#
-
ImageBuf OIIO::ImageBufAlgo::dilate(const ImageBuf &src, int width = 3, int height = -1, ROI roi = {}, int nthreads = 0)#
Return a dilated version of the corresponding region of
src
. Dilation is defined as the maximum value of all pixels under nonzero values of the structuring element (which is taken to be a width x height square). If height is not set, it will default to be the same as width. Dilation makes bright features wider and more prominent, dark features thinner, and removes small isolated dark spots.
-
ImageBuf OIIO::ImageBufAlgo::erode(const ImageBuf &src, int width = 3, int height = -1, ROI roi = {}, int nthreads = 0)#
Return an eroded version of the corresponding region of
src
. Erosion is defined as the minimum value of all pixels under nonzero values of the structuring element (which is taken to be a width x height square). If height is not set, it will default to be the same as width. Erosion makes dark features wider, bright features thinner, and removes small isolated bright spots.
Dilation and erosion are basic morphological filters, and more complex ones are often constructed from them:
“open” is erode followed by dilate, and it keeps the overall shape while removing small bright regions;
“close” is dilate followed by erode, and it keeps the overall shape while removing small dark regions;
“morphological gradient” is dilate minus erode, which gives a bright perimeter edge;
“tophat” is the original source minus the “open”, which isolates local peaks;
“bottomhat” is the “close” minus the original source, which isolates dark holes.
Examples:
ImageBuf Source ("source.tif"); ImageBuf Dilated = ImageBufAlgo::dilate (Source, 3, 3); ImageBuf Eroded = ImageBufAlgo::erode (Source, 3, 3); // Morphological "open" is dilate(erode((source)) ImageBuf Opened = ImageBufAlgo::dilate (Eroded, 3, 3); // Morphological "close" is erode(dilate(source)) ImageBuf Closed = ImageBufAlgo::erode (Dilated, 3, 3); // Morphological "gradient" is dilate minus erode ImageBuf Gradient = ImageBufAlgo::sub (Dilated, Eroded); // Tophat filter is source minus open ImageBuf Tophat = ImageBufAlgo::sub (Source, Opened); // Bottomhat filter is close minus source ImageBuf Bottomhat = ImageBufAlgo::sub (Close, Source);
Source = ImageBuf("source.tif") Dilated = ImageBufAlgo.dilate (Source, 3, 3) Eroded = ImageBufAlgo.erode (Source, 3, 3) # Morphological "open" is dilate(erode((source)) Opened = ImageBufAlgo.dilate (Eroded, 3, 3) # Morphological "close" is erode(dilate(source)) Closed = ImageBufAlgo.erode (Dilated, 3, 3) # Morphological "gradient" is dilate minus erode Gradient = ImageBufAlgo.sub (Dilated, Eroded) # Tophat filter is source minus open Tophat = ImageBufAlgo.sub (Source, Opened) # Bottomhat filter is close minus source Bottomhat = ImageBufAlgo.sub (Close, Source)
oiiotool source.tif --dilate 3x3 -o dilated.tif oiiotool source.tif --erode 3x3 -o eroded.tif # Morphological "open" is dilate(erode((source)) oiiotool source.tif --erode 3x3 --dilate 3x3 -o opened.tif # Morphological "close" is erode(dilate(source)) oiiotool source.tif --dilate 3x3 --erode 3x3 -o closed.tif # Morphological "gradient" is dilate minus erode oiiotool source.tif --dilate 3x3 source.tif --erode 3x3 --sub -o gradient.tif # Tophat filter is source minus open oiiotool source.tif source.tif --erode 3x3 --dilate 3x3 --sub -o tophat.tif # Bottomhat filter is close minus source oiiotool source.tif --dilate 3x3 --erode 3x3 source.tif --sub -o bottomhat.tif
Color space conversion#
- group colorconvert
Convert between color spaces
Return (or copy into
dst
) the pixels ofsrc
within the ROI, applying a color space transformation. In-place operations (dst
==src
) are supported.The first three channels are presumed to be the color to be transformed, and the fourth channel (if it exists) is presumed to be alpha. Any additional channels will be simply copied unaltered.
The transformation may be between any two spaces supported by the active OCIO configuration, or may be a “look” transformation created by
ColorConfig::createLookTransform
.- param fromspace/tospace:
For the varieties of
colorconvert()
that use named color spaces, these specify the color spaces by name.- param context_key/context_value:
For the varieties of
colorconvert()
that use named color spaces, these optionally specify a “key” name/value pair to establish a context (for example, a shot-specific transform).- param processor:
For the varieties of
colorconvert()
that have aprocessor
parameter, it is a rawColorProcessor*
object that implements the color transformation. This is a special object created by aColorConfig
(seeOpenImageIO/color.h
for details).- param unpremult:
If true, unpremultiply the image (divide the RGB channels by alpha if it exists and is nonzero) before color conversion, then repremult after the after the color conversion. Passing unpremult=false skips this step, which may be desirable if you know that the image is “unassociated alpha” (a.k.a., “not pre-multiplied colors”).
- param colorconfig:
An optional
ColorConfig*
specifying an OpenColorIO configuration. If not supplied, the default OpenColorIO color configuration found by examining the$OCIO
environment variable will be used instead.
Functions
-
ImageBuf colorconvert(const ImageBuf &src, string_view fromspace, string_view tospace, bool unpremult = true, string_view context_key = "", string_view context_value = "", const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Transform between named color spaces, returning an ImageBuf result.
-
ImageBuf colorconvert(const ImageBuf &src, const ColorProcessor *processor, bool unpremult, ROI roi = {}, int nthreads = 0)#
Transform using a ColorProcessor, returning an ImageBuf result.
-
bool colorconvert(ImageBuf &dst, const ImageBuf &src, string_view fromspace, string_view tospace, bool unpremult = true, string_view context_key = "", string_view context_value = "", const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Transform between named color spaces, storing reults into an existing ImageBuf.
-
bool colorconvert(ImageBuf &dst, const ImageBuf &src, const ColorProcessor *processor, bool unpremult, ROI roi = {}, int nthreads = 0)#
Transform using a ColorProcessor, storing reults into an existing ImageBuf.
-
bool colorconvert(span<float> color, const ColorProcessor *processor, bool unpremult)#
Apply a color transform in-place to just one color:
color[0..nchannels-1]
.nchannels
should either be 3 or 4 (if 4, the last channel is alpha).
Examples:
ImageBuf Src ("tahoe.jpg"); ImageBuf Dst = ImageBufAlgo::colorconvert (Src, "sRGB", "acescg", true);Src = ImageBuf("tahoe.jpg") Dst = ImageBufAlgo.colorconvert (Src, "sRGB", "acescg", True)oiiotool tahoe.jpg --colorconvert sRGB acescg -o tahoe_acescg.exr
-
ImageBuf OIIO::ImageBufAlgo::colormatrixtransform(const ImageBuf &src, M44fParam M, bool unpremult = true, ROI roi = {}, int nthreads = 0)#
Return a copy of the pixels of
src
within the ROI, applying a color transform specified by a 4x4 matrix. In-place operations (dst
==src
) are supported.The first three channels are presumed to be the color to be transformed, and the fourth channel (if it exists) is presumed to be alpha. Any additional channels will be simply copied unaltered.
- Version
2.1+
- Parameters:
M – A 4x4 matrix. Following Imath conventions, the color is a row vector and the matrix has the “translation” part in elements [12..14] (matching the memory layout of OpenGL or RenderMan), so the math is
color * Matrix
(NOTM*c
).unpremult – If true, unpremultiply the image (divide the RGB channels by alpha if it exists and is nonzero) before color conversion, then repremult after the after the color conversion. Passing unpremult=false skips this step, which may be desirable if you know that the image is “unassociated alpha” (a.k.a., “not pre-multiplied colors”).
- Result-as-parameter version:
Examples:
ImageBuf Src ("tahoe.exr"); Imath::M44f M ( .8047379, .5058794, -.3106172, 0, -.3106172, .8047379, .5058794, 0, .5058794, -.3106172, .8047379, 0, 0, 0, 0, 1); ImageBuf dst = ImageBufAlgo::colormatrixtransform (Src, M);Src = ImageBuf("tahoe.exr") M = ( .8047379, .5058794, -.3106172, 0, -.3106172, .8047379, .5058794, 0, .5058794, -.3106172, .8047379, 0, 0, 0, 0, 1 ) dst = ImageBufAlgo.colormatrixtransform (Src, M)oiiotool tahoe.exr --colormatrixtransform 0.8047379,0.5058794,-0.3106172,0,-0.3106172,0.8047379,0.5058794,0.5058794,-0.3106172,0,0,0,0,1,0 -o tahoe_matrix.exr
-
ImageBuf OIIO::ImageBufAlgo::ociolook(const ImageBuf &src, string_view looks, string_view fromspace, string_view tospace, bool unpremult = true, bool inverse = false, string_view context_key = "", string_view context_value = "", const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Return a copy of the pixels of
src
within the ROI, applying an OpenColorIO “look” transform to the pixel values. In-place operations (dst
==src
) are supported.The first three channels are presumed to be the color to be transformed, and the fourth channel (if it exists) is presumed to be alpha. Any additional channels will be simply copied unaltered.
- Parameters:
looks – The looks to apply (comma-separated).
fromspace/tospace – For the varieties of
colorconvert()
that use named color spaces, these specify the color spaces by name. If either is the empty string, it will use"scene_linear"
.unpremult – If true, unpremultiply the image (divide the RGB channels by alpha if it exists and is nonzero) before color conversion, then repremult after the after the color conversion. Passing unpremult=false skips this step, which may be desirable if you know that the image is “unassociated alpha” (a.k.a., “not pre-multiplied colors”).
inverse – If
true
, it will reverse the color transformation and look application.context_key/context_value – Optional key/value to establish a context (for example, a shot-specific transform).
colorconfig – An optional
ColorConfig*
specifying an OpenColorIO configuration. If not supplied, the default OpenColorIO color configuration found by examining the$OCIO
environment variable will be used instead.
- Result-as-parameter version:
- bool OIIO::ImageBufAlgo::ociolook(ImageBuf &dst, const ImageBuf &src, string_view looks, string_view fromspace, string_view tospace, bool unpremult = true, bool inverse = false, string_view context_key = "", string_view context_value = "", const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
ImageBuf Src ("tahoe.jpg"); ImageBuf Dst = ImageBufAlgo::ociolook (Src, "look", "vd8", "lnf", true, false, "SHOT", "pe0012");Src = ImageBuf("tahoe.jpg") Dst = ImageBufAlgo.ociolook (Src, "look", "vd8", "lnf", True, False, "SHOT", "pe0012")oiiotool tahoe.jpg --ociolook:from=vd8:to=lnf:unpremult=1:key=SHOT:value=pe0012 look -o out.exr
-
ImageBuf OIIO::ImageBufAlgo::ociodisplay(const ImageBuf &src, string_view display, string_view view, string_view fromspace = "", string_view looks = "", bool unpremult = true, bool inverse = false, string_view context_key = "", string_view context_value = "", const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Return the pixels of
src
within the ROI, applying an OpenColorIO “display” transform to the pixel values. In-place operations (dst
==src
) are supported.The first three channels are presumed to be the color to be transformed, and the fourth channel (if it exists) is presumed to be alpha. Any additional channels will be simply copied unaltered.
- Parameters:
display – The OCIO “display” to apply. If this is
"default"
or the empty string""
, the default display will be used.view – The OCIO “view” to use. If this is
"default"
or the empty string""
, the default view for this display will be used.fromspace – If
fromspace
is not supplied, it will assume that the source color space is whatever is indicated by the source image’s metadata or filename, and if that cannot be deduced, it will be assumed to be"scene_linear"
.looks – The looks to apply (comma-separated). This may be empty, in which case no “look” is used. Note: this parameter value is not used when building against OpenColorIO 2.x.
unpremult – If true, unpremultiply the image (divide the RGB channels by alpha if it exists and is nonzero) before color conversion, then repremult after the after the color conversion. Passing unpremult=false skips this step, which may be desirable if you know that the image is “unassociated alpha” (a.k.a., “not pre-multiplied colors”).
inverse – If
true
, it will reverse the color transformation and display application.context_key/context_value – Optional key/value to establish a context (for example, a shot-specific transform).
colorconfig – An optional
ColorConfig*
specifying an OpenColorIO configuration. If not supplied, the default OpenColorIO color configuration found by examining the$OCIO
environment variable will be used instead.
- Result-as-parameter version:
- bool OIIO::ImageBufAlgo::ociodisplay(ImageBuf &dst, const ImageBuf &src, string_view display, string_view view, string_view fromspace = "", string_view looks = "", bool unpremult = true, bool inverse = false, string_view context_key = "", string_view context_value = "", const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Write to an existing image
dst
(allocating if it is uninitialized).Examples:
ImageBuf Src ("tahoe.exr"); ImageBuf Dst = ImageBufAlgo::ociodisplay (Src, "sRGB", "Film", "lnf", "", true, "SHOT", "pe0012");Src = ImageBuf("tahoe.jpg") Dst = ImageBufAlgo.ociodisplay (Src, "sRGB", "Film", "lnf", "", True, "SHOT", "pe0012")oiiotool tahoe.jpg --ociodisplay:from=lnf:unpremult=1:key=SHOT:value=pe0012 sRGB Film -o out.exr
-
ImageBuf OIIO::ImageBufAlgo::ociofiletransform(const ImageBuf &src, string_view name, bool unpremult = true, bool inverse = false, const ColorConfig *colorconfig = nullptr, ROI roi = {}, int nthreads = 0)#
Return the pixels of
src
within the ROI, applying an OpenColorIO “file” transform. In-place operations (dst
==src
) are supported.The first three channels are presumed to be the color to be transformed, and the fourth channel (if it exists) is presumed to be alpha. Any additional channels will be simply copied unaltered.
- Parameters:
name – The name of the file containing the transform information.
unpremult – If true, unpremultiply the image (divide the RGB channels by alpha if it exists and is nonzero) before color conversion, then repremult after the after the color conversion. Passing unpremult=false skips this step, which may be desirable if you know that the image is “unassociated alpha” (a.k.a., “not pre-multiplied colors”).
inverse – If
true
, it will reverse the color transformation.colorconfig – An optional
ColorConfig*
specifying an OpenColorIO configuration. If not supplied, the default OpenColorIO color configuration found by examining the$OCIO
environment variable will be used instead.
- Result-as-parameter version:
Examples:
ImageBuf Src ("tahoe.exr"); ImageBuf Dst = ImageBufAlgo::ociofiletransform (Src, "footransform.csp");Src = ImageBuf("tahoe.exr") Dst = ImageBufAlgo.ociofiletransform (Src, "footransform.csp")oiiotool tahoe.exr --ociofiletransform:unpremult=1 footransform.csp -o out.exr
- group premult
Premultiply or un-premultiply color by alpha
The
unpremult
operation returns (or copies intodst
) the pixels ofsrc
within the ROI, and in the process divides all color channels (those not alpha or z) by the alpha value, to “un-premultiply” them. This presumes that the image starts of as “associated alpha” a.k.a. “premultipled,” and you are converting to “unassociated alpha.” For pixels with alpha == 0, the color values are not modified.The
premult
operation returns (or copies intodst
) the pixels ofsrc
within the ROI, and in the process multiplies all color channels (those not alpha or z) by the alpha value, to “premultiply” them. This presumes that the image starts of as “unassociated alpha” a.k.a. “non-premultipled” and converts it to “associated alpha / premultipled.”The
repremult
operation is likepremult
, but preserves the color values of pixels whose alpha is 0. This is intended for cases where you unpremult, do an operation (such as color transforms), then want to return to associated/premultiplied alpha — in that case, you want to make sure that “glow” pixels (those with alpha=0 but RGB > 0) are preserved for the round trip, and not crushed to black. This use case is distinct from a simplepremult
that is a one-time conversion from unassociated to associated alpha.All three operations are simply a copy if there is no identified alpha channel (and a no-op if
dst
andsrc
are the same image).Functions
-
ImageBuf unpremult(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool unpremult(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf premult(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool premult(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf repremult(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
bool repremult(ImageBuf &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
-
ImageBuf unpremult(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Examples:
// Convert from unassociated alpha to associated alpha by // straightforward multiplication of color by alpha. ImageBuf Unassoc; // Assume somehow this has unassociated alpha ImageBuf Assoc = ImageBufAlgo::premult (Unassoc); // Convert in-place from associated alpha to unassociated alpha, // preserving the color of alpha==0 pixels. ImageBuf A; ImageBufAlgo::unpremult (A, A); // Finish the round-trip back to associated, still preserving the // color of alpha==0 pixels. This should result in exactly the same // pixel values we started with (within precision limits). ImageBufAlgo::repremult (A, A);# Convert from unassociated alpha to associated alpha by # straightforward multiplication of color by alpha. Unassoc = ImageBuf(...) # Assume somehow this has unassociated alpha Assoc = ImageBufAlgo.premult (Unassoc) # Convert in-place from associated alpha to unassociated alpha, # preserving the color of alpha==0 pixels. A = ImageBuf(...) ImageBufAlgo.unpremult (A, A) # Finish the round-trip back to associated, still preserving the # color of alpha==0 pixels. This should result in exactly the same # pixel values we started with (within precision limits). ImageBufAlgo.repremult (A, A)# Convert from unassociated alpha to associated alpha by # straightforward multiplication of color by alpha. oiiotool unassoc.tif --premult -o assoc.tif # Convert in-place from associated alpha to unassociated alpha, # preserving the color of alpha==0 pixels. oiiotool A.tif --unpremult -o A.tif # Finish the round-trip back to associated, still preserving the # color of alpha==0 pixels. This should result in exactly the same # pixel values we started with (within precision limits). oiiotool A.tif --repremult -o A.tif
Import / export#
- group make_texture
The
make_texture()
function turns an image into a tiled, MIP-mapped, texture file and write it to disk (outputfilename).The return value is
true
for success,false
if an error occurred. If there was an error, any error message will be retrievable via the globalOIIO::geterror()
call (since there is no destinationImageBuf
in which to store it).Named fields in config:
format : Data format of the texture file (default: UNKNOWN = same format as the input)
tile_width/tile_height/tile_depth : Preferred tile size (default: 64x64x1)
Metadata in
config.extra_attribs
compression
(string) : Default: “zip”fovcot
(float) : Default: aspect ratio of the image resolution.planarconfig
(string) : Default: “separate”worldtocamera
(matrix) : World-to-camera matrix of the view.worldtoscreen
(matrix) : World-to-screen space matrix of the view.worldtoNDC
(matrix) : World-to-NDC space matrix of the view.wrapmodes
(string) : Default: “black,black”handed
(string) : “left” or “right” reveals the handedness of the coordinates for normal maps. (“”)maketx:verbose
(int) : How much detail should go to outstream (0).maketx:runstats
(int) : If nonzero, print run stats to outstream (0).maketx:resize
(int) : If nonzero, resize to power of 2. (0)maketx:nomipmap
(int) : If nonzero, only output the top MIP level (0).maketx:updatemode
(int) : If nonzero, write new output only if the output file doesn’t already exist, or is older than the input file, or was created with different command-line arguments. (0)maketx:constant_color_detect
(int) : If nonzero, detect images that are entirely one color, and change them to be low resolution (default: 0).maketx:monochrome_detect
(int) : If nonzero, change RGB images which have R==G==B everywhere to single-channel grayscale (default: 0).maketx:opaque_detect
(int) : If nonzero, drop the alpha channel if alpha is 1.0 in all pixels (default: 0).maketx:compute_average
(int) : If nonzero, compute and store the average color of the texture (default: 1).maketx:unpremult
(int) : If nonzero, unpremultiply color by alpha before color conversion, then multiply by alpha after color conversion (default: 0).maketx:incolorspace
,maketx:outcolorspace
(string) : These two together will apply a color conversion (with OpenColorIO, if compiled). Default: “”maketx:colorconfig
(string) : Specifies a custom OpenColorIO color config file. Default: “”maketx:checknan
(int) : If nonzero, will consider it an error if the input image has any NaN pixels. (0)maketx:fixnan
(string) : If set to “black” or “box3”, will attempt to repair any NaN pixels found in the input image (default: “none”).maketx:set_full_to_pixels
(int) : If nonzero, doctors the full/display window of the texture to be identical to the pixel/data window and reset the origin to 0,0 (default: 0).maketx:filtername
(string) : If set, will specify the name of a high-quality filter to use when resampling for MIPmap levels. Default: “”, use bilinear resampling.maketx:highlightcomp
(int) : If nonzero, performs highlight compensation — range compression and expansion around the resize, plus clamping negative pixel values to zero. This reduces ringing when using filters with negative lobes on HDR images.maketx:sharpen
(float) : If nonzero, sharpens details when creating MIPmap levels. The amount is the contrast metric. The default is 0, meaning no sharpening.maketx:nchannels
(int) : If nonzero, will specify how many channels the output texture should have, padding with 0 values or dropping channels, if it doesn’t the number of channels in the input. (default: 0, meaning keep all input channels)maketx:channelnames
(string) : If set, overrides the channel names of the output image (comma-separated).maketx:fileformatname
(string) : If set, will specify the output file format. (default: “”, meaning infer the format from the output filename)maketx:oiio_options
(int) : (Deprecated; all are handled by default)maketx:prman_options
(int) : If nonzero, override a whole bunch of settings as needed to make textures that are compatible with PRMan. This also enables prman_metadata. (0)maketx:prman_metadata
(int) : If set, output some metadata that PRMan will need for its textures. (0)maketx:mipimages
(string) : Semicolon-separated list of alternate images to be used for individual MIPmap levels, rather than simply downsizing. (default: “”)maketx:mipmap_metadata
(int) : If nonzero, will propagate metadata to every MIP level. The default (0) only writes metadata to the highest-resolution level. (0)maketx:full_command_line
(string) : The command or program used to generate this call, will be embedded in the metadata. (default: “”)maketx:ignore_unassoc
(int) : If nonzero, will disbelieve any evidence that the input image is unassociated alpha. (0)maketx:read_local_MB
(int) : If nonzero, will read the full input file locally if it is smaller than this threshold. Zero causes the system to make a good guess at a reasonable threshold (e.g. 1 GB). (0)maketx:forcefloat
(int) : Forces a conversion through float data for the sake of ImageBuf math. (1)maketx:hash
(int) : Compute the sha1 hash of the file in parallel. (1)maketx:allow_pixel_shift
(int) : Allow up to a half pixel shift per mipmap level. The fastest path may result in a slight shift in the image, accumulated for each mip level with an odd resolution. (0)maketx:bumpformat
(string) : For the MakeTxBumpWithSlopes mode, chooses whether to assume the map is a height map (“height”), a normal map (“normal”), or automatically determine it from the number of channels (“auto”, the default).maketx:uvslopes_scale
(float) : If nonzero, when used in MakeTxBumpWithSlopes mode, this computes derivatives for the bumpslopes data in UV space rather than in texel space, and divides them by this scale factor. The default is 0, disabling the feature. If you use this feature, a suggested value is 256.maketx:cdf
(int) : If nonzero, will write a Gaussian CDF and Inverse Gaussian CDF as per-channel metadata in the texture, which can be used by shaders to implement Histogram-Preserving Blending. This is only useful when the texture being created is written to an image format that supports arbitrary metadata (e.g. OpenEXR). (See Burley, “On Histogram-Preserving Blending
for Randomized Texture Tiling,” JCGT 8(4), 2019, and Heitz/Neyret, “High-Performance By-Example Noise using a Histogram-Preserving Blending Operator,” ACM SIGGRAPH / Eurographics Symposium on High-Performance Graphics 2018.) (default: 0)
maketx:cdfsigma
(float) : Whenmaketx:cdf
is active, determines the CDF sigma (default: 1.0/6).maketx:cdfbits
(int) : Whenmaketx:cdf
is active, determines the number of bits to use for the size of the CDF table. (default: 8, meaning 256 bins)
- param mode:
Describes what type of texture file we are creating and may be one of:
MakeTxTexture
: Ordinary 2D texture.MakeTxEnvLatl
: Latitude-longitude environment mapMakeTxEnvLatlFromLightProbe
: Latitude-longitude environment map constructed from a “light probe” image.MakeTxBumpWithSlopes
: Bump/displacement map with extra slope data channels (6 channels total, containing both the height and 1st and 2nd moments of slope distributions) for bump-to-roughness conversion in shaders.
- param outputfilename:
Name of the file in which to save the resulting texture.
- param config:
An ImageSpec that contains all the information and special instructions for making the texture. Anything set in config (format, tile size, or named metadata) will take precedence over whatever is specified by the input file itself. Additionally, named metadata that starts with “maketx:” will not be output to the file itself, but may contain instructions controlling how the texture is created. The full list of supported configuration options is listed below.
- param outstream:
If not
nullptr
, it should point to a stream (for example,&std::out
, or a pointer to a localstd::stringstream
to capture output), which is where console output and errors will be deposited. Note that error messages will also be retrievable from OIIO::geterror().
Functions
-
bool make_texture(MakeTextureMode mode, const ImageBuf &input, string_view outputfilename, const ImageSpec &config, std::ostream *outstream = nullptr)#
Version of make_texture that starts with an ImageBuf.
-
bool make_texture(MakeTextureMode mode, string_view filename, string_view outputfilename, const ImageSpec &config, std::ostream *outstream = nullptr)#
Version of make_texture that starts with a filename and reads the input from that file, rather than being given an ImageBuf directly.
-
bool make_texture(MakeTextureMode mode, const std::vector<std::string> &filenames, string_view outputfilename, const ImageSpec &config, std::ostream *outstream = nullptr)#
Version of make_texture that takes multiple filenames (reserved for future expansion, such as assembling several faces into a cube map).
Examples:
ImageBuf Input ("grid.exr"); ImageSpec config; config["maketx:highlightcomp"] = 1; config["maketx:filtername"] = "lanczos3"; config["maketx:opaque_detect"] = 1; bool ok = ImageBufAlgo::make_texture (ImageBufAlgo::MakeTxTexture, Input, "texture.exr", config); if (! ok) std::cout << "make_texture error: " << OIIO::geterror() << "\n";Input = ImageBuf("grid.exr") config = ImageSpec() config["maketx:highlightcomp"] = 1 config["maketx:filtername"] = "lanczos3" config["maketx:opaque_detect"] = 1 ok = ImageBufAlgo.make_texture (oiio.MakeTxTexture, Input, "texture.exr", config) if not ok : print("make_texture error:", oiio.geterror())oiiotool in.exr -otex:hilightcomp=1:filtername=lanczos3:opaque_detect=1 texture.exrmaketx in.exr --hicomp --filter lanczos3 --opaque-detect -o texture.exr
OpenCV interoperability is performed by the from_OpenCV()
and
to_OpenCV()
functions:
-
inline ImageBuf OIIO::ImageBufAlgo::from_OpenCV(const cv::Mat &mat, TypeDesc convert = TypeUnknown, ROI roi = {}, int nthreads = 0)#
Convert an OpenCV cv::Mat into an ImageBuf, copying the pixels (optionally converting to the pixel data type specified by
convert
, if not UNKNOWN, which means to preserve the original data type if possible). Return true if ok, false if it was not able to make the conversion from Mat to ImageBuf. Any error messages can be retrieved by callinggeterror()
on the returned ImageBuf. If OpenImageIO was compiled without OpenCV support, this function will return false.
-
inline bool OIIO::ImageBufAlgo::to_OpenCV(cv::Mat &dst, const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Construct an OpenCV cv::Mat containing the contents of ImageBuf src, and return true. If it is not possible, or if OpenImageIO was compiled without OpenCV support, then return false. Any error messages can be retrieved by calling OIIO::geterror(). Note that OpenCV only supports up to 4 channels, so >4 channel images will be truncated in the conversion.
-
inline ImageBuf OIIO::ImageBufAlgo::capture_image(int cameranum = 0, TypeDesc convert = TypeUnknown)#
Capture a still image from a designated camera. If able to do so, store the image in dst and return true. If there is no such device, or support for camera capture is not available (such as if OpenCV support was not enabled at compile time), return false and do not alter dst.
Examples:
ImageBuf WebcamImage = ImageBufAlgo::capture_image (0, TypeDesc::UINT8); WebcamImage.write ("webcam.jpg");
Deep images#
A number of ImageBufAlgo functions are designed to work with “deep” images. These are detailed below. In general, ImageBufAlgo functions not listed in this section should not be expected to work with deep images.
Functions specific to deep images#
-
ImageBuf OIIO::ImageBufAlgo::deepen(const ImageBuf &src, float zvalue = 1.0f, ROI roi = {}, int nthreads = 0)#
Return the “deep” equivalent of the “flat” input
src
. Turning a flat image into a deep one means:If the
src
image has a “Z” channel: if the source pixel’s Z channel value is not infinite, the corresponding pixel ofdst
will get a single depth sample that copies the data from the source pixel; otherwise, dst will get an empty pixel. In other words, infinitely far pixels will not turn into deep samples.If the
src
image lacks a “Z” channel: if any of the source pixel’s channel values are nonzero, the corresponding pixel ofdst
will get a single depth sample that copies the data from the source pixel and uses the zvalue parameter for the depth; otherwise, if all source channels in that pixel are zero, the destination pixel will get no depth samples.
If
src
is already a deep image, it will just copy pixel values fromsrc
.
- Result-as-parameter version:
Examples:
ImageBuf Flat ("RGBAZ.exr"); ImageBuf Deep = ImageBufAlgo::deepen (Flat);Flat = ImageBuf("RGBAZ.exr") Deep = ImageBufAlgo.deepen (Flat)oiiotool RGBAZ.exr --deepen -o deep.exr
-
ImageBuf OIIO::ImageBufAlgo::flatten(const ImageBuf &src, ROI roi = {}, int nthreads = 0)#
Return the “flattened” composite of deep image
src
. That is, it converts a deep image to a simple flat image by front-to- back compositing the samples within each pixel. Ifsrc
is already a non-deep/flat image, it will just copy pixel values fromsrc
todst
. Ifdst
is not already an initialized ImageBuf, it will be sized to matchsrc
(but made non-deep).
- Result-as-parameter version:
Examples:
ImageBuf Deep ("deepalpha.exr"); ImageBuf Flat = ImageBufAlgo::flatten (Deep);Deep = ImageBuf("deepalpha.exr") Flat = ImageBufAlgo.flatten (Deep)oiiotool deepalpha.exr --flatten -o flat.exr
-
ImageBuf OIIO::ImageBufAlgo::deep_merge(const ImageBuf &A, const ImageBuf &B, bool occlusion_cull = true, ROI roi = {}, int nthreads = 0)#
Return the deep merge of the samples of deep images
A
andB
, overwriting any existing samples ofdst
in the ROI. Ifocclusion_cull
is true, any samples occluded by an opaque sample will be deleted.
- Result-as-parameter version:
Examples:
ImageBuf DeepA ("hardsurf.exr"); ImageBuf DeepB ("volume.exr"); ImageBuf Merged = ImageBufAlgo::deep_merge (DeepA, DeepB);DeepA = ImageBuf("hardsurf.exr") DeepB = ImageBuf("volume.exr") Merged = ImageBufAlgo.deep_merge (DeepA, DeepB)oiiotool hardsurf.exr volume.exr --deep_merge -o merged.exr
-
ImageBuf OIIO::ImageBufAlgo::deep_holdout(const ImageBuf &src, const ImageBuf &holdout, ROI roi = {}, int nthreads = 0)#
Return the samples of deep image
src
that are closer than the opaque frontier of deep image holdout, returning true upon success and false for any failures. Samples ofsrc
that are farther than the first opaque sample of holdout (for the corresponding pixel)will not be copied todst
. Image holdout is only used as the depth threshold; no sample values from holdout are themselves copied todst
.