Skip to content

Instantly share code, notes, and snippets.

@MitchellMitch
Last active July 27, 2020 11:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MitchellMitch/354f98acb45c99027c0a1c15a8537a69 to your computer and use it in GitHub Desktop.
Save MitchellMitch/354f98acb45c99027c0a1c15a8537a69 to your computer and use it in GitHub Desktop.
/*
* 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/Event.h>
#include <vpi/Image.h>
#include <vpi/Stream.h>
#include <vpi/algo/GaussianImageFilter.h>
#include <vpi/algo/ImageResampler.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 output = NULL;
VPIStream stream = NULL;
VPIEvent evStart = NULL;
VPIEvent evUpload = NULL;
VPIEvent evResample = NULL;
VPIEvent evDownload = 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")
{
devType = VPI_DEVICE_TYPE_CPU;
}
else if (strDevType == "cuda")
{
devType = VPI_DEVICE_TYPE_CUDA;
}
else if (strDevType == "pva")
{
devType = VPI_DEVICE_TYPE_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));
// Create the events we'll need to get timing info
CHECK_STATUS(vpiEventCreate(0, &evStart));
CHECK_STATUS(vpiEventCreate(0, &evUpload));
CHECK_STATUS(vpiEventCreate(0, &evResample));
CHECK_STATUS(vpiEventCreate(0, &evDownload));
// 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));
VPIImageData imgData;
memset(&imgData, 0, sizeof(imgData));
VPIImageData outData;
int n_samples = 1000;
float elapsedUploadMS, elapsedResampleMS, elapsedDownloadMS, elapsedTotalMS;
double sumUploadMS, sumResampleMS, sumDownloadMS, sumTotalMS;
for(int i = 0; i < n_samples; i++) {
// Record stream queue when we start processing
CHECK_STATUS(vpiEventRecord(evStart, stream));
// We now wrap the loaded image into a VPIImage object to be used by VPI.
{
imgData.type = VPI_IMAGE_TYPE_U8;
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));
}
CHECK_STATUS(vpiEventRecord(evUpload, stream));
// Now we downsample
CHECK_STATUS(
vpiSubmitImageResampler(stream, image, output, VPI_INTERP_NEAREST, VPI_BOUNDARY_COND_ZERO));
CHECK_STATUS(vpiEventRecord(evResample, stream));
// Wait until the algorithm finishes processing
CHECK_STATUS(vpiStreamSync(stream));
// Now let's retrieve the output image contents and output it to disk
{
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("/data/resampled_timing.png", cvOut);
// Done handling output image, don't forget to unlock it.
CHECK_STATUS(vpiImageUnlock(output));
}
CHECK_STATUS(vpiEventRecord(evDownload, stream));
CHECK_STATUS(vpiStreamSync(stream));
CHECK_STATUS(vpiEventElapsedTime(evStart, evUpload, &elapsedUploadMS));
CHECK_STATUS(vpiEventElapsedTime(evUpload, evResample, &elapsedResampleMS));
CHECK_STATUS(vpiEventElapsedTime(evResample, evDownload, &elapsedDownloadMS));
CHECK_STATUS(vpiEventElapsedTime(evStart, evDownload, &elapsedTotalMS));
sumUploadMS += elapsedUploadMS;
sumResampleMS += elapsedResampleMS;
sumDownloadMS += elapsedDownloadMS;
sumTotalMS += elapsedTotalMS;
}
printf("Num samples = %d\n", n_samples);
printf("avg. Upload -> : %f ms\n", sumUploadMS / n_samples);
printf("avg. Resample -> : %f ms\n", sumResampleMS / n_samples);
printf("avg. Download-> : %f ms\n", sumDownloadMS / n_samples);
printf("avg. Total -> : %f ms\n", sumTotalMS / n_samples);
}
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(image);
vpiImageDestroy(output);
vpiStreamDestroy(stream);
return retval;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment