Cv運動分析與對象跟蹤(轉)


Cv運動分析與對象跟蹤

 

目錄

[隱藏]

 

[ 編輯]

背景統計量的累積

[ 編輯]

Acc

將幀疊加到累積器(accumulator)中

void cvAcc( const CvArr* image, CvArr* sum, const CvArr* mask=NULL );
image
輸入圖像, 1- 或 3-通道, 8-比特或32-比特浮點數. (多通道的每一個通道都單獨處理).
sum
同一個輸入圖像通道的累積,32-比特或64-比特浮點數數組.
mask
可選的運算 mask.

函數 cvAcc 將整個圖像 image 或某個選擇區域疊加到 sum 中:

sum(x,y)=sum(x,y)+image(x,y) if mask(x,y)!=0
[ 編輯]

SquareAcc

疊加輸入圖像的平方到累積器中

void cvSquareAcc( const CvArr* image, CvArr* sqsum, const CvArr* mask=NULL );
image
輸入圖像, 1- 或 3-通道, 8-比特或32-比特浮點數 (多通道的每一個通道都單獨處理)
sqsum
同一個輸入圖像通道的累積,32-比特或64-比特浮點數數組.
mask
可選的運算 mask.

函數 cvSquareAcc 疊加輸入圖像 image 或某個選擇區域的二次方,到累積器 sqsum 中

sqsum(x,y)=sqsum(x,y)+image(x,y)2 if mask(x,y)!=0
[ 編輯]

MultiplyAcc

將兩幅輸入圖像的乘積疊加到累積器中

void cvMultiplyAcc( const CvArr* image1, const CvArr* image2, CvArr* acc, const CvArr* mask=NULL );
image1
第一個輸入圖像, 1- or 3-通道, 8-比特 or 32-比特 浮點數 (多通道的每一個通道都單獨處理)
image2
第二個輸入圖像, 與第一個圖像的格式一樣
acc
同一個輸入圖像通道的累積,32-比特或64-比特浮點數數組.
mask
可選的運算 mask.

函數 cvMultiplyAcc 疊加兩個輸入圖像的乘積到累積器 acc:

acc(x,y)=acc(x,y) + image1(x,y)•image2(x,y) if mask(x,y)!=0
[ 編輯]

RunningAvg

更新 running average 滑動平均( Hunnish: 不知道 running average 如何翻譯才恰當)

void cvRunningAvg( const CvArr* image, CvArr* acc, double alpha, const CvArr* mask=NULL );
image
輸入圖像, 1- or 3-通道, 8-比特 or 32-比特 浮點數 (each channel of multi-channel image is processed independently).
acc
同一個輸入圖像通道的累積,32-比特或64-比特浮點數數組.
alpha
輸入圖像權重
mask
可選的運算 mask

函數 cvRunningAvg 計算輸入圖像 image 的加權和,以及累積器 acc 使得 acc 成為幀序列的一個 running average:

acc(x,y)=(1-α)•acc(x,y) + α•image(x,y) if mask(x,y)!=0

其中 α (alpha) 調節更新速率 (累積器以多快的速率忘掉前面的幀).

[ 編輯]

運動模板

[ 編輯]

UpdateMotionHistory

去掉影像(silhouette) 以更新運動歷史圖像

void cvUpdateMotionHistory( const CvArr* silhouette, CvArr* mhi,
                            double timestamp, double duration );
silhouette
影像 mask,運動發生地方具有非零象素
mhi
運動歷史圖像(單通道, 32-比特 浮點數),為本函數所更新
timestamp
當前時間,毫秒或其它單位
duration
運動跟蹤的最大持續時間,用 timestamp 一樣的時間單位

函數 cvUpdateMotionHistory 用下面方式更新運動歷史圖像:

mhi(x,y)=timestamp  if silhouette(x,y)!=0
         0          if silhouette(x,y)=0 and mhi(x,y)<timestamp-duration
         mhi(x,y)   otherwise

也就是,MHI(motion history image) 中在運動發生的象素點被設置為當前時間戳,而運動發生較久的象素點被清除。

[ 編輯]

CalcMotionGradient

計算運動歷史圖像的梯度方向

void cvCalcMotionGradient( const CvArr* mhi, CvArr* mask, CvArr* orientation,
                           double delta1, double delta2, int aperture_size=3 );
