VPI - Vision Programming Interface

0.2.0 Release

Image Format Converter

Overview

The Image Format Converter is used to convert an image with a given format into another format. It handles both color space, format and depth conversions. The algorithm also supports input range conversion, when one is required to map, for instance, an unsigned char \([0,255]\) image into signed short \([-32768,32767]\) range.

Color Input Grayscale Output

Implementation

The algorithm is implemented as a pixel-wise conversion function that reads in the input pixels, applies a conversion-dependent series of transformations and writes the result to the output image in the same position. User inputs are:

  • input image created with requested input type
  • output image created with requested output type
  • flags specify how type casts will be performed, see clamp/cast
  • scale and offset to be used in range conversions, see range.

Several types of conversion are available:

  • grayscale \(\leftrightarrow\) color
  • grayscale \(\leftrightarrow\) grayscale (useful in depth and range conversions)
  • color \(\leftrightarrow\) color (e.g. YUV to RGB and vice-versa)

The grayscale (or single channel) formats available are:

The color formats available are:

The following table shows which combinations of input and output image types are available for conversion.

in U8 S8 U16 S16 F32 NV12 RGB8 RGBA8 BGR8 BGRA8 2F32
out
U8 yes yes yes yes yes yes yes yes yes yes no
S8 yes yes yes yes yes yes yes yes yes yes no
U16 yes yes yes yes yes yes yes yes yes yes no
S16 yes yes yes yes yes yes yes yes yes yes no
F32 yes yes yes yes yes yes yes yes yes yes no
NV12 yes yes yes yes yes yes yes yes yes yes no
RGB8 yes yes yes yes yes yes yes yes yes yes no
RGBA8 yes yes yes yes yes yes yes yes yes yes no
BGR8 yes yes yes yes yes yes yes yes yes yes no
BGRA8 yes yes yes yes yes yes yes yes yes yes no
2F32 no no no no no no no no no no yes1

1 - Only available when scale == 1 and offset == 0

Conversion Formulas

The following sections describe how input value is converted into output. In general, these conversions amount to color space, depth, channel order (swizzle), adding or removing alpha channel, down- or up-sampling transformations. These are represented as conversion pipelines made out of basic processing blocks defined below.

Channel depth conversion

Channel depth conversion is represented by the block aptly named "depth" and is defined by the following sub-pipeline:

depth \(=\) range \(\rightarrow\) round \(\rightarrow\)

clamp/cast

  • range: input is converted to floating point (fp32) and the following formula is applied:

    \[ f(x) = \text{scale} \times x + \text{offset} \]

    If scale==1 and offset==0, a shortcut is taken and no operation (not even conversion to floating point) is performed.

  • round: round to the nearest integer, with halfway cases being rounded away from zero, e.g round(0.5) == 1.0 and round(-0.5) == -1.0.
  • clamp/cast: operation controlled by the passed flags:
    • VPI_CONVERSION_CAST : cast input to output type like regular C cast or C++'s static_cast would do. Underflows and overflows will behave as described by C specification (including undefined behavior). This is used when it's known that input range fits into output and maximum performance is needed.
    • VPI_CONVERSION_CLAMP : the value is clamped so that overflows and overflows will map to output type's maximum and minimum values, respectively. The result is then cast to the output type. When output type is floating point, clamp behaves like cast.

When applied to multiple channels such as RGB, the operation is performed on each channel independently.

Channel order conversion

This is represented by the following block:

swizzle

It's used to permute (or swizzle) input type's channel order. Used in conversions from/to color spaces that can be represented in multiple ways, like RGB and BGR. The color space conversion functions assume a pre-determined channel order. In order to use them, channels must be reordered.

Conversion between YUV and RGB

For RGB \(\leftrightarrow\) YUV conversions, VPI uses the ITU-R BT.601 625-line specification. It's the same standard used by JPEG File Interchange Format (JFIF).

To precisely establish the conversion, let's define the following constants:

\begin{align} K_r &= 0.299 \\ K_g &= 0.587 \\ K_b &= 0.114 \\ K_{c_b} &= 1.772 \\ K_{c_r} &= 1.402 \\ \end{align}

For notation convenience, we're assuming that \(U\) and \(V\) correspond to \(C_b\) and \(C_r\) respectively. This assumption doesn't hold in general.

The conversion blocks can be defined as:

rgb2yuv

\begin{align} Y(r,g,b) &= \text{round}(r K_r + g K_g + b K_b)\big|^{255}_{0} \\ C_b(r,g,b) &= \text{round}((-r K_r - g K_g + b (1 - K_b )) / K_ {c_b} + 128)\big|^{255}_{0} \\ C_r(r,g,b) &= \text{round}((r (1-K_r) - g K_g - b K_b) / K_{c_r} + 128)\big|^{255}_{0} \end{align}

These functions expect \(r,g,b \in [0,255]\)

yuv2rgb

\begin{align} R(y,c_b,c_r) &= \text{round}(y+K_{c_r}(c_r-128))\big|^{255}_{0} \\ G(y,c_b,c_r) &= \text{round}(y-[K_b K_{c_b} (c_b-128) + K_r K_{c_r} (c_r-128)] / K_g)\big|^{255}_{0} \\ B(y,c_b,c_r) &= \text{round}(y + K_{c_b} (c_b - 128))\big|^{255}_{0} \end{align}

These functions expect \(y,c_b,c_r \in [0,255]\)

The notation \(X\big|^{N} _ {M} \) represents clamping X's underflows and overflows to M and N respectively.

The round function follows the definition here.

Conversion between RGB and Grayscale

Conversion from RGB to grayscale follows the same specification used for conversion from RGB to YUV, but just returning the luma component. Hence, using the same constants defined here.

rgb2gray

\[ Y(r,g,b) = \text{round}(K_r \times r + K_g \times g + K_b \times b)\big|^{255}_{0} \]

For grayscale to RGB the conversion is simply:

gray2rgb

\[ f(x) = (x,x,x) \]

Up-/Down-sampling

For image formats that includes subsampled planes like VPI_IMAGE_TYPE_NV12, the following block definitions are needed:

2x downsample

\[ D[x,y] = S[2x,2y] \]

2x upsample

\[ D[x,y] = S[\lfloor x/2 \rfloor, \lfloor y/2 \rfloor] \]

Note
VPI is effectively upsamping using nearest-neighbor sampling. In a future version it'll use bilinear upsampling.

Alpha Channel Handling

Depending on input and output pixel type, i.e. whether it's required to remove or add an alpha channel, the following block might be used:

alpha
  • add alpha: append an opaque alpha channel to input pixel, e.g. RGB becomes RGBA. For integral channel types, the new alpha channel's value is the maximum representable of its type, e.g. 255 for 8-bit unsigned integer. Currently VPI doesn't support alpha channel on other channel types.
  • remove alpha: simply discards the alpha channel, e.g. RGBA becomes RGB.
  • do nothing: when input and output don't have alpha channel.

Conversion Pipelines

This section defines how input pixel is converted to output. It uses the basic conversion blocks defined in previous section.

Grayscale from/to Grayscale

input \(\rightarrow\) depth \(\rightarrow\)

output

Grayscale to NV12

input \(\rightarrow\) depth \(\rightarrow\) Y plane

\(\searrow\)

(128,128) \(\rightarrow\) UV plane

\(\nearrow\)

output
Note
Since NV12's pixel depth is 8-bit unsigned, \((u,v) = (128,128)\) corresponds to zero saturation.

NV12 to Grayscale

input

\(\rightarrow\)

Y plane \(\rightarrow\) depth \(\rightarrow\)

output

Grayscale to RGB space

input \(\rightarrow\) depth \(\rightarrow\) gray2rgb \(\rightarrow\) swizzle \(\rightarrow\) alpha \(\rightarrow\)

output

RGB space to Grayscale

input \(\rightarrow\) swizzle \(\rightarrow\) alpha \(\rightarrow\) rgb2gray \(\rightarrow\) depth \(\rightarrow\)

output

RGB space to NV12

input \(\rightarrow\) swizzle \(\rightarrow\) alpha \(\rightarrow\) depth \(\rightarrow\)

rgb2yuv

\(\nearrow\) Y plane

\(\searrow\)

\(\searrow\) UV plane \(\rightarrow\) 2x downsample

\(\nearrow\)

output

NV12 to RGB space

input
\(\nearrow\) Y plane \(\searrow\)
\(\searrow\) UV plane \(\rightarrow\) 2x upsample

\(\nearrow\)

