VPI - Vision Programming Interface

2.2 Release

ORB Feature Detector

Overview

Orientated FAST and rBRIEF (ORB) is a feature detection and description algorithm. It detects features across an input pyramid as well as a descriptor for each feature, returning the coordinates for each feature as well as its associated bitstring descriptor. This sample application detects ORB features from the given input image, prints the keypoints and descriptors to stdout, and draws the keypoints on the output image file. Green keypoints have valid descriptors, blue keypoints (descriptors with all values zero) don't. The cuda backend does not compute descriptors close to the border of the image, whereas the cpu backend does. Due to implementation differences, cuda and cpu do not return the same results.

Instructions

The command line parameters are:

<backend> <input image>

where

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

Here's one example:

  • C++
    ./vpi_sample_18_orb_feature_detector cuda ../assets/kodim08.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 imageMatched featurs between input image and flipped image image

Source Code

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

Language:
29 #include <opencv2/core.hpp>
30 #include <opencv2/features2d.hpp>
31 #include <opencv2/imgcodecs.hpp>
32 #include <opencv2/imgproc.hpp>
33 #include <vpi/OpenCVInterop.hpp>
34 
35 #include <vpi/Array.h>
36 #include <vpi/Image.h>
37 #include <vpi/Pyramid.h>
38 #include <vpi/Status.h>
39 #include <vpi/Stream.h>
42 #include <vpi/algo/ImageFlip.h>
43 #include <vpi/algo/ORB.h>
44 
45 #include <bitset>
46 #include <cstdio>
47 #include <cstring> // for memset
48 #include <iostream>
49 #include <sstream>
50 
51 #define CHECK_STATUS(STMT) \
52  do \
53  { \
54  VPIStatus status = (STMT); \
55  if (status != VPI_SUCCESS) \
56  { \
57  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
58  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
59  std::ostringstream ss; \
60  ss << vpiStatusGetName(status) << ": " << buffer; \
61  throw std::runtime_error(ss.str()); \
62  } \
63  } while (0);
64 
65 static cv::Mat DrawKeypoints(cv::Mat img, VPIKeypointF32 *kpts, VPIBriefDescriptor *outDescriptors, int numKeypoints)
66 {
67  cv::Mat out;
68  img.convertTo(out, CV_8UC1);
69  cvtColor(out, out, cv::COLOR_GRAY2BGR);
70 
71  if (numKeypoints == 0)
72  {
73  return out;
74  }
75 
76  for (int i = 0; i < numKeypoints; ++i)
77  {
78  auto de=outDescriptors[i];
79  cv::Scalar col(255,0,0);
80  for(int j=0; j<32;j++){
81  if(de.data[j]>0) { col=cv::Scalar(0,255, 0); break;}
82  }
83  circle(out, cv::Point(kpts[i].x, kpts[i].y), 3, col, -1);
84  }
85  return out;
86 }
87 
88 int main(int argc, char *argv[])
89 {
90  // OpenCV image that will be wrapped by a VPIImage.
91  // Define it here so that it's destroyed *after* wrapper is destroyed
92  cv::Mat cvImage;
93 
94  // VPI objects that will be used
95  VPIImage imgInput = NULL;
96  VPIImage imgGrayScale = NULL;
97 
98  VPIPyramid pyrInput = NULL;
99  VPIArray keypoints = NULL;
100  VPIArray descriptors = NULL;
101  VPIPayload orbPayload = NULL;
102  VPIStream stream = NULL;
103 
104  int retval = 0;
105 
106  try
107  {
108  // =============================
109  // Parse command line parameters
110 
111  if (argc != 3)
112  {
113  throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|cuda> <input image>");
114  }
115 
116  std::string strBackend = argv[1];
117  std::string strInputFileName = argv[2];
118 
119  // Now parse the backend
120  VPIBackend backend;
121 
122  if (strBackend == "cpu")
123  {
124  backend = VPI_BACKEND_CPU;
125  }
126  else if (strBackend == "cuda")
127  {
128  backend = VPI_BACKEND_CUDA;
129  }
130  else
131  {
132  throw std::runtime_error("Backend '" + strBackend + "' not recognized, it must be either cpu or cuda.");
133  }
134 
135  // =====================
136  // Load the input image
137 
138  cvImage = cv::imread(strInputFileName);
139  if (cvImage.empty())
140  {
141  throw std::runtime_error("Can't open first image: '" + strInputFileName + "'");
142  }
143 
144  // =================================
145  // Allocate all VPI resources needed
146 
147  // Create the stream where processing will happen
148  CHECK_STATUS(vpiStreamCreate(0, &stream));
149 
150  // Define the algorithm parameters.
151  VPIORBParams orbParams;
152  CHECK_STATUS(vpiInitORBParams(&orbParams));
153  //default params
154  //params.fastParams.circleRadius = 3;
155  //params.fastParams.arcLength = 9;
156  //params.fastParams.intensityThreshold = 20;
157  //params.fastParams.nonMaxSuppression = 1;
158  //params.maxFeatures = 100;
159  //params.pyramidLevels = 4;
160  //params.enableRBRIEF = true;
161  //params.scoreType = VPI_CORNER_SCORE_HARRIS;
162 
163 
164  orbParams.scoreType=VPI_CORNER_SCORE_HARRIS;
165  //orbParams.scoreType=VPI_CORNER_SCORE_FAST;
166  orbParams.maxFeatures=10000;
167  orbParams.pyramidLevels=6;
168 
169  VPIBorderExtension be=VPI_BORDER_CLAMP; //VPI_BORDER_ZERO
170 
171  // We now wrap the loaded image into a VPIImage object to be used by VPI.
172  // VPI won't make a copy of it, so the original
173  // image must be in scope at all times.
174  CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(cvImage, 0, &imgInput));
175  CHECK_STATUS(vpiImageCreate(cvImage.cols, cvImage.rows, VPI_IMAGE_FORMAT_U8, 0, &imgGrayScale));
176 
177  // Create the output keypoint array.
178  CHECK_STATUS( vpiArrayCreate(orbParams.maxFeatures, VPI_ARRAY_TYPE_KEYPOINT_F32, backend | VPI_BACKEND_CPU, &keypoints));
179 
180  // Create the output descriptors array.
181  CHECK_STATUS(vpiArrayCreate(orbParams.maxFeatures, VPI_ARRAY_TYPE_BRIEF_DESCRIPTOR, backend | VPI_BACKEND_CPU, &descriptors));
182 
183  // Create the payload for ORB Feature Detector algorithm
184  CHECK_STATUS( vpiCreateORBFeatureDetector(backend, 20000, &orbPayload));
185 
186  // ================
187  // Processing stage
188 
189  // First convert input to grayscale
190  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, backend, imgInput, imgGrayScale, NULL));
191 
192  // Then, create the Gaussian Pyramid for the image and wait for the execution to finish
193  CHECK_STATUS(vpiPyramidCreate(cvImage.cols, cvImage.rows, VPI_IMAGE_FORMAT_U8, orbParams.pyramidLevels, 0.5, backend, &pyrInput));
194  CHECK_STATUS(vpiSubmitGaussianPyramidGenerator(stream, backend, imgGrayScale, pyrInput, be));
195 
196  // Then get ORB features and wait for the execution to finish
197  CHECK_STATUS(vpiSubmitORBFeatureDetector(stream, backend, orbPayload, pyrInput, keypoints, descriptors, &orbParams, be));
198 
199  CHECK_STATUS(vpiStreamSync(stream));
200 
201  // =======================================
202  // Output processing and saving it to disk
203 
204  // Lock output keypoints and scores to retrieve its data on cpu memory
205  VPIArrayData outKeypointsData;
206  VPIArrayData outDescriptorsData;
207  VPIImageData imgData;
208  CHECK_STATUS(vpiArrayLockData(keypoints, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &outKeypointsData));
209  CHECK_STATUS(vpiArrayLockData(descriptors, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &outDescriptorsData));
210  CHECK_STATUS(vpiImageLockData(imgGrayScale, VPI_LOCK_READ, VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR, &imgData));
211 
212  VPIKeypointF32 *outKeypoints = (VPIKeypointF32 *)outKeypointsData.buffer.aos.data;
213  VPIBriefDescriptor *outDescriptors = (VPIBriefDescriptor *) outDescriptorsData.buffer.aos.data;
214 
215  int nkp = *outKeypointsData.buffer.aos.sizePointer;
216  int nde = *outDescriptorsData.buffer.aos.sizePointer;
217 
218  printf("%d keypoints found\n", nkp);
219  for(int i=0; i<nkp;i++)
220  {
221  printf("%d %f %f\n",i, (outKeypoints[i]).x,(outKeypoints[i]).y);
222  }
223 
224  printf("%d descriptors found\n", nde);
225  for(int i=0; i<nde;i++)
226  {
227  printf("%d: ",i);
228  for(int j=0; j<VPI_BRIEF_DESCRIPTOR_ARRAY_LENGTH; j++)
229  {
230  printf("%hhu ", (outDescriptors[i]).data[j]);
231  }
232  printf("\n");
233  }
234 
235  cv::Mat img;
236  CHECK_STATUS(vpiImageDataExportOpenCVMat(imgData, &img));
237 
238  cv::Mat outImage = DrawKeypoints(img, outKeypoints, outDescriptors, *outKeypointsData.buffer.aos.sizePointer);
239 
240  imwrite("orb_feature_detector_" + strBackend + ".png", outImage);
241 
242  // Done handling outputs, don't forget to unlock them.
243  CHECK_STATUS(vpiImageUnlock(imgGrayScale));
244  CHECK_STATUS(vpiArrayUnlock(keypoints));
245  CHECK_STATUS(vpiArrayUnlock(descriptors));
246 
247 
248  }
249  catch (std::exception &e)
250  {
251  std::cerr << e.what() << std::endl;
252  retval = 1;
253  }
254 
255  // ========
256  // Clean up
257 
258  // Make sure stream is synchronized before destroying the objects
259  // that might still be in use.
260  vpiStreamSync(stream);
261 
262  vpiImageDestroy(imgInput);
263  vpiImageDestroy(imgGrayScale);
264  vpiArrayDestroy(keypoints);
265  vpiArrayDestroy(descriptors);
266  vpiPayloadDestroy(orbPayload);
267  vpiStreamDestroy(stream);
268 
269  return retval;
270 }
Functions and structures for dealing with VPI arrays.
Declares functions that handle image format conversion.
Declares functions that handle gaussian pyramids.
Declares functions that implement Image flip algorithms.
#define VPI_IMAGE_FORMAT_U8
Single plane with one 8-bit unsigned integer channel.
Definition: ImageFormat.h:100
Functions and structures for dealing with VPI images.
Declares functions that implement support for ORB.
Functions for handling OpenCV interoperability with VPI.
Functions and structures for dealing with VPI pyramids.
Declaration of VPI status codes handling functions.
Declares functions dealing with VPI streams.
#define VPI_BRIEF_DESCRIPTOR_ARRAY_LENGTH
Length of Brief Descriptor Array.
Definition: Types.h:348
Stores a BRIEF Descriptor.
Definition: Types.h:359
void * data
Points to the first element of the array.
Definition: Array.h:135
VPIArrayBuffer buffer
Stores the array contents.
Definition: Array.h:175
int32_t * sizePointer
Points to the number of elements in the array.
Definition: Array.h:122
VPIArrayBufferAOS aos
Array stored in array-of-structures layout.
Definition: Array.h:162
VPIStatus vpiArrayUnlock(VPIArray array)
Releases the lock on array object.
VPIStatus vpiArrayLockData(VPIArray array, VPILockMode mode, VPIArrayBufferType bufType, VPIArrayData *data)
Acquires the lock on an array object and returns the array contents.
void vpiArrayDestroy(VPIArray array)
Destroy an array instance.
VPIStatus vpiArrayCreate(int32_t capacity, VPIArrayType type, uint64_t flags, VPIArray *array)
Create an empty array instance.
struct VPIArrayImpl * VPIArray
A handle to an array.
Definition: Types.h:232
@ VPI_ARRAY_TYPE_KEYPOINT_F32
VPIKeypointF32 element.
Definition: ArrayType.h:77
@ VPI_ARRAY_BUFFER_HOST_AOS
Host-accessible array-of-structures.
Definition: Array.h:146
Stores information about array characteristics and contents.
Definition: Array.h:168
VPIStatus vpiSubmitConvertImageFormat(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, const VPIConvertImageFormatParams *params)
Converts the image contents to the desired format, with optional scaling and offset.
VPIStatus vpiSubmitGaussianPyramidGenerator(VPIStream stream, uint64_t backend, VPIImage input, VPIPyramid output, VPIBorderExtension border)
Computes the Gaussian pyramid from the input image.
void vpiImageDestroy(VPIImage img)
Destroy an image instance.
struct VPIImageImpl * VPIImage
A handle to an image.
Definition: Types.h:256
VPIStatus vpiImageLockData(VPIImage img, VPILockMode mode, VPIImageBufferType bufType, VPIImageData *data)
Acquires the lock on an image object and returns the image contents.
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
Create an empty image instance with the specified flags.
VPIStatus vpiImageUnlock(VPIImage img)
Releases the lock on an image object.
@ VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR
Host-accessible with planes in pitch-linear memory layout.
Definition: Image.h:172
Stores information about image characteristics and content.
Definition: Image.h:230
VPIStatus vpiImageCreateWrapperOpenCVMat(const cv::Mat &mat, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
Wraps a cv::Mat in an VPIImage with the given image format.
VPIStatus vpiImageDataExportOpenCVMat(const VPIImageData &imgData, cv::Mat *mat)
Fills an existing cv::Mat with data from VPIImageData coming from a locked VPIImage.
VPICornerScore scoreType
The scoring criteria for ordering the top N FAST corners.
Definition: ORB.h:108
int32_t maxFeatures
The maximum number of features alloted per level of the scale pyramid.
Definition: ORB.h:93
int32_t pyramidLevels
The number of levels in the scale pyramid to utilize.
Definition: ORB.h:98
VPIStatus vpiInitORBParams(VPIORBParams *params)
Initializes VPIORBParams with default values.
VPIStatus vpiCreateORBFeatureDetector(uint64_t backends, size_t capacity, VPIPayload *payload)
Creates a ORB payload.
VPIStatus vpiSubmitORBFeatureDetector(VPIStream stream, uint64_t backend, VPIPayload payload, VPIPyramid input, VPIArray outCorners, VPIArray outDescriptors, const VPIORBParams *params, VPIBorderExtension border)
Submits a ORB operation to the stream.
Structure that defines the parameters for both vpiCreateORBFeatureDetector and vpiSubmitORBFeatureDet...
Definition: ORB.h:84
struct VPIPayloadImpl * VPIPayload
A handle to an algorithm payload.
Definition: Types.h:268
void vpiPayloadDestroy(VPIPayload payload)
Deallocates the payload object and all associated resources.
VPIStatus vpiPyramidCreate(int32_t width, int32_t height, VPIImageFormat fmt, int32_t numLevels, float scale, uint64_t flags, VPIPyramid *pyr)
Create an empty image pyramid instance with the specified flags.
struct VPIPyramidImpl * VPIPyramid
A handle to an image pyramid.
Definition: Types.h:262
struct VPIStreamImpl * VPIStream
A handle to a stream.
Definition: Types.h:250
VPIStatus vpiStreamSync(VPIStream stream)
Blocks the calling thread until all submitted commands in this stream queue are done (queue is empty)...
VPIBackend
VPI Backend types.
Definition: Types.h:91
void vpiStreamDestroy(VPIStream stream)
Destroy a stream instance and deallocate all HW resources.
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
Create a stream instance.
@ VPI_BACKEND_CUDA
CUDA backend.
Definition: Types.h:93
@ VPI_BACKEND_CPU
CPU backend.
Definition: Types.h:92
VPIBorderExtension
Image border extension specify how pixel values outside of the image domain should be constructed.
Definition: Types.h:277
@ VPI_BORDER_CLAMP
Border pixels are repeated indefinitely.
Definition: Types.h:279
@ VPI_LOCK_READ
Lock memory only for reading.
Definition: Types.h:498
Stores a float32 keypoint coordinate The coordinate is relative to the top-left corner of an image.
Definition: Types.h:315