VPI - 视觉编程接口

3.2 版本

立体视差

概述

立体视差应用程序接收左右立体图像对,并返回它们之间的视差,视差是图像深度的函数。结果将保存为图像文件到磁盘。如果可用,它还将输出相应的置信度图。

说明

命令行参数为

<backend> <left image> <right image>

其中

  • backend:可以是 cudaofaofa-pva-vic;它定义了将执行处理的后端。 ofa-pva-viccuda 允许除了视差之外还输出置信度图。
  • left image:校正后的立体图像对的左输入图像,它接受 png、jpeg 以及可能的其他格式。
  • right image:立体图像对的右输入图像。

这是一个例子

  • C++
    ./vpi_sample_02_stereo_disparity cuda ../assets/chair_stereo_left.png ../assets/chair_stereo_right.png
  • Python
    python3 main.py cuda ../assets/chair_stereo_left.png ../assets/chair_stereo_right.png

这是使用 CUDA 后端和提供的示例图像。您可以尝试使用其他立体图像对,但要遵守算法施加的约束。

此示例的 Python 版本还允许设置各种附加参数,以及附加的输入图像扩展名和打开详细模式。以下命令行参数可以传递给 Python 示例

  • Python
    python3 main.py <backend> <left image> <right image> --width W --height H --downscale D --window_size WIN
    --skip_confidence --conf_threshold T --conf_type absolute/relative -p1 P1 -p2 P2 --p2_alpha P2alpha
    --uniqueness U --skip_diagonal --num_passes N --min_disparity MIN --max_disparity MAX --output_mode 0/1/2
    -v/--verbose
    其中附加的可选参数为
  • width:当传递 ".raw" 输入图像时,设置宽度 W
  • height:当传递 ".raw" 输入图像时,设置高度 H
  • downscale:设置输出的缩小比例因子为 D
  • window_size:设置中值滤波器窗口大小为 WIN
  • skip_confidence:避免计算置信度并将其用作掩码
  • conf_threshold:设置置信度阈值为 T
  • conf_type:设置置信度类型为 absolute 或 relative
  • p1:设置 p1 惩罚为 P1
  • p2:设置 p2 惩罚为 P2
  • p2_alpha:设置 p2Alpha 自适应惩罚为 P2alpha
  • uniqueness:设置唯一性为 U
  • skip_diagonal:避免在 CUDA 或 OFA 后端中使用对角路径
  • num_passes:在 OFA 后端中设置通过次数 N
  • min_disparity:在 CUDA 后端中设置最小视差 MIN
  • max_disparity:在后端中设置最大视差 MAX
  • output_mode:0 表示彩色输出,1 表示灰度输出,2 表示原始二进制输出
  • verbose:打开详细模式。要详细了解与立体视差算法相关的每个附加参数,请阅读相应的文档。

结果

左输入图像右输入图像
立体视差置信度图

源代码

为了方便起见,这里是代码,它也安装在 samples 目录中。

