VPI - 视觉编程接口

3.2 版本

DCF 跟踪器

概述

此应用程序跟踪输入视频中的边界框,在每一帧上绘制它们,并将结果保存在一系列图像文件中。您可以定义用于处理的后端。

它作为一个简单的示例(或框架),展示了 DCF 跟踪器 算法如何在管道中实现。

注意
此示例实现了一个使用低跟踪质量的简单跟踪管道。为了获得生产级别的跟踪质量,您必须在名为“Custom target update”的代码部分实现正确的对象生命周期管理和边界框细化阶段。

说明

命令行参数是

./vpi_sample_19_dcf_tracker <backend> <input video> <input bboxes>

其中

  • backend:cudapva;它定义了将执行处理的后端。
  • input video:输入视频文件名,它接受 OpenCV 的 cv::VideoCapture 接受的所有视频类型。
  • input bboxes:包含输入边界框以及它们在哪个帧中出现的文件。该文件由多行组成,格式如下
      <target_id> <frame> <bbox_x> <bbox_y> <bbox_width> <bbox_height>

这是一个示例

  • C++
    ./vpi_sample_19_dcf_tracker cuda ../assets/pedestrians.mp4 ../assets/pedestrians_bboxes.txt

这是使用 CUDA 后端以及提供的示例视频和边界框之一。它会将跟踪的边界框渲染成一系列图像,然后保存到磁盘。

结果

简单跟踪结果
注意
视频输出需要支持 HTML5 且支持 H.264 mp4 视频解码的浏览器。

源代码

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

