VPI - Vision Programming Interface

0.3.7 Release

Image Resampling

Overview

The Image Resampling application resamples the input image by first applying a low-pass filter to avoid aliasing, then doing a downsampling. The resulting image has half of input's width and one third of input's height. The result is then saved to disk.

This sample shows the following:

  • Creating and destroying a VPI stream.
  • Wrapping an image hosted on CPU (the input) to be used by VPI
  • Creating a VPI-managed 2D image.
  • Create a pipeline with two operations, GaussianFilter and Resample.
  • Simple stream synchronization.
  • Image locking to access its contents from CPU side.
  • Error handling.
  • Environment clean up.

Instructions

The usage is:

./vpi_sample_04_resample <backend> <input image>

where

  • backend: either cpu, cuda or pva; it defines the backend that will perform the processing.
  • input image: input image file name to be downsampled, it accepts png, jpeg and possibly others.

Here's one example:

./vpi_sample_04_resample cuda ../assets/kodim8.png

This is using the CUDA backend and one of the provided sample images. You can try with other images, respecting the constraints imposed by the algorithm.

Results

Input imageOutput image, downsampled

Source code

For convenience, here's the code that is also installed in the samples directory.

/*
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <opencv2/core/version.hpp>
#if CV_MAJOR_VERSION >= 3
# include <opencv2/imgcodecs.hpp>
#else
# include <opencv2/highgui/highgui.hpp>
#endif
#include <vpi/Image.h>
#include <vpi/Stream.h>
#include <cstring> // for memset
#include <iostream>
#define CHECK_STATUS(STMT) \
do \
{ \
VPIStatus status = (STMT); \
if (status != VPI_SUCCESS) \
{ \
throw std::runtime_error(vpiStatusGetName(status)); \
} \
} while (0);
int main(int argc, char *argv[])
{
VPIImage image = NULL;
VPIImage blurred = NULL;
VPIImage output = NULL;
VPIStream stream = NULL;
int retval = 0;
try
{
if (argc != 3)
{
throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|pva|cuda> <input image>");
}
std::string strDevType = argv[1];
std::string strInputFileName = argv[2];
// Load the input image
cv::Mat cvImage = cv::imread(strInputFileName, cv::IMREAD_GRAYSCALE);
if (cvImage.empty())
{
throw std::runtime_error("Can't open '" + strInputFileName + "'");
}
assert(cvImage.type() == CV_8UC1);
// Now process the device type
VPIDeviceType devType;
if (strDevType == "cpu")
{
}
else if (strDevType == "cuda")
{
}
else if (strDevType == "pva")
{
}
else
{
throw std::runtime_error("Backend '" + strDevType +
"' not recognized, it must be either cpu, cuda or pva.");
}
// Create the stream for the given backend.
CHECK_STATUS(vpiStreamCreate(devType, &stream));
// We now wrap the loaded image into a VPIImage object to be used by VPI.
{
// First fill VPIImageData with the, well, image data...
VPIImageData imgData;
memset(&imgData, 0, sizeof(imgData));
imgData.numPlanes = 1;
imgData.planes[0].width = cvImage.cols;
imgData.planes[0].height = cvImage.rows;
imgData.planes[0].rowStride = cvImage.step[0];
imgData.planes[0].data = cvImage.data;
// Wrap it into a VPIImage. VPI won't make a copy of it, so the original
// image must be in scope at all times.
CHECK_STATUS(vpiImageWrapHostMem(&imgData, 0, &image));
}
// Now create the output images, single unsigned 8-bit channel.
CHECK_STATUS(vpiImageCreate(cvImage.cols / 2, cvImage.rows / 3, VPI_IMAGE_TYPE_U8, 0, &output));
// Create a temporary image convolved with a low-pass filter.
CHECK_STATUS(vpiImageCreate(cvImage.cols, cvImage.rows, VPI_IMAGE_TYPE_U8, 0, &blurred));
// First we apply a low-pass filter using gaussian to avoid aliasing
CHECK_STATUS(vpiSubmitGaussianImageFilter(stream, image, blurred, 3, 7, 1, 2, VPI_BOUNDARY_COND_ZERO));
// Now we downsample
CHECK_STATUS(vpiSubmitImageResampler(stream, blurred, output, VPI_INTERP_CATMULL_ROM, VPI_BOUNDARY_COND_ZERO));
// Wait until the algorithm finishes processing
CHECK_STATUS(vpiStreamSync(stream));
// Now let's retrieve the output image contents and output it to disk
{
// Lock output image to retrieve its data on cpu memory
VPIImageData outData;
CHECK_STATUS(vpiImageLock(output, VPI_LOCK_READ, &outData));
cv::Mat cvOut(outData.planes[0].height, outData.planes[0].width, CV_8UC1, outData.planes[0].data,
outData.planes[0].rowStride);
imwrite("resampled_" + strDevType + ".png", cvOut);
// Done handling output image, don't forget to unlock it.
CHECK_STATUS(vpiImageUnlock(output));
}
}
catch (std::exception &e)
{
std::cerr << e.what() << std::endl;
retval = 1;
}
// Clean up
// Make sure stream is synchronized before destroying the objects
// that might still be in use.
if (stream != NULL)
{
vpiStreamSync(stream);
}
vpiImageDestroy(output);
vpiImageDestroy(blurred);
return retval;
}
VPIImagePlane::height
uint32_t height
Height of this plane in pixels.
Definition: Image.h:137
VPIImagePlane::width
uint32_t width
Width of this plane in pixels.
Definition: Image.h:136
GaussianImageFilter.h
VPI_DEVICE_TYPE_CPU
@ VPI_DEVICE_TYPE_CPU
CPU backend.
Definition: Types.h:556
VPI_LOCK_READ
@ VPI_LOCK_READ
Lock memory only for reading.
Definition: Types.h:499
VPIImagePlane::rowStride
uint32_t rowStride
Difference in bytes of beginning of one row and the beginning of the previous.
Definition: Image.h:138
vpiImageUnlock
VPIStatus vpiImageUnlock(VPIImage img)
Releases the lock on an image object.
vpiStreamCreate
VPIStatus vpiStreamCreate(VPIDeviceType devType, VPIStream *stream)
Create a stream instance.
vpiStreamSync
VPIStatus vpiStreamSync(VPIStream stream)
Blocks the calling thread until all submitted commands in this stream queue are done (queue is empty)...
VPIImageData
Stores information about image characteristics and content.
Definition: Image.h:155
VPIStream
struct VPIStreamImpl * VPIStream
A handle to a stream.
Definition: Types.h:177
vpiSubmitImageResampler
VPIStatus vpiSubmitImageResampler(VPIStream stream, VPIImage input, VPIImage output, VPIInterpolationType interpolationType, VPIBoundaryCond boundary)
Runs a generic resampling algorithm on a 2D image.
VPI_DEVICE_TYPE_PVA
@ VPI_DEVICE_TYPE_PVA
PVA backend.
Definition: Types.h:558
vpiStreamDestroy
void vpiStreamDestroy(VPIStream stream)
Destroy a stream instance and deallocate all HW resources.
VPIImageData::planes
VPIImagePlane planes[VPI_MAX_PLANE_COUNT]
Data of all image planes.
Definition: Image.h:162
VPI_DEVICE_TYPE_CUDA
@ VPI_DEVICE_TYPE_CUDA
CUDA backend.
Definition: Types.h:557
ImageResampler.h
vpiImageDestroy
void vpiImageDestroy(VPIImage img)
Destroy an image instance as well as all resources it owns.
Image.h
VPI_INTERP_CATMULL_ROM
@ VPI_INTERP_CATMULL_ROM
Alias to fast Catmull-Rom cubic interpolator.
Definition: Types.h:373
vpiImageWrapHostMem
VPIStatus vpiImageWrapHostMem(const VPIImageData *hostData, uint32_t flags, VPIImage *img)
Create an image object by wrapping around an existing host-memory block.
VPIImage
struct VPIImageImpl * VPIImage
A handle to an image.
Definition: Types.h:183
VPIImageData::numPlanes
int32_t numPlanes
Number of planes.
Definition: Image.h:157
VPI_BOUNDARY_COND_ZERO
@ VPI_BOUNDARY_COND_ZERO
All pixels outside the image are considered to be zero.
Definition: Types.h:270
vpiImageLock
VPIStatus vpiImageLock(VPIImage img, VPILockMode mode, VPIImageData *hostData)
Acquires the lock on an image object and returns a pointer to the image planes Depending on the inter...
VPIImageData::type
VPIImageType type
Image type.
Definition: Image.h:156
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.
VPI_IMAGE_TYPE_U8
@ VPI_IMAGE_TYPE_U8
unsigned 8-bit grayscale.
Definition: Types.h:208
Stream.h
VPIDeviceType
VPIDeviceType
Device types.
Definition: Types.h:554
VPIImagePlane::data
void * data
Pointer to the first row of this plane.
Definition: Image.h:146
vpiSubmitGaussianImageFilter
VPIStatus vpiSubmitGaussianImageFilter(VPIStream stream, VPIImage input, VPIImage output, uint32_t kernelSizeX, uint32_t kernelSizeY, float sigmaX, float sigmaY, VPIBoundaryCond boundary)
Runs a 2D Gaussian filter over an image.