语言
27 import sys
28 import vpi
29 import numpy as np
30 from PIL import Image
31 from argparse import ArgumentParser
32 import cv2
33 
34 
35 def read_raw_file(fpath, resize_to=None, verbose=False)
36  try
37  if verbose
38  print(f'I Reading: {fpath}', end=' ', flush=True)
39  f = open(fpath, 'rb')
40  np_arr = np.fromfile(f, dtype=np.uint16, count=-1)
41  f.close()
42  if verbose
43  print(f'done!\nI Raw array: shape: {np_arr.shape} dtype: {np_arr.dtype}')
44  if resize_to is not None
45  np_arr = np_arr.reshape(resize_to, order='C')
46  if verbose
47  print(f'I Reshaped array: shape: {np_arr.shape} dtype: {np_arr.dtype}')
48  pil_img = Image.fromarray(np_arr, mode="I;16L")
49  return pil_img
50  except
51  raise ValueError(f'E Cannot process raw input: {fpath}')
52 
53 
54 def process_arguments()
55  parser = ArgumentParser()
56 
57  parser.add_argument('backend', choices=['cuda','ofa','ofa-pva-vic'],
58  help='Backend to be used for processing')
59  parser.add_argument('left', help='Rectified left input image from a stereo pair')
60  parser.add_argument('right', help='Rectified right input image from a stereo pair')
61  parser.add_argument('--width', default=-1, type=int, help='Input width for raw input files')
62  parser.add_argument('--height', default=-1, type=int, help='Input height for raw input files')
63  parser.add_argument('--downscale', default=1, type=int, help='Output downscale factor')
64  parser.add_argument('--window_size', default=5, type=int, help='Median filter window size')
65  parser.add_argument('--skip_confidence', default=False, action='store_true', help='Do not calculate confidence')
66  parser.add_argument('--conf_threshold', default=32767, type=int, help='Confidence threshold')
67  parser.add_argument('--conf_type', default='best', choices=['best', 'absolute', 'relative', 'inference'],
68  help='Computation type to produce the confidence output. Default will pick best option given backend.')
69  parser.add_argument('-p1', default=3, type=int, help='Penalty P1 on small disparities')
70  parser.add_argument('-p2', default=48, type=int, help='Penalty P2 on large disparities')
71  parser.add_argument('--p2_alpha', default=0, type=int, help='Alpha for adaptive P2 Penalty')
72  parser.add_argument('--uniqueness', default=-1, type=float, help='Uniqueness ratio')
73  parser.add_argument('--skip_diagonal', default=False, action='store_true', help='Do not use diagonal paths')
74  parser.add_argument('--num_passes', default=3, type=int, help='Number of passes')
75  parser.add_argument('--min_disparity', default=0, type=int, help='Minimum disparity')
76  parser.add_argument('--max_disparity', default=256, type=int, help='Maximum disparity')
77  parser.add_argument('--output_mode', default=0, type=int, help='0: color; 1: grayscale; 2: raw binary')
78  parser.add_argument('-v', '--verbose', default=False, action='store_true', help='Verbose mode')
79 
80  return parser.parse_args()
81 
82 
83 def main()
84  args = process_arguments()
85 
86  scale = 1 # pixel value scaling factor when loading input
87 
88  if args.backend == 'cuda'
89  backend = vpi.Backend.CUDA
90  elif args.backend == 'ofa'
91  backend = vpi.Backend.OFA
92  elif args.backend == 'ofa-pva-vic'
93  backend = vpi.Backend.OFA|vpi.Backend.PVA|vpi.Backend.VIC
94  else
95  raise ValueError(f'E Invalid backend: {args.backend}')
96 
97  conftype = None
98  if args.conf_type == 'best'
99  conftype = vpi.ConfidenceType.INFERENCE if args.backend == 'ofa-pva-vic' else vpi.ConfidenceType.ABSOLUTE
100  elif args.conf_type == 'absolute'
101  conftype = vpi.ConfidenceType.ABSOLUTE
102  elif args.conf_type == 'relative'
103  conftype = vpi.ConfidenceType.RELATIVE
104  elif args.conf_type == 'inference'
105  conftype = vpi.ConfidenceType.INFERENCE
106  else
107  raise ValueError(f'E Invalid confidence type: {args.conf_type}')
108 
109  minDisparity = args.min_disparity
110  maxDisparity = args.max_disparity
111  includeDiagonals = not args.skip_diagonal
112  numPasses = args.num_passes
113  calcConf = not args.skip_confidence
114  downscale = args.downscale
115  windowSize = args.window_size
116  quality = 6
117 
118  if args.verbose
119  print(f'I Backend: {backend}\nI Left image: {args.left}\nI Right image: {args.right}\n'
120  f'I Disparities (min, max): {(minDisparity, maxDisparity)}\n'
121  f'I Input scale factor: {scale}\nI Output downscale factor: {downscale}\n'
122  f'I Window size: {windowSize}\nI Quality: {quality}\n'
123  f'I Calculate confidence: {calcConf}\nI Confidence threshold: {args.conf_threshold}\n'
124  f'I Confidence type: {conftype}\nI Uniqueness ratio: {args.uniqueness}\n'
125  f'I Penalty P1: {args.p1}\nI Penalty P2: {args.p2}\nI Adaptive P2 alpha: {args.p2_alpha}\n'
126  f'I Include diagonals: {includeDiagonals}\nI Number of passes: {numPasses}\n'
127  f'I Output mode: {args.output_mode}\nI Verbose: {args.verbose}\n'
128  , end='', flush=True)
129 
130  if 'raw' in args.left
131  pil_left = read_raw_file(args.left, resize_to=[args.height, args.width], verbose=args.verbose)
132  np_left = np.asarray(pil_left)
133  else
134  try
135  pil_left = Image.open(args.left)
136  if pil_left.mode == 'I'
137  np_left = np.asarray(pil_left).astype(np.int16)
138  else
139  np_left = np.asarray(pil_left)
140  except
141  raise ValueError(f'E Cannot open left input image: {args.left}')
142 
143  if 'raw' in args.right
144  pil_right = read_raw_file(args.right, resize_to=[args.height, args.width], verbose=args.verbose)
145  np_right = np.asarray(pil_right)
146  else
147  try
148  pil_right = Image.open(args.right)
149  if pil_right.mode == 'I'
150  np_right = np.asarray(pil_right).astype(np.int16)
151  else
152  np_right = np.asarray(pil_right)
153  except
154  raise ValueError(f'E Cannot open right input image: {args.right}')
155 
156  # Streams for left and right independent pre-processing
157  streamLeft = vpi.Stream()
158  streamRight = vpi.Stream()
159 
160  # Load input into a vpi.Image and convert it to grayscale, 16bpp
161  with vpi.Backend.CUDA
162  with streamLeft
163  left = vpi.asimage(np_left).convert(vpi.Format.Y16_ER, scale=scale)
164  with streamRight
165  right = vpi.asimage(np_right).convert(vpi.Format.Y16_ER, scale=scale)
166 
167  # Preprocess input
168  # Block linear format is needed for ofa backends
169  # We use VIC backend for the format conversion because it is low power
170  if args.backend in {'ofa-pva-vic', 'ofa'}
171  if args.verbose
172  print(f'W {args.backend} forces to convert input images to block linear', flush=True)
173  with vpi.Backend.VIC
174  with streamLeft
175  left = left.convert(vpi.Format.Y16_ER_BL)
176  with streamRight
177  right = right.convert(vpi.Format.Y16_ER_BL)
178 
179  if args.verbose
180  print(f'I Input left image: {left.size} {left.format}\n'
181  f'I Input right image: {right.size} {right.format}', flush=True)
182 
183  confidenceU16 = None
184 
185  if calcConf
186  if args.backend not in {'cuda', 'ofa-pva-vic'}
187  # Only CUDA and OFA-PVA-VIC support confidence map
188  calcConf = False
189  if args.verbose
190  print(f'W {args.backend} does not allow to calculate confidence', flush=True)
191 
192 
193  outWidth = (left.size[0] + downscale - 1) // downscale
194  outHeight = (left.size[1] + downscale - 1) // downscale
195 
196  if calcConf
197  confidenceU16 = vpi.Image((outWidth, outHeight), vpi.Format.U16)
198 
199  # Use stream left to consolidate actual stereo processing
200  streamStereo = streamLeft
201 
202  if args.backend == 'ofa-pva-vic' and maxDisparity not in {128, 256}
203  maxDisparity = 128 if (maxDisparity // 128) < 1 else 256
204  if args.verbose
205  print(f'W {args.backend} only supports 128 or 256 maxDisparity. Overriding to {maxDisparity}', flush=True)
206 
207  if args.verbose
208  if 'ofa' not in args.backend
209  print('W Ignoring P2 alpha and number of passes since not an OFA backend', flush=True)
210  if args.backend != 'cuda'
211  print('W Ignoring uniqueness since not a CUDA backend', flush=True)
212  print('I Estimating stereo disparity ... ', end='', flush=True)
213 
214  # Estimate stereo disparity.
215  with streamStereo, backend
216  disparityS16 = vpi.stereodisp(left, right, downscale=downscale, out_confmap=confidenceU16,
217  window=windowSize, maxdisp=maxDisparity, confthreshold=args.conf_threshold,
218  quality=quality, conftype=conftype, mindisp=minDisparity,
219  p1=args.p1, p2=args.p2, p2alpha=args.p2_alpha, uniqueness=args.uniqueness,
220  includediagonals=includeDiagonals, numpasses=numPasses)
221 
222  if args.verbose
223  print('done!\nI Post-processing ... ', end='', flush=True)
224 
225  # Postprocess results and save them to disk
226  with streamStereo, vpi.Backend.CUDA
227  # Some backends outputs disparities in block-linear format, we must convert them to
228  # pitch-linear for consistency with other backends.
229  if disparityS16.format == vpi.Format.S16_BL
230  disparityS16 = disparityS16.convert(vpi.Format.S16, backend=vpi.Backend.VIC)
231 
232  # Scale disparity and confidence map so that values like between 0 and 255.
233 
234  # Disparities are in Q10.5 format, so to map it to float, it gets
235  # divided by 32. Then the resulting disparity range, from 0 to
236  # stereo.maxDisparity gets mapped to 0-255 for proper output.
237  # Copy disparity values back to the CPU.
238  disparityU8 = disparityS16.convert(vpi.Format.U8, scale=255.0/(32*maxDisparity)).cpu()
239 
240  # Apply JET colormap to turn the disparities into color, reddish hues
241  # represent objects closer to the camera, blueish are farther away.
242  disparityColor = cv2.applyColorMap(disparityU8, cv2.COLORMAP_JET)
243 
244  # Converts to RGB for output with PIL.
245  disparityColor = cv2.cvtColor(disparityColor, cv2.COLOR_BGR2RGB)
246 
247  if calcConf
248  confidenceU8 = confidenceU16.convert(vpi.Format.U8, scale=255.0/65535).cpu()
249 
250  # When pixel confidence is 0, its color in the disparity is black.
251  mask = cv2.threshold(confidenceU8, 1, 255, cv2.THRESH_BINARY)[1]
252  mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
253  disparityColor = cv2.bitwise_and(disparityColor, mask)
254 
255  fext = '.raw' if args.output_mode == 2 else '.png'
256 
257  disparity_fname = f'disparity_python{sys.version_info[0]}_{args.backend}' + fext
258  confidence_fname = f'confidence_python{sys.version_info[0]}_{args.backend}' + fext
259 
260  if args.verbose
261  print(f'done!\nI Disparity output: {disparity_fname}', flush=True)
262  if calcConf
263  print(f'I Confidence output: {confidence_fname}', flush=True)
264 
265  # Save results to disk.
266  try
267  if args.output_mode == 0
268  Image.fromarray(disparityColor).save(disparity_fname)
269  if args.verbose
270  print(f'I Output disparity image: {disparityColor.shape} '
271  f'{disparityColor.dtype}', flush=True)
272  elif args.output_mode == 1
273  Image.fromarray(disparityU8).save(disparity_fname)
274  if args.verbose
275  print(f'I Output disparity image: {disparityU8.shape} '
276  f'{disparityU8.dtype}', flush=True)
277  elif args.output_mode == 2
278  disparityS16.cpu().tofile(disparity_fname)
279  if args.verbose
280  print(f'I Output disparity image: {disparityS16.size} '
281  f'{disparityS16.format}', flush=True)
282 
283  if calcConf
284  if args.output_mode == 0 or args.output_mode == 1
285  Image.fromarray(confidenceU8).save(confidence_fname)
286  if args.verbose
287  print(f'I Output confidence image: {confidenceU8.shape} '
288  f'{confidenceU8.dtype}', flush=True)
289  else
290  confidenceU16.cpu().tofile(confidence_fname)
291  if args.verbose
292  print(f'I Output confidence image: {confidenceU16.size} '
293  f'{confidenceU16.format}', flush=True)
294 
295  except
296  raise ValueError(f'E Cannot write outputs: {disparity_fname}, {confidence_fname}\n'
297  f'E Using output mode: {args.output_mode}')
298 
299 
300 if __name__ == '__main__'
301  main()
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 colormap
34 # include <opencv2/highgui/highgui.hpp>
35 #endif
36 
37 #include <opencv2/imgproc/imgproc.hpp>
38 #include <vpi/OpenCVInterop.hpp>
39 
40 #include <vpi/Image.h>
41 #include <vpi/Status.h>
42 #include <vpi/Stream.h>
44 #include <vpi/algo/Rescale.h>
46 
47 #include <cstring>
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 << "line " << __LINE__ << " " << vpiStatusGetName(status) << ": " << buffer; \
61  throw std::runtime_error(ss.str()); \
62  } \
63  } while (0);
64 
65 int main(int argc, char *argv[])
66 {
67  // OpenCV 图像,将被 VPIImage 包裹。
68  // 在此处定义它,以便在 wrapper 被销毁*之后*再销毁
69  cv::Mat cvImageLeft, cvImageRight;
70 
71  // 将要使用的 VPI 对象
72  VPIImage inLeft = NULL;
73  VPIImage inRight = NULL;
74  VPIImage tmpLeft = NULL;
75  VPIImage tmpRight = NULL;
76  VPIImage stereoLeft = NULL;
77  VPIImage stereoRight = NULL;
78  VPIImage disparity = NULL;
79  VPIImage confidenceMap = NULL;
80  VPIStream stream = NULL;
81  VPIPayload stereo = NULL;
82 
83  int retval = 0;
84 
85  try
86  {
87  // =============================
88  // 解析命令行参数
89 
90  if (argc != 4)
91  {
92  throw std::runtime_error(std::string("Usage: ") + argv[0] +
93  " <cuda|ofa|ofa-pva-vic> <left image> <right image>");
94  }
95 
96  std::string strBackend = argv[1];
97  std::string strLeftFileName = argv[2];
98  std::string strRightFileName = argv[3];
99 
100  uint64_t backends;
101 
102  if (strBackend == "cuda")
103  {
104  backends = VPI_BACKEND_CUDA;
105  }
106  else if (strBackend == "ofa")
107  {
108  backends = VPI_BACKEND_OFA;
109  }
110  else if (strBackend == "ofa-pva-vic")
111  {
113  }
114  else
115  {
116  throw std::runtime_error("Backend '" + strBackend +
117  "' not recognized, it must be either cuda, ofa or ofa-pva-vic.");
118  }
119 
120  // =====================
121  // 加载输入图像
122  cvImageLeft = cv::imread(strLeftFileName);
123  if (cvImageLeft.empty())
124  {
125  throw std::runtime_error("Can't open '" + strLeftFileName + "'");
126  }
127 
128  cvImageRight = cv::imread(strRightFileName);
129  if (cvImageRight.empty())
130  {
131  throw std::runtime_error("Can't open '" + strRightFileName + "'");
132  }
133 
134  // =================================
135  // 分配所有需要的 VPI 资源
136 
137  int32_t inputWidth = cvImageLeft.cols;
138  int32_t inputHeight = cvImageLeft.rows;
139 
140  // 创建将用于处理的流。
141  CHECK_STATUS(vpiStreamCreate(0, &stream));
142 
143  // 现在我们将加载的图像包装到 VPIImage 对象中,以供 VPI 使用。
144  // VPI 不会复制它,因此原始图像必须始终在作用域内。
145  CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(cvImageLeft, 0, &inLeft));
146  CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(cvImageRight, 0, &inRight));
147 
148  // 输入预处理所需的格式转换参数
149  VPIConvertImageFormatParams convParams;
150  CHECK_STATUS(vpiInitConvertImageFormatParams(&convParams));
151 
152  // 初始化默认参数
154  CHECK_STATUS(vpiInitStereoDisparityEstimatorCreationParams(&createParams));
155 
156  // 选择最大视差,该视差适用于 chair_stereo_{left,right}_1920.png 文件
157  createParams.maxDisparity = 256;
158 
159  // 输入立体图像对的默认格式和大小(某些后端需要调整,请参见下文)
160  VPIImageFormat stereoFormat = VPI_IMAGE_FORMAT_Y8_ER;
161 
162  int stereoWidth = inputWidth;
163  int stereoHeight = inputHeight;
164 
165  // 输出的默认格式和大小
166  VPIImageFormat disparityFormat = VPI_IMAGE_FORMAT_S16;
167 
168  int outputWidth = inputWidth;
169  int outputHeight = inputHeight;
170 
171  // 覆盖一些后端相关的参数
172  if (strBackend.find("ofa") != std::string::npos)
173  {
174  // 使用 OFA 的实现需要 BL 输入
175  stereoFormat = VPI_IMAGE_FORMAT_Y8_ER_BL;
176 
177  if (strBackend == "ofa")
178  {
179  // 当单独使用 OFA 时,输出也必须是 BL
180  disparityFormat = VPI_IMAGE_FORMAT_S16_BL;
181  }
182 
183  // 将下采样因子与 OFA 一起使用可提高性能
184  createParams.downscaleFactor = 2;
185  outputWidth = (inputWidth + createParams.downscaleFactor - 1) / createParams.downscaleFactor;
186  outputHeight = (inputHeight + createParams.downscaleFactor - 1) / createParams.downscaleFactor;
187 
188  // 当使用 OFA+PVA+VIC 后端时,包括 downscaleFactor 在内的输出宽度必须至少为 max(64, maxDisparity/downscaleFactor)
189  // OFA+PVA+VIC 后端被使用
190  if (strBackend.find("pva") != std::string::npos)
191  {
192  int minWidth = std::max(createParams.maxDisparity / createParams.downscaleFactor, outputWidth);
193  outputWidth = std::max(64, minWidth);
194  outputHeight = (inputHeight * outputWidth) / inputWidth;
195  stereoWidth = outputWidth * createParams.downscaleFactor;
196  stereoHeight = outputHeight * createParams.downscaleFactor;
197  }
198  }
199 
200  // 为立体视差算法创建有效负载。
201  // 有效负载在图像对象之前创建,以便可以使用错误捕获不支持的后端。
202  CHECK_STATUS(vpiCreateStereoDisparityEstimator(backends, stereoWidth, stereoHeight, stereoFormat, &createParams,
203  &stereo));
204 
205  // 创建将存储视差图的输出图像。
206  CHECK_STATUS(vpiImageCreate(outputWidth, outputHeight, disparityFormat, 0, &disparity));
207 
208  // 创建输入立体图像
209  CHECK_STATUS(vpiImageCreate(stereoWidth, stereoHeight, stereoFormat, 0, &stereoLeft));
210  CHECK_STATUS(vpiImageCreate(stereoWidth, stereoHeight, stereoFormat, 0, &stereoRight));
211 
212  // 如果后端可以支持,则创建置信度图像
213  if (strBackend == "ofa-pva-vic" || strBackend == "cuda")
214  {
215  CHECK_STATUS(vpiImageCreate(outputWidth, outputHeight, VPI_IMAGE_FORMAT_U16, 0, &confidenceMap));
216  }
217 
218  // 如果需要重新缩放输入,则为初始格式转换创建临时图像。
219  bool const isRescaleRequired = (stereoWidth != inputWidth) || (stereoHeight != inputHeight);
220  if (isRescaleRequired)
221  {
222  CHECK_STATUS(vpiImageCreate(inputWidth, inputHeight, stereoFormat, 0, &tmpLeft));
223  CHECK_STATUS(vpiImageCreate(inputWidth, inputHeight, stereoFormat, 0, &tmpRight));
224  }
225 
226  // ================
227  // 处理阶段
228 
229  // 从默认参数开始,并根据使用的后端覆盖某些值。
231  CHECK_STATUS(vpiInitStereoDisparityEstimatorParams(&submitParams));
232  if (strBackend == "ofa-pva-vic")
233  {
234  // INFERENCE 置信度类型在使用 OFA+PVA+VIC 后端时可获得更好的性能。唯一的权衡是
235  // 基于深度学习的置信度图不容易表示为左右视差估计的函数,
236  // 与 ABSOLUTE 或 RELATIVE 置信度类型相反。
238  }
239  else if (strBackend == "cuda")
240  {
241  // chair_stereo_{left,right}_1920.png 输入受益于 CUDA 的更高置信度阈值
242  submitParams.confidenceThreshold = UINT16_MAX - 10000;
243  }
244 
245  // -----------------
246  // 预处理输入
247  if (isRescaleRequired)
248  {
249  // 我们只需要使用 CUDA 进行转换,因为我们从 OpenCV 以默认的 BGR 格式加载了图像
250  // 并且 VIC 后端不支持 3 通道 RGB/BGR 图像格式。
251  // 或者,我们可以加载灰度图像并在 VIC 上一次操作中处理转换+重新缩放。
252 
253  // 使用 CUDA 将 opencv 输入转换为灰度格式
254  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, inLeft, tmpLeft, &convParams));
255  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, inRight, tmpRight, &convParams));
256 
257  // 在 VIC 上重新缩放
258  CHECK_STATUS(
259  vpiSubmitRescale(stream, VPI_BACKEND_VIC, tmpLeft, stereoLeft, VPI_INTERP_LINEAR, VPI_BORDER_CLAMP, 0));
260  CHECK_STATUS(vpiSubmitRescale(stream, VPI_BACKEND_VIC, tmpRight, stereoRight, VPI_INTERP_LINEAR,
261  VPI_BORDER_CLAMP, 0));
262  }
263  else
264  {
265  // 使用 CUDA 将 opencv 输入转换为灰度格式
266  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, inLeft, stereoLeft, &convParams));
267  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, inRight, stereoRight, &convParams));
268  }
269 
270  // ------------------------------
271  // 进行立体视差估计
272 
273  // 使用输入和输出图像提交它
274  CHECK_STATUS(vpiSubmitStereoDisparityEstimator(stream, backends, stereo, stereoLeft, stereoRight, disparity,
275  confidenceMap, &submitParams));
276 
277  // 等待算法完成处理
278  CHECK_STATUS(vpiStreamSync(stream));
279 
280  // ========================================
281  // 输出预处理和保存到磁盘
282  // 锁定输出以在 cpu 内存中检索其数据
283  VPIImageData data;
284  CHECK_STATUS(vpiImageLockData(disparity, VPI_LOCK_READ, VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR, &data));
285 
286  // 从此图像创建一个 OpenCV 矩阵
287  cv::Mat cvDisparity;
288  CHECK_STATUS(vpiImageDataExportOpenCVMat(data, &cvDisparity));
289 
290  // 缩放结果并将其写入磁盘。视差以 Q10.5 格式表示,
291  // 因此要将其映射到浮点数,需要除以 32。然后将生成的视差范围,
292  // 从 0 到 maxDisparity 映射到 0-255 以获得正确的输出。
293  cvDisparity.convertTo(cvDisparity, CV_8UC1, 255.0 / (32 * createParams.maxDisparity), 0);
294 
295  // 应用 JET 颜色映射以将视差转换为颜色。
296  // 偏红色调表示更靠近相机的物体,偏蓝色调表示更远的物体。
297  cv::Mat cvDisparityColor;
298  applyColorMap(cvDisparity, cvDisparityColor, cv::COLORMAP_JET);
299 
300  // 输出处理完成,不要忘记解锁。
301  CHECK_STATUS(vpiImageUnlock(disparity));
302 
303  // 如果我们有置信度图,也调整它以进行显示并将其写入磁盘。
304  if (confidenceMap)
305  {
306  // 锁定图像数据并导出到 cv::Mat
307  VPIImageData data;
308  CHECK_STATUS(vpiImageLockData(confidenceMap, VPI_LOCK_READ, VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR, &data));
309  cv::Mat cvConfidence;
310  CHECK_STATUS(vpiImageDataExportOpenCVMat(data, &cvConfidence));
311 
312  // 置信度图的范围从 0 到 65535,我们将其缩放到 [0-255]。
313  cvConfidence.convertTo(cvConfidence, CV_8UC1, 255.0 / 65535, 0);
314  imwrite("confidence_" + strBackend + ".png", cvConfidence);
315 
316  CHECK_STATUS(vpiImageUnlock(confidenceMap));
317 
318  // 当像素置信度为 0 时,我们希望视差图像中的颜色为黑色。
319  cv::Mat cvMask;
320  threshold(cvConfidence, cvMask, 1, 255, cv::THRESH_BINARY);
321  cvtColor(cvMask, cvMask, cv::COLOR_GRAY2BGR);
322  bitwise_and(cvDisparityColor, cvMask, cvDisparityColor);
323  }
324 
325  imwrite("disparity_" + strBackend + ".png", cvDisparityColor);
326  }
327  catch (std::exception &e)
328  {
329  std::cerr << e.what() << std::endl;
330  retval = 1;
331  }
332 
333  // ========
334  // 清理
335 
336  // 首先销毁流可确保提交给它的所有工作
337  // 都已完成。
338  vpiStreamDestroy(stream);
339 
340  // 只有这样我们才能销毁其他对象,因为我们确信它们
341  // 不再被使用。
342 
343  vpiImageDestroy(inLeft);
344  vpiImageDestroy(inRight);
345  vpiImageDestroy(tmpLeft);
346  vpiImageDestroy(tmpRight);
347  vpiImageDestroy(stereoLeft);
348  vpiImageDestroy(stereoRight);
349  vpiImageDestroy(confidenceMap);
350  vpiImageDestroy(disparity);
351  vpiPayloadDestroy(stereo);
352 
353  return retval;
354 }
声明处理图像格式转换的函数。
#define VPI_IMAGE_FORMAT_S16_BL
单平面,带有一个块线性 16 位有符号整数通道。
Definition: ImageFormat.h:123
#define VPI_IMAGE_FORMAT_Y8_ER_BL
单平面,带有一个块线性 8 位无符号整数通道,具有全范围亮度(灰度)...
Definition: ImageFormat.h:164
#define VPI_IMAGE_FORMAT_U16
单平面,带有一个 16 位无符号整数通道。
Definition: ImageFormat.h:111
#define VPI_IMAGE_FORMAT_S16
单平面,带有一个 16 位有符号整数通道。
Definition: ImageFormat.h:120
#define VPI_IMAGE_FORMAT_Y8_ER
单平面,带有一个 pitch-linear 8 位无符号整数通道,具有全范围亮度(灰度)...
Definition: ImageFormat.h:159
用于处理 VPI 图像的函数和结构。
用于处理 VPI 的 OpenCV 互操作性的函数。
声明实现 Rescale 算法的函数。
VPI 状态代码处理函数的声明。
声明实现立体视差估计算法的函数。
声明处理 VPI 流的函数。
VPIStatus vpiInitConvertImageFormatParams(VPIConvertImageFormatParams *params)
使用默认值初始化 VPIConvertImageFormatParams。
VPIStatus vpiSubmitConvertImageFormat(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, const VPIConvertImageFormatParams *params)
将图像内容转换为所需的格式,可选择缩放和偏移。
用于自定义图像格式转换的参数。
uint64_t VPIImageFormat
预定义的图像格式。
Definition: ImageFormat.h:94
void vpiImageDestroy(VPIImage img)
销毁图像实例。
struct VPIImageImpl * VPIImage
图像的句柄。
Definition: Types.h:256
VPIStatus vpiImageLockData(VPIImage img, VPILockMode mode, VPIImageBufferType bufType, VPIImageData *data)
获取图像对象的锁并返回图像内容。
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用指定的标志创建空的图像实例。
VPIStatus vpiImageUnlock(VPIImage img)
释放图像对象的锁。
@ VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR
主机可访问,平面采用 pitch-linear 内存布局。
Definition: Image.h:172
存储有关图像特征和内容的信息。
Definition: Image.h:234
VPIStatus vpiImageCreateWrapperOpenCVMat(const cv::Mat &mat, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用给定的图像格式将 cv::Mat 封装到 VPIImage 中。
VPIStatus vpiImageDataExportOpenCVMat(const VPIImageData &imgData, cv::Mat *mat)
使用来自锁定 VPIImage 的 VPIImageData 数据填充现有的 cv::Mat。
struct VPIPayloadImpl * VPIPayload
算法有效负载的句柄。
Definition: Types.h:268
void vpiPayloadDestroy(VPIPayload payload)
释放有效负载对象和所有关联的资源。
VPIStatus vpiSubmitRescale(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, VPIInterpolationType interpolationType, VPIBorderExtension border, uint64_t flags)
更改 2D 图像的大小和比例。
int32_t maxDisparity
用于匹配搜索的最大视差。
VPIStereoDisparityConfidenceType confidenceType
用于生成置信度输出的计算类型。
int32_t confidenceThreshold
置信度阈值,高于该阈值视差值被认为是有效的。
int32_t downscaleFactor
输出相对于输入分辨率的降采样因子。
VPIStatus vpiInitStereoDisparityEstimatorCreationParams(VPIStereoDisparityEstimatorCreationParams *params)
使用默认值初始化 VPIStereoDisparityEstimatorCreationParams。
VPIStatus vpiCreateStereoDisparityEstimator(uint64_t backends, int32_t imageWidth, int32_t imageHeight, VPIImageFormat inputFormat, const VPIStereoDisparityEstimatorCreationParams *params, VPIPayload *payload)
为 vpiSubmitStereoDisparityEstimator 创建有效负载。
VPIStatus vpiInitStereoDisparityEstimatorParams(VPIStereoDisparityEstimatorParams *params)
使用默认值初始化 VPIStereoDisparityEstimatorParams。
VPIStatus vpiSubmitStereoDisparityEstimator(VPIStream stream, uint64_t backend, VPIPayload payload, VPIImage left, VPIImage right, VPIImage disparity, VPIImage confidenceMap, const VPIStereoDisparityEstimatorParams *params)
在一对图像上运行立体处理并输出视差图。
@ VPI_STEREO_CONFIDENCE_INFERENCE
像素的置信度值在 0:UINT16_MAX 范围内,从 0% 映射到 100%。
定义 vpiCreateStereoDisparityEstimator 参数的结构体。
定义 vpiSubmitStereoDisparityEstimator 参数的结构体。
struct VPIStreamImpl * VPIStream
流的句柄。
Definition: Types.h:250
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中的所有提交命令都完成(队列为空)...
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
@ VPI_BACKEND_CUDA
CUDA 后端。
Definition: Types.h:93
@ VPI_BACKEND_PVA
PVA 后端。
Definition: Types.h:94
@ VPI_BACKEND_OFA
OFA 后端。
Definition: Types.h:97
@ VPI_BACKEND_VIC
VIC 后端。
Definition: Types.h:95
@ VPI_BORDER_CLAMP
边界像素无限重复。
Definition: Types.h:279
@ VPI_INTERP_LINEAR
线性插值。
Definition: Interpolation.h:93
@ VPI_LOCK_READ
仅锁定内存以进行读取。
Definition: Types.h:617