目标跟踪之粒子滤波

基本思想

所谓粒子滤波就是指:通过寻找一组在状态空间中传播的随机样本来近似的表示概率密度函数,用样本均值代替积分运算,进而获得系统状态的最小方差估计的过程,这些样本被形象的称为“粒子”,故而叫粒子滤波。采用数学语言描述如下: 对于平稳的随机过程, 假定k - 1 时刻系统的后验概率密度为p ( xk-1 zk-1 ) , 依据一定原则选取n 个随机样本点, k 时刻获得测量信息后, 经过状态和时间更新过程, n 个粒子的后验概率密度可近似为p ( xk zk ) 。随着粒子数目的增加, 粒子的概率密度函数逐渐逼近状态的概率密度函数, 粒子滤波估计即达到了最优贝叶斯估计的效果。

粒子滤波算法摆脱了解决非线性滤波问题时随机量必须满足高斯分布的制约条件, 并在一定程度上解决了粒子数样本匮乏问题, 因此近年来该算法在许多领域得到成功应用。

贝叶斯滤波

动态系统的状态空间模型可描述为

其中f(),h()分别为状态转移方程与观测方程,xk为系统状态,yk为观测值,uk为过程噪声,vk为观测噪声。为了描述方便,用Xk=x0:k={x0,x1,…,xk}与Yk=y0:k={y0,y1,…,yk}分别表示0到k时刻所有的状态与观测值。在处理目标跟踪问题时,通常假设目标的状态转移过程服从一阶马尔可夫模型,即当前时刻的状态xk只与上一时刻的状态xk-1有关。另外一个假设为观测值相互独立,即观测值yk只与k时刻的状态xk有关。

贝叶斯滤波为非线性系统的状态估计问题提供了一种基于概率分布形式的解决方案。贝叶斯滤波将状态估计视为一个概率推理过程,即将目标状态的估计问题转换为利用贝叶斯公式求解后验概率密度p(Xk|Yk)或滤波概率密度p(xk|Yk),进而获得目标状态的最优估计。贝叶斯滤波包含预测和更新两个阶段,预测过程利用系统模型预测状态的先验概率密度,更新过程则利用最新的测量值对先验概率密度进行修正,得到后验概率密度。

假设已知k-1时刻的概率密度函数为p(xk-1|Yk-1),贝叶斯滤波的具体过程如下:

(1) 预测过程,由p(xk-1|Yk-1)得到p(xk|Yk-1):

p(xk,xk-1|Yk-1)=p(xk|xk-1,Yk-1)p(xk-1|Yk-1)       

当给定xk-1时,状态xk与Yk-1相互独立,因此

p(xk,xk-1|Yk-1)=p(xk|xk-1)p(xk-1|Yk-1)              

上式两端对xk-1积分,可得Chapman-Komolgorov方程

(2) 更新过程,由p(xk|Yk-1)得到p(xk|Yk):

获取k时刻的测量yk后,利用贝叶斯公式对先验概率密度进行更新,得到后验概率

假设yk只由xk决定,即

p(yk|xk,Yk-1)=p(yk|xk)                      

因此

                     

其中,p(yk|Yk-1)为归一化常数

               

贝叶斯滤波以递推的形式给出后验(或滤波)概率密度函数的最优解。目标状态的最优估计值可由后验(或滤波)概率密度函数进行计算。通常根据极大后验(MAP)准则或最小均方误差(MMSE)准则,将具有极大后验概率密度的状态或条件均值作为系统状态的估计值,即

                                                            

贝叶斯滤波需要进行积分运算,除了一些特殊的系统模型(如线性高斯系统,有限状态的离散系统)之外,对于一般的非线性、非高斯系统,贝叶斯滤波很难得到后验概率的封闭解析式。因此,现有的非线性滤波器多采用近似的计算方法解决积分问题,以此来获取估计的次优解。在系统的非线性模型可由在当前状态展开的线性模型有限近似的前提下,基于一阶或二阶Taylor级数展开的扩展Kalman滤波得到广泛应用。在一般情况下,逼近概率密度函数比逼近非线性函数容易实现。据此,Julier与Uhlmann提出一种Unscented Kalman滤波器,通过选定的sigma点来精确估计随机变量经非线性变换后的均值和方差,从而更好的近似状态的概率密度函数,其理论估计精度优于扩展Kalman滤波。获取次优解的另外一中方案便是基于蒙特卡洛模拟的粒子滤波器。

蒙特卡洛近似思想

蒙特卡洛积分是一项用随机釆样来估算积分值的技术,简单说就是以某事件出现的频率来指代该事件的概率。因此在滤波过程中,需要用到概率如P(x)的地方,一概对变量x采样,以大量采样及其相应的权值来近似表示P(x)。

然而,在计算机问世以前,随机试验却受到一定限制,这是因为要使计算结果的准确度足够高,需要进行的试验次数相当大。因此人们都认为随机试验要用人工进行冗长的计算,这实际上是不可能的。

随着电子计算机的出现,利用电子计算机可以实现大量的随机抽样试验,使得用随机试验方法解决实际问题才有了能。

它的基本思想是:为了求解数学、物理、工程技术以及生产管理等方面的问题,首先建立一个概率模型或随机过程,使它的参数等于问题的解,然后通过对模型或过程的观察或抽样试验来计算所求参数的统计特征,最后给出所求解的近似

值,而解的精确度可用估计值的标准误差来表示。 

粒子滤波算法的核心思想便是利用一系列随机样本的加权和表示后验概率密度,通过求和来近似积分操作。

重要性采样 (Importance Sampling)

这是一种蒙特卡洛方法(Monte Carlo)。在有限的采样次数内,尽量让采样点覆盖对积分贡献很大的点。该方法目的并不是用来产生一个样本的,而是求一个函数的定积分的,只是因为该定积分的求法是通过对另一个叫容易采集分布的随机采用得到的。

序贯重要性采样(Sequential Importance Sainpling,SIS)

在粒子滤波算法中重采样的基本思想是抛弃那些对估计系统后验概率密度权值较小的粒子,通过复制权值较大的粒子来代替它们,进行重釆样有多种方法,常见的有多项式重釆样、系统重采样、分层抽样、残差抽样等,目前最为常用的重采样方法就是序贯重要性釆样。

在基于重要性重采样的蒙特卡洛模拟方法中,估计后验滤波概率需要利用所有的观测数据,每次新的观测数据来到都需要重新计算整个状态序列的重要性权值。序贯重要性釆样作为粒子滤波的基础,它将统计学的序贯分析方法应用到蒙特卡洛方法中,其主要思想就是递归的计算重采样粒子,通过保留以前所有采样时刻的粒子状态以保持采样粒子的继承性,从而实现后验滤波概率密度的递归估计。

基于序贯蒙特卡洛模拟方法的粒子滤波算法存在采样粒子权值退化问题以及计算量过大的问题,在实际计算中,经过数次迭代,只有少数粒子的权值较大,其余粒子的权值较小甚至可以忽略不计,粒子权值的方差随着时间的推移而增大,状态空间中的有效粒子数减少,随着无效粒子数量的增加,使得大量的计算消耗在对估计后验滤波概率分布几乎不起作用的粒子上,使得计算量增大且估计性能下降。

SIS算法的具体步骤如下:
 

1.系统初始化
 

k = 0,随机提取N个样本点

并给采样粒子赋予相应的初始权值为



2.抽取N个样本

在时刻k=1,2,…,L通过随机釆样的方法从以下分布抽取N个样本

3.逐点计算对应的p(xk|xk-1)和p(zk|xk)


4.更新权值

该时刻的采样粒子点的权值按下式计算



3.粒子权值归一化



 

权值退化

粒子滤波的核心思想是系统随机釆样与重要性重釆样的相加,粒子滤波首先根据系统在t时刻的系统状态x(t)和系统的概率分布生成大量的采样,这些采样就称之为粒子,那么这些采样在状态空间中的分布实际上就是x(t)的概率分布了,其后根据系统状态转移方程就可以对每一个粒子得到一个预测粒子,所有的预测粒子就代表系统所涉及的参数化东西。在滤波的预估计阶段,随机进行粒子采样,采样完成后根据特征相似度计算每个粒子的重要性,并根据重要性赋予粒子相应的权值,因此粒子滤波方法较之蒙特卡洛方法计算量较小,但是这种方法严重依赖于对初始状态的估计,随着迭代算法的进行,在经过数次迭代后其粒子采样的分配权重的方差会随着时间的推移而不断增大,除少数粒子以外的其他所有粒子只具有微小的权值并最终趋向于0,而少数粒子的权值会变的越来越大,随着采样过程的继续,最终所产生的粒子只是最初一小部分粒子权值的衍生,采样粒子代表的系统就会失去多样性,而当前系统的后验概率密度分布情况不能够有效的表示,我们将其称之为权值退化问题。

由于采样粒子权值退化问题在基于序贯重要性采样的粒子滤波算法中广泛存在,在经过数次迭代之后,许多粒子的权值变得很小,大量的计算浪费在小权值的粒子上,从而影响系统效率。目前降低该问题影响的最有效方法是选择重要性函数和采用重采样方法

重要性函数的选择

在重要性概率密度函数选择中融入系统最新的观测信息,通过选取好的重要性概率密度函数来有效抑制退化问题。

重采样

通过对粒子及其相应权值表示的概率密度函数进行重新采样,形成一个新的粒子集,该粒子集构成后验密度离散近似的一个经验分布,在釆样总数保持不变的情况下,权值较大的样本被多次复制,从而实现重釆样过程,通过引入重釆样技术,增加了权值较大的粒子数,在一定程度上能够有效解决粒子权值退化问题。重采样过程是以牺牲系统鲁棒性和计算效率来解决粒子权值退化问题的,并不是所有状态下的粒子都需要进行重采样,因此,我们需要进一步研究粒子权值的退化程度如何进行准确度量,并对粒子是否需要重采样进行有效判断。

重新采样获得的样本可以认为是一系列独立同分布的样本,其权重是一样的,均设为1/N。

采样贫乏

由于包含了大量重复的粒子(这些粒子具有高权值被多次选中),重采样导致了粒子多样性的丧失,此类问题在小噪声的环境下更加突出。事实上如果系统噪声非常小的话,所有粒子会在几次迭代之后崩塌为一个单独的粒子。

经典粒子滤波算法步骤

1.初始化:

取k=0,按p(x0)抽取N个样本点,i=1,…,N。

2.重要性采样:

,其中i=1,…,N。

3.计算权值:

若采用一步转移后验状态分布,该式可简化为

4.归一化权值:

t=   

=/t

5.重采样:根据各自归一化权值的大小复制/舍弃样本,得到N个近似服从分布的样本。令=1/N,i=1,…,N。

6.输出结果:算法的输出是粒子集,用它可以近似表示后验概率和函数的期望

7.K=K+1,重复2步至6步。

粒子滤波其实质是利用一系列随机抽取的样本,也就是粒子,来替代状态的后验概率分布。当粒子的个数变得足够大时,通过这样的随机抽样方法就可以得到状态后验分布很好的近似。

 

<span style="font-size:18px;">function ParticleEx1 
 
% Particle filter example, adapted from Gordon, Salmond, and Smith paper. 
 
x = 0.1; % initial state 
Q = 1; % process noise covariance 
R = 1; % measurement noise covariance 
tf = 50; % simulation length 
 
N = 100; % number of particles in the particle filter 
 
xhat = x; 
P = 2; 
xhatPart = x; 
 
% Initialize the particle filter. 
for i = 1 : N 
    xpart(i) = x + sqrt(P) * randn; 
end 
 
xArr = [x]; 
yArr = [x^2 / 20 + sqrt(R) * randn]; 
xhatArr = [x]; 
PArr = [P]; 
xhatPartArr = [xhatPart]; 
 
close all; 
 
for k = 1 : tf 
    % System simulation 
    x = 0.5 * x + 25 * x / (1 + x^2) + 8 * cos(1.2*(k-1)) + sqrt(Q) * randn;%状态方程 
    y = x^2 / 20 + sqrt(R) * randn;%观测方程 
    % Extended Kalman filter 
    F = 0.5 + 25 * (1 - xhat^2) / (1 + xhat^2)^2; 
    P = F * P * F' + Q; 
    H = xhat / 10; 
    K = P * H' * (H * P * H' + R)^(-1); 
    xhat = 0.5 * xhat + 25 * xhat / (1 + xhat^2) + 8 * cos(1.2*(k-1));%预测 
    xhat = xhat + K * (y - xhat^2 / 20);%更新 
    P = (1 - K * H) * P; 
    % Particle filter 
    for i = 1 : N 
        xpartminus(i) = 0.5 * xpart(i) + 25 * xpart(i) / (1 + xpart(i)^2) + 8 * cos(1.2*(k-1)) + sqrt(Q) * randn; 
        ypart = xpartminus(i)^2 / 20; 
        vhat = y - ypart;%观测和预测的差 
        q(i) = (1 / sqrt(R) / sqrt(2*pi)) * exp(-vhat^2 / 2 / R); 
    end 
    % Normalize the likelihood of each a priori estimate. 
    qsum = sum(q); 
    for i = 1 : N 
        q(i) = q(i) / qsum;%归一化权重 
    end 
    % Resample. 
    for i = 1 : N 
        u = rand; % uniform random number between 0 and 1 
        qtempsum = 0; 
        for j = 1 : N 
            qtempsum = qtempsum + q(j); 
            if qtempsum >= u 
                xpart(i) = xpartminus(j); 
                break; 
            end 
        end 
    end 
    % The particle filter estimate is the mean of the particles. 
    xhatPart = mean(xpart); 
    % Plot the estimated pdf's at a specific time. 
    if k == 20 
        % Particle filter pdf 
        pdf = zeros(81,1); 
        for m = -40 : 40 
            for i = 1 : N 
                if (m <= xpart(i)) && (xpart(i) < m+1) 
                    pdf(m+41) = pdf(m+41) + 1; 
                end 
            end 
        end 
        figure; 
        m = -40 : 40; 
        plot(m, pdf / N, 'r'); 
        hold; 
        title('Estimated pdf at k=20'); 
        disp(['min, max xpart(i) at k = 20: ', num2str(min(xpart)), ', ', num2str(max(xpart))]); 
        % Kalman filter pdf 
        pdf = (1 / sqrt(P) / sqrt(2*pi)) .* exp(-(m - xhat).^2 / 2 / P); 
        plot(m, pdf, 'b'); 
        legend('Particle filter', 'Kalman filter'); 
    end 
    % Save data in arrays for later plotting 
    xArr = [xArr x]; 
    yArr = [yArr y]; 
    xhatArr = [xhatArr xhat]; 
    PArr = [PArr P]; 
    xhatPartArr = [xhatPartArr xhatPart]; 
end 
 
t = 0 : tf; 
 
%figure; 
%plot(t, xArr); 
%ylabel('true state'); 
 
figure; 
plot(t, xArr, 'b.', t, xhatArr, 'k-', t, xhatArr-2*sqrt(PArr), 'r:', t, xhatArr+2*sqrt(PArr), 'r:'); 
axis([0 tf -40 40]); 
set(gca,'FontSize',12); set(gcf,'Color','White');  
xlabel('time step'); ylabel('state'); 
legend('True state', 'EKF estimate', '95% confidence region');  
 
figure; 
plot(t, xArr, 'b.', t, xhatPartArr, 'k-'); 
set(gca,'FontSize',12); set(gcf,'Color','White');  
xlabel('time step'); ylabel('state'); 
legend('True state', 'Particle filter estimate');  
 
xhatRMS = sqrt((norm(xArr - xhatArr))^2 / tf); 
xhatPartRMS = sqrt((norm(xArr - xhatPartArr))^2 / tf); 
disp(['Kalman filter RMS error = ', num2str(xhatRMS)]); 
disp(['Particle filter RMS error = ', num2str(xhatPartRMS)]); </span>
 
  1. /** @file

  2. Definitions related to tracking with particle filtering

  3.  
  4. @author Rob Hess

  5. @version 1.0.0-20060307

  6. */

  7.  
  8. #ifndef PARTICLES_H

  9. #define PARTICLES_H

  10.  
  11.  
  12. /******************************* Definitions *********************************/

  13.  
  14. /* standard deviations for gaussian sampling in transition model */

  15. #define TRANS_X_STD 5.0

  16. #define TRANS_Y_STD 5.0

  17. #define TRANS_S_STD 0.001

  18.  
  19. /* autoregressive dynamics parameters for transition model */

  20. #define A1 2.0

  21. #define A2 -1.0

  22. #define B0 1.0000

  23.  
  24. /* number of bins of HSV in histogram */

  25. #define NH 10

  26. #define NS 10

  27. #define NV 10

  28.  
  29. /* max HSV values */

  30. #define H_MAX 360.0

  31. #define S_MAX 1.0

  32. #define V_MAX 1.0

  33.  
  34. /* low thresholds on saturation and value for histogramming */

  35. #define S_THRESH 0.1

  36. #define V_THRESH 0.2

  37.  
  38. /* distribution parameter */

  39. #define LAMBDA 20

  40.  
  41. #ifndef MIN

  42. # define MIN(a,b) ((a) > (b) ? (b) : (a))

  43. #endif

  44.  
  45. #ifndef MAX

  46. # define MAX(a,b) ((a) < (b) ? (b) : (a))

  47. #endif

  48.  
  49. //typedef unsigned char BYTE;

  50. class particle_filter

  51. {

  52. private:

  53.  
  54. typedef struct Rect

  55. {

  56. int leftupx;

  57. int leftupy;

  58. int width;

  59. int height;

  60. Rect(){}

  61. Rect(int X, int Y, int W, int H)

  62. :leftupx(X), leftupy(Y), width(W), height(H)

  63. {}

  64. }

  65. Rect;

  66.  
  67. struct Hsv

  68. {

  69. double H;//0-360

  70. double s;//0-1

  71. double v;//0-1

  72. };

  73.  
  74.  
  75. /**

  76. An HSV histogram represented by NH * NS + NV bins. Pixels with saturation

  77. and value greater than S_THRESH and V_THRESH fill the first NH * NS bins.

  78. Other, "colorless" pixels fill the last NV value-only bins.

  79. */

  80. typedef struct histogram {

  81. float histo[NH*NS + NV]; /**< histogram array */

  82. int n; /**< length of histogram array */

  83. ~histogram()

  84. {

  85. //if (this)

  86. // delete this;

  87. }

  88. } histogram;

  89.  
  90.  
  91. /******************************* Structures **********************************/

  92.  
  93. /**

  94. A particle is an instantiation of the state variables of the system

  95. being monitored. A collection of particles is essentially a

  96. discretization of the posterior probability of the system.

  97. */

  98. typedef struct particle {

  99. float x; /**< current x coordinate */

  100. float y; /**< current y coordinate */

  101. float s; /**< scale */

  102. float xp; /**< previous x coordinate */

  103. float yp; /**< previous y coordinate */

  104. float sp; /**< previous scale */

  105. float x0; /**< original x coordinate */

  106. float y0; /**< original y coordinate */

  107. int width; /**< original width of region described by particle */

  108. int height; /**< original height of region described by particle */

  109. histogram* histo; /**< reference histogram describing region being tracked */

  110. double w; /**< weight */

  111. particle()

  112. {

  113. s = 1;

  114. w = 0;

  115. }

  116. } particle;

  117. histogram** ref_histos;//

  118. unsigned int num_objects;

  119. Rect*target_rect_array;//

  120. unsigned int num_particles_for_each_object;

  121. particle** particles;

  122. Hsv*hsvimg;

  123. BYTE*RGBdata;

  124. unsigned int img_height;

  125. unsigned int img_width;

  126. bool isini;

  127. int current_frame;

  128. private:

  129.  
  130. void draw_point(BYTE*rgbdata, int centerX, int centerY, COLORREF color,int linewidth);

  131. void copy_partile(const particle &src, particle&dst)

  132. {

  133. dst.height = src.height;

  134. dst.histo = src.histo;//can be a problem memory leakage

  135. dst.s = src.s;

  136. dst.sp = src.sp;

  137. dst.w = src.w;

  138. dst.width = src.width;

  139. dst.x = src.x;

  140. dst.xp = src.xp;

  141. dst.x0 = src.x0;

  142. dst.y = src.y;

  143. dst.y0 = src.y0;

  144. dst.yp = src.yp;

  145.  
  146. }

  147.  
  148. /**************************** Function Prototypes ****************************/

  149. /**

  150. Creates an initial distribution of particles by sampling from a Gaussian

  151. window around each of a set of specified locations

  152.  
  153. @param regions an array of regions describing player locations around

  154. which particles are to be sampled

  155. @param histos array of histograms describing regions in \a regions

  156. @param n the number of regions in \a regions

  157. @param p the total number of particles to be assigned

  158.  
  159. @return Returns an array of \a p particles sampled from around regions in

  160. \a regions

  161. */

  162. particle**& init_distribution(Rect* regions, histogram** histos);

  163.  
  164.  
  165. /**

  166. Samples a transition model for a given particle

  167.  
  168. @param p a particle to be transitioned

  169. @param w video frame width

  170. @param h video frame height

  171. @param rng a random number generator from which to sample

  172.  
  173. @return Returns a new particle sampled based on <EM>p</EM>'s transition

  174. model

  175. */

  176. particle transition(particle p, int w, int h);

  177.  
  178.  
  179. /**

  180. Normalizes particle weights so they sum to 1

  181.  
  182. @param particles an array of particles whose weights are to be normalized

  183. @param n the number of particles in \a particles

  184. */

  185. void normalize_weights(particle* particles, int n);

  186.  
  187.  
  188. /**

  189. Re-samples a set of weighted particles to produce a new set of unweighted

  190. particles

  191.  
  192. @param particles an old set of weighted particles whose weights have been

  193. normalized with normalize_weights()

  194. @param n the number of particles in \a particles

  195.  
  196. @return Returns a new set of unweighted particles sampled from \a particles

  197. */

  198. particle* resample(particle* particles, int n);

  199.  
  200.  
  201. /**

  202. Compare two particles based on weight. For use in qsort.

  203.  
  204. @param p1 pointer to a particle

  205. @param p2 pointer to a particle

  206.  
  207. @return Returns -1 if the \a p1 has lower weight than \a p2, 1 if \a p1

  208. has higher weight than \a p2, and 0 if their weights are equal.

  209. */

  210. static int __cdecl particle_cmp(const void* p1,const void* p2);

  211.  
  212.  
  213. /**

  214. Displays a particle on an image as a rectangle around the region specified

  215. by the particle

  216.  
  217. @param img the image on which to display the particle

  218. @param p the particle to be displayed

  219. @param color the color in which \a p is to be displayed

  220. */

  221. //void display_particle(IplImage* img, particle p, CvScalar color);

  222.  
  223.  
  224.  
  225.  
  226. /**

  227. Calculates the histogram bin into which an HSV entry falls

  228.  
  229. @param h Hue

  230. @param s Saturation

  231. @param v Value

  232.  
  233. @return Returns the bin index corresponding to the HSV color defined by

  234. \a h, \a s, and \a v.

  235. */

  236. int histo_bin(float h, float s, float v);

  237.  
  238.  
  239. /**

  240. Calculates a cumulative histogram as defined above for a given array

  241. of images

  242.  
  243. @param imgs an array of images over which to compute a cumulative histogram;

  244. each must have been converted to HSV colorspace using bgr2hsv()

  245. @param n the number of images in imgs

  246.  
  247. @return Returns an un-normalized HSV histogram for \a imgs

  248. */

  249. histogram* calc_histogram(Hsv*img, Rect rec);

  250.  
  251.  
  252. /**

  253. Normalizes a histogram so all bins sum to 1.0

  254.  
  255. @param histo a histogram

  256. */

  257. void normalize_histogram(histogram* histo);

  258.  
  259.  
  260. /**

  261. Computes squared distance metric based on the Battacharyya similarity

  262. coefficient between histograms.

  263.  
  264. @param h1 first histogram; should be normalized

  265. @param h2 second histogram; should be normalized

  266.  
  267. @return Rerns a squared distance based on the Battacharyya similarity

  268. coefficient between \a h1 and \a h2

  269. */

  270. double histo_dist_sq(histogram* h1, histogram* h2);

  271.  
  272.  
  273. /**

  274. Computes the likelihood of there being a player at a given location in

  275. an image

  276.  
  277. @param img image that has been converted to HSV colorspace using bgr2hsv()

  278. @param r row location of center of window around which to compute likelihood

  279. @param c col location of center of window around which to compute likelihood

  280. @param w width of region over which to compute likelihood

  281. @param h height of region over which to compute likelihood

  282. @param ref_histo reference histogram for a player; must have been

  283. normalized with normalize_histogram()

  284.  
  285. @return Returns the likelihood of there being a player at location

  286. (\a r, \a c) in \a img

  287. */

  288. double likelihood(Hsv* img, int r, int c,

  289. int w, int h, histogram* ref_histo);

  290.  
  291.  
  292. /**

  293. Returns an image containing the likelihood of there being a player at

  294. each pixel location in an image

  295.  
  296. @param img the image for which likelihood is to be computed; should have

  297. been converted to HSV colorspace using bgr2hsv()

  298. @param w width of region over which to compute likelihood

  299. @param h height of region over which to compute likelihood

  300. @param ref_histo reference histogram for a player; must have been

  301. normalized with normalize_histogram()

  302.  
  303. @return Returns a single-channel, 32-bit floating point image containing

  304. the likelihood of every pixel location in \a img normalized so that the

  305. sum of likelihoods is 1.

  306. */

  307. double* likelihood_image(Hsv* img, int w, int h, histogram* ref_histo);

  308.  
  309.  
  310. /**

  311. Exports histogram data to a specified file. The file is formatted as

  312. follows (intended for use with gnuplot:

  313.  
  314.  
  315. Where n is the number of histogram bins and h_i, i = 1..n are

  316. floating point bin values

  317.  
  318. @param histo histogram to be exported

  319. @param filename name of file to which histogram is to be exported

  320.  
  321. @return Returns 1 on success or 0 on failure

  322. */

  323. int export_histogram(histogram* histo, char* filename);

  324.  
  325.  
  326.  
  327. /*

  328. Computes a reference histogram for each of the object regions defined by

  329. the user

  330.  
  331. @param frame video frame in which to compute histograms; should have been

  332. converted to hsv using bgr2hsv in observation.h

  333. @param regions regions of \a frame over which histograms should be computed

  334. @param n number of regions in \a regions

  335. @param export if TRUE, object region images are exported

  336.  
  337. @return Returns an \a n element array of normalized histograms corresponding

  338. to regions of \a frame specified in \a regions.

  339. */

  340. histogram** compute_ref_histos(Hsv* frame, Rect* regions, int n);

  341.  
  342.  
  343. public:

  344. particle_filter();

  345. ~particle_filter();

  346. void getHsvformRGBimg(BYTE*rgbdata, unsigned int W, unsigned int H);

  347. void get_target(RECT*target,int n);

  348. void track();

  349. void init();

  350. void track_single_frame();

  351.  
  352.  
  353. };

  354. #endif

 
  1. #include "particle_filter.h"

  2. #include<cstdlib>

  3. #include<time.h>

  4. using namespace std;

  5.  
  6. particle_filter::particle_filter()

  7. {

  8. ref_histos = NULL;

  9. time_t t;

  10. srand(time(&t));

  11. isini = true;

  12. current_frame = 0;

  13. }

  14.  
  15.  
  16. particle_filter::~particle_filter()

  17. {

  18. for (int i = 0; i < num_objects; i++)

  19. {

  20. free(particles[i]);

  21. free(ref_histos[i]);

  22. }

  23. free(particles);

  24. free(ref_histos);

  25. if (hsvimg)

  26. delete[]hsvimg;

  27. if (target_rect_array)

  28. delete[]target_rect_array;

  29. }

  30.  
  31.  
  32. double gaussrand()

  33. {

  34. static double V1, V2, S;

  35. static int phase = 0;

  36. double X;

  37.  
  38. if (phase == 0) {

  39. do {

  40. double U1 = (double)rand() / RAND_MAX;

  41. double U2 = (double)rand() / RAND_MAX;

  42.  
  43. V1 = 2 * U1 - 1;

  44. V2 = 2 * U2 - 1;

  45. S = V1 * V1 + V2 * V2;

  46. } while (S >= 1 || S == 0);

  47.  
  48. X = V1 * sqrt(-2 * log(S) / S);

  49. }

  50. else

  51. X = V2 * sqrt(-2 * log(S) / S);

  52.  
  53. phase = 1 - phase;

  54.  
  55. return X;

  56. }

  57.  
  58. /*************************** Function Definitions ****************************/

  59.  
  60. /*

  61. Creates an initial distribution of particles at specified locations

  62.  
  63. @param regions an array of regions describing player locations around

  64. which particles are to be sampled

  65. @param histos array of histograms describing regions in \a regions

  66. @param n the number of regions in \a regions

  67. @param p the total number of particles to be assigned

  68.  
  69. @return Returns an array of \a p particles sampled from around regions in

  70. \a regions

  71. */

  72. particle_filter::particle**&particle_filter::init_distribution(Rect* regions, histogram** histos)

  73. {

  74. //particle** particles;

  75.  
  76. float x, y;

  77. int i, j, width, height;

  78.  
  79. particles = (particle**)malloc(sizeof(particle*)*num_objects);

  80. for (int i = 0; i < num_objects; i++)

  81. particles[i] = (particle*)malloc(num_particles_for_each_object*sizeof(particle));

  82.  
  83. /* create particles at the centers of each of n regions */

  84. for (i = 0; i < num_objects; i++)

  85. {

  86. width = regions[i].width;

  87. height = regions[i].height;

  88. x = regions[i].leftupx + width / 2;

  89. y = regions[i].leftupy + height / 2;

  90. for (j = 0; j < num_particles_for_each_object; j++)

  91. {

  92. int xx = target_rect_array[i].leftupx + target_rect_array[i].width / 2 + target_rect_array[i].width* gaussrand();;//x;

  93. if (xx < 0)

  94. xx = 0;

  95. if (xx >= img_width)

  96. xx = img_width - 1;

  97. particles[i][j].x0 = particles[i][j].xp = particles[i][j].x = xx;

  98.  
  99. int yy = target_rect_array[i].leftupy + target_rect_array[i].height / 2 +target_rect_array[i].height* gaussrand();//y;

  100. if (yy < 0)

  101. yy = 0;

  102. if (yy >= img_height)

  103. yy = img_height - 1;

  104. particles[i][j].y0 = particles[i][j].yp = particles[i][j].y = yy;

  105.  
  106. particles[i][j].sp = particles[i][j].s = 1.0;

  107. particles[i][j].width = width;

  108. particles[i][j].height = height;

  109. particles[i][j].histo = calc_histogram(hsvimg, Rect(particles[i][j].x - width / 2,

  110. particles[i][j].y - height / 2, width, height));//histos[i];

  111. normalize_histogram(particles[i][j].histo);

  112. particles[i][j].w = 0;

  113. }

  114. }

  115.  
  116. return particles;

  117. }

  118.  
  119.  
  120.  
  121. /*

  122. Samples a transition model for a given particle

  123.  
  124. @param p a particle to be transitioned

  125. @param w video frame width

  126. @param h video frame height

  127. @param rng a random number generator from which to sample

  128.  
  129. @return Returns a new particle sampled based on <EM>p</EM>'s transition

  130. model

  131. */

  132. particle_filter::particle particle_filter::transition(particle p, int w, int h)

  133. {

  134. float x, y, s;

  135. particle pn;

  136. #define PI 3.1415926

  137.  
  138. //double tt = 3;

  139. // sample new state using second-order autoregressive dynamics

  140. int sign = rand() % 2 == 0 ? 1 : -1;

  141. x = A1 * (p.x - p.x0) + A2 * (p.xp - p.x0) +

  142. sign*0.05*(double(rand()) / RAND_MAX)*p.width*p.s + p.x0;//B0 * 1.0 / sqrt(2 * PI) / TRANS_X_STD*exp(-pow(double(rand()) / RAND_MAX / TRANS_X_STD, 2)) + p.x0;

  143. pn.x = MAX(0.0, MIN((float)w - 1.0, x));

  144. sign = rand() % 2 == 0 ? 1 : -1;

  145. y = A1 * (p.y - p.y0) + A2 * (p.yp - p.y0) +

  146. sign*0.05*(double(rand()) / RAND_MAX)*p.height*p.s + p.y0;//B0 * 1.0 / sqrt(2 * PI) / TRANS_Y_STD*exp(-pow(double(rand()) / RAND_MAX / TRANS_Y_STD, 2)) + p.y0;

  147. pn.y = MAX(0.0, MIN((float)h - 1.0, y));

  148. //s = A1 * (p.s - 1.0) + A2 * (p.sp - 1.0) +

  149. // B0 * 1.0 / sqrt(2 * PI) / TRANS_S_STD*exp(-pow(double(rand()) / RAND_MAX / TRANS_S_STD, 2)) + 1.0;

  150. //pn.s = MAX(0.1, s);

  151. pn.s = 1;

  152. pn.xp = p.x;

  153. pn.yp = p.y;

  154. pn.sp = p.s;

  155. pn.x0 = p.x0;

  156. pn.y0 = p.y0;

  157. pn.width = p.width;

  158. pn.height = p.height;

  159. pn.histo = p.histo;

  160. pn.w = 0;

  161. //assert(p.width == target_rect_array[0].width);

  162. return pn;

  163. }

  164.  
  165.  
  166.  
  167. /*

  168. Normalizes particle weights so they sum to 1

  169.  
  170. @param particles an array of particles whose weights are to be normalized

  171. @param n the number of particles in \a particles

  172. */

  173. void particle_filter::normalize_weights(particle* particles, int n)

  174. {

  175. double sum = 0;

  176. int i;

  177. double maxweight = 0;

  178. for (i = 0; i < n; i++)

  179. sum += particles[i].w;

  180. for (i = 0; i < n; i++)

  181. {

  182. particles[i].w /= sum;

  183. if (particles[i].w>maxweight)

  184. maxweight = particles[i].w;

  185. }

  186. }

  187.  
  188.  
  189.  
  190. /*

  191. Compare two particles based on weight. For use in qsort.

  192.  
  193. @param p1 pointer to a particle

  194. @param p2 pointer to a particle

  195.  
  196. @return Returns -1 if the \a p1 has lower weight than \a p2, 1 if \a p1

  197. has higher weight than \a p2, and 0 if their weights are equal.

  198. */

  199. int __cdecl particle_filter::particle_cmp(const void* p1, const void* p2)

  200. {

  201. particle* _p1 = (particle*)p1;

  202. particle* _p2 = (particle*)p2;

  203.  
  204. if (_p1->w > _p2->w)

  205. return -1;

  206. if (_p1->w < _p2->w)

  207. return 1;

  208. return 0;

  209. }

  210.  
  211.  
  212. /*

  213. Re-samples a set of particles according to their weights to produce a

  214. new set of unweighted particles

  215.  
  216. @param particles an old set of weighted particles whose weights have been

  217. normalized with normalize_weights()

  218. @param n the number of particles in \a particles

  219.  
  220. @return Returns a new set of unweighted particles sampled from \a particles

  221. */

  222. particle_filter::particle*particle_filter::resample(particle* particles, int n)

  223. {

  224. particle* new_particles;

  225. int i, j, np, k = 0;

  226.  
  227. qsort(particles, n, sizeof(particle), &particle_cmp);

  228. int nnn = 0.03*num_particles_for_each_object;

  229. int kk = 0;

  230. new_particles = (particle*)malloc(sizeof(particle)*n);

  231. int count = 0;

  232. int max_dis = (particles[0].height + particles[0].width);

  233. int cnt = 0;

  234. int maxnum = 0;

  235. for (i = 0; i < n; i++)

  236. {

  237. np = round(particles[i].w * n);

  238. //if (np <= 0)

  239. // np = 1;

  240. if (i == 0 && np < 30)

  241. np = 30;

  242. for (j = 0; j < np; j++)

  243. {

  244. //new_particles[k++] = particles[i];

  245. double dis = abs(particles[i].x - particles[0].x) + abs(particles[i].y - particles[0].y);

  246. if ( dis> max_dis/3)

  247. {

  248. copy_partile(particles[kk++%nnn], new_particles[k]);

  249. cnt++;

  250. }

  251. else

  252. copy_partile(particles[i], new_particles[k]);

  253. k++;

  254. if (k == n)

  255. goto exit;

  256. count++;

  257. }

  258. }

  259.  
  260. for (int i = k; i < n; i++)

  261. copy_partile(particles[kk++%nnn], new_particles[i]);

  262.  
  263. ///while (k < n)

  264. // new_particles[k++] = particles[0];

  265. exit:

  266. return new_particles;

  267. }

  268.  
  269.  
  270.  
  271. /*

  272. Displays a particle on an image as a rectangle around the region specified

  273. by the particle

  274.  
  275. @param img the image on which to display the particle

  276. @param p the particle to be displayed

  277. @param color the color in which \a p is to be displayed

  278. */

  279. /*void particle_filter::display_particle(IplImage* img, particle p, CvScalar color)

  280. {

  281. int x0, y0, x1, y1;

  282.  
  283. x0 = round(p.x - 0.5 * p.s * p.width);

  284. y0 = round(p.y - 0.5 * p.s * p.height);

  285. x1 = x0 + round(p.s * p.width);

  286. y1 = y0 + round(p.s * p.height);

  287.  
  288. //Rectangle(img, cvPoint(x0, y0), cvPoint(x1, y1), color, 1, 8, 0);

  289. }*/

  290.  
  291.  
  292. /*

  293. Calculates the histogram bin into which an HSV entry falls

  294.  
  295. @param h Hue

  296. @param s Saturation

  297. @param v Value

  298.  
  299. @return Returns the bin index corresponding to the HSV color defined by

  300. \a h, \a s, and \a v.

  301. */

  302. int particle_filter::histo_bin(float h, float s, float v)

  303. {

  304. int hd, sd, vd;

  305.  
  306. /* if S or V is less than its threshold, return a "colorless" bin */

  307. vd = MIN((int)(v * NV / V_MAX), NV - 1);

  308. if (s < S_THRESH || v < V_THRESH)

  309. return NH * NS + vd;

  310.  
  311. /* otherwise determine "colorful" bin */

  312. hd = MIN((int)(h * NH / H_MAX), NH - 1);

  313. sd = MIN((int)(s * NS / S_MAX), NS - 1);

  314. return sd * NH + hd;

  315. }

  316.  
  317. /*

  318. Calculates a cumulative histogram as defined above for a given array

  319. of images

  320.  
  321. @param img an array of images over which to compute a cumulative histogram;

  322. each must have been converted to HSV colorspace using bgr2hsv()

  323. @param n the number of images in imgs

  324.  
  325. @return Returns an un-normalized HSV histogram for \a imgs

  326. */

  327. particle_filter::histogram* particle_filter::calc_histogram(Hsv*img, Rect rec)

  328. {

  329. //IplImage* img;

  330. histogram* histo;

  331.  
  332. //correct window

  333. int leftup_X = rec.leftupx;

  334. int leftup_Y =rec.leftupy;

  335. if (leftup_X < 0)

  336. leftup_X = 0;

  337. if (leftup_X >= img_width - rec.width)

  338. leftup_X = img_width - rec.width - 1;

  339. if (leftup_Y < 0)

  340. leftup_Y = 0;

  341. if (leftup_Y >= img_height - rec.height)

  342. leftup_Y = img_height - rec.height - 1;

  343. Rect rect(leftup_X, leftup_Y, rec.width, rec.height);

  344.  
  345.  
  346.  
  347. float* hist;

  348. int i, r, c, bin;

  349.  
  350. int size = sizeof(histogram);

  351. histo = (histogram*)malloc(sizeof(histogram));

  352. histo->n = NH*NS + NV;

  353. hist = histo->histo;

  354. memset(hist, 0, histo->n * sizeof(float));

  355.  
  356. /* extract individual HSV planes from image */

  357.  
  358. /* increment appropriate histogram bin for each pixel */

  359. for (r = 0; r < rect.height; r++)

  360. for (c = 0; c < rect.width; c++)

  361. {

  362. bin = histo_bin( /*pixval32f( h, r, c )*/img[img_width*(rect.leftupy + r) + rect.leftupx + c].H,

  363. img[img_width*(rect.leftupy + r) + rect.leftupx + c].s,

  364. img[img_width*(rect.leftupy + r) + rect.leftupx + c].v);

  365. hist[bin] += 1;

  366. }

  367. return histo;

  368. }

  369.  
  370. /*

  371. Normalizes a histogram so all bins sum to 1.0

  372.  
  373. @param histo a histogram

  374. */

  375. void particle_filter::normalize_histogram(histogram* histo)

  376. {

  377. float* hist;

  378. float sum = 0, inv_sum;

  379. int i, n;

  380.  
  381. hist = histo->histo;

  382. n = histo->n;

  383.  
  384. /* compute sum of all bins and multiply each bin by the sum's inverse */

  385. for (i = 0; i < n; i++)

  386. sum += hist[i];

  387. inv_sum = 1.0 / sum;

  388. for (i = 0; i < n; i++)

  389. hist[i] *= inv_sum;

  390. }

  391.  
  392. /*

  393. Computes squared distance metric based on the Battacharyya similarity

  394. coefficient between histograms.

  395.  
  396. @param h1 first histogram; should be normalized

  397. @param h2 second histogram; should be normalized

  398.  
  399. @return Returns a squared distance based on the Battacharyya similarity

  400. coefficient between \a h1 and \a h2

  401. */

  402. double particle_filter::histo_dist_sq(histogram* h1, histogram* h2)

  403. {

  404. float* hist1, *hist2;

  405. double sum = 0;

  406. int i, n;

  407.  
  408. n = h1->n;

  409. hist1 = h1->histo;

  410. hist2 = h2->histo;

  411.  
  412. /*

  413. According the the Battacharyya similarity coefficient,

  414.  
  415. D = \sqrt{ 1 - \sum_1^n{ \sqrt{ h_1(i) * h_2(i) } } }

  416. */

  417. for (i = 0; i < n; i++)

  418. sum += sqrt(hist1[i] * hist2[i]);

  419. return 1.0 - sum;

  420. }

  421.  
  422.  
  423.  
  424. /*

  425. Computes the likelihood of there being a player at a given location in

  426. an image

  427.  
  428. @param img image that has been converted to HSV colorspace using bgr2hsv()

  429. @param r row location of center of window around which to compute likelihood

  430. @param c col location of center of window around which to compute likelihood

  431. @param w width of region over which to compute likelihood

  432. @param h height of region over which to compute likelihood

  433. @param ref_histo reference histogram for a player; must have been

  434. normalized with normalize_histogram()

  435.  
  436. @return Returns the likelihood of there being a player at location

  437. (\a r, \a c) in \a img

  438. */

  439. double particle_filter::likelihood(Hsv* img, int r, int c,

  440. int w, int h, histogram* ref_histo)

  441. {

  442. //IplImage* tmp;

  443. histogram* histo;

  444. float d_sq;

  445.  
  446. //correct window

  447. int leftup_X = c - w / 2;

  448. int leftup_Y = r - h / 2;

  449. if (leftup_X < 0)

  450. leftup_X = 0;

  451. if (leftup_X >= img_width - w)

  452. leftup_X = img_width - w - 1;

  453. if (leftup_Y < 0)

  454. leftup_Y = 0;

  455. if (leftup_Y >= img_height - h)

  456. leftup_Y = img_height - h - 1;

  457. Rect rec(leftup_X, leftup_Y, w, h);

  458. histo = calc_histogram(img, rec);

  459.  
  460. normalize_histogram(histo);

  461.  
  462. /* compute likelihood as e^{\lambda D^2(h, h^*)} */

  463. d_sq = histo_dist_sq(histo, ref_histo);

  464. free(histo);

  465. double re = exp(-LAMBDA * d_sq);

  466. return re;

  467. }

  468.  
  469.  
  470.  
  471. /*

  472. Returns an image containing the likelihood of there being a player at

  473. each pixel location in an image

  474.  
  475. @param img the image for which likelihood is to be computed; should have

  476. been converted to HSV colorspace using bgr2hsv()

  477. @param w width of region over which to compute likelihood

  478. @param h height of region over which to compute likelihood

  479. @param ref_histo reference histogram for a player; must have been

  480. normalized with normalize_histogram()

  481.  
  482. @return Returns a single-channel, 32-bit floating point image containing

  483. the likelihood of every pixel location in \a img normalized so that the

  484. sum of likelihoods is 1.

  485. */

  486. double* particle_filter::likelihood_image(Hsv* img, int w, int h, histogram* ref_histo)

  487. {

  488. double* l, *l2;

  489. double sum = 0;

  490. int i, j;

  491.  
  492. l = new double[img_height*img_width];

  493. for (i = 0; i < img_height; i++)

  494. for (j = 0; j < img_width; j++)

  495. { //setpix32f( l, i, j, likelihood( img, i, j, w, h, ref_histo ) );

  496. l[i*img_width + j] = likelihood(img, i, j, w, h, ref_histo);

  497. sum += l[i*img_width + j];

  498. }

  499.  
  500. for (i = 0; i < img_height; i++)

  501. for (j = 0; j < img_width; j++)

  502. {

  503. l[i*img_width + j] /= sum;

  504. }

  505. return l;

  506. }

  507.  
  508.  
  509.  
  510.  
  511.  
  512. /*

  513. Exports histogram data to a specified file. The file is formatted as

  514. follows (intended for use with gnuplot:

  515.  
  516. Where n is the number of histogram bins and h_i, i = 1..n are

  517. floating point bin values

  518.  
  519. @param histo histogram to be exported

  520. @param filename name of file to which histogram is to be exported

  521.  
  522. @return Returns 1 on success or 0 on failure

  523. */

  524. int particle_filter::export_histogram(histogram* histo, char* filename)

  525. {

  526. int i, n;

  527. float* h;

  528. FILE* file = fopen(filename, "w");

  529.  
  530. if (!file)

  531. return 0;

  532. n = histo->n;

  533. h = histo->histo;

  534. for (i = 0; i < n; i++)

  535. fprintf(file, "%d %f\n", i, h[i]);

  536. fclose(file);

  537. return 1;

  538. }

  539.  
  540.  
  541.  
  542. //RGBdata不需要排列成BGRBGR的格式,原始数据就行

  543. void particle_filter::getHsvformRGBimg(BYTE*RGBdata, unsigned int W, unsigned int H)

  544. {

  545. this->RGBdata = RGBdata;

  546. #define LINEWIDTH(bits) (((bits) + 31) / 32 * 4)

  547. int nSrcLine = LINEWIDTH(W * 24);

  548. if (isini)

  549. {

  550. isini = false;

  551. img_height = H;

  552. img_width = W;

  553. hsvimg = new Hsv[W*H];

  554. }

  555. else

  556. if (W != img_height || H != img_height)

  557. {

  558. delete[]hsvimg;

  559. hsvimg = new Hsv[W*H];

  560. img_height = H;

  561. img_width = W;

  562. }

  563. for (int i = 0; i < img_height; i++)

  564. for (int j = 0; j < img_width; j++)

  565. {

  566. float min, max,r,g,b;

  567. r = RGBdata[i*nSrcLine + j * 3 + 2];

  568. g = RGBdata[i*nSrcLine + j * 3 + 1];

  569. b = RGBdata[i*nSrcLine + j * 3 ];

  570. float delta;

  571. float tmp = min(r, g);

  572. min = min(tmp, b);

  573. tmp = max(r, g);

  574. max = max(tmp, b);

  575. //min = MIN(r, g, b);

  576. //max = MAX(r, g, b);

  577. hsvimg[img_width*i + j].v = max; // v

  578. delta = max - min;

  579.  
  580. if (max != 0)

  581. {

  582. hsvimg[img_width*i+j].s = delta / max; // s

  583. }

  584. else

  585. {

  586. // r = g = b = 0 // s = 0, v is undefined

  587. hsvimg[img_width*i + j].s = 0;

  588. //hsvimg[img_width*i + j].H = -1;

  589.  
  590. }

  591. if (max == min)

  592. {

  593. hsvimg[img_width*i + j].H = 0;

  594. }

  595. else if (r == max)

  596. {

  597. hsvimg[img_width*i + j].H = (g - b) / delta; // between yellow & magenta

  598. }

  599. else if (g == max)

  600. {

  601. hsvimg[img_width*i + j].H = 2 + (b - r) / delta; // between cyan & yellow

  602. }

  603. else

  604. {

  605. hsvimg[img_width*i + j].H = 4 + (r - g) / delta; // between magenta & cyan

  606. }

  607.  
  608. hsvimg[img_width*i + j].H *= 60; // degrees

  609.  
  610. if (hsvimg[img_width*i + j].H < 0)

  611. {

  612. hsvimg[img_width*i + j].H += 360;

  613. }

  614. if (hsvimg[img_width*i + j].H > 360)

  615. {

  616. hsvimg[img_width*i + j].H = hsvimg[img_width*i + j].H - 360;

  617. }

  618. }

  619. }

  620.  
  621.  
  622.  
  623.  
  624. particle_filter::histogram** particle_filter::compute_ref_histos(Hsv* frame, Rect* regions, int n)

  625. {

  626. histogram** histos = (histogram**)malloc(n * sizeof(histogram*));

  627. int i;

  628. /* extract each region from frame and compute its histogram */

  629. for (i = 0; i < n; i++)

  630. {

  631. histos[i] = calc_histogram(frame, regions[i]);

  632. normalize_histogram(histos[i]);

  633. }

  634. return histos;

  635. }

  636.  
  637. void particle_filter::init()

  638. {

  639. num_particles_for_each_object = 500;

  640. ref_histos = compute_ref_histos(hsvimg, target_rect_array, num_objects);

  641. init_distribution(target_rect_array, ref_histos);

  642.  
  643. }

  644.  
  645. void particle_filter::track_single_frame()

  646. {

  647. current_frame++;

  648. for (int i = 0; i < num_objects; i++)

  649. {/* perform prediction and measurement for each particle */

  650. for (int j = 0; j < num_particles_for_each_object; j++)

  651. {

  652. particles[i][j] = transition(particles[i][j], img_width, img_height);

  653. double s = particles[i][j].s;

  654. //assert(int(particles[i][j].width * s) == target_rect_array[i].width);

  655. //assert(int(particles[i][j].height * s) == target_rect_array[i].height);

  656. //if (particles[i][j].width != target_rect_array[i].width)

  657. // particles[i][j].width = target_rect_array[i].width;

  658. //if (particles[i][j].height != target_rect_array[i].height)

  659. // particles[i][j].height = target_rect_array[i].height;

  660. particles[i][j].w = likelihood(hsvimg,

  661. round(particles[i][j].y),//center of window

  662. round(particles[i][j].x),//center of window

  663. round(particles[i][j].width * s),

  664. round(particles[i][j].height * s),

  665. ref_histos[i]);

  666.  
  667. }

  668.  
  669. /* normalize weights and resample a set of unweighted particles */

  670. normalize_weights(particles[i], num_particles_for_each_object);

  671. particle* new_particles = resample(particles[i], num_particles_for_each_object);

  672. free(particles[i]);

  673. particles[i] = new_particles;

  674. /* display all particles if requested */

  675. qsort(particles[i], num_particles_for_each_object, sizeof(particle), &particle_cmp);

  676.  
  677. //display result

  678. COLORREF color = RGB(255, 255, 255);

  679. for (int j = 0; j < num_particles_for_each_object; j++)

  680. {

  681. draw_point(this->RGBdata, particles[i][j].x, particles[i][j].y, color, 5);

  682. }

  683. color = RGB(0, 255, 0);

  684. draw_point(this->RGBdata, particles[i][0].x, particles[i][0].y, color, 15);

  685.  
  686. if (current_frame % 2 == 0)

  687. // init_distribution(target_rect_array, ref_histos);

  688. //update model

  689. {

  690. double s = particles[i][0].s;

  691. int leftup_X = particles[i][0].x - particles[i][0].width*s / 2;

  692. int leftup_Y = particles[i][0].y - particles[i][0].height*s / 2;

  693. if (leftup_X < 0)

  694. leftup_X = 0;

  695. if (leftup_X >= img_width - particles[i][0].width*s)

  696. leftup_X = img_width - particles[i][0].width*s - 1;

  697. if (leftup_Y < 0)

  698. leftup_Y = 0;

  699. if (leftup_Y >= img_height - particles[i][0].height*s)

  700. leftup_Y = img_height - particles[i][0].height*s - 1;

  701. Rect rec(leftup_X, leftup_Y, particles[i][0].width*s, particles[i][0].height*s);

  702.  
  703. histogram*newhist = calc_histogram(hsvimg, rec);

  704. normalize_histogram(newhist);

  705. //delete[]ref_histos[i];

  706. for (int j = 0; j < ref_histos[i]->n; j++)

  707. ref_histos[i]->histo[j] = newhist->histo[j];

  708. delete newhist;

  709. }

  710. }

  711.  
  712. }

  713.  
  714. void particle_filter::draw_point(BYTE*rgbdata, int centerX, int centerY, COLORREF clo, int linewidth)

  715. {

  716. assert(rgbdata);

  717. //#define LINEWIDTH(bits) (((bits) + 31) / 32 * 4)

  718. int nSrcLine = LINEWIDTH(img_width * 24);

  719. for (int j = -linewidth; j < linewidth + 1; j++)

  720. {

  721. if (centerX + j >= 0 && centerX + j < img_width)

  722. {

  723. rgbdata[centerY*nSrcLine + 3 * (centerX + j)] = GetBValue(clo);

  724. rgbdata[centerY*nSrcLine + 3 * (centerX + j) + 1] = GetGValue(clo);

  725. rgbdata[centerY*nSrcLine + 3 * (centerX + j) + 2] = GetRValue(clo);

  726. rgbdata[(centerY-1)*nSrcLine + 3 * (centerX + j)] = GetBValue(clo);

  727. rgbdata[(centerY-1)*nSrcLine + 3 * (centerX + j) + 1] = GetGValue(clo);

  728. rgbdata[(centerY-1)*nSrcLine + 3 * (centerX + j) + 2] = GetRValue(clo);

  729. }

  730. }

  731. for (int j = -linewidth; j < linewidth + 1; j++)

  732. {

  733. if (centerY + j >= 0 && centerY + j < img_height)

  734. {

  735. rgbdata[(centerY + j)*nSrcLine + 3 * centerX] = GetBValue(clo);

  736. rgbdata[(centerY + j)*nSrcLine + 3 * centerX + 1] = GetGValue(clo);

  737. rgbdata[(centerY + j)*nSrcLine + 3 * centerX + 2] = GetRValue(clo);

  738. rgbdata[(centerY + j)*nSrcLine + 3 * centerX-3] = GetBValue(clo);

  739. rgbdata[(centerY + j)*nSrcLine + 3 * centerX -2] = GetGValue(clo);

  740. rgbdata[(centerY + j)*nSrcLine + 3 * centerX -1] = GetRValue(clo);

  741. }

  742. }

  743. }

  744.  
  745. void particle_filter::get_target(RECT*target,int n)

  746. {

  747. assert(target);

  748. num_objects = n;

  749. target_rect_array = new Rect[n];

  750. for (int i = 0; i < n; i++)

  751. {

  752. target_rect_array[i].leftupy = target[i].top;

  753. target_rect_array[i].leftupx = target[i].left;

  754. target_rect_array[i].width = target[i].right-target[i].left;

  755. target_rect_array[i].height = target[i].bottom - target[i].top;

  756. }

  757.  
  758. }

  759.  

下面是我实现的跟踪结果,白色十字代表粒子,绿色大十字代表目标最可能的位置。

如何理解 重要性采样(importance sampling)

 Particle Filter Tutorial 粒子滤波:从推导到应用

粒子滤波小结

[CODE]基于粒子滤波的跟踪算法 Particle Filter Object Tracking 

发布了39 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34763204/article/details/85114267