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>
57 #define CHECK_STATUS(STMT) \
60 VPIStatus status = (STMT); \
61 if (status != VPI_SUCCESS) \
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()); \
82 using TargetTrackInfoMap = std::map<int, TrackInfo>;
85 struct DetectedTargetInfo
91 bool lostTrack()
const
98 using DetectedTargetInfoMap = std::multimap<int, DetectedTargetInfo>;
100 VPIBackend ParseBackend(
const std::string &str)
106 else if (str ==
"pva")
112 throw std::runtime_error(
"Backend '" + str +
"' not recognized, it must be either cuda or pva.");
117 cv::VideoCapture ParseVideo(
const std::string &fname)
119 cv::VideoCapture video;
120 if (!video.open(fname))
122 throw std::runtime_error(
"Can't open '" + fname +
"'");
128 DetectedTargetInfoMap ParseTargetInfoAtFrame(
const std::string &fname)
130 std::ifstream in(fname);
133 throw std::runtime_error(
"Can't open '" + fname +
"'");
136 DetectedTargetInfoMap out;
140 DetectedTargetInfo tinfo;
141 while (in >> tinfo.idTarget >> frame >> tinfo.bbox.left >> tinfo.bbox.top >> tinfo.bbox.width >> tinfo.bbox.height)
143 out.emplace(frame, tinfo);
150 cv::Scalar GetRandomColor(cv::RNG &rng)
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);
158 bool AddNewTargetsFromFrame(
int idxFrame, DetectedTargetInfoMap &tgtInfos, TargetTrackInfoMap &trackInfo,
166 const auto *tgtBegin = pTarget;
168 static cv::RNG rng(1);
171 auto tgtInfoRange = tgtInfos.equal_range(idxFrame);
172 for (
auto it = tgtInfoRange.first; it != tgtInfoRange.second; ++it)
175 if (it->second.lostTrack())
182 auto itTrackInfo = trackInfo.find(it->second.idTarget);
183 if (itTrackInfo != trackInfo.end() && itTrackInfo->second.enabled)
201 pTarget->bbox = it->second.bbox;
203 pTarget->seqIndex = 0;
205 pTarget->filterLR = 0.075;
206 pTarget->filterChannelWeightsLR = 0.1;
209 if (itTrackInfo == trackInfo.end())
213 tinfo.idTarget = it->second.idTarget;
214 tinfo.color = GetRandomColor(rng);
215 tinfo.enabled =
true;
216 itTrackInfo = trackInfo.emplace(tinfo.idTarget, tinfo).first;
221 itTrackInfo->second.enabled =
true;
224 pTarget->userData = &itTrackInfo->second;
238 bool DetectTrackingLost(
int idxFrame, DetectedTargetInfoMap &tgtInfos,
VPIArrayData &targets, cv::Size frameSize)
240 auto tgtInfoRange = tgtInfos.equal_range(idxFrame);
245 bool atLeastOneLost =
false;
250 pTarget >= pBeginTarget; --pTarget)
252 bool trackingLost =
false;
256 pTarget->bbox.left + pTarget->bbox.width > frameSize.width ||
257 pTarget->bbox.top + pTarget->bbox.height > frameSize.height))
265 for (
auto itInfo = tgtInfoRange.first; itInfo != tgtInfoRange.second; ++itInfo)
269 static_cast<const TrackInfo *
>(pTarget->userData)->idTarget == itInfo->second.idTarget &&
270 itInfo->second.lostTrack())
281 atLeastOneLost =
true;
285 static_cast<TrackInfo *
>(pTarget->userData)->enabled =
false;
298 return atLeastOneLost;
302 bool RefineTracksAtFrame(
int idxFrame, DetectedTargetInfoMap &tgtInfos,
VPIArrayData &targets)
304 auto tgtInfoRange = tgtInfos.equal_range(idxFrame);
306 bool atLeastOneUpdated =
false;
321 for (
auto itInfo = tgtInfoRange.first; itInfo != tgtInfoRange.second; ++itInfo)
324 if (itInfo->second.lostTrack())
331 static_cast<const TrackInfo *
>(pTarget->userData)->idTarget == itInfo->second.idTarget)
333 pTarget->bbox = itInfo->second.bbox;
341 atLeastOneUpdated =
true;
450 return atLeastOneUpdated;
453 void DrawTargets(cv::Mat &frame,
VPIArray targets)
461 for (
int o = 0; o < numObjs; ++o, ++ptgt)
469 auto &tinfo = *
static_cast<TrackInfo *
>(ptgt->userData);
472 cv::Rect{(int)ptgt->bbox.left, (
int)ptgt->bbox.top, (int)ptgt->bbox.width, (
int)ptgt->bbox.height},
479 void WriteToDisk(
const cv::Mat &img, std::string name,
int idx)
482 snprintf(buf,
sizeof(buf) - 1,
"%s_%03d.jpg", name.c_str(), idx);
483 buf[
sizeof(buf) - 1] =
'\0';
505 int main(
int argc,
char *argv[])
510 VPIArray inTargets = NULL, outTargets = NULL;
522 throw std::runtime_error(std::string(
"Usage: ") + argv[0] +
" <pva|cuda> <input_video> <bbox descr>");
526 cv::VideoCapture invid = ParseVideo(argv[2]);
527 DetectedTargetInfoMap targetInfoAtFrame = ParseTargetInfoAtFrame(argv[3]);
529 TargetTrackInfoMap trackInfo;
534 const int maxTrackedTargets = targetInfoAtFrame.size();
539 maxTrackedTargets, &cropScale));
548 maxTrackedTargets, &dcfInitParams, &dcf));
571 CHECK_STATUS(
vpiImageCreate(tgtPatchSize, tgtPatchSize * maxTrackedTargets, tgtPatchFormat, 0, &tgtPatches));
577 CHECK_STATUS(
vpiImageCreate(invid.get(cv::CAP_PROP_FRAME_WIDTH), invid.get(cv::CAP_PROP_FRAME_HEIGHT),
590 AddNewTargetsFromFrame(curFrame, targetInfoAtFrame, trackInfo, tgtData);
601 while (invid.read(cvFrame))
603 printf(
"Frame %d\n", curFrame);
606 PreprocessFrame(stream, cvFrame, wrappedOCVFrame, frame);
611 tgtPatchSize, tgtPatches));
625 tgtPatches, inTargets, outTargets,
629 targets = outTargets;
646 bool mustUpdateTargetPatches =
false;
671 DetectTrackingLost(curFrame, targetInfoAtFrame, tgtData, cv::Size{cvFrame.cols, cvFrame.rows});
674 mustUpdateTargetPatches |= RefineTracksAtFrame(curFrame, targetInfoAtFrame, tgtData);
577 mustUpdateTargetPatches |= AddNewTargetsFromFrame(curFrame, targetInfoAtFrame, trackInfo, tgtData);
586 if (mustUpdateTargetPatches)
590 tgtPatchSize, tgtPatches));
605 DrawTargets(cvFrame, targets);
606 WriteToDisk(cvFrame,
"frame", curFrame);
611 std::swap(inTargets, targets);
615 catch (std::exception &e)
617 std::cerr << e.what() << std::endl;
用于处理 OpenCV 与 VPI 互操作性的函数。
@ VPI_TRACKING_STATE_LOST
对象不再被跟踪。
@ VPI_TRACKING_STATE_SHADOW_TRACKED
对象正以低置信度被跟踪。
@ VPI_TRACKING_STATE_TRACKED
对象正以高置信度被跟踪。
@ VPI_TRACKING_STATE_NEW
要跟踪的新对象。
VPIArrayBuffer buffer
存储数组内容。
int32_t * sizePointer
指向数组中元素的数量。
VPIArrayBufferAOS aos
以结构体数组布局存储的数组。
int32_t capacity
数组可以容纳的最大元素数量。
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
数组的句柄。
@ VPI_ARRAY_TYPE_DCF_TRACKED_BOUNDING_BOX
VPIDCFTrackedBoundingBox 元素。
@ VPI_ARRAY_BUFFER_HOST_AOS
主机可访问的结构体数组。
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 跟踪的对象的信息。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
struct VPIImageImpl * VPIImage
图像的句柄。
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 的句柄。
void vpiPayloadDestroy(VPIPayload payload)
释放 payload 对象和所有相关的资源。
struct VPIStreamImpl * VPIStream
流的句柄。
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中所有提交的命令都完成(队列为空)...
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
@ VPI_BACKEND_CUDA
CUDA 后端。
@ VPI_LOCK_READ_WRITE
锁定内存以进行读取和写入。
@ VPI_LOCK_READ
仅锁定内存以进行读取。