本文结合上文《OpenCV2 计算机视觉编码手册》视频处理一的基础上,添加视频跟踪类,来对视频中运动对象进行跟踪。
1. 添加特征跟踪类
#ifndef FTRACKER #define FTRACKER #include "head.h" #include "videoprocessor.h" #include <opencv2/video/tracking.hpp> #include <opencv2/features2d/features2d.hpp> class FeatureTracker : public FrameProcessor { private: cv::Mat gray; // 当前灰度图像 cv::Mat gray_prev; // 前一个灰度图像 std::vector<cv::Point2f> points[2]; // 两幅图像跟踪特征 0->1 std::vector<cv::Point2f> initial; // 跟踪点的初始化 std::vector<cv::Point2f> features; // 检测到的特征 int max_count; // 需要跟踪的最大特征数目 double qlevel; // 特征检测中的质量等级 double minDist; // 两特征点之间的最小距离 std::vector<uchar> status; // 跟踪的特征状态 std::vector<float> err; // 跟踪错误 public: // 构造函数 FeatureTracker() : max_count(500), qlevel(0.01), minDist(10.) {} // 处理方法 void process(cv:: Mat &frame, cv:: Mat &output) { cv::cvtColor(frame, gray, CV_BGR2GRAY); // 转换为灰度图像 frame.copyTo(output); // 1. 如果需要添加新的特征点 if(addNewPoints()) { detectFeaturePoints(); // 检测特征点 points[0].insert(points[0].end(),features.begin(),features.end());// 添加检测的特征到当前跟踪的特征 initial.insert(initial.end(),features.begin(),features.end()); } // 对应视频序列中的第一幅图像 if(gray_prev.empty()) gray.copyTo(gray_prev); // 2.跟踪特征 cv::calcOpticalFlowPyrLK(gray_prev, gray, // 两幅连续图像 points[0], // 图1中的输入点坐标 points[1], // 图2中的输出点坐标 status, // 跟踪成功 err); // 跟踪失败 // 2. 遍历所有跟踪点进行筛选 int k=0; for( int i= 0; i < points[1].size(); i++ ) { // 是否需要保留该跟踪点? if (acceptTrackedPoint(i)) { // 保留该跟踪点到vector initial[k]= initial[i]; points[1][k++] = points[1][i]; } } // 去除不成功点 points[1].resize(k); initial.resize(k); // 3. 处理接受的跟踪点 handleTrackedPoints(frame, output); // 4. 当前的点和图像变为它之前的点和图像 std::swap(points[1], points[0]); cv::swap(gray_prev, gray); } // 特征点检测 void detectFeaturePoints() { // 检测特征 cv::goodFeaturesToTrack(gray, // 图像 features, // 检测到的特征 max_count, // 特征的最大数目 qlevel, // 质量等级 minDist); // 两个特征之间的最小距离 } // 决定是否添加新点 bool addNewPoints() { // 如果点的数量太少 return points[0].size()<=10; } // 决定哪些点应该跟踪 bool acceptTrackedPoint(int i) { return status[i] && // 如果它移动了 (abs(points[0][i].x-points[1][i].x)+ (abs(points[0][i].y-points[1][i].y))>2); } // 处理当前跟踪点 void handleTrackedPoints(cv:: Mat &frame, cv:: Mat &output) { // 遍历所有跟踪点 for(int i= 0; i < points[1].size(); i++ ) { // 绘制直线和圆 cv::line(output, initial[i], // 初始位置 points[1][i], // 新位置 cv::Scalar(255,255,255)// 白色 ); cv::circle(output, // 输出图像 points[1][i], // 圆心 3, // 半径 cv::Scalar(255,255,255),// 白色 -1 // 负数表示填充圆圈, 整数表示线条厚度 ); } } }; #endif
#include "featuretracker.h" int main() { VideoProcessor processor; // 创建一个视频处理实例 FeatureTracker tracker; // 创建一个特征跟踪实例 processor.setInput("../bike.avi"); // 打开视频文件 processor.setFrameProcessor(&tracker); // 设置帧处理器为一个特征跟踪实例tracker processor.displayOutput("Tracked Features"); // 声明跟踪特征显示窗口 processor.setDelay(1000./processor.getFrameRate()); // 设置视频播放帧率为原始帧率 processor.run(); // 开始处理 cv::waitKey(); // 等待按键响应 return 0; }