mhi
運動歷史圖像
mask
Mask 圖像;用來標注運動梯度數據正確的點,為輸出參數。
orientation
運動梯度的方向圖像,包含從 0 到 360 角度
delta1, delta2
函數在每個象素點 (x,y) 鄰域尋找 MHI 的最小值 (m(x,y)) 和最大值 (M(x,y)),並且假設梯度是正確的,當且僅當:
min(delta1,delta2) <= M(x,y)-m(x,y) <= max(delta1,delta2).
aperture_size
函數所用微分算子的開孔尺寸 CV_SCHARR, 1, 3, 5 or 7 (見 cvSobel).

函數 cvCalcMotionGradient 計算 MHI 的差分 Dx 和 Dy ,然后計算梯度方向如下式:

orientation(x,y)=arctan(Dy(x,y)/Dx(x,y))

其中都要考慮 Dx(x,y)' 和 Dy(x,y)' 的符號 (如 cvCartToPolar 類似). 然后填充 mask 以表示哪些方向是正確的(見 delta1 和delta2 的描述).

[ 編輯]

CalcGlobalOrientation

計算某些選擇區域的全局運動方向

double cvCalcGlobalOrientation( const CvArr* orientation, const CvArr* mask, const CvArr* mhi,
                                double timestamp, double duration );
orientation
運動梯度方向圖像,由函數 cvCalcMotionGradient 得到
mask
Mask 圖像. 它可以是正確梯度 mask (由函數 cvCalcMotionGradient 得到)與區域 mask 的結合,其中區域 mask 確定哪些方向需要計算。
mhi
運動歷史圖象
timestamp
當前時間(單位毫秒或其它)最好在傳遞它到函數 cvUpdateMotionHistory 之前存儲一下以便以后的重用,因為對大圖像運行 cvUpdateMotionHistory 和 cvCalcMotionGradient 會花費一些時間
duration
運動跟蹤的最大持續時間,用法與 cvUpdateMotionHistory 中的一致

函數 cvCalcGlobalOrientation 在選擇的區域內計算整個運動方向,並且返回 0° 到 360° 之間的角度值。首先函數創建運動直方圖,尋找基本方向做為直方圖最大值的坐標。然后函數計算與基本方向的相對偏移量,做為所有方向向量的加權和:運行越近,權重越大。得到的角度是基本方向和偏移量的循環和。

[ 編輯]

SegmentMotion

將整個運動分割為獨立的運動部分

CvSeq* cvSegmentMotion( const CvArr* mhi, CvArr* seg_mask, CvMemStorage* storage,
                        double timestamp, double seg_thresh );
mhi
運動歷史圖像
seg_mask
發現應當存儲的 mask 的圖像, 單通道, 32bits, 浮點數.
storage
包含運動連通域序列的內存存儲倉
timestamp
當前時間,毫秒單位
seg_thresh
分割閾值,推薦等於或大於運動歷史“每步”之間的間隔。

函數 cvSegmentMotion 尋找所有的運動分割,並且在seg_mask 用不同的單獨數字(1,2,...)標識它們。它也返回一個具有 CvConnectedComp 結構的序列,其中每個結構對應一個運動部件。在這之后,每個運動部件的運動方向就可以被函數 cvCalcGlobalOrientation 利用提取的特定部件的掩模(mask)計算出來(使用 cvCmp)

[ 編輯]

對象跟蹤

[ 編輯]

MeanShift

在反向投影圖中發現目標中心

int cvMeanShift( const CvArr* prob_image, CvRect window,
                 CvTermCriteria criteria, CvConnectedComp* comp );
prob_image
目標直方圖的反向投影(見 cvCalcBackProject).
window
初始搜索窗口
criteria
確定窗口搜索停止的准則
comp
生成的結構,包含收斂的搜索窗口坐標 (comp->rect 字段) 與窗口內部所有象素點的和 (comp->area 字段).

函數 cvMeanShift 在給定反向投影和初始搜索窗口位置的情況下,用迭代方法尋找目標中心。當搜索窗口中心的移動小於某個給定值時或者函數已經達到最大迭代次數時停止迭代。 函數返回迭代次數。

[ 編輯]

CamShift

發現目標中心,尺寸和方向

int cvCamShift( const CvArr* prob_image, CvRect window, CvTermCriteria criteria,
                CvConnectedComp* comp, CvBox2D* box=NULL );
