首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

光流法原理與 OpenCV 實作:Lucas-Kanade 光流追蹤完整指南

     編輯:關於C++

光流概念

光流描述畫面中像素在時序上的位移速度場。Gibson 1950 年提出,核心假設:像素亮度隨時間不變(亮度恆定假設)。

應用:運動偵測、物體追蹤、視覺里程計、動作辨識。

數學推導:從亮度恆定到光流方程

像素 I(x,y,t) 在 Δt 後移至 (x+Δx, y+Δy),亮度不變:

泰勒展開一階近似(忽略高階項):

整理得光流方程:

單一像素兩未知數 (u,v) 一方程,無法唯一解。

Lucas-Kanade 方法:局部窗口最小二乘

假設 3×3 鄰域像素共享相同位移,得 9 條方程,2 未知數,超定系統,用最小二乘求解:

矩陣形式 Av = b,解為 v = (AᵀA)⁻¹Aᵀb。

金字塔層級 (Pyramid) 解決大位移問題:粗略層估大位移,細層細化。

OpenCV 實作:calcOpticalFlowPyrLK


#include <opencv2/video/tracking.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv; using namespace std;

int main() {
    VideoCapture cap("G:/.../sample.avi");
    TermCriteria termcrit(TermCriteria::COUNT|TermCriteria::EPS, 20, 0.03);
    Size subPixWinSize(10,10), winSize(31,31);
    const int MAX_COUNT = 500;
    bool needToInit = false, nightMode = false;
    vector<Point2f> points[2];
    Mat gray, prevGray, frame, image;

    namedWindow("LK Demo", 1);
    setMouseCallback("LK Demo", [](int e, int x, int y, int, void*) {
        if (e == EVENT_LBUTTONDOWN) { point = Point2f(x,y); addRemovePt = true; }
    }, 0);

    for (;;) {
        cap >> frame; if (frame.empty()) break;
        frame.copyTo(image);
        cvtColor(image, gray, COLOR_BGR2GRAY);
        if (nightMode) image = Scalar::all(0);

        if (needToInit) {
            goodFeaturesToTrack(gray, points[1], 100, 0.01, 10, Mat(), 3, 0, 0.04);
            cornerSubPix(gray, points[1], subPixWinSize, Size(-1,-1), termcrit);
            needToInit = false;
        } else if (!points[0].empty()) {
            vector<uchar> status; vector<float> err;
            if (prevGray.empty()) gray.copyTo(prevGray);
            calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err,
                                 winSize, 3, termcrit, 0, 0.001);
            // 過濾失效點、繪製軌跡...
            size_t k = 0;
            for (size_t i = 0; i < points[1].size(); ++i) {
                if (addRemovePt && norm(point - points[1][i]) <= 5) { addRemovePt = false; continue; }
                if (!status[i]) continue;
                points[1][k++] = points[1][i];
                circle(image, points[1][i], 3, Scalar(0,255,0), -1, 8);
            }
            points[1].resize(k);
        }
        if (addRemovePt && points[1].size() < MAX_COUNT) {
            vector<Point2f> tmp = {point};
            cornerSubPix(gray, tmp, winSize, Size(-1,-1), termcrit);
            points[1].push_back(tmp[0]); addRemovePt = false;
        }
        swap(points[1], points[0]); swap(prevGray, gray);
        imshow("LK Demo", image);
        char c = waitKey(100);
        if (c == 27) break;
        if (c == 'r') needToInit = true;
        else if (c == 'c') { points[0].clear(); points[1].clear(); }
        else if (c == 'n') nightMode = !nightMode;
    }
    return 0;
}

執行效果

特徵點隨車輛移動自動追蹤:

關鍵函式說明

  • goodFeaturesToTrack:Shi-Tomasi 角點偵測,取得初始追蹤點。
  • cornerSubPix:亞像素級角點優化。
  • calcOpticalFlowPyrLK:金字塔 Lucas-Kanade 光流,回傳新位置、狀態、誤差。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved