VPI - 视觉编程接口

3.2 版本

金字塔 LK 光流法

概述

此应用程序跟踪输入视频中的特征点,在每帧上绘制这些特征点,并将它们保存到磁盘。您可以定义将用于处理的后端。

注意
输出将为灰度,因为该算法目前不支持彩色输入。

说明

命令行参数为

<后端> <输入视频> <金字塔层级> <输出帧>

其中

  • 后端:cpucudapva 之一;它定义了将执行处理的后端。
  • 输入视频:输入视频文件名,它接受 OpenCV 的 cv::VideoCapture 接受的所有视频类型。
  • 金字塔层级:指定算法中使用的金字塔层数。
  • 输出帧:将用于输出帧的文件名。例如:output.png 将生成帧 output_0000.pngoutput_0001.pngoutput_0002.png,依此类推。

这是一个示例

  • C++
    ./vpi_sample_12_optflow_lk cuda ../assets/dashcam.mp4 5 frame.png
  • Python
    python3 main.py cuda ../assets/dashcam.mp4 5 frame.png

这是使用 CUDA 后端和一个提供的示例视频,金字塔层级为 5。

结果

帧 0009

源代码

为了方便起见,这里提供了也安装在示例目录中的代码。

语言
27 import sys
28 import vpi
29 import numpy as np
30 from os import path
31 from argparse import ArgumentParser
32 from contextlib import contextmanager
33 import cv2
34 
35 
36 # --------------------------------------
37 # Some definitions and utility functions
38 
39 # Maximum number of keypoints that will be tracked
40 MAX_KEYPOINTS = 100
41 
42 def update_mask(mask, trackColors, prevFeatures, curFeatures, status = None)
43  '''Draw keypoint path from previous frame to current one'''
44 
45  numTrackedKeypoints = 0
46 
47  def none_context(a=None): return contextmanager(lambda: (x for x in [a]))()
48 
49  with curFeatures.rlock_cpu(), \
50  (status.rlock_cpu() if status else none_context()), \
51  (prevFeatures.rlock_cpu() if prevFeatures else none_context())
52 
53  for i in range(curFeatures.size)
54  # keypoint is being tracked?
55  if not status or status.cpu()[i] == 0
56  color = tuple(trackColors[i,0].tolist())
57 
58  # OpenCV 4.5+ wants integers in the tuple arguments below
59  cf = tuple(np.round(curFeatures.cpu()[i]).astype(int))
60 
61  # draw the tracks
62  if prevFeatures
63  pf = tuple(np.round(prevFeatures.cpu()[i]).astype(int))
64  cv2.line(mask, pf, cf, color, 2)
65 
66  cv2.circle(mask, cf, 5, color, -1)
67 
68  numTrackedKeypoints += 1
69 
70  return numTrackedKeypoints
71 
72 def save_file_to_disk(frame, mask, baseFileName, frameCounter)
73  '''Apply mask on frame and save it to disk'''
74 
75  frame = frame.convert(vpi.Format.BGR8, backend=vpi.Backend.CUDA)
76  with frame.rlock_cpu() as frameData
77  frame = cv2.add(frameData, mask)
78 
79  name, ext = path.splitext(baseFileName)
80  fname = "{}_{:04d}{}".format(name, frameCounter, ext)
81 
82  cv2.imwrite(fname, frame, [cv2.IMWRITE_JPEG_QUALITY, 70])
83 
84 # ----------------------------
85 # Parse command line arguments
86 
87 parser = ArgumentParser()
88 parser.add_argument('backend', choices=['cpu', 'cuda', 'pva'],
89  help='Backend to be used for processing')
90 
91 parser.add_argument('input',
92  help='Input video to be processed')
93 
94 parser.add_argument('pyramid_levels', type=int,
95  help='Number of levels in the pyramid used with the algorithm')
96 
97 parser.add_argument('output',
98  help='Output file name')
99 
100 args = parser.parse_args();
101 
102 if args.backend == 'cuda'
103  backend = vpi.Backend.CUDA
104 elif args.backend == 'pva'
105  backend = vpi.Backend.PVA
106 else
107  assert args.backend == 'cpu'
108  backend = vpi.Backend.CPU
109 
110 # adjust output file name to take into account backend used and python version
111 name, ext = path.splitext(args.output)
112 args.output = "{}_python{}_{}{}".format(name, sys.version_info[0], args.backend, ext)
113 
114 # ----------------
115 # Open input video
116 
117 inVideo = cv2.VideoCapture(args.input)
118 
119 # Read first input frame
120 ok, cvFrame = inVideo.read()
121 if not ok
122  exit('Cannot read first input frame')
123 
124 # ---------------------------
125 # Perform some pre-processing
126 
127 # Retrieve features to be tracked from first frame using
128 # Harris Corners Detector
129 with vpi.Backend.CPU
130  frame = vpi.asimage(cvFrame, vpi.Format.BGR8).convert(vpi.Format.U8)
131  curFeatures, scores = frame.harriscorners(strength=0.1, sensitivity=0.01)
132 
133 # Limit the number of features we'll track and calculate their colors on the
134 # output image
135 with curFeatures.lock_cpu() as featData, scores.rlock_cpu() as scoresData
136  # Sort features in descending scores order and keep the first MAX_KEYPOINTS
137  ind = np.argsort(scoresData, kind='mergesort')[::-1]
138  featData[:] = np.take(featData, ind, axis=0)
139  curFeatures.size = min(curFeatures.size, MAX_KEYPOINTS)
140 
141  # Keypoints' have different hues, calculated from their position in the first frame
142  trackColors = np.array([[(int(p[0]) ^ int(p[1])) % 180,255,255] for p in featData], np.uint8).reshape(-1,1,3)
143  # Convert colors from HSV to RGB
144  trackColors = cv2.cvtColor(trackColors, cv2.COLOR_HSV2BGR).astype(int)
145 
146 with backend
147  optflow = vpi.OpticalFlowPyrLK(frame, curFeatures, args.pyramid_levels)
148 
149 # Counter for the frames
150 idFrame = 0
151 
152 # Create mask with features' tracks over time
153 mask = np.zeros((frame.height, frame.width, 3), np.uint8)
154 numTrackedKeypoints = update_mask(mask, trackColors, None, curFeatures)
155 
156 while True
157  # Apply mask to frame and save it to disk
158  save_file_to_disk(frame, mask, args.output, idFrame)
159 
160  print("Frame id={}: {} points tracked.".format(idFrame, numTrackedKeypoints))
161 
162  prevFeatures = curFeatures
163 
164  # Read one input frame
165  ret, cvFrame = inVideo.read()
166  if not ret
167  print("Video ended.")
168  break
169  idFrame += 1
170 
171  # Convert frame to grayscale
172  with vpi.Backend.CUDA
173  frame = vpi.asimage(cvFrame, vpi.Format.BGR8).convert(vpi.Format.U8);
174 
175  # Calculate where keypoints are in current frame
176  curFeatures, status = optflow(frame)
177 
178  # Update the mask with the current keypoints' position
179  numTrackedKeypoints = update_mask(mask, trackColors, prevFeatures, curFeatures, status)
180 
181  # No more keypoints to track?
182  if numTrackedKeypoints == 0
183  print("No keypoints to track.")
184  break # nothing else to do
29 #include <opencv2/core/version.hpp>
30 #if CV_MAJOR_VERSION >= 3
31 # include <opencv2/imgcodecs.hpp>
32 # include <opencv2/videoio.hpp>
33 #else
34 # include <opencv2/highgui/highgui.hpp>
35 #endif
36 
37 #include <opencv2/imgproc/imgproc.hpp>
38 #include <vpi/OpenCVInterop.hpp>
39 
40 #include <vpi/Array.h>
41 #include <vpi/Image.h>
42 #include <vpi/Pyramid.h>
43 #include <vpi/Status.h>
44 #include <vpi/Stream.h>
47 #include <vpi/algo/HarrisCorners.h>
49 
50 #include <algorithm>
51 #include <cstring> // for memset
52 #include <fstream>
53 #include <iostream>
54 #include <map>
55 #include <numeric>
56 #include <sstream>
57 #include <vector>
58 
59 // Max number of corners detected by harris corner algo
60 constexpr int MAX_HARRIS_CORNERS = 8192;
61 
62 // Max number of keypoints to be tracked
63 constexpr int MAX_KEYPOINTS = 100;
64 
65 #define CHECK_STATUS(STMT) \
66  do \
67  { \
68  VPIStatus status__ = (STMT); \
69  if (status__ != VPI_SUCCESS) \
70  { \
71  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
72  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
73  std::ostringstream ss; \
74  ss << vpiStatusGetName(status__) << ": " << buffer; \
75  throw std::runtime_error(ss.str()); \
76  } \
77  } while (0);
78 
79 static void SaveFileToDisk(VPIImage img, cv::Mat cvMask, std::string baseFileName, int32_t frameCounter)
80 {
81  VPIImageData imgData;
83 
84  cv::Mat cvImage;
85  try
86  {
87  cv::Mat tmp;
88  CHECK_STATUS(vpiImageDataExportOpenCVMat(imgData, &tmp));
89  cvtColor(tmp, cvImage, cv::COLOR_GRAY2BGR);
90 
91  CHECK_STATUS(vpiImageUnlock(img));
92  }
93  catch (...)
94  {
95  CHECK_STATUS(vpiImageUnlock(img));
96  throw;
97  }
98 
99  add(cvImage, cvMask, cvImage);
100 
101  // Create the output file name
102  std::string fname = baseFileName;
103  int ext = fname.rfind('.');
104 
105  char buffer[512] = {};
106  snprintf(buffer, sizeof(buffer) - 1, "%s_%04d%s", fname.substr(0, ext).c_str(), frameCounter,
107  fname.substr(ext).c_str());
108 
109  // Finally, write frame to disk
110  if (!imwrite(buffer, cvImage, {cv::IMWRITE_JPEG_QUALITY, 70}))
111  {
112  throw std::runtime_error("Can't write to " + std::string(buffer));
113  }
114 }
115 
116 // Sort keypoints by decreasing score, and retain only the first 'max'
117 static void SortKeypoints(VPIArray keypoints, VPIArray scores, int max)
118 {
119  VPIArrayData ptsData, scoresData;
120  CHECK_STATUS(vpiArrayLockData(keypoints, VPI_LOCK_READ_WRITE, VPI_ARRAY_BUFFER_HOST_AOS, &ptsData));
121  CHECK_STATUS(vpiArrayLockData(scores, VPI_LOCK_READ_WRITE, VPI_ARRAY_BUFFER_HOST_AOS, &scoresData));
122 
123  VPIArrayBufferAOS &aosKeypoints = ptsData.buffer.aos;
124  VPIArrayBufferAOS &aosScores = scoresData.buffer.aos;
125 
126  std::vector<int> indices(*aosKeypoints.sizePointer);
127  std::iota(indices.begin(), indices.end(), 0);
128 
129  stable_sort(indices.begin(), indices.end(), [&aosScores](int a, int b) {
130  uint32_t *score = reinterpret_cast<uint32_t *>(aosScores.data);
131  return score[a] >= score[b]; // decreasing score order
132  });
133 
134  // keep the only 'max' indexes.
135  indices.resize(std::min<size_t>(indices.size(), max));
136 
137  VPIKeypointF32 *kptData = reinterpret_cast<VPIKeypointF32 *>(aosKeypoints.data);
138 
139  // reorder the keypoints to keep the first 'max' with highest scores.
140  std::vector<VPIKeypointF32> kpt;
141  std::transform(indices.begin(), indices.end(), std::back_inserter(kpt),
142  [kptData](int idx) { return kptData[idx]; });
143  std::copy(kpt.begin(), kpt.end(), kptData);
144 
145  // update keypoint array size.
146  *aosKeypoints.sizePointer = kpt.size();
147 
148  vpiArrayUnlock(scores);
149  vpiArrayUnlock(keypoints);
150 }
151 
152 static int UpdateMask(cv::Mat &cvMask, const std::vector<cv::Scalar> &trackColors, VPIArray prevFeatures,
153  VPIArray curFeatures, VPIArray status)
154 {
155  // Now that optical flow is completed, there are usually two approaches to take:
156  // 1. Add new feature points from current frame using a feature detector such as
157  // \ref algo_harris_corners "Harris Corner Detector"
158  // 2. Keep using the points that are being tracked.
159  //
160  // The sample app uses the valid feature point and continue to do the tracking.
161 
162  // Lock the input and output arrays to draw the tracks to the output mask.
163  VPIArrayData curFeaturesData, statusData;
164  CHECK_STATUS(vpiArrayLockData(curFeatures, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &curFeaturesData));
165  CHECK_STATUS(vpiArrayLockData(status, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &statusData));
166 
167  const VPIArrayBufferAOS &aosCurFeatures = curFeaturesData.buffer.aos;
168  const VPIArrayBufferAOS &aosStatus = statusData.buffer.aos;
169 
170  const VPIKeypointF32 *pCurFeatures = (VPIKeypointF32 *)aosCurFeatures.data;
171  const uint8_t *pStatus = (uint8_t *)aosStatus.data;
172 
173  const VPIKeypointF32 *pPrevFeatures;
174  if (prevFeatures)
175  {
176  VPIArrayData prevFeaturesData;
177  CHECK_STATUS(vpiArrayLockData(prevFeatures, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &prevFeaturesData));
178  pPrevFeatures = (VPIKeypointF32 *)prevFeaturesData.buffer.aos.data;
179  }
180  else
181  {
182  pPrevFeatures = NULL;
183  }
184 
185  int numTrackedKeypoints = 0;
186  int totKeypoints = *curFeaturesData.buffer.aos.sizePointer;
187 
188  for (int i = 0; i < totKeypoints; i++)
189  {
190  // keypoint is being tracked?
191  if (pStatus[i] == 0)
192  {
193  // draw the tracks
194  cv::Point curPoint{(int)round(pCurFeatures[i].x), (int)round(pCurFeatures[i].y)};
195  if (pPrevFeatures != NULL)
196  {
197  cv::Point2f prevPoint{pPrevFeatures[i].x, pPrevFeatures[i].y};
198  line(cvMask, prevPoint, curPoint, trackColors[i], 2);
199  }
200 
201  circle(cvMask, curPoint, 5, trackColors[i], -1);
202 
203  numTrackedKeypoints++;
204  }
205  }
206 
207  // 我们完成了对数组的操作。
208  if (prevFeatures)
209  {
210  CHECK_STATUS(vpiArrayUnlock(prevFeatures));
211  }
212  CHECK_STATUS(vpiArrayUnlock(curFeatures));
213  CHECK_STATUS(vpiArrayUnlock(status));
214 
215  return numTrackedKeypoints;
216 }
217 
218 int main(int argc, char *argv[])
219 {
220  // 将被 VPIImage 封装的 OpenCV 图像。
221  // 在此处定义,以便在 wrapper 销毁*之后*销毁它
222  cv::Mat cvFrame;
223 
224  // 将要使用的 VPI 对象
225  VPIStream stream = NULL;
226  VPIImage imgTempFrame = NULL;
227  VPIImage imgFrame = NULL;
228  VPIPyramid pyrPrevFrame = NULL, pyrCurFrame = NULL;
229  VPIArray prevFeatures = NULL, curFeatures = NULL, status = NULL;
230  VPIPayload optflow = NULL;
231  VPIArray scores = NULL;
232  VPIPayload harris = NULL;
233 
234  int retval = 0;
235 
236  try
237  {
238  // ============================
239  // 解析命令行参数
240 
241  if (argc != 5)
242  {
243  throw std::runtime_error(std::string("Usage: ") + argv[0] +
244  " 用法: ");
245  }
246 
247  std::string strBackend = argv[1];
248  std::string strInputVideo = argv[2];
249  int32_t pyrLevel = std::stoi(argv[3]);
250  std::string strOutputFiles = argv[4];
251 
252  // 现在解析后端
253  VPIBackend backend;
254 
255  if (strBackend == "cpu")
256  {
257  backend = VPI_BACKEND_CPU;
258  }
259  else if (strBackend == "cuda")
260  {
261  backend = VPI_BACKEND_CUDA;
262  }
263  else if (strBackend == "pva")
264  {
265  backend = VPI_BACKEND_PVA;
266  }
267  else
268  {
269  "后端 '" + strBackend +
270  "' 无法识别,它必须是 cpu、cuda 或 pva 之一。");
271  }
272 
273  {
274  int ext = strOutputFiles.rfind('.');
275  strOutputFiles = strOutputFiles.substr(0, ext) + "_" + strBackend + strOutputFiles.substr(ext);
276  }
277 
278  // ====================
279  // 加载输入视频
280  cv::VideoCapture invid;
281  if (!invid.open(strInputVideo))
282  {
283  "无法打开 '" + strInputVideo + "'");
284  }
285 
286  // 获取第一帧并将其封装到 VPIImage 中。
287  // 稍后将从此帧收集要跟踪的点。
288  if (!invid.read(cvFrame))
289  {
290  "无法从 '" + strInputVideo + "' 中检索第一帧");
291  }
292 
293  // =================================================
294  // 分配 VPI 资源并进行一些预处理
295 
296  // 创建将要进行处理的流。
297  CHECK_STATUS(vpiStreamCreate(0, &stream));
298 
299  CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(cvFrame, 0, &imgTempFrame));
300 
301  // 创建输入的灰度图像表示。
302  CHECK_STATUS(vpiImageCreate(cvFrame.cols, cvFrame.rows, VPI_IMAGE_FORMAT_U8, 0, &imgFrame));
303 
304  // 创建算法使用的图像金字塔
305  CHECK_STATUS(
306  vpiPyramidCreate(cvFrame.cols, cvFrame.rows, VPI_IMAGE_FORMAT_U8, pyrLevel, 0.5, 0, &pyrPrevFrame));
307  CHECK_STATUS(vpiPyramidCreate(cvFrame.cols, cvFrame.rows, VPI_IMAGE_FORMAT_U8, pyrLevel, 0.5, 0, &pyrCurFrame));
308 
309  // 创建输入和输出数组
310  CHECK_STATUS(vpiArrayCreate(MAX_HARRIS_CORNERS, VPI_ARRAY_TYPE_KEYPOINT_F32, 0, &prevFeatures));
311  CHECK_STATUS(vpiArrayCreate(MAX_HARRIS_CORNERS, VPI_ARRAY_TYPE_KEYPOINT_F32, 0, &curFeatures));
312  CHECK_STATUS(vpiArrayCreate(MAX_HARRIS_CORNERS, VPI_ARRAY_TYPE_U8, 0, &status));
313 
314  // 创建光流负载
315  CHECK_STATUS(vpiCreateOpticalFlowPyrLK(backend, cvFrame.cols, cvFrame.rows, VPI_IMAGE_FORMAT_U8, pyrLevel, 0.5,
316  &optflow));
317 
318  // 我们将要使用的参数。无需动态更改它们,因此只需在此处定义它们即可。
319  // 我们正在使用默认参数。
320  VPIOpticalFlowPyrLKParams lkParams;
321  CHECK_STATUS(vpiInitOpticalFlowPyrLKParams(backend, &lkParams));
322 
323  // 创建用于绘制目的的掩码图像
324  cv::Mat cvMask = cv::Mat::zeros(cvFrame.size(), CV_8UC3);
325 
326  // 使用 CPU 上的 Harris 角点检测器从第一帧收集特征点。
327  {
328  CHECK_STATUS(vpiArrayCreate(MAX_HARRIS_CORNERS, VPI_ARRAY_TYPE_U32, 0, &scores));
329 
330  VPIHarrisCornerDetectorParams harrisParams;
331  CHECK_STATUS(vpiInitHarrisCornerDetectorParams(&harrisParams));
332  harrisParams.strengthThresh = 0;
333  harrisParams.sensitivity = 0.01;
334 
335  CHECK_STATUS(vpiCreateHarrisCornerDetector(VPI_BACKEND_CPU, cvFrame.cols, cvFrame.rows, &harris));
336 
337  // 将输入转换为灰度以符合 Harris 角点检测器的限制
338  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, imgTempFrame, imgFrame, NULL));
339 
340  CHECK_STATUS(vpiSubmitHarrisCornerDetector(stream, VPI_BACKEND_CPU, harris, imgFrame, curFeatures, scores,
341  &harrisParams));
342 
343  CHECK_STATUS(vpiStreamSync(stream));
344 
345  SortKeypoints(curFeatures, scores, MAX_KEYPOINTS);
346  }
347 
348  // 创建一些随机颜色
349  std::vector<cv::Scalar> trackColors;
350  {
351  std::vector<cv::Vec3b> tmpTrackColors;
352 
353  VPIArrayData ptsData;
354  CHECK_STATUS(vpiArrayLockData(curFeatures, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &ptsData));
355 
356  const VPIArrayBufferAOS &aosKeypoints = ptsData.buffer.aos;
357 
358  const VPIKeypointF32 *pts = (VPIKeypointF32 *)aosKeypoints.data;
359 
360  for (int i = 0; i < *aosKeypoints.sizePointer; i++)
361  {
362  // 轨迹色调取决于其初始位置
363  int hue = ((int)pts[i].x ^ (int)pts[i].y) % 180;
364 
365  tmpTrackColors.push_back(cv::Vec3b(hue, 255, 255));
366  }
367  CHECK_STATUS(vpiArrayUnlock(curFeatures));
368 
369  cvtColor(tmpTrackColors, tmpTrackColors, cv::COLOR_HSV2BGR);
370 
371  for (size_t i = 0; i < tmpTrackColors.size(); i++)
372  {
373  trackColors.push_back(cv::Scalar(tmpTrackColors[i]));
374  }
375  }
376 
377  // 使用第一帧的信息更新掩码。
378  int numTrackedKeypoints = UpdateMask(cvMask, trackColors, NULL, curFeatures, status);
379 
380  // =================================================
381  // 主要处理阶段
382 
383  // 为第一帧生成金字塔。
384  CHECK_STATUS(vpiSubmitGaussianPyramidGenerator(stream, backend, imgFrame, pyrCurFrame, VPI_BORDER_CLAMP));
385 
386  // 帧计数器
387  int idxFrame = 0;
388 
389  while (true)
390  {
391  // 将帧保存到磁盘
392  SaveFileToDisk(imgFrame, cvMask, strOutputFiles, idxFrame);
393 
394  printf("帧 ID=%d: 跟踪了 %d 个点。\n", idxFrame, numTrackedKeypoints);
395 
396  // 上一次迭代的当前帧/特征变为本次迭代的上一帧/特征。
397  // 前者将包含在此迭代中收集的信息。
398  std::swap(prevFeatures, curFeatures);
399  std::swap(pyrPrevFrame, pyrCurFrame);
400 
401  // 获取新帧
402  if (!invid.read(cvFrame))
403  {
404  printf("视频结束。\n");
405  break;
406  }
407 
408  ++idxFrame;
409 
410  // 将帧封装到 VPIImage 中,重用现有的 imgFrame。
411  CHECK_STATUS(vpiImageSetWrappedOpenCVMat(imgTempFrame, cvFrame));
412 
413  // 将其转换为灰度
414  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, imgTempFrame, imgFrame, NULL))
415 
416  // 从中生成金字塔
417  CHECK_STATUS(vpiSubmitGaussianPyramidGenerator(stream, backend, imgFrame, pyrCurFrame, VPI_BORDER_CLAMP));
418 
419  // 根据特征点在上一帧中的位置,估计其在当前帧中的位置
420  CHECK_STATUS(vpiSubmitOpticalFlowPyrLK(stream, 0, optflow, pyrPrevFrame, pyrCurFrame, prevFeatures,
421  curFeatures, status, &lkParams));
422 
423  // 等待处理完成。
424  CHECK_STATUS(vpiStreamSync(stream));
425 
426  // 更新输出掩码
427  numTrackedKeypoints = UpdateMask(cvMask, trackColors, prevFeatures, curFeatures, status);
428 
429  // 没有更多关键点被跟踪了吗?
430  if (numTrackedKeypoints == 0)
431  {
432  printf("没有关键点可以跟踪。\n");
433  break; // 我们可以结束处理。
434  }
435  }
436  }
437  catch (std::exception &e)
438  {
439  std::cerr << e.what() << std::endl;
440  retval = 1;
441  }
442 
443  vpiStreamDestroy(stream);
444  vpiPayloadDestroy(harris);
445  vpiPayloadDestroy(optflow);
446 
447  vpiPyramidDestroy(pyrPrevFrame);
448  vpiImageDestroy(imgTempFrame);
449  vpiImageDestroy(imgFrame);
450  vpiArrayDestroy(prevFeatures);
451  vpiArrayDestroy(curFeatures);
452  vpiArrayDestroy(status);
453  vpiArrayDestroy(scores);
454 
455  return retval;
456 }
用于处理 VPI 数组的函数和结构。
声明处理图像格式转换的函数。
声明处理高斯金字塔的函数。
声明实现 Harris 角点检测器算法的函数。
#define VPI_IMAGE_FORMAT_U8
单平面,带有一个 8 位无符号整数通道。
用于处理 VPI 图像的函数和结构。
用于处理 OpenCV 与 VPI 互操作性的函数。
声明了实现金字塔 LK 光流算法的函数。
用于处理 VPI 金字塔的函数和结构。
VPI 状态码处理函数的声明。
声明了处理 VPI 流的函数。
void * data
指向数组的第一个元素。
定义: Array.h:135
VPIArrayBuffer buffer
存储数组内容。
定义: Array.h:175
int32_t * sizePointer
指向数组中元素的数量。
定义: Array.h:122
VPIArrayBufferAOS aos
以结构体数组布局存储的数组。
定义: Array.h:162
VPIStatus vpiArrayUnlock(VPIArray array)
释放数组对象的锁。
VPIStatus vpiArrayLockData(VPIArray array, VPILockMode mode, VPIArrayBufferType bufType, VPIArrayData *data)
获取数组对象的锁并返回数组内容。
void vpiArrayDestroy(VPIArray array)
销毁数组实例。
VPIStatus vpiArrayCreate(int32_t capacity, VPIArrayType type, uint64_t flags, VPIArray *array)
创建空的数组实例。
struct VPIArrayImpl * VPIArray
数组的句柄。
定义: Types.h:232
@ VPI_ARRAY_TYPE_U32
无符号 32 位。
定义: ArrayType.h:76
@ VPI_ARRAY_TYPE_KEYPOINT_F32
VPIKeypointF32 元素。
定义: ArrayType.h:77
@ VPI_ARRAY_TYPE_U8
无符号 8 位。
定义: ArrayType.h:73
@ VPI_ARRAY_BUFFER_HOST_AOS
主机可访问的结构体数组。
定义: Array.h:146
存储关于数组特性和内容的信息。
定义: Array.h:116
存储关于数组特性和内容的信息。
定义: Array.h:168
VPIStatus vpiSubmitConvertImageFormat(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, const VPIConvertImageFormatParams *params)
将图像内容转换为所需的格式,带有可选的缩放和偏移。
VPIStatus vpiSubmitGaussianPyramidGenerator(VPIStream stream, uint64_t backend, VPIImage input, VPIPyramid output, VPIBorderExtension border)
从输入图像计算高斯金字塔。
float strengthThresh
指定用于消除 Harris 角点得分的最小阈值。
float sensitivity
从 Harris-Stephens 方程指定灵敏度阈值。
VPIStatus vpiSubmitHarrisCornerDetector(VPIStream stream, uint64_t backend, VPIPayload payload, VPIImage input, VPIArray outFeatures, VPIArray outScores, const VPIHarrisCornerDetectorParams *params)
向流提交 Harris 角点检测器操作。
VPIStatus vpiInitHarrisCornerDetectorParams(VPIHarrisCornerDetectorParams *params)
使用默认值初始化 VPIHarrisCornerDetectorParams。
VPIStatus vpiCreateHarrisCornerDetector(uint64_t backends, int32_t inputWidth, int32_t inputHeight, VPIPayload *payload)
创建 Harris 角点检测器负载。
定义 vpiSubmitHarrisCornerDetector 参数的结构体。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
struct VPIImageImpl * VPIImage
图像的句柄。
定义: 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 内存布局。
定义: Image.h:172
存储关于图像特性和内容的信息。
定义: 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。
VPIStatus vpiImageSetWrappedOpenCVMat(VPIImage img, const cv::Mat &mat)
重新定义现有 VPIImage 封装器的被封装的 cv::Mat。
VPIStatus vpiSubmitOpticalFlowPyrLK(VPIStream stream, uint64_t backend, VPIPayload payload, VPIPyramid prevPyr, VPIPyramid curPyr, VPIArray prevPts, VPIArray curPts, VPIArray trackingStatus, const VPIOpticalFlowPyrLKParams *params)
在两个帧上运行金字塔 LK 光流。
VPIStatus vpiInitOpticalFlowPyrLKParams(uint64_t backends, VPIOpticalFlowPyrLKParams *params)
使用默认值初始化 VPIOpticalFlowPyrLKParams。
VPIStatus vpiCreateOpticalFlowPyrLK(uint64_t backends, int32_t width, int32_t height, VPIImageFormat fmt, int32_t levels, float scale, VPIPayload *payload)
为 vpiSubmitOpticalFlowPyrLK 创建负载。
定义 vpiSubmitOpticalFlowPyrLK 参数的结构体。
struct VPIPayloadImpl * VPIPayload
算法负载的句柄。
定义: Types.h:268
void vpiPayloadDestroy(VPIPayload payload)
释放负载对象和所有相关的资源。
VPIStatus vpiPyramidCreate(int32_t width, int32_t height, VPIImageFormat fmt, int32_t numLevels, float scale, uint64_t flags, VPIPyramid *pyr)
使用指定的标志创建空的图像金字塔实例。
struct VPIPyramidImpl * VPIPyramid
图像金字塔的句柄。
定义: Types.h:262
void vpiPyramidDestroy(VPIPyramid pyr)
销毁图像金字塔实例以及它拥有的所有资源。
struct VPIStreamImpl * VPIStream
流的句柄。
定义: Types.h:250
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中所有提交的命令都完成(队列为空)。。。
VPIBackend
VPI 后端类型。
定义: Types.h:91
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
@ VPI_BACKEND_CUDA
CUDA 后端。
定义: Types.h:93
@ VPI_BACKEND_PVA
PVA 后端。
定义: Types.h:94
@ VPI_BACKEND_CPU
CPU 后端。
定义: Types.h:92
float x
关键点的 x 坐标。
定义: Types.h:335
float y
关键点的 y 坐标。
定义: Types.h:336
@ VPI_BORDER_CLAMP
边界像素无限重复。
定义: Types.h:279
@ VPI_LOCK_READ_WRITE
锁定内存以进行读取和写入。
定义: Types.h:631
@ VPI_LOCK_READ
仅锁定内存以进行读取。
定义: Types.h:617
存储 float32 关键点坐标。坐标相对于图像的左上角。
定义: Types.h:334