干货 | OpenCV中KLT光流跟踪原理详解与代码演示

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

本文转自:opencv学堂

稀疏光流跟踪(KLT)详解

在视频移动对象跟踪中,稀疏光流跟踪是一种经典的对象跟踪算法,可以绘制运动对象的跟踪轨迹与运行方向,是一种简单、实时高效的跟踪算法,这个算法最早是有Bruce D. Lucas and Takeo Kanade两位作者提出来的,所以又被称为KLT。KLT算法工作有三个假设前提条件:

  • 亮度恒定

  • 短距离移动

  • 空间一致性

亮度恒定

对象中任意像素点p(x,y)亮度值,在t-1时候的值,在t时刻移动(u, v)之后亮度值保持不变

空间一致性

假设对像素点p(x, y)来说,周围的像素点都保持相同的移动距离(u, v) 假设窗口大小为5x5,则对于25个窗口内的像素点来说,就会如下等式成立:

得到下面的过约束等式,根据最小二乘可以求解(u, v):

这样我们就得到了KLT光流等式与该窗口的的Hessian矩阵

空间尺度不变性

通过建立每一帧的图像金字塔,实现尺度空间窗口目标对象搜索

OpenCV中KLT演示代码实现

OpenCV中KLT算法API及其参数解释如下:

void cv::calcOpticalFlowPyrLK(
InputArray     prevImg, // 前一帧图像
InputArray     nextImg, // 后一帧图像
InputArray     prevPts, // 前一帧的稀疏光流点
InputOutputArray     nextPts, // 后一帧光流点
OutputArray     status, // 输出状态,1 表示正常该点保留,否则丢弃
OutputArray     err, // 表示错误
Size winSize = Size(21, 21), // 光流法对象窗口大小
int maxLevel = 3, // 金字塔层数,0表示只检测当前图像,不构建金字塔图像
TermCriteria     criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), // 窗口搜索时候停止条件
int flags = 0, // 操作标志
double     minEigThreshold = 1e-4 // 最小特征值响应,低于最小值不做处理
)

特征点检测与绘制的代码实现如下:

// detect first frame and find corners in it
Mat old_frame, old_gray;
capture.read(old_frame);
cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);
goodFeaturesToTrack(old_gray, featurePoints, maxCorners, qualityLevel, minDistance, Mat(), blockSize, useHarrisDetector, k);

特征点绘制

void draw_goodFeatures(Mat &image, vector<Point2f> goodFeatures) {
    for (size_t t = 0; t < goodFeatures.size(); t++) {
        circle(image, goodFeatures[t], 2, Scalar(0, 255, 0), 2, 8, 0);
    }
}

KLT跟踪代码如下

TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 0.01);
double derivlambda = 0.5;
int flags = 0;

bool ret = capture.read(frame);
if (!ret) break;
imshow("frame", frame);
roi.x = 0;
frame.copyTo(result(roi));
cvtColor(frame, gray, COLOR_BGR2GRAY);

// calculate optical flow
calcOpticalFlowPyrLK(old_gray, gray, pts[0], pts[1], status, err, Size(31, 31), 3, criteria, derivlambda, flags);

特征点状态检查与匹配的代码如下

size_t i, k;
for (i = k = 0; i < pts[1].size(); i++)
{
    // 距离与状态测量
    double dist = abs(pts[0][i].x - pts[1][i].x) + abs(pts[0][i].y - pts[1][i].y);
    if (status[i] && dist > 2) {
        pts[0][k] = pts[0][i];
        initPoints[k] = initPoints[i];
        pts[1][k++] = pts[1][i];
        circle(frame, pts[1][i], 3, Scalar(0, 255, 0), -1, 8);
    }
}
// resize 有用特征点
pts[1].resize(k);
pts[0].resize(k);
initPoints.resize(k);

绘制跟踪轨迹的代码如下

// 绘制跟踪轨迹
draw_lines(frame, initPoints, pts[1]);

该方法实现如下:

void draw_lines(Mat &image, vector<Point2f> pt1, vector<Point2f> pt2) {
    if (color_lut.size() < pt1.size()) {
        for (size_t t = 0; t < pt1.size(); t++) {
            color_lut.push_back(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
        }
    }
    for (size_t t = 0; t < pt1.size(); t++) {
        line(image, pt1[t], pt2[t], color_lut[t], 2, 8, 0);
    }
}

运行效果

左侧是视频的原始每一帧、右侧视频是每一帧中KLT算法实时轨迹绘制

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲

在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用OpenCV的稀疏光流算法,可以跟踪人脸的运动。以下是一个简单的示例代码: ``` import cv2 import numpy as np # 读取视频 cap = cv2.VideoCapture('face_video.mp4') # 读取第一帧并检测人脸 ret, frame = cap.read() face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') faces = face_cascade.detectMultiScale(frame, scaleFactor=1.1, minNeighbors=5) # 取第一个人脸的位置作为初始跟踪点 x, y, w, h = faces[0] prev_pts = np.array([[x + w/2, y + h/2]], dtype=np.float32) # 创建Lucas-Kanade稀疏光流对象 lk_params = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) color = (0, 255, 0) # 逐帧进行跟踪 while True: # 读取下一帧 ret, frame = cap.read() if not ret: break # 检测人脸 faces = face_cascade.detectMultiScale(frame, scaleFactor=1.1, minNeighbors=5) # 计算光流 curr_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, None, **lk_params) # 选出跟踪成功的点 good_new = curr_pts[status == 1] good_old = prev_pts[status == 1] # 绘制跟踪结果 for i, (new, old) in enumerate(zip(good_new, good_old)): a, b = new.ravel() c, d = old.ravel() frame = cv2.line(frame, (a, b), (c, d), color, 2) frame = cv2.circle(frame, (a, b), 3, color, -1) # 更新跟踪点和图像 prev_gray = curr_gray.copy() prev_pts = good_new.reshape(-1, 1, 2) # 显示图像 cv2.imshow('frame', frame) if cv2.waitKey(1) == ord('q'): break # 释放资源 cap.release() cv2.destroyAllWindows() ``` 其,使用了Haar级联分类器来检测人脸,使用calcOpticalFlowPyrLK计算稀疏光流,使用line和circle函数绘制跟踪结果。运行后,程序会打开视频窗口并进行人脸跟踪,直到用户按下q键退出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值