yuv2rgb \(\rightarrow\) depth \(\rightarrow\) swizzle \(\rightarrow\) alpha \(\rightarrow\)

output

Usage

  1. Initialization phase
    1. Include the header that defines the image format converter function.
    2. Define the stream on which the algorithm will be executed.
      VPIStream stream = /*...*/;
    3. Define the input image. Here as an example we're creating a color image with dimensions \(w \times h\) and NV12 image type.
      VPIImage input;
    4. Create the output image with the destination image type. In this case, we want to convert the input to 16-bit signed integer grayscale.
      VPIImage output;
      vpiImageCreate(w, h, VPI_IMAGE_TYPE_S16, 0, &output);
  2. Processing phase
    1. Submit the algorithm to the stream, input, output images, specify we want clamping and also map the range from \([0,255]\) to \([-32768,32767]\).
      vpiSubmitImageFormatConverter(stream, input, output, VPI_CONVERSION_CLAMP, 257, -32768);
    2. Optionally, wait until the processing is done.
      vpiStreamSync(stream);

Limitations and Constraints

PVA

  • Not implemented.

Performance

For further information on how performance was benchmarked, see Performance Measurement.

Jetson AGX Xavier
sizeinput
type
output
type
conv.scaleoffsetCPUCUDAPVA
1920x1080u8u8cast10 0.1452 ms0.0603 msn/a
1920x1080u8u8clamp2128 1.37 ms0.1157 msn/a
1920x1080u8u16cast10 0.79 ms0.1234 msn/a
1920x1080u8f32cast10 0.211 ms0.1604 msn/a
1920x1080u8nv12cast10 0.749 ms0.1186 msn/a
1920x1080u8rgb8cast10 0.4 ms0.1929 msn/a
1920x1080u8rgba8cast10 0.2 ms0.1620 msn/a
1920x1080u16u8cast10 0.669 ms0.1120 msn/a
1920x1080u16u16cast10 0.322 ms0.1230 msn/a
1920x1080u16u16clamp2128 0.919 ms0.1402 msn/a
1920x1080u16f32cast10 0.882 ms0.1688 msn/a
1920x1080u16nv12cast10 0.737 ms0.1253 msn/a
1920x1080u16rgb8cast10 0.40 ms0.1961 msn/a
1920x1080u16rgba8cast10 0.3 ms0.1675 msn/a
1920x1080f32u8cast10 0.867 ms0.1219 msn/a
1920x1080f32u16cast10 0.694 ms0.1368 msn/a
1920x1080f32f32cast10 0.786 ms0.2505 msn/a
1920x1080f32f32clamp2128 1.036 ms0.1651 msn/a
1920x1080f32nv12cast10 0.93 ms0.1351 msn/a
1920x1080f32rgb8cast10 0.534 ms0.2057 msn/a
1920x1080f32rgba8cast10 0.414 ms0.1658 msn/a
1920x1080nv12u8cast10 0.449 ms0.1057 msn/a
1920x1080nv12u16cast10 0.84 ms0.1237 msn/a
1920x1080nv12f32cast10 0.233 ms0.1608 msn/a
1920x1080nv12nv12cast10 0.222 ms0.0927 msn/a
1920x1080nv12nv12clamp2128 1.70 ms0.1534 msn/a
1920x1080nv12rgb8cast10 3.75 ms0.1918 msn/a
1920x1080nv12rgba8cast10 3.21 ms0.1821 msn/a
1920x1080rgb8u8cast10 3.56 ms0.1263 msn/a
1920x1080rgb8u16cast10 3.65 ms0.1410 msn/a
1920x1080rgb8f32cast10 3.85 ms0.1663 msn/a
1920x1080rgb8nv12cast10 4.6 ms0.1480 msn/a
1920x1080rgb8rgb8cast10 0.569 ms0.1875 msn/a
1920x1080rgb8rgb8clamp2128 1.463 ms0.1817 msn/a
1920x1080rgb8bgr8cast10 1.0 ms0.2042 msn/a
1920x1080rgb8rgba8cast10 0.941 ms0.1601 msn/a
1920x1080rgba8u8cast10 4.34 ms0.1292 msn/a
1920x1080rgba8u16cast10 4.44 ms0.1417 msn/a
1920x1080rgba8f32cast10 4.85 ms0.1706 msn/a
1920x1080rgba8nv12cast10 5.3 ms0.1473 msn/a
1920x1080rgba8rgb8cast10 0.574 ms0.2038 msn/a
1920x1080rgba8rgba8cast10 0.797 ms0.2509 msn/a
1920x1080rgba8rgba8clamp2128 4.29 ms0.1743 msn/a
1920x1080rgba8bgra8cast10 0.41 ms0.1702 msn/a
Jetson TX2
sizeinput
type
output
type
conv.scaleoffsetCPUCUDAPVA
1920x1080u8u8cast10 0.553 ms1.770 msn/a
1920x1080u8u8clamp2128 2.4 ms0.448 msn/a
1920x1080u8u16cast10 0.45 ms0.430 msn/a
1920x1080u8f32cast10 0.645 ms0.50 msn/a
1920x1080u8nv12cast10 1.087 ms0.430 msn/a
1920x1080u8rgb8cast10 0.57 ms0.56 msn/a
1920x1080u8rgba8cast10 0.701 ms0.50 msn/a
1920x1080u16u8cast10 1.25 ms0.431 msn/a
1920x1080u16u16cast10 1.078 ms0.479 msn/a
1920x1080u16u16clamp2128 1.68 ms0.50 msn/a
1920x1080u16f32cast10 1.042 ms0.53 msn/a
1920x1080u16nv12cast10 1.29 ms0.457 msn/a
1920x1080u16rgb8cast10 1.132 ms0.58 msn/a
1920x1080u16rgba8cast10 1.16 ms0.53 msn/a
1920x1080f32u8cast10 1.83 ms0.47 msn/a
1920x1080f32u16cast10 1.053 ms0.50 msn/a
1920x1080f32f32cast10 2.060 ms0.804 msn/a
1920x1080f32f32clamp2128 1.35 ms0.56 msn/a
1920x1080f32nv12cast10 1.90 ms0.496 msn/a
1920x1080f32rgb8cast10 1.20 ms0.61 msn/a
1920x1080f32rgba8cast10 1.40 ms0.57 msn/a
1920x1080nv12u8cast10 0.84 ms0.405 msn/a
1920x1080nv12u16cast10 0.438 ms0.428 msn/a
1920x1080nv12f32cast10 0.65 ms0.50 msn/a
1920x1080nv12nv12cast10 0.895 ms2.572 msn/a
1920x1080nv12nv12clamp2128 3.04 ms0.579 msn/a
1920x1080nv12rgb8cast10 8.84 ms0.67 msn/a
1920x1080nv12rgba8cast10 8.6 ms0.65 msn/a
1920x1080rgb8u8cast10 11.9 ms0.52 msn/a
1920x1080rgb8u16cast10 13.39 ms0.54 msn/a
1920x1080rgb8f32cast10 13.98 ms0.60 msn/a
1920x1080rgb8nv12cast10 13.93 ms0.63 msn/a
1920x1080rgb8rgb8cast10 1.595 ms2.088 msn/a
1920x1080rgb8rgb8clamp2128 3.34 ms0.69 msn/a
1920x1080rgb8bgr8cast10 1.13 ms0.61 msn/a
1920x1080rgb8rgba8cast10 1.30 ms0.57 msn/a
1920x1080rgba8u8cast10 13.39 ms0.50 msn/a
1920x1080rgba8u16cast10 13.59 ms0.53 msn/a
1920x1080rgba8f32cast10 14.30 ms0.60 msn/a
1920x1080rgba8nv12cast10 14.08 ms0.59 msn/a
1920x1080rgba8rgb8cast10 1.15 ms0.60 msn/a
1920x1080rgba8rgba8cast10 2.088 ms0.804 msn/a
1920x1080rgba8rgba8clamp2128 11.1 ms0.70 msn/a
1920x1080rgba8bgra8cast10 1.310 ms0.57 msn/a
Jetson Nano
sizeinput
type
output
type
conv.scaleoffsetCPUCUDAPVA
1920x1080u8u8cast10 0.679 ms2.25 msn/a
1920x1080u8u8clamp2128 5.63 ms1.120 msn/a
1920x1080u8u16cast10 0.855 ms1.023 msn/a
1920x1080u8f32cast10 1.156 ms1.117 msn/a
1920x1080u8nv12cast10 1.731 ms1.044 msn/a
1920x1080u8rgb8cast10 1.007 ms1.303 msn/a
1920x1080u8rgba8cast10 1.112 ms1.137 msn/a
1920x1080u16u8cast10 2.65 ms1.029 msn/a
1920x1080u16u16cast10 1.2304 ms0.4015 msn/a
1920x1080u16u16clamp2128 4.26 ms1.194 msn/a
1920x1080u16f32cast10 2.45 ms1.174 msn/a
1920x1080u16nv12cast10 2.83 ms1.086 msn/a
1920x1080u16rgb8cast10 2.43 ms1.331 msn/a
1920x1080u16rgba8cast10 2.57 ms1.187 msn/a
1920x1080f32u8cast10 3.199 ms1.095 msn/a
1920x1080f32u16cast10 1.746 ms1.145 msn/a
1920x1080f32f32cast10 2.290 ms0.8010 msn/a
1920x1080f32f32clamp2128 1.909 ms1.239 msn/a
1920x1080f32nv12cast10 3.32 ms1.150 msn/a
1920x1080f32rgb8cast10 2.072 ms1.410 msn/a
1920x1080f32rgba8cast10 2.122 ms1.278 msn/a
1920x1080nv12u8cast10 1.622 ms0.988 msn/a
1920x1080nv12u16cast10 0.808 ms1.024 msn/a
1920x1080nv12f32cast10 0.910 ms1.116 msn/a
1920x1080nv12nv12cast10 0.963 ms3.285 msn/a
1920x1080nv12nv12clamp2128 6.95 ms1.458 msn/a
1920x1080nv12rgb8cast10 15.14 ms1.826 msn/a
1920x1080nv12rgba8cast10 14.929 ms1.766 msn/a
1920x1080rgb8u8cast10 24.41 ms1.331 msn/a
1920x1080rgb8u16cast10 24.667 ms1.378 msn/a
1920x1080rgb8f32cast10 25.28 ms1.452 msn/a
1920x1080rgb8nv12cast10 25.46 ms1.7450 msn/a
1920x1080rgb8rgb8cast10 1.772 ms2.48 msn/a
1920x1080rgb8rgb8clamp2128 7.2 ms1.737 msn/a
1920x1080rgb8bgr8cast10 1.88 ms1.472 msn/a
1920x1080rgb8rgba8cast10 2.5 ms1.332 msn/a
1920x1080rgba8u8cast10 24.67 ms1.214 msn/a
1920x1080rgba8u16cast10 25.14 ms1.272 msn/a
1920x1080rgba8f32cast10 25.68 ms1.375 msn/a
1920x1080rgba8nv12cast10 25.81 ms1.577 msn/a
1920x1080rgba8rgb8cast10 1.820 ms1.380 msn/a
1920x1080rgba8rgba8cast10 2.323 ms0.8022 msn/a
1920x1080rgba8rgba8clamp2128 29.57 ms1.696 msn/a
1920x1080rgba8bgra8cast10 1.892 ms1.292 msn/a
VPI_IMAGE_TYPE_S16
@ VPI_IMAGE_TYPE_S16
signed 16-bit grayscale.
Definition: Types.h:195
vpiStreamSync
VPIStatus vpiStreamSync(VPIStream stream)
Blocks the calling thread until all submitted commands in this stream queue are done (queue is empty)...
VPI_CONVERSION_CLAMP
@ VPI_CONVERSION_CLAMP
Clamps input to output's type range.
Definition: Types.h:372
ImageFormatConverter.h
VPIImage
struct VPIImageImpl * VPIImage
Definition: Types.h:170
vpiSubmitImageFormatConverter
VPIStatus vpiSubmitImageFormatConverter(VPIStream stream, VPIImage input, VPIImage output, VPIConversionPolicy convPolicy, float scale, float offset)
Converts the image contents to the desired format, with optional scaling and offset.
VPI_IMAGE_TYPE_NV12
@ VPI_IMAGE_TYPE_NV12
8-bit NV12.
Definition: Types.h:196
vpiImageCreate
VPIStatus vpiImageCreate(uint32_t width, uint32_t height, VPIImageType type, uint32_t flags, VPIImage *img)
Create an empty image instance with the specified flags.
VPIStream
struct VPIStreamImpl * VPIStream
Definition: Types.h:164