C# 实现卡尔曼滤波

最近做一个人流量计数项目,需要对视频流中的人进行目标识别并进行目标跟踪。在图片流中识别出人员目标后需要预测下一帧中目标的位置,查阅各种资料后决定采用卡尔曼滤波法对目标的一位置进行预测。

网上也有别人实现的方法,但都不能直接运行,总是缺出类库或组件,我在别人实现的基础上进行了修改,增加了个矩阵运算类,将两个类文件加入项目后可以直接使用。

类文件一(KalmanFace.cs)

    public class KalmanFacade
    {
        #region inner class
        class KalmanFilter
        {
            ///


            /// 测量向量维数
            ///

            int MP;
            ///
            /// 状态向量维数
            ///

            int DP;
            ///
            /// 控制向量维数
            ///

            int CP; 
            ///
            /// 预测状态(x'(k)):x'(k)=A*x(k-1)+B*u(k)
            ///

            public Matrix state_pre;

            ///


            /// 修正状态 (x(k)):x(k)=x'(k)+K(k)*(z(k)-H*x'(k))
            ///

            public Matrix state_post;

            ///


            /// 状态转移矩阵 (A)
            ///

            public Matrix transition_matrix;
            ///
            /// 控制矩阵 (B)
            /// (如果没有控制,则不使用它)
            ///

            public Matrix control_matrix;
            ///
            /// 测量矩阵 (H)
            ///

            public Matrix measurement_matrix;
            ///
            /// 过程噪声协方差矩阵 (Q)
            ///

            public Matrix process_noise_cov;
            ///
            /// 测量噪声协方差矩阵 (R)
            ///

            public Matrix measurement_noise_cov;
            ///
            /// 先验误差估计协方差矩阵 (P'(k)):P'(k)=A*P(k-1)*At + Q)
            ///

            public Matrix error_cov_pre;
            ///
            /// 卡尔曼增益矩阵 (K(k)):K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)
            ///

            Matrix gain;
            ///
            /// 后验误差估计协方差矩阵 (P(k)):P(k)=(I-K(k)*H)*P'(k)
            ///

            Matrix error_cov_post;
            ///
            /// 临时矩阵
            ///

            Matrix tempMatrix1;
            Matrix tempMatrix2;
            Matrix tempMatrix3;
            Matrix tempMatrix4;
            Matrix tempMatrix5;

            public KalmanFilter()
            {
                MP = 1;
                DP = 2;
                CP = 0;
                state_pre = new Matrix(DP, 1);
                state_post = new Matrix(DP, 1);
                transition_matrix = new Matrix(DP, DP);
                transition_matrix.SetIdentity(1.0);
                transition_matrix[0, 1] = 1;
                process_noise_cov = new Matrix(DP, DP);
                process_noise_cov.SetIdentity(1.0);
                measurement_matrix = new Matrix(MP, DP);
                measurement_matrix.SetIdentity(1.0);
                measurement_noise_cov = new Matrix(MP, MP);
                measurement_noise_cov.SetIdentity(1.0);
                error_cov_pre = new Matrix(DP, DP);
                error_cov_post = new Matrix(DP, DP);
                error_cov_post.SetIdentity(1);
                gain = new Matrix(DP, MP);
                if (CP > 0)
                {
                    control_matrix = new Matrix(DP, CP);
                    control_matrix.Zero();
                }
                tempMatrix1 = new Matrix(DP, DP);
                tempMatrix2 = new Matrix(MP, DP);
                tempMatrix3 = new Matrix(MP, MP);
                tempMatrix4 = new Matrix(MP, DP);
                tempMatrix5 = new Matrix(MP, 1);
            }

            public Matrix Predict()
            {
                state_pre = transition_matrix * state_post;
                tempMatrix1 = transition_matrix * error_cov_post;
                Matrix at = transition_matrix.Transpose();
                error_cov_pre = tempMatrix1 * at + process_noise_cov;
                Matrix result = state_pre.DeepCopy();
                return result;
            }

            public Matrix Correct(Matrix measurement)
            {
                tempMatrix2 = measurement_matrix * error_cov_pre;
                Matrix ht = measurement_matrix.Transpose();
                tempMatrix3 = tempMatrix2 * ht + measurement_noise_cov;
                tempMatrix3 = tempMatrix3.Inverse();
                tempMatrix4 = tempMatrix3 * tempMatrix2;
                gain = tempMatrix4.Transpose();

                tempMatrix5 = measurement - (measurement_matrix * state_pre);
                state_post = gain * tempMatrix5 + state_pre;

                error_cov_post = error_cov_pre - (gain * tempMatrix2);

                Matrix result = state_post.DeepCopy();
                return result;
            }

            public Matrix AutoPredict(Matrix measurement)
            {
                Matrix result = Predict();

                Correct(measurement);

                return result;
            }
        }
        #endregion
        ///


        /// 卡尔曼滤波器构造器
        ///

        /// 状态值数组长度,预测下一位置状态值(x,y)数组长度为2
        public KalmanFacade(int valueItem)
        {
            if (valueItem <= 0)
            {
                throw new Exception("not enough value items!");
            }
            kmfilter = new KalmanFilter[valueItem];
            Random rand = new Random(1001);
            for (int i = 0; i < valueItem; i++)
            {
                kmfilter[i] = new KalmanFilter();
                kmfilter[i].state_post[0, 0] = rand.Next(10);
                kmfilter[i].state_post[1, 0] = rand.Next(10);
                //
                kmfilter[i].process_noise_cov.SetIdentity(1e-5);
                kmfilter[i].measurement_noise_cov.SetIdentity(1e-1);
            }
        }

        private KalmanFilter[] kmfilter = null;
        ///


        /// 根据现有状态值对下一组状态值进行预测
        ///

        /// 现有的状态值数组
        /// 预测的状态值结果数组
        ///
        public bool GetValue(double[] inValue, ref double[] outValue)
        {
            if (inValue.Length != kmfilter.Length || outValue.Length != kmfilter.Length)
            {
                return false;
            }

            Matrix[] measures = new Matrix[kmfilter.Length];

            for (int i = 0; i < kmfilter.Length; i++)
            {
                measures[i] = new Matrix(1,1);
                measures[i][0, 0] = inValue[i];
                outValue[i] = kmfilter[i].AutoPredict(measures[i])[0, 0];
            }
            return true;
        }

    }
 

类文件二(Matrix.cs)

    ///


    /// 矩阵类
    ///

    [Serializable]
    public class Matrix
    {
        public double[] element;
        private int rows = 0;
        private int cols = 0;
        ///
        /// 获取矩阵行数
        ///

        public int Rows
        {
            get
            {
                return rows;
            }
        }
        ///
        /// 获取矩阵列数
        ///

        public int Cols
        {
            get
            {
                return cols;
            }
        }
        ///
        /// 获取或设置第i行第j列的元素值
        ///

        /// 第i行
        /// 第j列
        /// 返回第i行第j列的元素值
        public double this[int i, int j]
        {
            get
            {
                if (i < Rows && j < Cols)
                {
                    return element[i * cols + j];
                }
                else
                {
                    throw new Exception("索引越界");
                }
            }
            set
            {
                element[i * cols + j] = value;
            }
        }

        public Matrix(int rows,int cols)
        {
            this.rows = rows;
            this.cols = cols;
            int count = 0;
            this.element = new double[Rows * Cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    element[count++] = 0;
                }
            }
        }
        ///


        /// 用二维数组初始化Matrix
        ///

        /// 二维数组
        public Matrix(double[][] m)
        {
            this.rows = m.GetLength(0);
            this.cols = m.GetLength(1);
            int count = 0;
            this.element = new double[Rows * Cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    element[count++] = m[i][j];
                }
            }
        }
        public Matrix(double[,] m)
        {
            this.rows = m.GetLength(0);
            this.cols = m.GetLength(1);
            this.element = new double[this.rows * this.cols];
            int count = 0;
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    element[count++] = m[i, j];
                }
            }
        }
        public Matrix(List> m)
        {
            this.rows = m.Count;
            this.cols = m[0].Count;
            this.element = new double[Rows * Cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    this[i, j] = m[i][j];
                }
            }
        }

        public void Zero()
        {
            int count = 0;
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    element[count++] = 0;
                }
            }
        }
        ///


        /// 设置单元矩阵
        ///

        /// 对角线值
        public void SetIdentity(double value)
        {
            for (int i = 0; i < rows; i++)
            {
                this[i, i] = value;
            }
        }
        #region 矩阵数学运算
        public static Matrix MAbs(Matrix a)
        {
            Matrix _thisCopy = a.DeepCopy();
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    _thisCopy[i, j] = Math.Abs(a[i, j]);
                }
            }
            return _thisCopy;
        }
        ///
        /// 矩阵相加
        ///

        /// 第一个矩阵,和b矩阵必须同等大小
        /// 第二个矩阵
        /// 返回矩阵相加后的结果
        public static Matrix operator +(Matrix a, Matrix b)
        {
            if (a.cols == b.cols && a.rows == b.rows)
            {
                double[,] res = new double[a.rows, a.cols];
                for (int i = 0; i < a.Rows; i++)
                {
                    for (int j = 0; j < a.Cols; j++)
                    {
                        res[i, j] = a[i, j] + b[i, j];
                    }
                }
                return new Matrix(res);
            }
            else
            {
                throw new Exception("两个矩阵行列不相等");
            }
        }
        ///
        /// 矩阵相减
        ///

        /// 第一个矩阵,和b矩阵必须同等大小
        /// 第二个矩阵
        /// 返回矩阵相减后的结果
        public static Matrix operator -(Matrix a, Matrix b)
        {
            if (a.cols == b.cols && a.rows == b.rows)
            {
                double[,] res = new double[a.rows, a.cols];
                for (int i = 0; i < a.Rows; i++)
                {
                    for (int j = 0; j < a.Cols; j++)
                    {
                        res[i, j] = a[i, j] - b[i, j];
                    }
                }
                return new Matrix(res);
            }
            else
            {
                throw new Exception("两个矩阵行列不相等");
            }
        }
        ///
        /// 对矩阵每个元素取相反数
        ///

        /// 二维矩阵
        /// 得到矩阵的相反数
        public static Matrix operator -(Matrix a)
        {
            Matrix res = a;
            for (int i = 0; i < a.rows; i++)
            {
                for (int j = 0; j < a.cols; j++)
                {
                    res.element[i * a.cols + j] = -res.element[i * a.cols + j];
                }
            }
            return res;
        }
        ///
        /// 矩阵相乘
        ///

        /// 第一个矩阵
        /// 第二个矩阵,这个矩阵的行要与第一个矩阵的列相等
        /// 返回相乘后的一个新的矩阵
        public static Matrix operator *(Matrix a, Matrix b)
        {
            if (a.cols == b.rows)
            {
                double[,] res = new double[a.rows, b.cols];
                for (int i = 0; i < a.rows; i++)
                {
                    for (int j = 0; j < b.cols; j++)
                    {
                        for (int k = 0; k < a.cols; k++)
                        {
                            res[i, j] += a[i, k] * b[k, j];
                        }
                    }
                }
                return new Matrix(res);
            }
            else
            {
                throw new Exception("两个矩阵行和列不等");
            }
        }
        ///
        /// 矩阵与数相乘
        ///

        /// 第一个矩阵
        /// 一个实数
        /// 返回相乘后的新的矩阵
        public static Matrix operator *(Matrix a, double num)
        {
            Matrix res = a;
            for (int i = 0; i < a.rows; i++)
            {
                for (int j = 0; j < a.cols; j++)
                {
                    res.element[i * a.cols + j] *= num;
                }
            }
            return res;
        }
        ///
        /// 矩阵转置
        ///

        /// 返回当前矩阵转置后的新矩阵
        public Matrix Transpose()
        {
            double[,] res = new double[cols, rows];
            for (int i = 0; i < cols; i++)
            {
                for (int j = 0; j < rows; j++)
                {
                    res[i, j] = this[j, i];
                }
            }
            return new Matrix(res);
        }
        ///
        /// 矩阵求逆
        ///

        /// 返回求逆后的新的矩阵
        public Matrix Inverse()
        {
            //最后原始矩阵并不变,所以需要深拷贝一份
            Matrix _thisCopy = this.DeepCopy();
            if (cols == rows && this.Determinant() != 0)
            {
                //初始化一个同等大小的单位阵
                Matrix res = _thisCopy.EMatrix();
                for (int i = 0; i < rows; i++)
                {
                    //首先找到第i列的绝对值最大的数,并将该行和第i行互换
                    int rowMax = i;
                    double max = Math.Abs(_thisCopy[i, i]);
                    for (int j = i; j < rows; j++)
                    {
                        if (Math.Abs(_thisCopy[j, i]) > max)
                        {
                            rowMax = j;
                            max = Math.Abs(_thisCopy[j, i]);
                        }
                    }
                    //将第i行和找到最大数那一行rowMax交换
                    if (rowMax != i)
                    {
                        _thisCopy.Exchange(i, rowMax);
                        res.Exchange(i, rowMax);

                    }
                    //将第i行做初等行变换,将第一个非0元素化为1
                    double r = 1.0 / _thisCopy[i, i];
                    _thisCopy.Exchange(i, -1, r);
                    res.Exchange(i, -1, r);
                    //消元
                    for (int j = 0; j < rows; j++)
                    {
                        //到本行后跳过
                        if (j == i)
                            continue;
                        else
                        {
                            r = -_thisCopy[j, i];
                            _thisCopy.Exchange(i, j, r);
                            res.Exchange(i, j, r);
                        }
                    }
                }
                return res;
            }
            else
            {
                throw new Exception("矩阵不是方阵无法求逆");
            }
        }
        #region 重载比较运算符
        public static bool operator <(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] >= b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator >(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] <= b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator <=(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] > b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator >=(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] < b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator !=(Matrix a, Matrix b)
        {
            bool issmall = true;
            issmall = ReferenceEquals(a, b);
            if (issmall) return issmall;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] == b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator ==(Matrix a, Matrix b)
        {
            bool issmall = true;
            issmall = ReferenceEquals(a, b);
            if (issmall) return issmall;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] != b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public override bool Equals(object obj)
        {
            Matrix b = obj as Matrix;
            return this == b;
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion
        public double Determinant()
        {
            if (cols == rows)
            {
                Matrix _thisCopy = this.DeepCopy();
                //行列式每次交换行,都需要乘以-1
                double res = 1;
                for (int i = 0; i < rows; i++)
                {
                    //首先找到第i列的绝对值最大的数
                    int rowMax = i;
                    double max = Math.Abs(_thisCopy[i, i]);
                    for (int j = i; j < rows; j++)
                    {
                        if (Math.Abs(_thisCopy[j, i]) > max)
                        {
                            rowMax = j;
                            max = Math.Abs(_thisCopy[j, i]);
                        }
                    }
                    //将第i行和找到最大数那一行rowMax交换,同时将单位阵做相同初等变换
                    if (rowMax != i)
                    {
                        _thisCopy.Exchange(i, rowMax);
                        res *= -1;
                    }
                    //消元
                    for (int j = i + 1; j < rows; j++)
                    {
                        double r = -_thisCopy[j, i] / _thisCopy[i, i];
                        _thisCopy.Exchange(i, j, r);
                    }
                }
                //计算对角线乘积
                for (int i = 0; i < rows; i++)
                {
                    res *= _thisCopy[i, i];
                }
                return res;
            }
            else
            {
                throw new Exception("不是行列式");
            }
        }
        #endregion
        #region 初等变换
        ///


        /// 初等变换:交换第r1和第r2行
        ///

        /// 第r1行
        /// 第r2行
        /// 返回交换两行后的新的矩阵
        public Matrix Exchange(int r1, int r2)
        {
            if (Math.Min(r2, r1) >= 0 && Math.Max(r1, r2) < rows)
            {
                for (int j = 0; j < cols; j++)
                {
                    double temp = this[r1, j];
                    this[r1, j] = this[r2, j];
                    this[r2, j] = temp;
                }
                return this;
            }
            else
            {
                throw new Exception("超出索引");
            }
        }
        ///
        /// 初等变换:将r1行乘以某个数加到r2行
        ///

        /// 第r1行乘以num
        /// 加到第r2行,若第r2行为负,则直接将r1乘以num并返回
        /// 某行放大的倍数
        ///
        public Matrix Exchange(int r1, int r2, double num)
        {
            if (Math.Min(r2, r1) >= 0 && Math.Max(r1, r2) < rows)
            {
                for (int j = 0; j < cols; j++)
                {
                    this[r2, j] += this[r1, j] * num;
                }
                return this;
            }
            else if (r2 < 0)
            {
                for (int j = 0; j < cols; j++)
                {
                    this[r1, j] *= num;
                }
                return this;
            }
            else
            {
                throw new Exception("超出索引");
            }
        }
        ///
        /// 得到一个同等大小的单位矩阵
        ///

        /// 返回一个同等大小的单位矩阵
        public Matrix EMatrix()
        {
            if (rows == cols)
            {
                double[,] res = new double[rows, cols];
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        if (i == j)
                            res[i, j] = 1;
                        else
                            res[i, j] = 0;
                    }
                }
                return new Matrix(res);
            }
            else
                throw new Exception("不是方阵,无法得到单位矩阵");
        }
        #endregion
        ///
        /// 深拷贝,仅仅将值拷贝给一个新的对象
        ///

        /// 返回深拷贝后的新对象
        public Matrix DeepCopy()
        {
            double[,] ele = new double[rows, cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    ele[i, j] = this[i, j];
                }
            }
            return new Matrix(ele);
        }

        public override string ToString()
        {
            string str = "";
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    str += this[i, j].ToString();
                    if (j != Cols - 1)
                        str += " ";
                    else if (i != Rows - 1)
                        str += Environment.NewLine;
                }
            }
            return str;
        }
    }
 

你可能感兴趣的:(c#,开发语言,后端)