> 文章列表 > 基于光流方法实时跟踪目标在图像中的运动轨迹(python和C++实现)

基于光流方法实时跟踪目标在图像中的运动轨迹(python和C++实现)

基于光流方法实时跟踪目标在图像中的运动轨迹(python和C++实现)

光流方法是通过跟踪图像中的特征点(角点,边缘点等),分析这些点在帧与帧之间的运动,来计算物体运动轨迹和速度。具体实现目标如下:
1、选取图像中的易被识别的特征点,如Harris角点,FAST角点。
2、为每个特征点选取一个领域窗口,跟踪该窗口在连续视频帧中的变化。
3、计算窗口中每个像素在两帧之间的光流,也就是像素位移量,常用的光流计算方法有Lucas-Kanada法、Gunner Farneback法等。
4、根据窗口中的光流情况判断该特征点的位移量。可以采取投票机制或窗口内光流的中值作为该点的移动量。
5、 根据特征点的移动向量就可以计算出物体运动的速度和方向。 通过跟踪多个特征点并做平均可以得到更精确的运动速度估计。
6、结合物体在三维空间的位置信息,可以将二维图像平面上的特征点轨迹还原出三维空间中的运动路径。
7、当特征点消失或运动过快时,需要选取图像中新的特征点进行跟踪,确保在每一帧中有足够的特征点对物体进行跟踪。
8、根据目标的运动趋势,可以预测其未来的移动位置和速度。为了实现精确定位,预测结果需要与实时检测结果进行融合。
以上是使用光流方法实现目标跟踪的基本思路和技术步骤。通过选取图像中的特征点,分析其在连续视频帧之间的运动变化,实现对目标运动的检测、跟踪和预测。在实际实现中存在光流计算的准确性与速度问题,这需要选择适合的算法与优化方法。

python版domo
这个Demo通过Opencv的calcOpticalFlowFarneback()方法计算两帧图像之间的光流。然后绘制光流向量和场,实现了基本的目标运动跟踪和显示。
在实际项目中,可以根据光流分析得到的目标移动信息,预测其未来位置,并结合三维位置实现精确跟踪。如果光流无法准确跟踪,还需要选取新的特征点进行跟踪。
这只是一个基本Demo,实际项目实现会更加复杂。但基本思路与步骤仍然适用。请根据具体需求对代码进行完善和优化。

import cv2
import numpy as npcap = cv2.VideoCapture('input.mp4')  # 读取视频文件
ret, frame1 = cap.read()  # 读取第一帧
prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY) # 转换为灰度图像while(1):ret, frame2 = cap.read()  # 读取后续帧next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY) # 转化为灰度图像# 计算光流flow = cv2.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)# 计算光流的角度和幅值h, w = next.shape[:2]y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)fx, fy = flow[y,x].T# 绘制光流场和向量lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)lines = np.int32(lines + 0.5)vis = cv2.cvtColor(next, cv2.COLOR_GRAY2BGR)for (x1, y1), (x2, y2) in lines:cv2.line(vis, (x1, y1), (x2, y2), (0, 255, 0), 1)cv2.circle(vis, (x1, y1), 1, (0, 255, 0), -1)#显示图像cv2.imshow('frame2', vis)prvs = next # 更新前一帧k = cv2.waitKey(30) & 0xffif k == 27:break

C++版demo
该代码完成了视频中目标的光流跟踪。主要步骤为:

  1. 对第一帧图像检测Harris角点作为特征点。
  2. 读取第二帧图像,同样检测特征点。
  3. 利用calcOpticalFlowPyrLK函数计算第一帧和第二帧特征点之间的光流,获得新的特征点位置。
  4. 在图像上绘制光流跟踪结果,并更新特征点用于下一帧跟踪。
  5. 不断读取新帧并重复以上步骤,实现对目标运动的连续跟踪。
    该实现较为简单,主要目的在于演示光流方法的基本思想和步骤。实际项目中会根据具体应用对算法进行优化和改进。
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() 
{// 读取视频文件VideoCapture cap("input.avi"); // 获取第一帧Mat frame1, frame2;cap >> frame1;// 对第一帧检测Harris角点 vector<Point2f> points1;cornerHarris(frame1, points1, 2, 3, 0.04, 3, 0);while (cap.read(frame2)) {// 对第二帧进行角点检测vector<Point2f> points2;cornerHarris(frame2, points2, 2, 3, 0.04, 3, 0);// 光流跟踪vector<Point2f> newPoints; calcOpticalFlowPyrLK(frame1, frame2, points1, newPoints);// 显示跟踪结果 for (int i = 0; i < points1.size(); i++) {  line(frame1, points1[i], newPoints[i], Scalar(0,255,0), 1.5);  circle(frame1, newPoints[i], 3, Scalar(0,0,255), -1); }// 更新帧和跟踪角点 points1 = newPoints; frame1 = frame2.clone();// 显示视频 imshow("Tracking", frame1);if (waitKey(30) == 27) break; }
}