prob_image
目標直方圖的反向投影 (見 cvCalcBackProject).
window
初始搜索窗口
criteria
確定窗口搜索停止的准則
comp
生成的結構,包含收斂的搜索窗口坐標 (comp->rect 字段) 與窗口內部所有象素點的和 (comp->area 字段).
box
目標的帶邊界盒子。如果非 NULL, 則包含目標的尺寸和方向。

函數 cvCamShift 實現了 CAMSHIFT 目標跟蹤算法([Bradski98]). 首先它調用函數 cvMeanShift 尋找目標中心,然后計算目標尺寸和方向。最后返回函數 cvMeanShift 中的迭代次數。

CvCamShiftTracker 類在 cv.hpp 中被聲明,函數實現了彩色目標的跟蹤。

[ 編輯]

SnakeImage

改變輪廓位置使得它的能量最小

void cvSnakeImage( const IplImage* image, CvPoint* points, int length,
                   float* alpha, float* beta, float* gamma, int coeff_usage,
                   CvSize win, CvTermCriteria criteria, int calc_gradient=1 );
image
輸入圖像或外部能量域
points
輪廓點 (snake).
length
輪廓點的數目
alpha
連續性能量的權 Weight[s],單個浮點數或長度為 length 的浮點數數組,每個輪廓點有一個權
beta
曲率能量的權 Weight[s],與 alpha 類似
gamma
圖像能量的權 Weight[s],與 alpha 類似
coeff_usage
前面三個參數的不同使用方法:
  • CV_VALUE 表示每個 alpha, beta, gamma 都是指向為所有點所用的一個單獨數值;
  • CV_ARRAY 表示每個 alpha, beta, gamma 是一個指向系數數組的指針,snake 上面各點的系數都不相同。因此,各個系數數組必須與輪廓具有同樣的大小。所有數組必須與輪廓具有同樣大小
win
每個點用於搜索最小值的鄰域尺寸,兩個 win.width 和 win.height 都必須是奇數
criteria
終止條件
calc_gradient
梯度符號。如果非零,函數為每一個圖像象素計算梯度幅值,且把它當成能量場,否則考慮輸入圖像本身。

函數 cvSnakeImage 更新 snake 是為了最小化 snake 的整個能量,其中能量是依賴於輪廓形狀的內部能量(輪廓越光滑,內部能量越小)以及依賴於能量場的外部能量之和,外部能量通常在哪些局部能量極值點中達到最小值(這些局部能量極值點與圖像梯度表示的圖像邊緣相對應)。

參數 criteria.epsilon 用來定義必須從迭代中除掉以保證迭代正常運行的點的最少數目。

如果在迭代中去掉的點數目小於 criteria.epsilon 或者函數達到了最大的迭代次數 criteria.max_iter ,則終止函數。

[ 編輯]

光流

[ 編輯]

CalcOpticalFlowHS

計算兩幅圖像的光流

void cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr, int use_previous,
                          CvArr* velx, CvArr* vely, double lambda,
                          CvTermCriteria criteria );
prev
第一幅圖像, 8-比特, 單通道.
curr
第二幅圖像, 8-比特, 單通道.
use_previous
使用以前的 (輸入) 速度域
velx
光流的水平部分,與輸入圖像大小一樣, 32-比特,浮點數, 單通道.
vely
光流的垂直部分,與輸入圖像大小一樣, 32-比特, 浮點數, 單通道.
lambda
Lagrangian 乘子
criteria
速度計算的終止條件

函數 cvCalcOpticalFlowHS 為輸入圖像的每一個象素計算光流,使用 Horn & Schunck 算法 [Horn81].

[ 編輯]

CalcOpticalFlowLK

計算兩幅圖像的光流

void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize win_size,
                          CvArr* velx, CvArr* vely );
prev
第一幅圖像, 8-比特, 單通道.
curr
第二幅圖像, 8-比特, 單通道.
win_size
用來歸類象素的平均窗口尺寸 (Size of the averaging window used for grouping pixels)
velx
光流的水平部分,與輸入圖像大小一樣, 32-比特, 浮點數, 單通道.
vely
光流的垂直部分,與 輸入圖像大小一樣, 32-比特, 浮點數, 單通道.

函數 cvCalcOpticalFlowLK 為輸入圖像的每一個象素計算光流,使用 Lucas & Kanade 算法 [Lucas81].

[ 編輯]

CalcOpticalFlowBM

用塊匹配方法計算兩幅圖像的光流

void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize block_size,
                          CvSize shift_size, CvSize max_range, int use_previous,
                          CvArr* velx, CvArr* vely );
prev
第一幅圖像, 8-比特, 單通道.
curr
第二幅圖像, 8-比特, 單通道.
block_size
比較的基本塊尺寸
shift_size
塊坐標的增量
max_range
塊周圍象素的掃描鄰域的尺寸
use_previous
使用以前的 (輸入) 速度域
velx
光流的水平部分,尺寸為 floor((prev->width - block_size.width)/shiftSize.width) × floor((prev->height - block_size.height)/shiftSize.height) , 32-比特,浮點數, 單通道.
vely
光流的垂直部分,與 velx 大小一樣,32-比特,浮點數, 單通道.

函數 cvCalcOpticalFlowBM 為重疊塊 block_size.width×block_size.height 中的每一個象素計算光流,因此其速度域小於整個圖像的速度域。對每一個在圖像 prev 中的塊,函數試圖在 curr 中某些原始塊或其偏移 (velx(x0,y0),vely(x0,y0)) 塊的鄰域里尋找類似的塊,如同在前一個函數調用中所計算的類似(如果 use_previous=1)

[ 編輯]

CalcOpticalFlowPyrLK

計算一個稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法

void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prev_pyr, CvArr* curr_pyr,
                             const CvPoint2D32f* prev_features, CvPoint2D32f* curr_features,
                             int count, CvSize win_size, int level, char* status,
                             float* track_error, CvTermCriteria criteria, int flags );
prev
在時間 t 的第一幀
curr
在時間 t + dt 的第二幀
prev_pyr
第一幀的金字塔緩存. 如果指針非 NULL , 則緩存必須有足夠的空間來存儲金字塔從層 1 到層 #level 的內容。尺寸 (image_width+8)*image_height/3 比特足夠了
curr_pyr
與 prev_pyr 類似, 用於第二幀
prev_features
需要發現光流的點集
curr_features
包含新計算出來的位置的 點集
count
特征點的數目
win_size
每個金字塔層的搜索窗口尺寸
level
最大的金字塔層數。如果為 0 , 不使用金字塔 (即金字塔為單層), 如果為 1 , 使用兩層,下面依次類推。
status
數組。如果對應特征的光流被發現,數組中的每一個元素都被設置為 1, 否則設置為 0。
error
雙精度數組,包含原始圖像碎片與移動點之間的差。為可選參數,可以是 NULL .
criteria
准則,指定在每個金字塔層,為某點尋找光流的迭代過程的終止條件。
flags
其它選項:
  • CV_LKFLOW_PYR_A_READY , 在調用之前,第一幀的金字塔已經准備好
  • CV_LKFLOW_PYR_B_READY , 在調用之前,第二幀的金字塔已經准備好
  • CV_LKFLOW_INITIAL_GUESSES , 在調用之前,數組 B 包含特征的初始坐標 (Hunnish: 在本節中沒有出現數組 B,不知是指的哪一個)

函數 cvCalcOpticalFlowPyrLK 實現了金字塔中 Lucas-Kanade 光流計算的稀疏迭代版本 ([Bouguet00])。 它根據給出的前一幀特征點坐標計算當前視頻幀上的特征點坐標。 函數尋找具有子象素精度的坐標值。

兩個參數 prev_pyr 和 curr_pyr 都遵循下列規則: 如果圖像指針為 0, 函數在內部為其分配緩存空間,計算金字塔,然后再處理過后釋放緩存。 否則,函數計算金字塔且存儲它到緩存中,除非設置標識 CV_LKFLOW_PYR_A[B]_READY 。 圖像應該足夠大以便能夠容納 Gaussian 金字塔數據。 調用函數以后,金字塔被計算而且相應圖像的標識可以被設置,為下一次調用准備就緒 (比如:對除了第一個圖像的所有圖像序列,標識 CV_LKFLOW_PYR_A_READY 被設置).

[ 編輯]

預估器

[ 編輯]

CvKalman

Kalman 濾波器狀態

