DriveWorks SDK Reference
5.10.90 Release
For Test and Development only

Image initialization using PNG file

e

This tutorial demonstrates how to initialize a DW Image. A CUDA image is used as an example to show how it can be initialized using pixels obtained from a PNG file and how color pixels can be read from dw image and saved to PNG file. For interacting with PNG files, publicly available lodepng library is used.

Note
1. Lodepng library mentioned in this tutorial is a 3rd party library for PNG image files. Any other library can also be used for PNG or other file formats to load image file with specific format.
2. Refer to public documentation for Lodepng online for more details, error checking etc.
3. This tutorial uses cuda images. NvMedia or CPU images can also be used similarly by using respective APIs to copy pixels.
4. Error checking macros are for illustration purpose and may not actually be part of DW SDK

Steps for initializing DW image from an image file

Step 1: Loading a PNG image file

As described below, decode the PNG file to get image attributes and pixel data. These pixels will be used to initialize the DW image and the size(wxh) will be used to allocate DW image in next step.

uint8_t* pBytes = nullptr;
uint32_t width = 0;
uint32_t height = 0;
uint32_t bitDepth = 8;
uint32_t decodeRes = lodepng_decode_file(&pBytes, &width, &height, inFilePath.c_str(), LCT_RGBA, bitDepth);
if (decodeRes != 0)
{
std::cerr <<": loading png file failed. Error= "<< lodepng_error_text(decodeRes) << "(" << decodeRes << ") \n";
}

Step 2: Create a DW image file

Create an image as described here in "Basic Creation". This will allocate memory for the underlying image allocation.

dwImageProperties props = {};
props.height = height;
props.width = width;
CHECK_AND_HANDLE_ERROR(dwImage_create(&image, props, sdkContext));
dwImageType type
Specifies the type of image.
Definition: Image.h:392
uint32_t height
Specifies the height of the image in pixels.
Definition: Image.h:396
uint32_t width
Specifies the width of the image in pixels.
Definition: Image.h:394
dwImageFormat format
Specifies the format of the image.
Definition: Image.h:398
dwImageMemoryType memoryLayout
Memory layout type.
Definition: Image.h:402
DW_API_PUBLIC dwStatus dwImage_create(dwImageHandle_t *const image, dwImageProperties properties, dwContextHandle_t const ctx)
Creates and allocates resources for a dwImageHandle_t based on the properties passed as input.
@ DW_IMAGE_CUDA
Definition: Image.h:92
@ DW_IMAGE_MEMORY_TYPE_PITCH
pitch linear memory layout
Definition: Image.h:198
@ DW_IMAGE_FORMAT_RGBA_UINT8
Definition: Image.h:144
Defines the properties of the image.
Definition: Image.h:390

Step 3: Get cuda pointer for image memory

Get the underlying memory using dwImage_getCUDA API to get the cuda pointer for the underlying image

dwImageCUDA* imageCUDA = nullptr;
CHECK_AND_HANDLE_ERROR(dwImage_getCUDA(&imageCUDA, image));
DW_API_PUBLIC dwStatus dwImage_getCUDA(dwImageCUDA **const imageCUDA, dwImageHandle_t const image)
Retrieves the dwImageCUDA of a dwImageHandle_t.
Defines a CUDA image.
Definition: Image.h:420

Step 4: Initialize DW image using pixel data

Using the pixel data obtained above as source, copy it to the cuda pointer using cudaMemcpy2D API as shown below.

size_t elemSize = 0;
size_t planeCount = 0;
uint32_t planeChannels[DW_MAX_IMAGE_PLANES];
CHECK_AND_HANDLE_ERROR(dwImage_getDataLayout(&elemSize, &planeCount, planeChannels, planeSize, &imageCUDA->prop));
size_t srcPitch = planeChannels[0] * elemSize * imageCUDA->prop.width;
CHECK_FOR_CUDA_SUCCESS(cudaMemcpy2D(imageCUDA->dptr[0],
imageCUDA->pitch[0], // dst pitch
pBytes,
srcPitch, // src pitch
srcPitch, // src width
imageCUDA->prop.height,
cudaMemcpyHostToDevice),
"ImageCreateFromPNG: updateImage: Error: failed to copy to device buffer");
Defines a two-element unsigned-integer vector.
Definition: MatrixTypes.h:71
void * dptr[DW_MAX_IMAGE_PLANES]
Holds the pointer to the image planes.
Definition: Image.h:426
dwImageProperties prop
Defines the properties of the image.
Definition: Image.h:422
size_t pitch[DW_MAX_IMAGE_PLANES]
Defines the pitch of each plane in bytes.
Definition: Image.h:424
DW_API_PUBLIC dwStatus dwImage_getDataLayout(size_t *const elementSize, size_t *const planeCount, uint32_t planeChannelCount[DW_MAX_IMAGE_PLANES], dwVector2ui planeSize[DW_MAX_IMAGE_PLANES], dwImageProperties const *const prop)
Returns the expected data layout of an image given its properties.
#define DW_MAX_IMAGE_PLANES
Definition: Image.h:83

With above steps, a DW image can be initialized with pixel data obtained from png file.

Note
cudaMemcpy2D should be used as source and destination pitch may differ
Appropriate synchronization can be added when using cuda APIs as required

Saving image contents to file

Step 1: Get image pixels

The DW image pixel data is accessible using cuda pointer and can be copied using cudaMemcpy2D with cuda pointer as source and an array as destination. The destination shoulkd be large enough to hold pixel data.

const dwImageProperties& props = imageCUDA->prop;
size_t elemSize = 0;
size_t planeCount = 0;
uint32_t planeChannels[DW_MAX_IMAGE_PLANES];
CHECK_AND_HANDLE_ERROR(dwImage_getDataLayout(&elemSize, &planeCount, planeChannels, planeSize, &imageCUDA->prop));
size_t size = imageCUDA->prop.width * imageCUDA->prop.height * elemSize * planeChannels[0]; // use only 0th plane for planar image
size_t dstWidth = planeChannels[0] * elemSize * imageCUDA->prop.width;
std::unique_ptr<uint8_t[]> bytes(new uint8_t[size]);
CHECK_FOR_CUDA_SUCCESS(cudaMemcpy2D(bytes.get(),
dstWidth,
imageCUDA->dptr[0],
imageCUDA->pitch[0],
dstWidth,
props.height,
cudaMemcpyDeviceToHost),
"cudaMemcpy2DA failed");
Note
Before reading image using cudaMemcpy2D, application has to ensure that previous writes has finished.

Step 2: Wait for cuda copy to finish

After cudaMemcpy2D, and before using the destination, application should ensure that copy has finished before using the destination.

Step 3: Save the pixel bytes to PNG file

The pixel data buffer obtained from DW image can now be processed by application as desired or can be saved to an image file. An example to store it as PNG file is shown below.

uint32_t res = lodepng_encode_file(destPath.c_str(), bytes.get(), props.width, props.height, LCT_RGBA, elemSize * 8);
if (res != 0)
{
std::cerr << " saveImage: lodepng_encode_file returned error= "
<< lodepng_error_text(res) << "(" << res << ")\n";
}