语言
29 #include <opencv2/core.hpp>
30 #include <opencv2/features2d.hpp>
31 #include <opencv2/imgcodecs.hpp>
32 #include <opencv2/imgproc.hpp>
33 #include <opencv2/videoio.hpp>
34 #include <vpi/OpenCVInterop.hpp>
35 
36 #include <vpi/Array.h>
37 #include <vpi/Image.h>
38 #include <vpi/Pyramid.h>
39 #include <vpi/Status.h>
40 #include <vpi/Stream.h>
42 #include <vpi/algo/CropScaler.h>
43 #include <vpi/algo/DCFTracker.h>
44 
45 #include <cmath>
46 #include <cstdio>
47 #include <cstring>
48 #include <fstream>
49 #include <iostream>
50 #include <list>
51 #include <map>
52 #include <numeric>
53 #include <optional>
54 #include <sstream>
55 #include <vector>
56 
57 #define CHECK_STATUS(STMT) \
58  do \
59  { \
60  VPIStatus status = (STMT); \
61  if (status != VPI_SUCCESS) \
62  { \
63  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
64  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
65  std::ostringstream ss; \
66  ss << vpiStatusGetName(status) << ": " << buffer; \
67  throw std::runtime_error(ss.str()); \
68  } \
69  } while (0);
70 
71 namespace {
72 
73 // 目标跟踪信息。
74 struct TrackInfo
75 {
76  int idTarget;
77  cv::Scalar color;
78  bool enabled; // 目标是否丢失。
79 };
80 
81 // idTarget -> 信息
82 using TargetTrackInfoMap = std::map<int, TrackInfo>;
83 
84 // 存储有关检测到的目标的信息。
85 struct DetectedTargetInfo
86 {
87  int idTarget;
88 
90 
91  bool lostTrack() const
92  {
93  return bbox.width == 0 || bbox.height == 0;
94  }
95 };
96 
97 // idTarget -> 信息
98 using DetectedTargetInfoMap = std::multimap<int, DetectedTargetInfo>;
99 
100 VPIBackend ParseBackend(const std::string &str)
101 {
102  if (str == "cuda")
103  {
104  return VPI_BACKEND_CUDA;
105  }
106  else if (str == "pva")
107  {
108  return VPI_BACKEND_PVA;
109  }
110  else
111  {
112  throw std::runtime_error("Backend '" + str + "' not recognized, it must be either cuda or pva.");
113  }
114 }
115 
116 // 打开由文件名指定的视频。
117 cv::VideoCapture ParseVideo(const std::string &fname)
118 {
119  cv::VideoCapture video;
120  if (!video.open(fname))
121  {
122  throw std::runtime_error("Can't open '" + fname + "'");
123  }
124  return video;
125 }
126 
127 // 解析目标边界框,以及它们出现的帧。
128 DetectedTargetInfoMap ParseTargetInfoAtFrame(const std::string &fname)
129 {
130  std::ifstream in(fname);
131  if (!in)
132  {
133  throw std::runtime_error("Can't open '" + fname + "'");
134  }
135 
136  DetectedTargetInfoMap out;
137 
138 // 对于每个边界框,
139  int frame;
140  DetectedTargetInfo tinfo;
141  while (in >> tinfo.idTarget >> frame >> tinfo.bbox.left >> tinfo.bbox.top >> tinfo.bbox.width >> tinfo.bbox.height)
142  {
143  out.emplace(frame, tinfo);
144  }
145 
146  return out;
147 }
148 
149 // 返回随机的高饱和度颜色。
150 cv::Scalar GetRandomColor(cv::RNG &rng)
151 {
152  std::vector<cv::Vec3b> color = {cv::Vec3b{(unsigned char)rng.uniform(0, 180), 255, 255}};
153  cvtColor(color, color, cv::COLOR_HSV2BGR);
154  return cv::Scalar(color[0][0], color[0][1], color[0][2], 255);
155 }
156 
157 // 将在帧 'idxFrame' 中找到的新目标添加到 'targets'。
158 bool AddNewTargetsFromFrame(int idxFrame, DetectedTargetInfoMap &tgtInfos, TargetTrackInfoMap &trackInfo,
159  VPIArrayData &targets)
160 {
161  // 尝试将新目标添加到现有目标的槽位中
162  // 这些现有目标的跟踪已丢失。如果没有这样的目标,则会追加到
163  // 数组的末尾。
164 
165  auto *pTarget = static_cast<VPIDCFTrackedBoundingBox *>(targets.buffer.aos.data);
166  const auto *tgtBegin = pTarget;
167 
168  static cv::RNG rng(1);
169 
170  // 对于 'idxFrame' 中的所有新目标,
171  auto tgtInfoRange = tgtInfos.equal_range(idxFrame);
172  for (auto it = tgtInfoRange.first; it != tgtInfoRange.second; ++it)
173  {
174  // 如果信息表明目标的跟踪已完成,
175  if (it->second.lostTrack())
176  {
177  // 跳过它,我们这里只添加新目标。
178  continue;
179  }
180 
181  // 如果相应的目标已启用(即正在被跟踪)
182  auto itTrackInfo = trackInfo.find(it->second.idTarget);
183  if (itTrackInfo != trackInfo.end() && itTrackInfo->second.enabled)
184  {
185  // 也跳过它
186  continue;
187  }
188 
189  // @注意:当分配数组时,其内容将填充零,
190  // 直到其容量。这意味着目标的状态丢失了。
191  static_assert(VPI_TRACKING_STATE_LOST == 0, "Unexpected value for lost state");
192 
193  // 搜索第一个跟踪丢失的目标。
194  while (pTarget->state != VPI_TRACKING_STATE_LOST && pTarget < tgtBegin + targets.buffer.aos.capacity)
195  {
196  ++pTarget;
197  }
198 
199  assert(pTarget < tgtBegin + targets.buffer.aos.capacity);
200 
201  pTarget->bbox = it->second.bbox;
202  pTarget->state = VPI_TRACKING_STATE_NEW;
203  pTarget->seqIndex = 0;
204  // 合理的默认值。
205  pTarget->filterLR = 0.075;
206  pTarget->filterChannelWeightsLR = 0.1;
207 
208  // 这是我们第一次看到这个目标吗?
209  if (itTrackInfo == trackInfo.end())
210  {
211  // 为其创建跟踪信息。
212  TrackInfo tinfo;
213  tinfo.idTarget = it->second.idTarget;
214  tinfo.color = GetRandomColor(rng);
215  tinfo.enabled = true;
216  itTrackInfo = trackInfo.emplace(tinfo.idTarget, tinfo).first;
217  }
218  else
219  {
220  // 现在已启用。
221  itTrackInfo->second.enabled = true;
222  }
223 
224  pTarget->userData = &itTrackInfo->second;
225 
226  ++pTarget;
227  }
228 
229  // 仅当我们将目标追加到数组末尾时才更新数组大小。
230  *targets.buffer.aos.sizePointer = std::max<int32_t>(*targets.buffer.aos.sizePointer, pTarget - tgtBegin);
231 
232  assert(*targets.buffer.aos.sizePointer >= 0);
233 
234  return true;
235 }
236 
237 // 将边界框超出帧区域或被检测器认为丢失的目标标记为丢失。
238 bool DetectTrackingLost(int idxFrame, DetectedTargetInfoMap &tgtInfos, VPIArrayData &targets, cv::Size frameSize)
239 {
240  auto tgtInfoRange = tgtInfos.equal_range(idxFrame);
241 
242  // 这是一种简单的方法,在鲁棒的跟踪器中不可靠。
243  // 鲁棒的方法需要由用户实现。
244 
245  bool atLeastOneLost = false;
246 
247  // 对于所有目标,从后向前,以便在需要时轻松减小数组大小。
248  for (auto *pBeginTarget = static_cast<VPIDCFTrackedBoundingBox *>(targets.buffer.aos.data),
249  *pTarget = pBeginTarget + *targets.buffer.aos.sizePointer - 1;
250  pTarget >= pBeginTarget; --pTarget)
251  {
252  bool trackingLost = false;
253 
254  // 这是一个有效的目标,但其边界框并非完全在帧内,
255  if (pTarget->state != VPI_TRACKING_STATE_LOST && (pTarget->bbox.left < 0 || pTarget->bbox.top < 0 ||
256  pTarget->bbox.left + pTarget->bbox.width > frameSize.width ||
257  pTarget->bbox.top + pTarget->bbox.height > frameSize.height))
258  {
259  // 认为它的跟踪丢失。
260  trackingLost = true;
261  }
262  else
263  {
264  // 遍历当前帧中的所有目标信息
265  for (auto itInfo = tgtInfoRange.first; itInfo != tgtInfoRange.second; ++itInfo)
266  {
267  // 这是当前目标的信息,并且跟踪丢失了吗?
268  if (pTarget->state != VPI_TRACKING_STATE_LOST &&
269  static_cast<const TrackInfo *>(pTarget->userData)->idTarget == itInfo->second.idTarget &&
270  itInfo->second.lostTrack())
271  {
272  // 标记它,
273  trackingLost = true;
274  break;
275  }
276  }
277  }
278 
279  if (trackingLost)
280  {
281  atLeastOneLost = true;
282 
283  // 更新目标状态以反映它。
284  pTarget->state = VPI_TRACKING_STATE_LOST;
285  static_cast<TrackInfo *>(pTarget->userData)->enabled = false;
286 
287  assert(*targets.buffer.aos.sizePointer >= 1);
288 
289  // 如果目标位于目标数组的末尾,
290  if (pTarget == pBeginTarget + *targets.buffer.aos.sizePointer - 1)
291  {
292  // 我们可以减小数组大小以提高跟踪处理时间。
293  *targets.buffer.aos.sizePointer = -1;
294  }
295  }
296  }
297 
298  return atLeastOneLost;
299 }
300 
301 // 使用来自检测器输出的输入更新目标的边界框。
302 bool RefineTracksAtFrame(int idxFrame, DetectedTargetInfoMap &tgtInfos, VPIArrayData &targets)
303 {
304  auto tgtInfoRange = tgtInfos.equal_range(idxFrame);
305 
306  bool atLeastOneUpdated = false;
307 
308  for (auto *pBeginTarget = static_cast<VPIDCFTrackedBoundingBox *>(targets.buffer.aos.data), *pTarget = pBeginTarget;
309  pTarget < pBeginTarget + *targets.buffer.aos.sizePointer; ++pTarget)
310  {
311  // 如果跟踪丢失,
312  if (pTarget->state == VPI_TRACKING_STATE_LOST)
313  {
314  // 则无需优化。
315  continue;
316  }
317 
318  bool found = false;
319 
320  // 对于 'idxFrame' 中的所有目标,
321  for (auto itInfo = tgtInfoRange.first; itInfo != tgtInfoRange.second; ++itInfo)
322  {
323  // 如果信息指示跟踪丢失,
324  if (itInfo->second.lostTrack())
325  {
326  // 跳过它,我们只更新现有目标。
327  continue;
328  }
329 
330  if ((pTarget->state == VPI_TRACKING_STATE_TRACKED || pTarget->state == VPI_TRACKING_STATE_SHADOW_TRACKED) &&
331  static_cast<const TrackInfo *>(pTarget->userData)->idTarget == itInfo->second.idTarget)
332  {
333  pTarget->bbox = itInfo->second.bbox;
334  found = true;
335  break;
336  }
337  }
338 
339  if (found)
340  {
341  atLeastOneUpdated = true;
342  pTarget->state = VPI_TRACKING_STATE_TRACKED;
343  }
344  else if (pTarget->state == VPI_TRACKING_STATE_TRACKED)
345  {
346  pTarget->state = VPI_TRACKING_STATE_SHADOW_TRACKED;
447  }
448  }
449 
450  return atLeastOneUpdated;
451 }
452 
453 void DrawTargets(cv::Mat &frame, VPIArray targets)
454 {
455  VPIArrayData tgtData;
456  CHECK_STATUS(vpiArrayLockData(targets, VPI_LOCK_READ, VPI_ARRAY_BUFFER_HOST_AOS, &tgtData));
457 
458  auto *ptgt = static_cast<VPIDCFTrackedBoundingBox *>(tgtData.buffer.aos.data);
459  int numObjs = *tgtData.buffer.aos.sizePointer;
460 
461  for (int o = 0; o < numObjs; ++o, ++ptgt)
462  {
463  // 仅绘制未丢失的对象
464  if (ptgt->state == VPI_TRACKING_STATE_LOST)
465  {
466  continue;
467  }
468 
469  auto &tinfo = *static_cast<TrackInfo *>(ptgt->userData);
470 
471  rectangle(frame,
472  cv::Rect{(int)ptgt->bbox.left, (int)ptgt->bbox.top, (int)ptgt->bbox.width, (int)ptgt->bbox.height},
473  tinfo.color);
474  }
475 
476  CHECK_STATUS(vpiArrayUnlock(targets));
477 }
478 
479 void WriteToDisk(const cv::Mat &img, std::string name, int idx)
480 {
481  char buf[128];
482  snprintf(buf, sizeof(buf) - 1, "%s_%03d.jpg", name.c_str(), idx);
483  buf[sizeof(buf) - 1] = '\0';
484 
485  imwrite(buf, img);
486 }
487 
488 void PreprocessFrame(VPIStream stream, const cv::Mat &in, VPIImage &wrapper, VPIImage out)
489 {
490  // 预处理当前帧
491  if (wrapper == NULL)
492  {
493  CHECK_STATUS(vpiImageCreateWrapperOpenCVMat(in, 0, &wrapper));
494  }
495  else
496  {
497  CHECK_STATUS(vpiImageSetWrappedOpenCVMat(wrapper, in));
498  }
499 
500  CHECK_STATUS(vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, wrapper, out, NULL));
501 }
502 
503 } // namespace
504 
505 int main(int argc, char *argv[])
506 {
507  VPIPayload cropScale = NULL;
508  VPIPayload dcf = NULL;
509  VPIStream stream = NULL;
510  VPIArray inTargets = NULL, outTargets = NULL;
511  VPIImage tgtPatches = NULL;
512  VPIImage frame = NULL;
513  VPIImage wrappedOCVFrame = NULL;
514 
515  int retval = 0;
516  try
517  {
518  // 命令行参数处理
519  // --------------------------------
520  if (argc != 4)
521  {
522  throw std::runtime_error(std::string("Usage: ") + argv[0] + " <pva|cuda> <input_video> <bbox descr>");
523  }
524 
525  VPIBackend backend = ParseBackend(argv[1]);
526  cv::VideoCapture invid = ParseVideo(argv[2]);
527  DetectedTargetInfoMap targetInfoAtFrame = ParseTargetInfoAtFrame(argv[3]);
528 
529  TargetTrackInfoMap trackInfo;
530 
531  // 分配所有需要的 VPI 资源
532  // ---------------------------------
533 
534  const int maxTrackedTargets = targetInfoAtFrame.size();
535 
536  // 创建 CropScale 有效负载
537  CHECK_STATUS(vpiCreateCropScaler(backend,
538  1, // 最大序列数(仅处理一个视频)
539  maxTrackedTargets, &cropScale));
540 
541  // 配置并创建 DCFTracker 有效负载
542  VPIDCFTrackerCreationParams dcfInitParams;
543  CHECK_STATUS(vpiInitDCFTrackerCreationParams(&dcfInitParams));
544 
545  VPIPayload dcf;
546  CHECK_STATUS(vpiCreateDCFTracker(backend,
547  1, // 最大序列数
548  maxTrackedTargets, &dcfInitParams, &dcf));
549 
550  // (可选)用户可以检索内部数组,该数组存储通道权重和
551  // 每个被跟踪目标的最大相关性响应。这些可以与
552  // 相关性图一起使用,以确定跟踪是否丢失。
553  // 尽管在本示例中没有这样做。
554  /*
555  VPIArray channelWeights;
556  int32_t numFeatureChannels
557  CHECK_STATUS(vpiDCFTrackerGetChannelWeights(dcf, &channelWeights, &numFeatureChannels));
558  */
559 
560  // 创建目标数组
561  VPIArray inTargets, outTargets;
562  CHECK_STATUS(vpiArrayCreate(maxTrackedTargets, VPI_ARRAY_TYPE_DCF_TRACKED_BOUNDING_BOX, 0, &inTargets));
563  CHECK_STATUS(vpiArrayCreate(maxTrackedTargets, VPI_ARRAY_TYPE_DCF_TRACKED_BOUNDING_BOX, 0, &outTargets));
564 
565  // 创建图像以存储目标块
566  const int tgtPatchSize = dcfInitParams.featurePatchSize * dcfInitParams.hogCellSize;
567  const VPIImageFormat tgtPatchFormat = backend == VPI_BACKEND_PVA
569  : VPI_IMAGE_FORMAT_RGBA8; // 使用后端支持的块格式
570 
571  CHECK_STATUS(vpiImageCreate(tgtPatchSize, tgtPatchSize * maxTrackedTargets, tgtPatchFormat, 0, &tgtPatches));
572 
573  // 创建用于处理的流
574  CHECK_STATUS(vpiStreamCreate(0, &stream));
575 
576  // 创建图像以存储输入帧
577  CHECK_STATUS(vpiImageCreate(invid.get(cv::CAP_PROP_FRAME_WIDTH), invid.get(cv::CAP_PROP_FRAME_HEIGHT),
578  VPI_IMAGE_FORMAT_RGBA8, 0, &frame));
579 
580  // 目标跟踪
581  // ---------------
582 
583  int curFrame = 0;
584 
585  // 使用在第一帧中找到的目标填充目标数组。
586  VPIArrayData tgtData;
587  CHECK_STATUS(vpiArrayLockData(inTargets, VPI_LOCK_READ_WRITE, VPI_ARRAY_BUFFER_HOST_AOS, &tgtData));
588  try
589  {
590  AddNewTargetsFromFrame(curFrame, targetInfoAtFrame, trackInfo, tgtData);
591  }
592  catch (...)
593  {
594  CHECK_STATUS(vpiArrayUnlock(inTargets));
595  throw;
596  }
597  CHECK_STATUS(vpiArrayUnlock(inTargets));
598 
599  // 对于每个输入帧,
600  cv::Mat cvFrame;
601  while (invid.read(cvFrame))
602  {
603  printf("Frame %d\n", curFrame);
604 
605  // 将 opencv 帧 (cvFrame) 转换为合适的 VPIImage (frame)。
606  PreprocessFrame(stream, cvFrame, wrappedOCVFrame, frame);
607 
608  // 使用来自先前迭代的边界框从当前帧中裁剪目标,
609  // 然后将它们重新缩放到 tgtPatches 中。
610  CHECK_STATUS(vpiSubmitCropScalerBatch(stream, 0, cropScale, &frame, 1, inTargets, tgtPatchSize,
611  tgtPatchSize, tgtPatches));
612 
613  // 如果我们在第一帧中,
614  VPIArray targets;
615  if (curFrame == 0)
616  {
617  // 目标只是找到的那些。
618  targets = inTargets;
619  }
620  else
621  {
622  // 在当前帧中定位和优化当前目标的边界框。
623  CHECK_STATUS(vpiSubmitDCFTrackerLocalizeBatch(stream, 0, dcf, NULL, 0, // 处理所有序列
624  NULL, // 特征掩蔽窗口(不需要)
625  tgtPatches, inTargets, outTargets,
626  NULL, // outCorrelationResponses(不需要)
627  NULL, // outMaxCorrelationResponses(不需要)
628  NULL)); // 算法旋钮(使用默认值)
629  targets = outTargets;
630 
631  // 自定义目标更新
632  // --------------------
633 
634  // 此时可以进行其他额外的处理,
635  // 例如目标生命周期管理和边界框优化。
636  // 它通常使用来自 'outMaxCorrelationResponses'、
637  // 'outCorrelationResponses' 和/或 'channelWeights' 的信息。
638  // 由于此处理通常很耗时,
639  // 因此通常每隔几帧执行一次。
640 
641  // 由于我们正在主机上更新目标数组,因此我们需要同步流。
642  CHECK_STATUS(vpiStreamSync(stream));
643 
644  // 如果对应的目标是新的,或者其边界框被优化,则必须更新目标块。
645  // 框被优化。
646  bool mustUpdateTargetPatches = false;
647 
648  VPIArrayData tgtData;
649  CHECK_STATUS(vpiArrayLockData(targets, VPI_LOCK_READ_WRITE, VPI_ARRAY_BUFFER_HOST_AOS, &tgtData));
650  try
651  {
652  // 这些函数基于当前帧上的对象检测器的
653  // 输出更新目标数组。此
654  // 检测器负责关联检测到的
655  // 对象与相应的现有目标(如果
656  // 可能)。
657  //
658  // 基于此信息,这些函数更新
659  // 对象生命周期(对象是新的还是跟踪
660  // 丢失),并更新其边界框和状态。
661  //
662  // 对于此示例应用程序,检测和
663  // 重新关联在 'targetInfoAtFrame' 中硬编码。对于
664  // 生产级质量,需要用户实现稳健且通用的解决方案。
665  // 需要用户实现稳健且通用的解决方案。
666 
667  // 注意:为了演示目的,目标更新在三个单独的
668  // 函数中实现。
669 
670  // 检测目标跟踪是否丢失,并相应地更新 tgtData。
671  DetectTrackingLost(curFrame, targetInfoAtFrame, tgtData, cv::Size{cvFrame.cols, cvFrame.rows});
672 
673  // 目标边界框优化
674  mustUpdateTargetPatches |= RefineTracksAtFrame(curFrame, targetInfoAtFrame, tgtData);
675 
576  // 检测当前帧中是否找到新目标。
577  mustUpdateTargetPatches |= AddNewTargetsFromFrame(curFrame, targetInfoAtFrame, trackInfo, tgtData);
578  }
579  catch (...)
580  {
581  CHECK_STATUS(vpiArrayUnlock(targets));
582  throw;
583  }
584  CHECK_STATUS(vpiArrayUnlock(targets));
585 
586  if (mustUpdateTargetPatches)
587  {
588  // 裁剪+缩放更新后的目标,并将它们复制到 tgtPatches 中。
589  CHECK_STATUS(vpiSubmitCropScalerBatch(stream, 0, cropScale, &frame, 1, targets, tgtPatchSize,
590  tgtPatchSize, tgtPatches));
591  }
592  }
593 
594  // 根据目标的新边界框更新目标的内部元数据。
595  CHECK_STATUS(vpiSubmitDCFTrackerUpdateBatch(stream, 0, dcf, nullptr, 0, // 处理所有序列
596  NULL, // featureMaskingWindow(不需要)
597  NULL, // modelMaskingWindow(不需要)
598  tgtPatches, targets,
599  NULL)); // 算法旋钮(使用默认值)
600 
601  // 等待帧处理完成
602  CHECK_STATUS(vpiStreamSync(stream));
603 
604  // 将帧写入磁盘
605  DrawTargets(cvFrame, targets);
606  WriteToDisk(cvFrame, "frame", curFrame);
607 
608  // 乒乓操作目标数组:
609  // 本次迭代中更新的目标将作为下一次迭代的输入 (inTargets),
610  // 而当前输入将存储更新后的目标。
611  std::swap(inTargets, targets);
612  ++curFrame;
613  }
614  }
615  catch (std::exception &e)
616  {
617  std::cerr << e.what() << std::endl;
618  retval = 1;
619  }
620 
621  // 销毁所有 VPI 资源
622  // -------------------------
623 
624  vpiStreamDestroy(stream);
625 
626  vpiPayloadDestroy(cropScale);
627  vpiPayloadDestroy(dcf);
628  vpiArrayDestroy(inTargets);
629  vpiArrayDestroy(outTargets);
630  vpiImageDestroy(tgtPatches);
631  vpiImageDestroy(frame);
632  vpiImageDestroy(wrappedOCVFrame);
633 
634  return retval;
635 }
用于处理 VPI 数组的函数和结构。
声明处理图像格式转换的函数。
声明实现 Crop Scaler 算法的函数。
声明实现 DCF Tracker 算法的函数。
#define VPI_IMAGE_FORMAT_RGB8p
具有无符号 8 位通道的平面 RGB。
#define VPI_IMAGE_FORMAT_RGBA8
具有交错 RGBA 8 位通道的单平面。
用于处理 VPI 图像的函数和结构。
用于处理 OpenCV 与 VPI 互操作性的函数。
用于处理 VPI 金字塔的函数和结构。
VPI 状态码处理函数的声明。
声明处理 VPI 流的函数。
@ VPI_TRACKING_STATE_LOST
对象不再被跟踪。
定义: Types.h:454
@ VPI_TRACKING_STATE_SHADOW_TRACKED
对象正以低置信度被跟踪。
定义: Types.h:480
@ VPI_TRACKING_STATE_TRACKED
对象正以高置信度被跟踪。
定义: Types.h:471
@ VPI_TRACKING_STATE_NEW
要跟踪的新对象。
定义: Types.h:461
void * data
指向数组的第一个元素。
定义: Array.h:135
VPIArrayBuffer buffer
存储数组内容。
定义: Array.h:175
int32_t * sizePointer
指向数组中元素的数量。
定义: Array.h:122
VPIArrayBufferAOS aos
以结构体数组布局存储的数组。
定义: Array.h:162
int32_t capacity
数组可以容纳的最大元素数量。
定义: Array.h:126
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_DCF_TRACKED_BOUNDING_BOX
VPIDCFTrackedBoundingBox 元素。
@ VPI_ARRAY_BUFFER_HOST_AOS
主机可访问的结构体数组。
定义: Array.h:146
存储关于数组特性和内容的信息。
定义: Array.h:168
VPIStatus vpiSubmitConvertImageFormat(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, const VPIConvertImageFormatParams *params)
将图像内容转换为所需的格式,可选择进行缩放和偏移。
VPIStatus vpiCreateCropScaler(uint64_t backends, int maxFrames, int maxObjects, VPIPayload *payload)
为 Crop Scale 算法创建 payload 实例。
VPIStatus vpiSubmitCropScalerBatch(VPIStream stream, uint64_t backend, VPIPayload payload, VPIImage *frameList, int32_t numFrames, VPIArray objects, int32_t patchWidth, int32_t patchHeight, VPIImage outPatches)
从输入帧中裁剪矩形区域,并将它们全部缩放到相同的尺寸。
int32_t hogCellSize
来自定向梯度直方图的特征的单元格大小。
int32_t featurePatchSize
对象特征块的大小。
VPIStatus vpiSubmitDCFTrackerLocalizeBatch(VPIStream stream, uint64_t backend, VPIPayload payload, const int32_t *enabledSequences, int32_t numSequences, VPIImage featureMaskingWindow, VPIImage inPatches, VPIArray inObjects, VPIArray outObjects, VPIImage outCorrelationResponses, VPIArray outMaxCorrelationResponses, const VPIDCFTrackerParams *params)
使用判别相关滤波器在输入图像块中定位每个被跟踪的对象...
VPIStatus vpiSubmitDCFTrackerUpdateBatch(VPIStream stream, uint64_t backend, VPIPayload payload, const int32_t *enabledSequences, int32_t numSequences, VPIImage featureMaskingWindow, VPIImage modelMaskingWindow, VPIImage inPatches, VPIArray trackedObjects, const VPIDCFTrackerParams *params)
根据对象的当前状态及其对应的输入图像块,更新内部对象跟踪信息...
VPIStatus vpiCreateDCFTracker(uint64_t backends, int32_t maxNumSequences, int32_t maxNumObjects, const VPIDCFTrackerCreationParams *params, VPIPayload *payload)
为 DCF Tracker 创建 payload。
VPIStatus vpiInitDCFTrackerCreationParams(VPIDCFTrackerCreationParams *params)
使用默认值初始化 VPIDCFTrackerCreationParams。
存储关于 DCF Tracker 跟踪的对象的信息。
定义: Types.h:516
DCF Tracker 的创建参数。
uint64_t VPIImageFormat
预定义的图像格式。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
struct VPIImageImpl * VPIImage
图像的句柄。
定义: Types.h:256
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用指定的标志创建空图像实例。
VPIStatus vpiImageCreateWrapperOpenCVMat(const cv::Mat &mat, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用给定的图像格式将 cv::Mat 封装到 VPIImage 中。
VPIStatus vpiImageSetWrappedOpenCVMat(VPIImage img, const cv::Mat &mat)
重新定义现有 VPIImage 封装器的已封装 cv::Mat。
struct VPIPayloadImpl * VPIPayload
算法 payload 的句柄。
定义: Types.h:268
void vpiPayloadDestroy(VPIPayload payload)
释放 payload 对象和所有相关的资源。
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
float height
边界框高度。
定义: Types.h:440
float width
边界框宽度。
定义: Types.h:439
@ VPI_LOCK_READ_WRITE
锁定内存以进行读取和写入。
定义: Types.h:631
@ VPI_LOCK_READ
仅锁定内存以进行读取。
定义: Types.h:617
存储轴对齐的 32 位浮点 2D 边界框。
定义: Types.h:436