OpenCV目標跟蹤(四)-運動模板
OpenCV中運動與跟蹤這一章節中,在前面的介紹中,主要給出了LK光流法,以及基於概率統計,視窗搜尋的meanshif演算法以及meanshif演算法的改進版-camshift演算法,這兩天主要在看運動模板的跟蹤運動方法,下面就簡要的介紹下。
運動模板的方法是美國的MIT實驗室提出來的,是一種有效的跟蹤普通運動的方法,尤其可應用在姿態識別中。運動模板的方法首先需要的是知道物體的輪廓,而輪廓的獲取可以有很多的方法,關於輪廓的獲取的方法在此不做多餘的贅述。
運動模板的方法程式的大致程式設計思路應該是是這樣的:獲得當前幀與上一幀的差,然後對差影象進行二值化;更新運動歷史影象;然後計算運動歷史影象的梯度方向,並將整個運動分割為獨立的運動部分,在用一個結構序列標記每一個運動分割,最後計算出選擇區域的全域性運動方向,從而獲得運動目標的質心位置與運動方向。
關於上面的思路,給出幾個主要的函式,對其引數進行介紹。
void cvUpdateMotionHistory(
const CvArr* silhouette,//非0畫素代表前景物體的最新的分割輪廓
CvArr* mhi,//運動模板,也即運動歷史影象
double timestamp,//當前系統時間
double duration//運動跟蹤的最大持續時間
);
一旦運動模板記錄了不同時間的物體輪廓,就快成用計算mhi影象的梯度來獲取全域性運動資訊。即有函式:
void cvCalcMotionGradient(
const CvArrs* mhi,//運動歷史影象
CvArr* mask,//非0值代表此點處的梯度有效
CvArr* orientation,//每一點梯度方向的角度
double delta1,
double delta2,//delta1,2分別是允許的最小和最大梯度值
int aperture_size=3//設定梯度運算元的寬和高
);
梯度方向求出後,即可以計算全域性運動方向,給出如下函式:
double cvCalcGlobalOrientation(
const CvArr* orientation,
const CvArr* mask,
const CvArr* mhi,//前三個引數都是根據上面兩個函式得出來的
double timestamp,
double duration
);
關於運動模板後面的數學原理,我其實還沒找到相關的文獻閱讀,有些數學原理地方不是特別明白。下面給出完整的運動模板示例程式。
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include <time.h>
#include <stdio.h>
#include <ctype.h>
//不同的跟蹤引數
const double MHI_DURATION = 0.5;
const double MAX_TIME_DELTA = 0.5;
const double MIN_TIME_DELTA = 0.05;
// 用於運動檢測的迴圈幀數,與機器速度及FPS設定有關
const int N = 2;
IplImage **buf = 0;
int last = 0;
// 臨時影象
IplImage *mhi = 0; // MHI: 運動歷史影象
IplImage *orient = 0; // 方向
IplImage *mask = 0; // 有效的運動掩碼
IplImage *segmask = 0; // 運動分割對映
CvMemStorage* storage = 0; // 臨時儲存區 // parameters:
// img - input video frame
// dst - resultant motion picture
// args - optional parameters
void update_mhi( IplImage* img, IplImage* dst, int diff_threshold ){
double timestamp = (double)clock()/CLOCKS_PER_SEC; // 獲取當前時間,以秒為單位
CvSize size = cvSize(img->width,img->height); // 獲取當前幀尺寸
int i, idx1 = last, idx2;
IplImage* silh;
CvSeq* seq;
CvRect comp_rect;
double count;
double angle;
CvPoint center;
double magnitude;
CvScalar color;
// 開始時為影象分配記憶體 or 幀尺寸改變時重新分配記憶體
if( !mhi || mhi->width != size.width || mhi->height != size.height ){
if( buf == 0 ){
buf = (IplImage**)malloc(N*sizeof(buf[0]));
memset( buf, 0, N*sizeof(buf[0]));
}
for( i = 0; i < N; i++ ){
cvReleaseImage( &buf[i] );
buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
cvZero( buf[i] );
}
cvReleaseImage( &mhi );
cvReleaseImage( &orient );
cvReleaseImage( &segmask );
cvReleaseImage( &mask );
mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
cvZero( mhi ); // clear MHI at the beginning
orient = cvCreateImage( size, IPL_DEPTH_32F, 1 );
segmask = cvCreateImage( size, IPL_DEPTH_32F, 1 );
mask = cvCreateImage( size, IPL_DEPTH_8U, 1 );
}
cvCvtColor( img, buf[last], CV_BGR2GRAY ); //RGB幀影象格式轉換為gray
idx2 = (last + 1) % N; // index of (last - (N-1))th frame
last = idx2;
silh = buf[idx2];
// 相鄰兩幀的差
cvAbsDiff( buf[idx1], buf[idx2], silh );
cvThreshold( silh, silh, diff_threshold, 1, CV_THRESH_BINARY ); // 對差影象做二值化
cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // 更新運動歷史
// convert MHI to blue 8u image
// cvCvtScale的第四個引數 shift = (MHI_DURATION - timestamp)*255./MHI_DURATION
// 控制幀差的消失速率
cvCvtScale( mhi, mask, 255./MHI_DURATION,
(MHI_DURATION - timestamp)*255./MHI_DURATION );
cvZero( dst );
cvMerge( mask, 0, 0, 0, dst );
// B,G,R,0 convert to BLUE image
// 計算運動的梯度方向以及正確的方向掩碼
// Filter size = 3
cvCalcMotionGradient( mhi, mask, orient,
MAX_TIME_DELTA, MIN_TIME_DELTA, 3 );
if( !storage )
storage = cvCreateMemStorage(0);
else
cvClearMemStorage(storage);
// 運動分割: 獲得運動部件的連續序列
seq = cvSegmentMotion( mhi, segmask, storage, timestamp, MAX_TIME_DELTA );
for( i = -1; i < seq->total; i++ ){
if( i < 0 ) { // 對整幅影象操作
comp_rect = cvRect( 0, 0, size.width, size.height );
color = CV_RGB(255,255,255);
magnitude = 100; // 畫線長度以及圓半徑的大小控制
}
else { // 第i個運動元件
comp_rect = ((CvConnectedComp*)cvGetSeqElem( seq, i ))->rect;
// 去掉小的部分
if( comp_rect.width + comp_rect.height < 100 )
continue;
color = CV_RGB(255,0,0);
magnitude = 30;
//if(seq->total > 0) MessageBox(NULL,"Motion Detected",NULL,0);
}
// 選擇元件ROI
cvSetImageROI( silh, comp_rect );
cvSetImageROI( mhi, comp_rect );
cvSetImageROI( orient, comp_rect );
cvSetImageROI( mask, comp_rect );
// 在選擇的區域內,計算運動方向
angle = cvCalcGlobalOrientation( orient, mask, mhi, timestamp, MHI_DURATION);
angle = 360.0 - angle; // adjust for images with top-left origin
// 在輪廓內計算點數
// Norm(L1) = 所有畫素值的和
count = cvNorm( silh, 0, CV_L1, 0 );
cvResetImageROI( mhi );
cvResetImageROI( orient );
cvResetImageROI( mask );
cvResetImageROI( silh );
// 檢查小運動的情形
if( count < comp_rect.width*comp_rect.height * 0.05 ) // 畫素的5%
continue;
// 畫一個帶箭頭的記錄以表示方向
center = cvPoint( (comp_rect.x+comp_rect.width/2),(comp_rect.y + comp_rect.height/2) );
cvCircle( dst, center, cvRound(magnitude*1.2), color, 3, CV_AA, 0 );
cvLine( dst, center, cvPoint( cvRound( center.x +magnitude*cos(angle*CV_PI/180)),
cvRound( center.y - magnitude*sin(angle*CV_PI/180))), color, 3, CV_AA, 0 );
}
}
int main(int argc, char** argv){
IplImage* motion = 0;
CvCapture* capture = 0;
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
else if( argc == 2 )
capture = cvCaptureFromAVI( argv[1] );
if( capture ){
cvNamedWindow( "Motion", 1 );
for(;;){
IplImage* image = cvQueryFrame( capture );
if( !image )
break;
if( !motion )
{
motion = cvCreateImage( cvSize(image->width,image->height), 8, 3 );
cvZero( motion );
motion->origin = image->origin;
}
update_mhi( image, motion, 30 );
cvShowImage( "Motion", motion );
if( cvWaitKey(10) >= 0 )
break;
}
cvReleaseCapture( &capture );
cvDestroyWindow( "Motion" );
}
return 0;
}
#ifdef _EiC
main(1,"motempl.c");
#endif
最後的執行結果如圖所示:
相關推薦
OpenCV目標跟蹤(四)-運動模板
OpenCV中運動與跟蹤這一章節中,在前面的介紹中,主要給出了LK光流法,以及基於概率統計,視窗搜尋的meanshif演算法以及meanshif演算法的改進版-camshift演算法,這兩天主要在看運動模板的跟蹤運動方法,下面就簡要的介紹下。 運動模板的方法是
運動目標跟蹤(一)--搜尋演算法預測模型之KF,EKF,UKF
這裡先總體介紹下,原文轉自: 任何感測器,鐳射也好,視覺也好,整個SLAM系統也好,要解決的問題只有一個:如何通過資料來估計自身狀態。每種感測器的測量模型不一樣,它們的精度也不一樣。換句話說,狀態估計問題,也就是“如何最好地使用感測器資料”。可以說,SLAM是狀態估計的一
Flask 學習系列(四)---Jinjia2 模板繼承
list size border padding sub -- margin nbsp 中文 1.基模板 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF
Spring Boot入門(四)——使用模板FreeMaker
junit boot.s char pack utf put 常見 節點 簡單的 這周主要學習怎麽在Spring Boot中使用模板引擎FreeMaker,主要從以下幾方面進行學習。 (1) freemarker介紹: FreeMarker是一款模板引擎: 即
tensorflow利用預訓練模型進行目標檢測(四):檢測中的精度問題以及evaluation
一、tensorflow提供的evaluation Inference and evaluation on the Open Images dataset:https://github.com/tensorflow/models/blob/master/research/object_detection/g
OpenCV(C++) 基礎(四)-- 邊緣檢測與霍夫變換
1. 邊緣檢測 Sobel():靈活調整水平或者垂直邊緣檢測,基於高斯平滑和微分求導 void Sobel(src, dst, depth, dx, dy, ksize=3); // depth: 對應影象型別 // dx, dy: x,y方向的差分階數,控制在x,y軸上
雙攝像頭的實時視訊拼接及目標跟蹤(二)
視訊拼接演算法 視訊拼接思想及總體框圖 影象拼接是視訊拼接的基礎,是將多張影象生成一張全景圖,衡量的指標主要在於全景圖的質量,而對拼接速度的要求並不高。對於視訊拼接而言,視訊流的輸入是源源不斷的,需要將多個攝像頭採集的圖片進行拼接,每個攝像頭的影象幀序列必須一一
雙攝像頭的實時視訊拼接及目標跟蹤(三)
實時視訊拼接 初步視訊拼接虛影問題的探討 經過上述方案處理之後的初步拼接視訊,將會存在目前視訊拼接技術中一個普遍的問題,即重合區域存在運動物體產生虛影。效果圖如下, 產生偽影的影象幀 可以看到,重疊區域內,存在運動物體時,出現了虛影,並且都
雙攝像頭的實時視訊拼接及目標跟蹤(五)
實時視訊拼接速度的優化方案 優化方案,提高拼接速度 根據之前章節的方法,進行初步視訊拼接得到的效果,其速度並不是最快,需要進行一定的優化。通過實驗,得到下面幾種優化方式。 1.程式碼執行的環境是在VS2017上執行的,其中有兩種執行模式,分別為Debug模式和R
Python3+OpenCV學習筆記(四):影象濾波基礎(均值、高斯、中值、雙邊)
OpenCV中還可以在影象上進行繪圖操作,由於資料都比較完善,所以附上鍊接,自行參悟。 好了,進入正題。在一張影象,在資料儲存或傳輸的過程中,或多或少都會引入噪聲,常見的影象噪聲如高斯噪聲、瑞利噪聲、椒鹽噪聲等,可參加連結:數字影象噪聲 為了避免噪聲對影象資訊進行干擾或
flask(四)jinja2模板
from flask import Flask,render_template @app.route("/index/") def index(): return render_template("",) render_templ
ubuntu下利用Dlib實現目標跟蹤(上)
本文將介紹在Ub
Opencv學習手冊(四)--- 影象灰度變換
#include <opencv2/opencv.hpp> using namespace cv; /* 灰度變換函式ImageAdjust 其中,源影象src和目標影象dst均為8位元的灰度影象 預設的引數值有: [low, high]
SLAM筆記(四)運動恢復結構的幾何數學(本徵矩陣、單應矩陣、基礎矩陣)
1. 間接法進行運動恢復的前提假設 對於結構與運動或視覺三維重建中,通常假設已經通過特徵匹配等方法獲取了匹配好的點對。 先求出匹配點對再獲取結構和運動資訊的方法稱作間接法。 間接法最重要的三個假設是: 1.擁有一系列兩幀之間的匹配點對。但同時假設匹配關係不一定精
SpringBoot入門系列(四)整合模板引擎Thymeleaf
前面介紹了Spring Boot的優點,然後介紹瞭如何快速建立Spring Boot 專案。不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html。 今天我們主要來看看 Thymeleaf 在 Spring Boo
運動目標跟蹤(十四)--MIL跟蹤
原文: http://blog.csdn.net/ikerpeng/article/details/19235391 文章:Robust object tracking with on-line multiple instance learning Boris Baben
OpenCV學習總結(4)- 目標跟蹤
opened 背景 key font sin mic 目標 mil cap 視覺算法原理:背景提取 1. 打開視頻(文件或攝像頭) 2. 從視頻中提取當前幀 3. 計算背景:以前多幀求取平均 4. 根據背景得到運動目標(當前幀 - 背景) 5. 返回2,程序不斷循
ARCore之路-運動跟蹤之3D聲場(四)
上節我們已經利用共振音訊(Resonance Audio)SDK實現了3D音效,這只是使用了共振音訊(Resonance Audio)最簡單的特性,共振音訊(Resonance Audio)提供了遠比示例中高階的功能技術特性,特別是模擬房間的引數,可以模擬很
Python-OpenCV 處理視訊(三)(四)(五): 標記運動軌跡 運動檢測 運動方向判斷
0x00. 光流 光流是進行視訊中運動物件軌跡標記的一種很常用的方法,在OpenCV中實現光流也很容易。 CalcOpticalFlowPyrLK 函式計算一個稀疏特徵集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。 簡單的實現流程: 載入一段視訊。
目標檢測的影象特徵提取之(四)OpenCV中BLOB特徵提取與幾何形狀分類
OpenCV中BLOB特徵提取與幾何形狀分類一:方法二值影象幾何形狀提取與分離,是機器視覺中重點之一,在CT影象分析與機器人視覺感知等領域應用廣泛,OpenCV中提供了一個對二值影象幾何特徵描述與分析最有效的工具 - SimpleBlobDetector類,使用它可以實現對二