VPI - Vision Programming Interface

0.4.4 Release

Stereo Disparity

Overview

The Stereo Disparity application receives left and right stereo pair images and returns the disparity between them, which is a function of image depth. The result is saved into disparity.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 2D image where output will be written to
  • Create a properly-configured StereoProcess algorithm and submit it to the stream.
  • Simple stream synchronization.
  • Image locking to access its contents from CPU side.
  • Error handling.
  • Environment clean up.

Instructions

The usage is:

./vpi_sample_02_stereo_disparity <backend> <input image>

where

  • backend: either cpu, cuda or pva; it defines the backend that will perform the processing.
  • left image: left input image of a stereo pair, it accepts png, jpeg and possibly others.
  • right image: right input image of a stereo pair.

Here's one example:

./vpi_sample_02_stereo_disparity cuda ../assets/chair_stereo_left.png ../assets/chair_stereo_right.png

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

Results

Left input image Right input image
Stereo disparity

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/highgui/highgui.hpp>
34 #endif
35 
36 #include <opencv2/imgproc/imgproc.hpp>
37 
38 #include <vpi/Image.h>
39 #include <vpi/Status.h>
40 #include <vpi/Stream.h>
42 
43 #include <cstring> // for memset
44 #include <iostream>
45 #include <sstream>
46 
47 #define CHECK_STATUS(STMT) \
48  do \
49  { \
50  VPIStatus status = (STMT); \
51  if (status != VPI_SUCCESS) \
52  { \
53  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
54  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
55  std::ostringstream ss; \
56  ss << vpiStatusGetName(status) << ": " << buffer; \
57  throw std::runtime_error(ss.str()); \
58  } \
59  } while (0);
60 
61 int main(int argc, char *argv[])
62 {
63  VPIImage left = NULL;
64  VPIImage right = NULL;
65  VPIImage disparity = NULL;
66  VPIStream stream = NULL;
67  VPIPayload stereo = NULL;
68 
69  int retval = 0;
70 
71  try
72  {
73  if (argc != 4)
74  {
75  throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|pva|cuda> <left image> <right image>");
76  }
77 
78  std::string strBackend = argv[1];
79  std::string strLeftFileName = argv[2];
80  std::string strRightFileName = argv[3];
81 
82  // Load the input images
83  cv::Mat cvImageLeft = cv::imread(strLeftFileName, cv::IMREAD_GRAYSCALE);
84  if (cvImageLeft.empty())
85  {
86  throw std::runtime_error("Can't open '" + strLeftFileName + "'");
87  }
88 
89  cv::Mat cvImageRight = cv::imread(strRightFileName, cv::IMREAD_GRAYSCALE);
90  if (cvImageRight.empty())
91  {
92  throw std::runtime_error("Can't open '" + strRightFileName + "'");
93  }
94 
95  // Currently we only accept unsigned 16bpp inputs.
96  cvImageLeft.convertTo(cvImageLeft, CV_16UC1);
97  cvImageRight.convertTo(cvImageRight, CV_16UC1);
98 
99  // Now parse the backend
100  VPIBackend backendType;
101 
102  if (strBackend == "cpu")
103  {
104  backendType = VPI_BACKEND_CPU;
105  }
106  else if (strBackend == "cuda")
107  {
108  backendType = VPI_BACKEND_CUDA;
109  }
110  else if (strBackend == "pva")
111  {
112  backendType = VPI_BACKEND_PVA;
113  }
114  else
115  {
116  throw std::runtime_error("Backend '" + strBackend +
117  "' not recognized, it must be either cpu, cuda or pva.");
118  }
119 
120  // Create the stream for the given backend.
121  CHECK_STATUS(vpiStreamCreate(backendType, &stream));
122 
123  // We now wrap the loaded images into a VPIImage object to be used by VPI.
124  {
125  // First fill VPIImageData with the, well, image data...
126  VPIImageData imgData;
127  memset(&imgData, 0, sizeof(imgData));
128  imgData.type = VPI_IMAGE_FORMAT_U16;
129  imgData.numPlanes = 1;
130  imgData.planes[0].width = cvImageLeft.cols;
131  imgData.planes[0].height = cvImageLeft.rows;
132  imgData.planes[0].pitchBytes = cvImageLeft.step[0];
133  imgData.planes[0].data = cvImageLeft.data;
134 
135  // Wrap it into a VPIImage. VPI won't make a copy of it, so the original
136  // image must be in scope at all times.
137  CHECK_STATUS(vpiImageCreateHostMemWrapper(&imgData, 0, &left));
138 
139  imgData.planes[0].width = cvImageRight.cols;
140  imgData.planes[0].height = cvImageRight.rows;
141  imgData.planes[0].pitchBytes = cvImageRight.step[0];
142  imgData.planes[0].data = cvImageRight.data;
143 
144  CHECK_STATUS(vpiImageCreateHostMemWrapper(&imgData, 0, &right));
145  }
146 
147  // Create the image where the disparity map will be stored.
148  CHECK_STATUS(vpiImageCreate(cvImageLeft.cols, cvImageLeft.rows, VPI_IMAGE_FORMAT_U16, 0, &disparity));
149 
150  // Create the payload for Harris Corners Detector algorithm
151 
153  params.windowSize = 5;
154  params.maxDisparity = 64;
155  CHECK_STATUS(vpiCreateStereoDisparityEstimator(backendType, cvImageLeft.cols, cvImageLeft.rows,
156  VPI_IMAGE_FORMAT_U16, params.maxDisparity, &stereo));
157 
158  // Submit it with the input and output images
159  CHECK_STATUS(vpiSubmitStereoDisparityEstimator(stream, stereo, left, right, disparity, &params));
160 
161  // Wait until the algorithm finishes processing
162  CHECK_STATUS(vpiStreamSync(stream));
163 
164  // Now let's retrieve the output
165  {
166  // Lock output to retrieve its data on cpu memory
167  VPIImageData data;
168  CHECK_STATUS(vpiImageLock(disparity, VPI_LOCK_READ, &data));
169 
170  // Make an OpenCV matrix out of this image
171  cv::Mat cvOut(data.planes[0].height, data.planes[0].width, CV_16UC1, data.planes[0].data,
172  data.planes[0].pitchBytes);
173 
174  // Scale result and write it to disk
175  double min, max;
176  minMaxLoc(cvOut, &min, &max);
177  cvOut.convertTo(cvOut, CV_8UC1, 255.0 / (max - min), -min);
178 
179  imwrite("disparity_" + strBackend + ".png", cvOut);
180 
181  // Done handling output, don't forget to unlock it.
182  CHECK_STATUS(vpiImageUnlock(disparity));
183  }
184  }
185  catch (std::exception &e)
186  {
187  std::cerr << e.what() << std::endl;
188  retval = 1;
189  }
190 
191  // Clean up
192 
193  // Make sure stream is synchronized before destroying the objects
194  // that might still be in use.
195  if (stream != NULL)
196  {
197  vpiStreamSync(stream);
198  }
199 
200  vpiImageDestroy(left);
201  vpiImageDestroy(right);
202  vpiImageDestroy(disparity);
203  vpiPayloadDestroy(stereo);
204  vpiStreamDestroy(stream);
205 
206  return retval;
207 }
VPIImagePlane::height
uint32_t height
Height of this plane in pixels.
Definition: Image.h:138
VPIImagePlane::width
uint32_t width
Width of this plane in pixels.
Definition: Image.h:137
vpiStreamCreate
VPIStatus vpiStreamCreate(uint32_t flags, VPIStream *stream)
Create a stream instance.
VPIBackend
VPIBackend
VPI Backend types.
Definition: Types.h:89
vpiSubmitStereoDisparityEstimator
VPIStatus vpiSubmitStereoDisparityEstimator(VPIStream stream, VPIPayload payload, VPIImage left, VPIImage right, VPIImage disparity, const VPIStereoDisparityEstimatorParams *params)
Runs stereo processing on a pair of images and outputs a disparity map.
VPI_LOCK_READ
@ VPI_LOCK_READ
Lock memory only for reading.
Definition: Types.h:447
VPI_IMAGE_FORMAT_U16
@ VPI_IMAGE_FORMAT_U16
Single plane with one 16-bit unsigned integer channel.
Definition: ImageFormat.h:105
vpiImageUnlock
VPIStatus vpiImageUnlock(VPIImage img)
Releases the lock on an image object.
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
VPIStream
struct VPIStreamImpl * VPIStream
A handle to a stream.
Definition: Types.h:190
vpiCreateStereoDisparityEstimator
VPIStatus vpiCreateStereoDisparityEstimator(VPIBackend backend, uint32_t imageWidth, uint32_t imageHeight, const VPIImageFormat inputFormat, const uint32_t maxDisparity, VPIPayload *payload)
Creates payload for vpiSubmitStereoDisparityEstimator.
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:166
vpiImageCreate
VPIStatus vpiImageCreate(uint32_t width, uint32_t height, VPIImageFormat fmt, uint32_t flags, VPIImage *img)
Create an empty image instance with the specified flags.
vpiImageDestroy
void vpiImageDestroy(VPIImage img)
Destroy an image instance.
Image.h
Functions and structures for dealing with VPI images.
StereoDisparity.h
Declares functions that implement stereo disparity estimation algorithms.
VPIStereoDisparityEstimatorParams::windowSize
uint32_t windowSize
Width of Census Transform window for disparity features.
Definition: StereoDisparity.h:83
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
VPIPayload
struct VPIPayloadImpl * VPIPayload
A handle to an algorithm payload.
Definition: Types.h:208
vpiImageLock
VPIStatus vpiImageLock(VPIImage img, VPILockMode mode, VPIImageData *hostData)
Acquires the lock on an image object and returns a pointer to the image planes.
VPIImageData::type
VPIImageFormat type
Image type.
Definition: Image.h:160
Status.h
Declaration of VPI status codes handling functions.
VPI_BACKEND_CPU
@ VPI_BACKEND_CPU
CPU backend.
Definition: Types.h:90
VPIStereoDisparityEstimatorParams::maxDisparity
uint32_t maxDisparity
Maximum disparity for matching search.
Definition: StereoDisparity.h:84
VPIStereoDisparityEstimatorParams
Structure that defines the parameters for vpiCreateStereoDisparityEstimator.
Definition: StereoDisparity.h:82
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_BACKEND_PVA
@ VPI_BACKEND_PVA
PVA backend.
Definition: Types.h:92