typedef struct CvKalman
{
    int MP;                     /* 測量向量維數 */
    int DP;                     /* 狀態向量維數 */
    int CP;                     /* 控制向量維數 */

    /* 向后兼容字段 */
#if 1
    float* PosterState;         /* =state_pre->data.fl */
    float* PriorState;          /* =state_post->data.fl */
    float* DynamMatr;           /* =transition_matrix->data.fl */
    float* MeasurementMatr;     /* =measurement_matrix->data.fl */
    float* MNCovariance;        /* =measurement_noise_cov->data.fl */
    float* PNCovariance;        /* =process_noise_cov->data.fl */
    float* KalmGainMatr;        /* =gain->data.fl */
    float* PriorErrorCovariance;/* =error_cov_pre->data.fl */
    float* PosterErrorCovariance;/* =error_cov_post->data.fl */
    float* Temp1;               /* temp1->data.fl */
    float* Temp2;               /* temp2->data.fl */
#endif

    CvMat* state_pre;           /* 預測狀態 (x'(k)): 
                                    x(k)=A*x(k-1)+B*u(k) */
    CvMat* state_post;          /* 矯正狀態 (x(k)):
                                    x(k)=x'(k)+K(k)*(z(k)-H*x'(k)) */
    CvMat* transition_matrix;   /* 狀態傳遞矩陣 state transition matrix (A) */
    CvMat* control_matrix;      /* 控制矩陣 control matrix (B)
                                   (如果沒有控制,則不使用它)*/
    CvMat* measurement_matrix;  /* 測量矩陣 measurement matrix (H) */
    CvMat* process_noise_cov;   /* 過程噪聲協方差矩陣
                                        process noise covariance matrix (Q) */
    CvMat* measurement_noise_cov; /* 測量噪聲協方差矩陣
                                          measurement noise covariance matrix (R) */
    CvMat* error_cov_pre;       /* 先驗誤差計協方差矩陣
                                        priori error estimate covariance matrix (P'(k)):
                                     P'(k)=A*P(k-1)*At + Q)*/
    CvMat* gain;                /* Kalman 增益矩陣 gain matrix (K(k)):
                                    K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)*/
    CvMat* error_cov_post;      /* 后驗錯誤估計協方差矩陣
                                        posteriori error estimate covariance matrix (P(k)):
                                     P(k)=(I-K(k)*H)*P'(k) */
    CvMat* temp1;               /* 臨時矩陣 temporary matrices */
    CvMat* temp2;
    CvMat* temp3;
    CvMat* temp4;
    CvMat* temp5;
}
CvKalman;

結構 CvKalman 用來保存 Kalman 濾波器狀態。它由函數 cvCreateKalman 創建,由函數f cvKalmanPredict 和 cvKalmanCorrect 更新,由 cvReleaseKalman 釋放. 通常該結構是為標准 Kalman 所使用的 (符號和公式都借自非常優秀的 Kalman 教程 [Welch95]):

系統運動方程: x_k=A\cdot x_{k-1}+ B\cdot u_k+w_k
系統觀測方程: z_k=H\cdot x_k + v_k

其中:

xk(xk − 1) - 系統在時刻 k (k-1) 的狀態向量 (state of the system at the moment k (k-1))
zk - 在時刻 k 的系統狀態測量向量 (measurement of the system state at the moment k)
uk - 應用於時刻 k 的外部控制 (external control applied at the moment k)
wkvk 分別為正態分布的運動和測量噪聲
p(w) ~ N(0,Q)
p(v) ~ N(0,R),
即,
Q - 運動噪聲的相關矩陣,常量或變量
R - 測量噪聲的相關矩陣,常量或變量

對標准 Kalman 濾波器,所有矩陣: A, B, H, Q 和 R 都是通過 cvCreateKalman 在分配結構 CvKalman 時初始化一次。但是,同樣的結構和函數,通過在當前系統狀態鄰域中線性化擴展 Kalman 濾波器方程,可以用來模擬擴展 Kalman 濾波器,在這種情況下, A, B, H (也許還有 Q 和 R) 在每一步中都被更新。

[ 編輯]

CreateKalman

分配 Kalman 濾波器結構

CvKalman* cvCreateKalman( int dynam_params, int measure_params, int control_params=0 );
dynam_params
狀態向量維數
measure_params
測量向量維數
control_params
控制向量維數

函數 cvCreateKalman 分配 CvKalman 以及它的所有矩陣和初始參數

[ 編輯]

ReleaseKalman

釋放 Kalman 濾波器結構

void cvReleaseKalman( CvKalman** kalman );
kalman
指向 Kalman 濾波器結構的雙指針

函數 cvReleaseKalman 釋放結構 CvKalman 和里面所有矩陣

[ 編輯]

KalmanPredict

估計后來的模型狀態

const CvMat* cvKalmanPredict( CvKalman* kalman, const CvMat* control=NULL );
#define cvKalmanUpdateByTime cvKalmanPredict
kalman
Kalman 濾波器狀態
control
控制向量 (uk), 如果沒有外部控制 (control_params=0) 應該為 NULL

函數 cvKalmanPredict 根據當前狀態估計后來的隨機模型狀態,並存儲於 kalman->state_pre:

x'_k=A \cdot x_{k-1}+ B \cdot u_k
P'_k=A \cdot P_{k-1} \cdot A^T + Q,

其中

x'k 是預測狀態 (kalman->state_pre),
xk − 1 是前一步的矯正狀態 (kalman->state_post),應該在開始的某個地方初始化,即缺省為零向量,
uk 是外部控制(control 參數),
P'k 是先驗誤差相關矩陣 (kalman->error_cov_pre)
Pk − 1 是前一步的后驗誤差相關矩陣(kalman->error_cov_post),應該在開始的某個地方初始化,即缺省為單位矩陣.

函數返回估計得到的狀態值

[ 編輯]

KalmanCorrect

調節模型狀態

const CvMat* cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement );
#define cvKalmanUpdateByMeasurement cvKalmanCorrect
kalman
被更新的 Kalman 結構的指針
measurement
指向測量向量的指針,向量形式為 CvMat

函數 cvKalmanCorrect 在給定的模型狀態的測量基礎上,調節隨機模型狀態:

K_k=P'_k\cdot H^T \cdot (H \cdot P'_k \cdot H^T+R)^{-1}
x_k=x'_k+K_k \cdot (z_k-H \cdot x'_k)
P_k=(I-K_k \cdot H)\cdot P'_k

其中

zk - 給定測量(mesurement parameter)
Kk - Kalman "增益" 矩陣

函數存儲調節狀態到 kalman->state_post 中並且輸出時返回它。

例子. 使用 Kalman 濾波器跟蹤一個旋轉的點

#include "cv.h"
#include "highgui.h"
#include <math.h>

int main(int argc, char** argv)
{
    /* A matrix data */
    const float A[] = { 1, 1, 0, 1 };

    IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
    CvKalman* kalman = cvCreateKalman( 2, 1, 0 );
    /* state is (phi, delta_phi) - angle and angle increment */
    CvMat* state = cvCreateMat( 2, 1, CV_32FC1 );
    CvMat* process_noise = cvCreateMat( 2, 1, CV_32FC1 );
    /* only phi (angle) is measured */
    CvMat* measurement = cvCreateMat( 1, 1, CV_32FC1 );
    CvRandState rng;
    int code = -1;

    cvRandInit( &rng, 0, 1, -1, CV_RAND_UNI );

    cvZero( measurement );
    cvNamedWindow( "Kalman", 1 );

    for(;;)
    {
        cvRandSetRange( &rng, 0, 0.1, 0 );
        rng.disttype = CV_RAND_NORMAL;

        cvRand( &rng, state );

        memcpy( kalman->transition_matrix->data.fl, A, sizeof(A));
        cvSetIdentity( kalman->measurement_matrix, cvRealScalar(1) );//初始化帶尺度的單位矩陣 
        cvSetIdentity( kalman->process_noise_cov, cvRealScalar(1e-5) );
        cvSetIdentity( kalman->measurement_noise_cov, cvRealScalar(1e-1) );
        cvSetIdentity( kalman->error_cov_post, cvRealScalar(1));
        /* choose random initial state */
        cvRand( &rng, kalman->state_post );

        rng.disttype = CV_RAND_NORMAL;

        for(;;)
        {
            #define calc_point(angle)                                      \
                cvPoint( cvRound(img->width/2 + img->width/3*cos(angle)),  \
                         cvRound(img->height/2 - img->width/3*sin(angle)))

            float state_angle = state->data.fl[0];
            CvPoint state_pt = calc_point(state_angle);

            /* predict point position */
            const CvMat* prediction = cvKalmanPredict( kalman, 0 );
            float predict_angle = prediction->data.fl[0];
            CvPoint predict_pt = calc_point(predict_angle);
            float measurement_angle;
            CvPoint measurement_pt;

            cvRandSetRange( &rng, 0, sqrt(kalman->measurement_noise_cov->data.fl[0]), 0 );
            cvRand( &rng, measurement );

            /* generate measurement */
            cvMatMulAdd( kalman->measurement_matrix, state, measurement, measurement );

            measurement_angle = measurement->data.fl[0];
            measurement_pt = calc_point(measurement_angle);

            /* plot points */
            #define draw_cross( center, color, d )                                 \
                cvLine( img, cvPoint( center.x - d, center.y - d ),                \
                             cvPoint( center.x + d, center.y + d ), color, 1, 0 ); \
                cvLine( img, cvPoint( center.x + d, center.y - d ),                \
                             cvPoint( center.x - d, center.y + d ), color, 1, 0 )

            cvZero( img );
            draw_cross( state_pt, CV_RGB(255,255,255), 3 );
            draw_cross( measurement_pt, CV_RGB(255,0,0), 3 );
            draw_cross( predict_pt, CV_RGB(0,255,0), 3 );
            cvLine( img, state_pt, predict_pt, CV_RGB(255,255,0), 3, 0 );

            /* adjust Kalman filter state */
            cvKalmanCorrect( kalman, measurement );

            cvRandSetRange( &rng, 0, sqrt(kalman->process_noise_cov->data.fl[0]), 0 );
            cvRand( &rng, process_noise );
            cvMatMulAdd( kalman->transition_matrix, state, process_noise, state );

            cvShowImage( "Kalman", img );
            code = cvWaitKey( 100 );

            if( code > 0 ) /* break current simulation by pressing a key */
                break;
        }
        if( code == 27 ) /* exit by ESCAPE */
            break;
    }

    return 0;
}
[ 編輯]

