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.
dwImageType type
Specifies the type of image.
uint32_t height
Specifies the height of the image in pixels.
uint32_t width
Specifies the width of the image in pixels.
dwImageFormat format
Specifies the format of the image.
dwImageMemoryType memoryLayout
Memory layout type.
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_MEMORY_TYPE_PITCH
pitch linear memory layout
@ DW_IMAGE_FORMAT_RGBA_UINT8
Defines the properties of the image.
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
DW_API_PUBLIC dwStatus dwImage_getCUDA(dwImageCUDA **const imageCUDA, dwImageHandle_t const image)
Retrieves the dwImageCUDA of a dwImageHandle_t.
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;
size_t srcPitch = planeChannels[0] * elemSize * imageCUDA->
prop.
width;
CHECK_FOR_CUDA_SUCCESS(cudaMemcpy2D(imageCUDA->
dptr[0],
pBytes,
srcPitch,
srcPitch,
cudaMemcpyHostToDevice),
"ImageCreateFromPNG: updateImage: Error: failed to copy to device buffer");
Defines a two-element unsigned-integer vector.
void * dptr[DW_MAX_IMAGE_PLANES]
Holds the pointer to the image planes.
dwImageProperties prop
Defines the properties of the image.
size_t pitch[DW_MAX_IMAGE_PLANES]
Defines the pitch of each plane in bytes.
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
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.
size_t elemSize = 0;
size_t planeCount = 0;
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,
dstWidth,
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";
}