「計算機視覺C++」

1.點追蹤介紹

通常在連續幀中檢測到的目標被表達為點。再引入其它方法來進行目標檢測。其問題可以用幀與幀之間檢測到的目標點之間的關係來表達。方法可分為兩大類:確定性方法和統計性方法。前者通常用定性的運動限制方法,後者用目標檢測和不確定性的建模來建立關聯。

「計算機視覺C++」

2.寫幾點思考

  1. 確定性的方法定義了在一系列約束條件下,關聯t時刻和t-1時刻圖像幀中每個目標的成本。關聯成本的最小化規劃為一個優化組合問題。可以用最優分配方法求解,如匈牙利算法,貪婪搜索算法。
  2. 統計性方法在目標狀態估計中考慮了觀測噪聲和模型不確定性,用狀態空間方法建模速度、位置、加速度等目標屬性。對於單個目標的情況,狀態可簡單估計得到;對於多目標的情況,則需要將觀測域相應目標對應起來。
  3. 對於單目標狀態估計:如果狀態轉移矩陣和觀測矩陣都是線性的,狀態和噪聲是高斯分佈的,則最優的狀態估計方法是卡爾曼濾波。
  4. 對於 多目標狀態估計:廣泛採用的兩種方法是Joint Probability Data Association Filtering (JPDAF)和Multiple Hypothesis Tracking (MHT)

3.OpenCV3 C++實現

<code>//--------------------------------------【程序說明】-------------------------------------------
//\t\t程序描述:點追蹤技術演示
//\t\t測試所用操作系統: Windows 10 64bit
//\t\t測試所用IDE版本:Visual Studio 2017
//\t\t測試所用OpenCV版本:\t3.4

//\t\t2020年3月 Revised by @DL小寶
//------------------------------------------------------------------------------------------------

//---------------------------------【頭文件、命名空間包含部分】----------------------------
//\t\t描述:包含程序所使用的頭文件和命名空間
//-------------------------------------------------------------------------------------------------
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;

//--------------------------------【help( )函數】----------------------------------------------
//\t\t描述:輸出幫助信息
//-------------------------------------------------------------------------------------------------
static void help()
{
\t//輸出歡迎信息和OpenCV版本
\tcout << "\\n\\n\\t\\t\\t 當前使用的OpenCV版本為:" << CV_VERSION
\t\t<< "\\n\\n ----------------------------------------------------------------------------";
\tcout << "\\n\\n\\t該Demo演示了 Lukas-Kanade基於光流的lkdemo\\n";
\tcout << "\\n\\t程序默認從攝像頭讀入視頻,可以按需改為從視頻文件讀入圖像\\n";
\tcout << "\\n\\t操作說明: \\n"
\t\t"\\t\\t通過點擊在圖像中添加/刪除特徵點\\n"
\t\t"\\t\\tESC - 退出程序\\n"
\t\t"\\t\\tr -自動進行追蹤\\n"
\t\t"\\t\\tc - 刪除所有點\\n"
\t\t"\\t\\tn - 開/光-夜晚模式\\n" << endl;
}

Point2f point;
bool addRemovePt = false;

//--------------------------------【onMouse( )回調函數】------------------------------------
//\t\t描述:鼠標操作回調
//-------------------------------------------------------------------------------------------------
static void onMouse(int event, int x, int y, int /*flags*/, void* /*param*/)
{
\t//此句代碼的OpenCV2版為:
\t//if( event == CV_EVENT_LBUTTONDOWN )
\t//此句代碼的OpenCV3版為:
\tif (event == EVENT_LBUTTONDOWN)
\t{
\t\tpoint = Point2f((float)x, (float)y);
\t\taddRemovePt = true;
\t}
}

//-----------------------------------【main( )函數】--------------------------------------------
//\t\t描述:控制檯應用程序的入口函數,我們的程序從這裡開始
//-------------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
\thelp();

\tVideoCapture cap;

