用了OpenCV的AKAZE和ORB算法来追踪给定视频中的目标对象
这段代码是一个简单的视觉追踪系统,使用了OpenCV的AKAZE和ORB算法来追踪给定视频中的目标对象。主要包含一下几个部分:
Tracker
类:这是核心的追踪类,包括下面重要的方法;
setFirstFrame
: 这个方法设置了第一帧图像及目标的边界包围框。它先根据给定的边界框,得到掩膜图像,然后提取特征点和特征描述符。process
: 这个方法处理每一帧图像,提取其特征点及描述符,并与第一帧进行匹配、模型拟合,得到当前帧的目标边界包围框。
main
函数:主函数首先进行初始化工作,比如解析命令行参数,创建检测器(AKAZE和ORB)和匹配器,初始化两个Tracker。然后进入一个循环中,处理每一帧图像,每10帧更新一次统计信息,最后打印整体的统计信息。
#include <opencv2/features2d.hpp> // 导入OpenCV特征检测库
#include <opencv2/videoio.hpp> // 导入OpenCV视频输入输出库
#include <opencv2/imgproc.hpp> // 导入OpenCV图像处理库
#include <opencv2/calib3d.hpp> // 导入OpenCV相机标定和三维重建库
#include <opencv2/highgui.hpp> // 导入OpenCV显示图像的库
#include <vector> // 导入标准模版库中的向量库
#include <iostream> // 导入输入输出流库
#include <iomanip> // 导入输入输出流操作库
#include "stats.h" // 导入统计结构体的定义
#include "utils.h" // 导入绘图和打印功能的工具库
using namespace std; // 使用标准命名空间
using namespace cv; // 使用OpenCV命名空间
// 定义一些常量参数
const double akaze_thresh = 3e-4; // AKAZE检测阈值, 用于定位大约1000个关键点 控制AKAZE算法的特征点检测敏感度。
const double ransac_thresh = 2.5f; // RANSAC内点阈值
const double nn_match_ratio = 0.8f; // 最近邻匹配比率
const int bb_min_inliers = 100; // 绘制边界框的最少内点数
const int stats_update_period = 10; // 每10帧更新一次屏幕上的统计信息
// 定义example命名空间下的Tracker类
namespace example {
class Tracker
{
public:
Tracker(Ptr<Feature2D> _detector, Ptr<DescriptorMatcher> _matcher) :
detector(_detector),
matcher(_matcher)
{}
// 设置视频的第一帧以及目标边界框
void setFirstFrame(const Mat frame, vector<Point2f> bb, string title, Stats& stats);
// 处理视频的每一帧
Mat process(const Mat frame, Stats& stats);
// 获取特征检测器
Ptr<Feature2D> getDetector() {
return detector;
}
protected:
Ptr<Feature2D> detector; // 特征检测器指针
Ptr<DescriptorMatcher> matcher; // 描述子匹配器指针
Mat first_frame, first_desc; // 第一帧和它的描述子
vector<KeyPoint> first_kp; // 第一帧中的关键点
vector<Point2f> object_bb; // 目标的边界框
};
// setFirstFrame 函数实现
void Tracker::setFirstFrame(const Mat frame, vector<Point2f> bb, string title, Stats& stats)
{
// 根据边界框创建掩码
// 使用new关键字动态创建一个Point类型的数组,大小为bb容器的大小
cv::Point *ptMask = new cv::Point[bb.size()];
// 创建指向Point数组的指针数组,准备传递给绘图函数
const Point* ptContain = { &ptMask[0] };
// 计算bb容器大小,并转换为int类型
int iSize = static_cast<int>(bb.size());
// 遍历bb容器中的所有Point2f点
for (size_t i=0; i<bb.size(); i++) {
// 将每个Point2f点转换为Point,并赋值给前面创建的Point数组
ptMask[i].x = static_cast<int>(bb[i].x);
ptMask[i].y = static_cast<int>(bb[i].y);
}
first_frame = frame.clone(); // 克隆帧到first_frame
cv::Mat matMask = cv::Mat::zeros(frame.size(), CV_8UC1); // 创建和第一帧同样大小的掩码Mat
cv::fillPoly(matMask, &ptContain, &iSize, 1, cv::Scalar::all(255)); // 将所选区域填充为255
// 用掩码检测特征点并计算描述子
detector->detectAndCompute(first_frame, matMask, first_kp, first_desc);
stats.keypoints = (int)first_kp.si