计算机视觉中的特征跟踪与目标跟踪技术解析
1. 特征点跟踪原理
在视频序列中,为了逐帧跟踪特征点,我们需要确定特征点在后续帧中的新位置。假设特征点的强度在相邻帧之间保持不变,我们可以寻找一个位移
(u, v)
。这一恒定强度假设通常适用于在相邻时刻拍摄的图像中的小位移情况。
利用泰勒展开,我们可以将其近似为一个涉及图像导数的方程,进而得到基本的光流约束方程,也就是亮度恒定方程。
Lukas - Kanade 特征跟踪算法利用了这一约束。该算法还假设特征点邻域内所有点的位移相同,这样我们就可以对这些点施加光流约束,得到比未知数(两个)更多的方程,从而以均方意义求解该方程组。在实际应用中,通常采用迭代方式求解,并且可以在不同分辨率下进行估计,以提高搜索效率和对大位移的容忍度。默认情况下,图像级别数为 3,窗口大小为 15,这些参数都可以进行修改。
2. 光流估计
2.1 光流的概念
当相机观察场景时,观察到的亮度模式会投影到图像传感器上形成图像。在视频序列中,我们通常关注捕捉运动模式,即不同场景元素的 3D 运动在图像平面上的投影,这被称为运动场。然而,我们无法直接从相机传感器测量场景点的 3D 运动,只能观察到亮度模式在帧与帧之间的运动,这种亮度模式的表观运动就是光流。运动场和光流并不总是相等,例如观察均匀物体(如相机在白色墙壁前移动)时,不会产生光流;旋转的理发店标志杆也是一个经典例子,其运动场显示水平方向的运动向量,但观察者会感知到红蓝色条纹向上移动,这就是光流所显示的内容。尽管存在这些差异,光流仍被认为是运动场的有效近似。
2.2 准备工作
估计光流意味着量化图像序列中亮度模式的表观运动。考虑视频在某一时刻的一帧,对于当前帧上的一个特定像素
(x, y)
,我们想知道它在后续帧中的移动位置,即其坐标随时间变化为
(x(t), y(t))
,我们的目标是估计该点的速度
(dx/dt, dy/dt)
。该点在时间
t
的亮度可以通过查看序列中相应的帧得到,即
I(x(t), y(t), t)
。
基于图像亮度恒定假设,该点的亮度不随时间变化,根据链式法则可以得到亮度恒定方程,该方程将光流分量(
x
和
y
关于时间的导数)与图像导数联系起来。但这个单一方程(包含两个未知数)不足以计算像素位置的光流,因此需要添加额外的约束,常见的选择是假设光流的平滑性,即相邻光流向量应该相似,任何偏离这一假设的情况都应受到惩罚,一种特定的约束公式基于光流的拉普拉斯算子。我们的目标是找到一个光流场,使亮度恒定方程的偏差和光流向量的拉普拉斯算子都最小化。
2.3 实现步骤
OpenCV 实现了几种解决密集光流估计问题的方法,我们可以使用
cv::DualTVL1OpticalFlow
类,它是通用
cv::Algorithm
基类的子类。具体步骤如下:
//Create the optical flow algorithm
cv::Ptr<cv::DualTVL1OpticalFlow> tvl1 = cv::createOptFlow_DualTVL1();
cv::Mat oflow; // image of 2D flow vectors
//compute optical flow between frame1 and frame2
tvl1->calc(frame1, frame2, oflow);
为了显示结果,我们创建了一个函数来生成光流场的图像映射:
// Drawing optical flow vectors on an image
void drawOpticalFlow(const cv::Mat& oflow, // the optical flow
cv::Mat& flowImage, // the produced image
int stride, // the stride for displaying the vectors
float scale, // multiplying factor for the vectors
const cv::Scalar& color) // the color of the vectors
{
// create the image if required
if (flowImage.size() != oflow.size()) {
flowImage.create(oflow.size(), CV_8UC3);
flowImage = cv::Vec3i(255,255,255);
}
//for all vectors using stride as a step
for (int y = 0; y < oflow.rows; y += stride)
for (int x = 0; x < oflow.cols; x += stride) {
//gets the vector
cv::Point2f vector = oflow.at< cv::Point2f>(y, x);
// draw the line
cv::line(flowImage, cv::Point(x,y),
cv::Point(static_cast<int>(x + scale*vector.x + 0.5),
static_cast<int>(y + scale*vector.y + 0.5)),
color);
// draw the arrow tip
cv::circle(flowImage,
cv::Point(static_cast<int>(x + scale*vector.x + 0.5),
static_cast<int>(y + scale*vector.y + 0.5)),
1, color, -1);
}
}
调用该函数可以可视化估计的光流场:
// Draw the optical flow image
cv::Mat flowImage;
drawOpticalFlow(oflow, // input flow vectors
flowImage, // image to be generated
8, // display vectors every 8 pixels
2, // multiply size of vectors by 2
cv::Scalar(0, 0, 0)); // vector color
2.4 工作原理
我们使用的 Dual TV - L1 方法有两个主要特点。一是使用平滑约束,旨在最小化光流梯度的绝对值(而非其平方),这减少了平滑项的影响,特别是在不连续区域,如移动物体的光流向量与其背景的光流向量差异较大的地方。二是使用一阶泰勒近似,将亮度恒定约束的公式线性化,便于光流场的迭代估计。但由于线性近似仅适用于小位移,该方法需要采用从粗到细的估计方案。
以下是整个光流估计的流程图:
graph TD;
A[开始] --> B[创建光流算法实例];
B --> C[计算两帧之间的光流];
C --> D[生成光流图像映射];
D --> E[显示光流图像];
E --> F[结束];
3. 视频中的目标跟踪
3.1 目标跟踪问题
在许多应用中,我们需要在视频中跟踪特定的移动物体。目标跟踪面临诸多挑战,因为随着物体在场景中的演变,其图像外观会因视角、光照变化、非刚性运动、遮挡等因素发生许多变化。
3.2 实现步骤
OpenCV 的
cv::Tracker
类定义了目标跟踪框架,有两个主要方法:
init
方法用于定义初始目标边界框,
update
方法根据新帧输出新的边界框。
为了测试目标跟踪算法,我们使用视频处理框架,定义一个帧处理子类
VisualTracker
:
class VisualTracker : public FrameProcessor {
cv::Ptr<cv::Tracker> tracker;
cv::Rect2d box;
bool reset;
public:
// constructor specifying the tracker to be used
VisualTracker(cv::Ptr<cv::Tracker> tracker) :
reset(true), tracker(tracker) {}
// set the bounding box to initiate tracking
void setBoundingBox(const cv::Rect2d& bb) {
box = bb;
reset = true;
}
// callback processing method
void process(cv:: Mat &frame, cv:: Mat &output) {
if (reset) { // new tracking session
reset = false;
tracker->init(frame, box);
} else {
// update the target's position
tracker->update(frame, box);
}
// draw bounding box on current frame
frame.copyTo(output);
cv::rectangle(output, box, cv::Scalar(255, 255, 255), 2);
}
};
以下是使用 Median Flow 跟踪器的示例代码:
int main(){
// Create video procesor instance
VideoProcessor processor;
// generate the filename
std::vector<std::string> imgs;
std::string prefix = "goose/goose";
std::string ext = ".bmp";
// Add the image names to be used for tracking
for (long i = 130; i < 317; i++) {
std::string name(prefix);
std::ostringstream ss; ss << std::setfill('0') <<
std::setw(3) << i; name += ss.str();
name += ext;
imgs.push_back(name);
}
// Create feature tracker instance
VisualTracker tracker(cv::TrackerMedianFlow::createTracker());
// Open video file
processor.setInput(imgs);
// set frame processor
processor.setFrameProcessor(&tracker);
// Declare a window to display the video
processor.displayOutput("Tracked object");
// Define the frame rate for display
processor.setDelay(50);
// Specify the original target position
tracker.setBoundingBox(cv::Rect(290,100,65,40));
// Start the tracking
processor.run();
}
3.3 工作原理
以 Median Flow 跟踪器为例,它基于特征点跟踪。首先在要跟踪的物体上定义一个点网格(默认使用 10x10 的网格),这样做有诸多优点,如节省计算兴趣点的时间、保证有足够的点用于跟踪、确保点在整个物体上均匀分布。
然后使用 Lukas - Kanade 特征跟踪算法跟踪网格中的每个点,接着估计跟踪这些点时产生的误差,例如计算点在初始位置和跟踪位置周围窗口内的绝对像素差之和,或者使用前后向误差(将点跟踪到下一帧后,再反向跟踪回初始帧,比较得到的位置与初始位置的差异)。
计算每个点的跟踪误差后,只考虑误差最小的 50% 的点,这些点用于计算下一帧中边界框的新位置,每个点对位移值进行投票,取这些可能位移的中位数。对于尺度变化,将点成对考虑,估计初始帧和下一帧中两点之间距离的比率,同样取这些尺度的中位数。
除了基于特征点跟踪的方法,还有基于模板匹配的方法,如 Kernelized Correlation Filter (KCF) 算法,它使用目标的边界框作为模板在后续视图中搜索新的目标位置,利用傅里叶变换加速匹配窗口的识别,是一种快速且鲁棒的跟踪器。
以下是目标跟踪的流程图:
graph TD;
A[开始] --> B[创建视频处理器和跟踪器实例];
B --> C[设置输入图像和帧处理器];
C --> D[设置初始目标边界框];
D --> E[开始跟踪];
E --> F{是否为新跟踪会话};
F -- 是 --> G[初始化跟踪器];
F -- 否 --> H[更新目标位置];
G --> I[绘制边界框];
H --> I;
I --> J{是否还有帧};
J -- 是 --> E;
J -- 否 --> K[结束];
综上所述,特征点跟踪、光流估计和目标跟踪在计算机视觉中都有着重要的应用,通过合理选择算法和参数,可以实现更准确、高效的跟踪效果。
计算机视觉中的特征跟踪与目标跟踪技术解析
4. 不同跟踪算法的对比
为了更清晰地了解不同跟踪算法的特点,我们对前面提到的 Median Flow 跟踪器和 Kernelized Correlation Filter (KCF) 跟踪器进行对比,具体内容如下表所示:
| 算法名称 | 算法原理 | 优点 | 缺点 | 适用场景 |
| — | — | — | — | — |
| Median Flow 跟踪器 | 基于特征点跟踪,在目标物体上定义点网格,利用 Lukas - Kanade 算法跟踪点,计算跟踪误差,选取误差小的点计算新位置和尺度变化 | 简单有效,能保证有足够点用于跟踪且分布均匀,节省计算兴趣点时间 | 对目标快速运动和严重遮挡情况处理效果不佳 | 目标运动速度适中、遮挡较少且有一定纹理的场景 |
| Kernelized Correlation Filter (KCF) 跟踪器 | 使用目标的边界框作为模板,利用傅里叶变换在后续视图中搜索新目标位置 | 速度快、鲁棒性强 | 对目标外观变化适应能力有限 | 目标外观相对稳定、需要快速跟踪的场景 |
5. 跟踪算法的参数调整与优化
5.1 光流估计算法参数调整
在使用 Dual TV - L1 光流估计方法时,有许多参数可以调整以影响解决方案的质量和计算速度。以下是一些重要参数及其调整方式:
-
金字塔估计的尺度数量
:增加尺度数量可以提高对大位移的跟踪能力,但会增加计算量;减少尺度数量则相反,适用于位移较小的场景。可以使用
tvl1->setScalesNumber(int scalesNumber)
方法进行设置。
-
迭代估计步骤的停止准则
:可以设置更严格或宽松的停止准则来控制迭代次数。例如,通过
tvl1->setEpsilon(double epsilon)
方法设置收敛阈值,值越小,迭代越精确,但计算时间可能越长。
-
亮度恒定约束与平滑约束的权重
:调整该权重可以改变光流场的平滑程度。如
tvl1->setLambda(double lambda)
方法,减小
lambda
值会降低亮度恒定约束的重要性,得到更平滑的光流场。
以下是调整权重得到更平滑光流场的示例代码:
// compute a smoother optical flow between 2 frames
tvl1->setLambda(0.075);
tvl1->calc(frame1, frame2, oflow);
5.2 目标跟踪算法参数调整
对于目标跟踪算法,不同的跟踪器有不同的可调整参数。以 Median Flow 跟踪器为例,虽然它没有太多公开的可调整参数,但可以通过改变初始点网格的密度来影响跟踪效果。而 KCF 跟踪器可以调整一些与模板匹配相关的参数,如正则化参数等,不过这些参数的调整需要根据具体场景进行试验。
6. 跟踪算法的应用场景拓展
跟踪算法在许多领域都有广泛的应用,以下是一些常见的应用场景:
-
视频监控
:在安防监控系统中,通过跟踪特定目标(如人员、车辆等),可以及时发现异常行为,如非法入侵、违规停车等。
-
自动驾驶
:自动驾驶车辆需要实时跟踪周围的车辆、行人、交通标志等物体,以做出安全的驾驶决策。
-
人机交互
:在虚拟现实、增强现实等领域,跟踪用户的手部动作、头部位置等,实现更自然的人机交互。
-
体育分析
:在体育赛事中,跟踪运动员的运动轨迹、动作姿态等,为教练和运动员提供数据支持,进行战术分析和训练改进。
7. 总结与展望
计算机视觉中的特征跟踪与目标跟踪技术是一个充满挑战和机遇的领域。通过对特征点跟踪、光流估计和目标跟踪算法的研究和应用,我们可以解决许多实际问题。不同的跟踪算法有各自的优缺点和适用场景,在实际应用中需要根据具体需求选择合适的算法,并进行合理的参数调整和优化。
未来,随着计算机硬件性能的不断提升和算法的不断创新,跟踪技术将在更多领域得到应用,并且跟踪的精度和速度将进一步提高。例如,结合深度学习技术,跟踪算法可以更好地处理复杂场景下的目标外观变化、遮挡等问题。同时,多模态数据(如视觉、雷达、激光雷达等)的融合也将为跟踪技术带来新的发展机遇。
以下是整个跟踪技术应用的流程图:
graph TD;
A[开始] --> B{选择应用场景};
B -- 视频监控 --> C[选择合适跟踪算法];
B -- 自动驾驶 --> C;
B -- 人机交互 --> C;
B -- 体育分析 --> C;
C --> D[调整算法参数];
D --> E[进行跟踪任务];
E --> F{是否满足需求};
F -- 是 --> G[应用结果];
F -- 否 --> D;
G --> H[结束];
总之,特征跟踪与目标跟踪技术在计算机视觉领域有着重要的地位,并且具有广阔的发展前景。我们需要不断探索和研究,以推动这一技术的不断进步。
超级会员免费看
11万+

被折叠的 条评论
为什么被折叠?



