VPI - Vision Programming Interface

0.4.4 Release

Harris Corners Detector

Overview

This application detects Harris corners from a given input image. The corners are then drawn onto the input image and the result is saved to harris.png.

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 1D array where corners output will be written to.
  • Create a properly-configured Harris algorithm and submit it to the stream.
  • Simple stream synchronization.
  • Array locking to access its contents from CPU side.
  • Error handling.
  • Environment clean up.

Instructions

The usage is:

./vpi_sample_03_harris_corners <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, it accepts png, jpeg and possibly others.

Once the sample is built, you can run it with the following command:

./vpi_sample_03_harris_corners pva ../assets/kodim08.png

This is using the PVA backend and one of the provided sample images. You can try with other input images, respecting the constraints imposed by the algorithm. If your stream doesn't support PVA, an error is printed. In this case, just try another backend.

Results

Input imageOutput image, Harris keypoints

Source Code

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

1 /*
2 * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of NVIDIA CORPORATION nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <opencv2/core/version.hpp>
30 #if CV_MAJOR_VERSION >= 3
31 # include <opencv2/imgcodecs.hpp>
32 #else
33 # include <opencv2/contrib/contrib.hpp> // for applyColorMap
34 # include <opencv2/highgui/highgui.hpp>
35 #endif
36 
37 #include <opencv2/imgproc/imgproc.hpp>
38 
39 #include <vpi/Array.h>
40 #include <vpi/Image.h>
41 #include <vpi/Status.h>
42 #include <vpi/Stream.h>
44 
45 #include <cstdio>
46 #include <cstring> // for memset
47 #include <iostream>
48 #include <sstream>
49 
50 #define CHECK_STATUS(STMT) \
51  do \
52  { \
53  VPIStatus status = (STMT); \
54  if (status != VPI_SUCCESS) \
55  { \
56  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
57  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
58  std::ostringstream ss; \
59  ss << vpiStatusGetName(status) << ": " << buffer; \
60  throw std::runtime_error(ss.str()); \
61  } \
62  } while (0);
63 
64 static cv::Mat DrawKeypoints(cv::Mat img, VPIKeypoint *kpts, uint32_t *scores, int numKeypoints)
65 {
66  cv::Mat out;
67  img.convertTo(out, CV_8UC1);
68  cvtColor(out, out, cv::COLOR_GRAY2BGR);
69 
70  if (numKeypoints == 0)
71  {
72  return out;
73  }
74 
75  // prepare our colormap
76  cv::Mat cmap(1, 256, CV_8UC3);
77  {
78  cv::Mat gray(1, 256, CV_8UC1);
79  for (int i = 0; i < 256; ++i)
80  {
81  gray.at<unsigned char>(0, i) = i;
82  }
83  applyColorMap(gray, cmap, cv::COLORMAP_HOT);
84  }
85 
86  float maxScore = *std::max_element(scores, scores + numKeypoints);
87 
88  for (int i = 0; i < numKeypoints; ++i)
89  {
90  cv::Vec3b color = cmap.at<cv::Vec3b>(scores[i] / maxScore * 255);
91  circle(out, cv::Point(kpts[i].x, kpts[i].y), 3, cv::Scalar(color[0], color[1], color[2]), -1);
92  }
93 
94  return out;
95 }
96 
97 int main(int argc, char *argv[])
98 {
99  VPIImage image = NULL;
100  VPIArray keypoints = NULL;
101  VPIArray scores = NULL;
102  VPIStream stream = NULL;
103  VPIPayload harris = NULL;
104 
105  int retval = 0;
106 
107  try
108  {
109  if (argc != 3)
110  {
111  throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|pva|cuda> <input image>");
112  }
113 
114  std::string strBackend = argv[1];
115  std::string strInputFileName = argv[2];
116 
117  // Load the input image
118  cv::Mat cvImage = cv::imread(strInputFileName, cv::IMREAD_GRAYSCALE);
119  if (cvImage.empty())
120  {
121  throw std::runtime_error("Can't open '" + strInputFileName + "'");
122  }
123 
124  // Currently we only accept signed 16bpp
125  cvImage.convertTo(cvImage, CV_16SC1);
126 
127  // Now parse the backend
128  VPIBackend backendType;
129 
130  if (strBackend == "cpu")
131  {
132  backendType = VPI_BACKEND_CPU;
133  }
134  else if (strBackend == "cuda")
135  {
136  backendType = VPI_BACKEND_CUDA;
137  }
138  else if (strBackend == "pva")
139  {
140  backendType = VPI_BACKEND_PVA;
141  }
142  else
143  {
144  throw std::runtime_error("Backend '" + strBackend +
145  "' not recognized, it must be either cpu, cuda or pva.");
146  }
147 
148  // Create the stream for the given backend.
149  CHECK_STATUS(vpiStreamCreate(backendType, &stream));
150 
151  // We now wrap the loaded image into a VPIImage object to be used by VPI.
152  {
153  // First fill VPIImageData with the, well, image data...
154  VPIImageData imgData;
155  memset(&imgData, 0, sizeof(imgData));
156  imgData.type = VPI_IMAGE_FORMAT_S16;
157  imgData.numPlanes = 1;
158  imgData.planes[0].width = cvImage.cols;
159  imgData.planes[0].height = cvImage.rows;
160  imgData.planes[0].pitchBytes = cvImage.step[0];
161  imgData.planes[0].data = cvImage.data;
162 
163  // Wrap it into a VPIImage. VPI won't make a copy of it, so the original
164  // image must be in scope at all times.
165  CHECK_STATUS(vpiImageCreateHostMemWrapper(&imgData, 0, &image));
166  }
167 
168  // Create the output keypoint array. Currently for PVA backend it must have 8192 elements.
169  CHECK_STATUS(vpiArrayCreate(8192, VPI_ARRAY_TYPE_KEYPOINT, 0, &keypoints));
170 
171  // Create the output scores array. It also must have 8192 elements and elements must be uint32_t.
172  CHECK_STATUS(vpiArrayCreate(8192, VPI_ARRAY_TYPE_U32, 0, &scores));
173 
174  // Create the payload for Harris Corners Detector algorithm
175  CHECK_STATUS(vpiCreateHarrisCornerDetector(backendType, cvImage.cols, cvImage.rows, &harris));
176 
177  // Submit it for processing passing the inputs and outputs.
178  {
180  params.gradientSize = 5;
181  params.blockSize = 5;
182  params.strengthThresh = 20;
183  params.sensitivity = 0.01;
184  params.minNMSDistance = 8; // must be 8 for PVA backend
185 
186  CHECK_STATUS(vpiSubmitHarrisCornerDetector(stream, harris, image, keypoints, scores, &params));
187  }
188 
189  // Wait until the algorithm finishes processing
190  CHECK_STATUS(vpiStreamSync(stream));
191 
192  // Now let's retrieve the output
193  {
194  // Lock output keypoints and scores to retrieve its data on cpu memory
195  VPIArrayData outKeypointsData;
196  VPIArrayData outScoresData;
197  CHECK_STATUS(vpiArrayLock(keypoints, VPI_LOCK_READ, &outKeypointsData));
198  CHECK_STATUS(vpiArrayLock(scores, VPI_LOCK_READ, &outScoresData));
199 
200  VPIKeypoint *outKeypoints = (VPIKeypoint *)outKeypointsData.data;
201  uint32_t *outScores = (uint32_t *)outScoresData.data;
202 
203  printf("%d keypoints found\n", outKeypointsData.size);
204 
205  cv::Mat outImage = DrawKeypoints(cvImage, outKeypoints, outScores, outKeypointsData.size);
206 
207  imwrite("harris_corners_" + strBackend + ".png", outImage);
208 
209  // Done handling outputs, don't forget to unlock them.
210  CHECK_STATUS(vpiArrayUnlock(scores));
211  CHECK_STATUS(vpiArrayUnlock(keypoints));
212  }
213  }
214  catch (std::exception &e)
215  {
216  std::cerr << e.what() << std::endl;
217  retval = 1;
218  }
219 
220  // Clean up
221 
222  // Make sure stream is synchronized before destroying the objects
223  // that might still be in use.
224  if (stream != NULL)
225  {
226  vpiStreamSync(stream);
227  }
228 
229  vpiImageDestroy(image);
230  vpiArrayDestroy(keypoints);
231  vpiArrayDestroy(scores);
232  vpiPayloadDestroy(harris);
233  vpiStreamDestroy(stream);
234 
235  return retval;
236 }
VPIImagePlane::height
uint32_t height
Height of this plane in pixels.
Definition: Image.h:138
vpiArrayDestroy
void vpiArrayDestroy(VPIArray array)
Destroy an array instance.
VPIHarrisCornerDetectorParams::strengthThresh
float strengthThresh
Specifies the minimum threshold with which to eliminate Harris Corner scores.
Definition: HarrisCornerDetector.h:88
VPIImagePlane::width
uint32_t width
Width of this plane in pixels.
Definition: Image.h:137
vpiArrayCreate
VPIStatus vpiArrayCreate(uint32_t capacity, VPIArrayType fmt, uint32_t flags, VPIArray *array)
Create an empty array instance.
vpiStreamCreate
VPIStatus vpiStreamCreate(uint32_t flags, VPIStream *stream)
Create a stream instance.
VPIBackend
VPIBackend
VPI Backend types.
Definition: Types.h:89
VPI_LOCK_READ
@ VPI_LOCK_READ
Lock memory only for reading.
Definition: Types.h:447
vpiCreateHarrisCornerDetector
VPIStatus vpiCreateHarrisCornerDetector(VPIBackend backend, uint32_t inputWidth, uint32_t inputHeight, VPIPayload *payload)
Creates a Harris Corner Detector payload.
vpiArrayUnlock
VPIStatus vpiArrayUnlock(VPIArray array)
Releases the lock on array object.
Array.h
Functions and structures for dealing with VPI arrays.
vpiPayloadDestroy
void vpiPayloadDestroy(VPIPayload payload)
Deallocates the payload object and all associated resources.
vpiStreamSync
VPIStatus vpiStreamSync(VPIStream stream)
Blocks the calling thread until all submitted commands in this stream queue are done (queue is empty)...
VPI_BACKEND_CUDA
@ VPI_BACKEND_CUDA
CUDA backend.
Definition: Types.h:91
VPIImageData
Stores information about image characteristics and content.
Definition: Image.h:159
VPI_IMAGE_FORMAT_S16
@ VPI_IMAGE_FORMAT_S16
Single plane with one 16-bit signed integer channel.
Definition: ImageFormat.h:108
VPIStream
struct VPIStreamImpl * VPIStream
A handle to a stream.
Definition: Types.h:190
VPIArrayData::size
uint32_t size
Number of elements in the array.
Definition: Array.h:119
vpiStreamDestroy
void vpiStreamDestroy(VPIStream stream)
Destroy a stream instance and deallocate all HW resources.
VPIArrayData::data
void * data
Points to the first element of the array.
Definition: Array.h:122
VPIImageData::planes
VPIImagePlane planes[VPI_MAX_PLANE_COUNT]
Data of all image planes.
Definition: Image.h:166
vpiImageDestroy
void vpiImageDestroy(VPIImage img)
Destroy an image instance.
VPIHarrisCornerDetectorParams::gradientSize
uint32_t gradientSize
Gradient window size.
Definition: HarrisCornerDetector.h:82
VPI_ARRAY_TYPE_KEYPOINT
@ VPI_ARRAY_TYPE_KEYPOINT
VPIKeypoint element.
Definition: Types.h:233
vpiSubmitHarrisCornerDetector
VPIStatus vpiSubmitHarrisCornerDetector(VPIStream stream, VPIPayload payload, VPIImage input, VPIArray outFeatures, VPIArray outScores, const VPIHarrisCornerDetectorParams *params)
Submits Harris Corner Detector operation to the stream associated with the payload.
Image.h
Functions and structures for dealing with VPI images.
VPIImagePlane::pitchBytes
uint32_t pitchBytes
Difference in bytes of beginning of one row and the beginning of the previous.
Definition: Image.h:139
VPIImage
struct VPIImageImpl * VPIImage
A handle to an image.
Definition: Types.h:196
VPIImageData::numPlanes
int32_t numPlanes
Number of planes.
Definition: Image.h:161
VPIArrayData
Stores information about array characteristics and content.
Definition: Array.h:117
VPIPayload
struct VPIPayloadImpl * VPIPayload
A handle to an algorithm payload.
Definition: Types.h:208
VPIHarrisCornerDetectorParams::sensitivity
float sensitivity
Specifies sensitivity threshold from the Harris-Stephens equation.
Definition: HarrisCornerDetector.h:91
HarrisCornerDetector.h
Declares functions that implement the Harris Corner Detector algorithm.
VPIHarrisCornerDetectorParams::minNMSDistance
float minNMSDistance
Non-maximum suppression radius, set to 0 to disable it.
Definition: HarrisCornerDetector.h:94
VPIHarrisCornerDetectorParams::blockSize
uint32_t blockSize
Block window size used to compute the Harris Corner score.
Definition: HarrisCornerDetector.h:85
VPIHarrisCornerDetectorParams
Structure that defines the parameters for vpiSubmitHarrisCornerDetector.
Definition: HarrisCornerDetector.h:80
VPIImageData::type
VPIImageFormat type
Image type.
Definition: Image.h:160
Status.h
Declaration of VPI status codes handling functions.
vpiArrayLock
VPIStatus vpiArrayLock(VPIArray array, VPILockMode mode, VPIArrayData *arrayData)
Acquires the lock on array object and returns a pointer to array data.
VPI_BACKEND_CPU
@ VPI_BACKEND_CPU
CPU backend.
Definition: Types.h:90
VPIArray
struct VPIArrayImpl * VPIArray
A handle to an array.
Definition: Types.h:172
vpiImageCreateHostMemWrapper
VPIStatus vpiImageCreateHostMemWrapper(const VPIImageData *hostData, uint32_t flags, VPIImage *img)
Create an image object by wrapping around an existing host memory block.
Stream.h
Declares functions dealing with VPI streams.
VPIImagePlane::data
void * data
Pointer to the first row of this plane.
Definition: Image.h:147
VPI_ARRAY_TYPE_U32
@ VPI_ARRAY_TYPE_U32
unsigned 32-bit.
Definition: Types.h:232
VPI_BACKEND_PVA
@ VPI_BACKEND_PVA
PVA backend.
Definition: Types.h:92
VPIKeypoint
Stores a keypoint coordinate.
Definition: Types.h:354