\t//此句代碼的OpenCV2版為:
\t//TermCriteria termcrit(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03);
\t//此句代碼的OpenCV3版為:
\tTermCriteria termcrit(TermCriteria::MAX_ITER | TermCriteria::EPS, 20, 0.03);
\tSize subPixWinSize(10, 10), winSize(31, 31);

\tconst int MAX_COUNT = 500;
\tbool needToInit = false;
\tbool nightMode = false;
\tcap.open(0);

\tif (!cap.isOpened())
\t{
\t\tcout << "Could not initialize capturing...\\n";
\t\treturn 0;
\t}

\tnamedWindow("LK Demo", 1);
\tsetMouseCallback("LK Demo", onMouse, 0);


\tMat gray, prevGray, image;
\tvector<point2f> points[2];

\tfor (;;)
\t{
\t\tMat frame;
\t\tcap >> frame;
\t\tif (frame.empty())
\t\t\tbreak;

\t\tframe.copyTo(image);
\t\tcvtColor(image, gray, COLOR_BGR2GRAY);

\t\tif (nightMode)
\t\t\timage = Scalar::all(0);

\t\tif (needToInit)
\t\t{
\t\t\t// 自動初始化
\t\t\t//goodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 0, 0.04);
\t\t\tcornerSubPix(gray, points[1], subPixWinSize, Size(-1, -1), termcrit);
\t\t\taddRemovePt = false;
\t\t}
\t\telse if (!points[0].empty())
\t\t{
\t\t\tvector<uchar> status;
\t\t\tvector<float> err;
\t\t\tif (prevGray.empty())
\t\t\t\tgray.copyTo(prevGray);
\t\t\tcalcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize,
\t\t\t\t3, termcrit, 0, 0.001);
\t\t\tsize_t i, k;
\t\t\tfor (i = k = 0; i < points[1].size(); i++)
\t\t\t{
\t\t\t\tif (addRemovePt)
\t\t\t\t{
\t\t\t\t\tif (norm(point - points[1][i]) <= 5)
\t\t\t\t\t{
\t\t\t\t\t\taddRemovePt = false;
\t\t\t\t\t\tcontinue;
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (!status[i])
\t\t\t\t\tcontinue;

\t\t\t\tpoints[1][k++] = points[1][i];
\t\t\t\tcircle(image, points[1][i], 3, Scalar(0, 255, 0), -1, 8);
\t\t\t}

\t\t\tpoints[1].resize(k);
\t\t}

\t\tif (addRemovePt && points[1].size() < (size_t)MAX_COUNT)
\t\t{
\t\t\tvector<point2f> tmp;
\t\t\ttmp.push_back(point);

\t\t\t//此句代碼的OpenCV2版為:
\t\t\t//cornerSubPix( gray, tmp, winSize, cvSize(-1,-1), termcrit);
\t\t\t//此句代碼的OpenCV3版為:
\t\t\tcornerSubPix(gray, tmp, winSize, Size(-1, -1), termcrit);
\t\t\tpoints[1].push_back(tmp[0]);
\t\t\taddRemovePt = false;
\t\t}
\t\tneedToInit = false;
\t\timshow("LK Demo", image);

\t\tchar c = (char)waitKey(10);
\t\tif (c == 27)
\t\t\tbreak;
\t\tswitch (c)
\t\t{
\t\tcase 'r':
\t\t\tneedToInit = true;
\t\t\tbreak;
\t\tcase 'c':
\t\t\tpoints[0].clear();
\t\t\tpoints[1].clear();
\t\t\tbreak;
\t\tcase 'n':
\t\t\tnightMode = !nightMode;
\t\t\tbreak;
\t\t}
\t\tstd::swap(points[1], points[0]);
\t\tcv::swap(prevGray, gray);
\t}
\treturn 0;
}/<point2f>/<float>/<uchar>/<point2f>/<ctype.h>/<iostream>/<code>
「計算機視覺C++」


分享到:


相關文章: