Image Objects¶
Image objects are how kernels interact with and process images within Blink. They are instantiated by declaring an image specification, and are usually the first things listed in a Blink kernel.
Image Specification¶
A kernel image specification takes the following form. The items specified in the angle brackets <>
describe how the image will be used in the kernel.
Image<*ReadSpec*, *AccessPattern*, *EdgeMethod*> image;
- ReadSpec
- This describes how the data in the image can be accessed. The options are:
eRead
Read-only access to the image data.eWrite
Write-only access to the image data.eReadWrite
Both read and write access to the image data.
Note
eReadWrite
is not available when writing kernels for BlinkScript nodes in Nuke.
- AccessPattern
- This describes how the kernel will access pixels in the image within the iteration space.
eAccessPoint
(Default). Access only the current position in the iteration space.eAccessRanged1D
Access a one-dimensional range of positions relative to the current position in the iteration space.eAccessRanged2D
Access a two-dimensional range of positions relative to the current position in the iteration space.eAccessRandom
Access any pixel in the iteration space using absolute pixel positions.
- EdgeMethod
- The edge method for an image defines the behaviour if a kernel function tries to access data outside the image bounds.
eEdgeNone
(Default). Values are undefined outside the image bounds and no within-bounds checks will be done when you access the image. This is the most efficient access method to use when you do not require access outside the bounds, because of the lack of bounds checks.eEdgeClamped
The edge values will be repeated outside the image bounds.eEdgeConstant
Zero values will be returned outside the image bounds.
Image Properties¶
The following properties are available from an Image
. More detail on the different variable types can be found here.
image.kMin
float
type. The minimum possible value for any component of the image data. Typically0.0f
.image.kMax
float
type. The maximum possible value for any component of the provided image data. Typically1.0f
.image.kWhitePoint
float
type. The minimum value for any component of the image data which is considered to be white. All values above this will be what are known as “super-whites”. A floating-point image will usually have a white point of1.0f
, though other values are also valid.image.kComps
int
type. The number of components in the image. For example in an RBGA image, this will be4
.image.kClamps
bool
type. Whether the image data should be clamped or not. For example, floating point data can take any value and thereforeimage.kClamps
will be false.image.bounds
The bounds of the image, used to find information such as the images width and height.
image.bounds.x1
int
type. The left-most horizontal value within the bounds.
image.bounds.x2
int
type. The right-most horizontal value within the bounds.
image.bounds.y1
int
type. The top-most vertical value within the bounds.
image.bounds.y2
int
type. The bottom-most vertical value within the bounds.
image.bounds.width()
Returns
int
type. The width of the bounds.x2 - x1
.
image.bounds.height()
Returns
int
type. The height of the bounds.y2 - y1
.
image.bounds.size()
Returns
int2
type. The width and height of the bounds as a vector.
Image variables can be used in the process()
and init()
kernel functions. For example:
kernel ImagePropertiesExample : ImageComputationKernel<eComponentWise>
{
Image<eRead, eAccessRandom, eEdgeConstant> src;
Image<eWrite> dst;
local:
float halfImgWidth;
float halfImgHeight;
void init() {
// Calculate half of the image bounds that will be used by all threads
halfImgWidth = (float)src.bounds.width() / 2.f;
halfImgHeight = (float)src.bounds.height() / 2.f;
}
void process(int3 pos) {
// Check that our component position is within the source image's components
if(pos.z < src.kComps) {
dst() = src(pos.x * 2 - halfImgWidth, pos.y * 2 - halfImgHeight);
}
else {
dst() = 0.f;
}
}
};
Using src.bounds
in the init()
method allows for expensive divide operations to be performed once and then used at every pixel position, optimising performance.
Using src.kComps
makes sure that if the number of output components is greater than the number of available input components, for example if this kernel is run on a four channel RGBA dst
image with a three channel RGB src
image, then the kernel will not try and access data that is not there.