CvConDensation

ConDensaation 狀態

typedef struct CvConDensation
{
    int MP;     // 測量向量的維數: Dimension of measurement vector
    int DP;     // 狀態向量的維數: Dimension of state vector
    float* DynamMatr;       // 線性動態系統矩陣:Matrix of the linear Dynamics system
    float* State;           // 狀態向量: Vector of State
    int SamplesNum;         // 粒子數: Number of the Samples
    float** flSamples;      // 粒子向量數組: array of the Sample Vectors
    float** flNewSamples;   // 粒子向量臨時數組: temporary array of the Sample Vectors
    float* flConfidence;    // 每個粒子的置信度(譯者注:也就是粒子的權值):Confidence for each Sample
    float* flCumulative;    // 權值的累計: Cumulative confidence
    float* Temp;            // 臨時向量:Temporary vector
    float* RandomSample;    // 用來更新粒子集的隨機向量: RandomVector to update sample set
    CvRandState* RandS;     // 產生隨機向量的結構數組: Array of structures to generate random vectors
} CvConDensation;

結構 CvConDensation中條件概率密度傳播(譯者注:粒子濾波的一種特例)(Con-Dens-Ation: 單詞 CONditional DENSity propagATION 的縮寫)跟蹤器的狀態。該算法描述可參考 http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/ISARD1/condensation.html

[ 編輯]

CreateConDensation

分配 ConDensation 濾波器結構

CvConDensation* cvCreateConDensation( int dynam_params, int measure_params, int sample_count );
dynam_params
狀態向量的維數
measure_params
測量向量的維數
sample_count
粒子數

函數 cvCreateConDensation 創建結構 CvConDensation 並且返回結構指針。

[ 編輯]

ReleaseConDensation

釋放 ConDensation 濾波器結構

void cvReleaseConDensation( CvConDensation** condens );
condens
要釋放結構的雙指針

函數 cvReleaseConDensation 釋放結構 CvConDensation (見cvConDensation) 並且清空所有事先被開辟的內存空間。

[ 編輯]

ConDensInitSampleSet

初始化 ConDensation 算法中的粒子集

void cvConDensInitSampleSet( CvConDensation* condens, CvMat* lower_bound, CvMat* upper_bound );
condens
需要初始化的結構指針
lower_bound
每一維的下界向量
upper_bound
每一維的上界向量

函數 cvConDensInitSampleSet 在指定區間內填充結構 CvConDensation 中的樣例數組。

[ 編輯]

ConDensUpdateByTime

估計下個模型狀態

void cvConDensUpdateByTime( CvConDensation* condens );
condens
要更新的結構指針

函數 cvConDensUpdateByTime 從當前狀態估計下一個隨機模型狀態。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM