OpenCV3之卡尔曼滤波KalmanFilter例子魔改代码

文章目录


OpenCV3之卡尔曼滤波KalmanFilter原理

魔改例子
在这里插入图片描述

#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
 
/** @brief 计算圆周上的点相对窗口的坐标值 = 中心点 + 圆周上的点相对圆心

@param center 中心点
@param R 半径
@param angle 角度,因为坐标原点在左上角,角度是逆时针的(和通常的极坐标系顺时针的相反),所以sin前有个负号
 */ 
Point calcPoint(Point2f center, double R, double angle)
{
    angle = angle / 180.0 * 3.1415926;
    return center + Point2f( (float)cos(angle), (float)-sin(angle) ) *(float)R;
}

/** @brief 画X形十字线,通过中心点和半长计算四个顶点的坐标

@param img 要作画的图像.
@param center 中心点.
@param d 一半长.
@param color 颜色.
 */ 
void drawCross(const Mat & img, Point center, int d ,const Scalar & color){
    line( img, Point( center.x - d, center.y - d ),Point( center.x + d, center.y + d ), color, 4);
    line( img, Point( center.x + d, center.y - d ),Point( center.x - d, center.y + d ), color, 5);
}


 
int main(int, char**)
{
    Mat img(800, 800, CV_8UC3);
    
    /** @brief 创建卡尔曼滤波器对象KF.
    
    @param dynamParams 2,状态向量的维度,二维列向量(角度,△角度)
    @param measureParams 1,测量向量的维度,一维列向量(角度)
    @param controlParams 0,控制向量的维度  
     */ 
    KalmanFilter KF(2, 1, 0);



    /* 定义三个列向量:状态向量Xk(state)、测量向量Zk(measurement)和控制向量Uk(control) */

    // 定义状态向量Xk(state):不用它的值,所以不用初始化

    // 定义测量向量Zk(measurement)
    // for循环中需要传入其测量值,所以初始化
    Mat measurement = Mat::zeros(1, 1, CV_32F);

    // 控制向量Uk(control)简单实例就不考虑了



    /* 初始化三个矩阵:状态转移矩阵Ak(transitionMatrix),控制矩阵Bk(controlMatrix)和测量矩阵Hk(measurementMatrix) */
    
    // 初始化状态转移矩阵Ak(transitionMatrix):定值
    KF.transitionMatrix = (Mat_<float>(2, 2) << 1, 1, 0, 1);

    // 初始化测量矩阵Hk(measurementMatrix):单位矩阵化
    setIdentity(KF.measurementMatrix);
    
    // 控制向量都没有,控制矩阵Bk(controlMatrix)更没有。


    
    /* 两个估计的状态向量:先验估计的状态向量(statePre)和后验估计的状态向量P(k-1|k-1)(statePost) */

    // 先验估计的状态向量(statePre)第一次循环完在函数predict中就自己初始化了

    // 初始化后验估计的状态向量P(statePost):
    randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));



	/* 定义两个噪声:系统噪声Wk和测量噪声Vk */
    
    // 定义系统噪声Wk:二维列向量 
    Mat processNoise(2, 1, CV_32F);

    // 测量噪声Vk之后再说

    

    /* 两个噪声的协方差矩阵: 系统噪声的协方差矩阵Qk(processNoiseCov)和测量噪声的协方差矩阵Rk(measurementNoiseCov)*/

    // 系统噪声的协方差矩阵Qk(processNoiseCov)
    setIdentity(KF.processNoiseCov, Scalar::all(1e-5));

    // 测量噪声的协方差矩阵Rk(measurementNoiseCov)
    setIdentity(KF.measurementNoiseCov, Scalar::all(1e-5));



    /** @brief 初始化系统噪声
    不加噪声的话就是匀速圆周运动,加了点噪声类似匀速圆周运动,因为噪声的原因,运动方向可能会改变
    */ 
    randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));



    /* 两个错误估计的协方差矩阵: 后验错误估计的协方差矩阵P(errorCovPost)和*/ 
    
    //  errorCovPost 后验错误估计的协方差矩阵P
    setIdentity(KF.errorCovPost, Scalar::all(1));

    // errorCovPre 先验错误估计的协方差矩阵P之后再说

    

    /* 圆周运动的设定 */
    
    // center图像中心点
    Point2f center(img.cols*0.5f, img.rows*0.5f);

    // 半径
    float R = img.cols/3.f;

    
    
    // 退出waitKey()的返回值
    char code = (char)-1;


    
    for(;;)
    {
        // 清零画布
        img = Scalar::all(0);



        /* 上一次的点 */

        // 上一次的点的角度stateAngle:取状态向量state的第一个值,即角度
        double lastAngle = KF.statePost.at<float>(0);

        // 上一次的点的坐标statePt:(在圆周上)相对Mat画布的点。 
        Point lastPt = calcPoint(center, R, lastAngle);



        // 计算预测值
        KF.predict();
        


        /* 预测点 */

        // 预测点的角度predictAngle:取预测值prediction的第一个值,即角度
        double predictAngle = KF.statePre.at<float>(0);

        // 预测点的坐标predictPt:(在圆周上)相对Mat画布的点。
        Point predictPt = calcPoint(center, R, predictAngle);


        /* 测量点 */

        // 初始化测量向量Zk(measurement):随机值;然后和上一次的测量值加起来
        // 表示每次的测量值都不一样,物体在移动
        measurement += Scalar(theRNG().uniform(10.0, 40.0));

        // 测量点的角度measAngle:取预测值measurement的第一个值,即角度
        double measAngle = measurement.at<float>(0);

        // 测量点的坐标measPt:(在圆周上)相对Mat画布的点。
        Point measPt = calcPoint(center, R, measAngle);
        


        // 融合更新
        KF.correct(measurement);

        
        
        // 最优点的角度measAngle:取预测值measurement的第一个值,即角度
        double optimalAngle = KF.statePost.at<float>(0);

        // 测量点的坐标measPt:(在圆周上)相对Mat画布的点。
        Point optimalPt = calcPoint(center, R, optimalAngle);



        /* 画 */
        // 轨道
        circle(img, center, R, Scalar::all(70), 1);
        // 上一个的点(白色)
        drawCross( img , lastPt,  3 ,Scalar(255,255,255));
        // 测量点(红色)
        drawCross( img , measPt, 3 ,Scalar(0,0,255));
        // 预测点(绿色)
        drawCross( img , predictPt, 10 , Scalar(0,255,0));
        // 最优点(蓝色)
        drawCross( img , optimalPt, 10 , Scalar(255,0,0));
        // 测量点到预测点
        line( img, measPt, predictPt, Scalar(0,255,0), 2);
        // 测量点到最优点
        line( img, measPt, optimalPt, Scalar(255,0,0), 2);
        

        // cout << "角度:\n";
        // cout << lastAngle << endl;
        // cout << measAngle << endl;
        // cout << predictAngle << endl;
        // cout << optimalAngle << endl;


        imshow( "Kalman", img );
        code = (char)waitKey(400);

        
        if( code == 27 || code == 'q' || code == 'Q' )
            break;
    }
 
    return 0;
}
  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Python和OpenCV实现卡尔曼滤波的示例代码: ```python import numpy as np import cv2 # 初始化卡尔曼滤波kalman = cv2.KalmanFilter(4, 2) kalman.measurementMatrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0]], np.float32) kalman.transitionMatrix = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32) kalman.processNoiseCov = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32) * 0.03 kalman.measurementNoiseCov = np.array([[1, 0], [0, 1]], np.float32) * 0.1 # 初始化视频捕捉 cap = cv2.VideoCapture(0) while True: # 读取一帧 ret, frame = cap.read() # 对帧进行预处理 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (5, 5), 0) # 检测边缘 edges = cv2.Canny(gray, 50, 150, apertureSize=3) # 检测直线 lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10) # 如果检测到直线 if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] # 使用卡尔曼滤波器估计下一帧的线段 prediction = kalman.predict() measurement = np.array([[np.float32(x1)], [np.float32(y1)]]) kalman.correct(measurement) # 绘制估计线段 x1p, y1p, x2p, y2p = np.int32(prediction) cv2.line(frame, (x1p, y1p), (x2p, y2p), (0, 255, 0), 2) # 显示结果 cv2.imshow('frame', frame) # 按下Esc键退出 if cv2.waitKey(1) == 27: break # 清理 cap.release() cv2.destroyAllWindows() ``` 这段代码使用OpenCV捕获实时视频流,并使用卡尔曼滤波器对检测到的直线进行估计。卡尔曼滤波器的参数在初始化时设置。首先,我们设置卡尔曼滤波器的状态向量和观测向量的维数(在本例中为4和2)。然后,我们设置测量矩阵、转移矩阵和过程噪声协方差矩阵。最后,我们设置测量噪声协方差矩阵。在每一帧中,我们使用卡尔曼滤波器来估计下一帧的线段,并绘制估计线段。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值