中值积分的对比实验(2)

欧拉积分和中值积分的对比实验

仿真模拟进行对比,构建一个刚体运动,运动的模型如下:

在运行过程中,出现的问题是:

mkdir build
cd build
camke …
make
cd …/bin
./data_gen

make过程出错,

[ 20%] Building CXX object CMakeFiles/data_gen.dir/main/gener_alldata.cpp.o
[ 40%] Building CXX object CMakeFiles/data_gen.dir/src/param.cpp.o
[ 60%] Building CXX object CMakeFiles/data_gen.dir/src/utilities.cpp.o
[ 80%] Building CXX object CMakeFiles/data_gen.dir/src/imu.cpp.o
/home/wpf/SLAM/vio/VIOLearning_Note_Code-master(1)/VIOLearning_Note_Code-master/ch2/vio_data_simulation-master/src/imu.cpp: In member function ‘void IMU::addIMUnoise(MotionData&)’:
/home/wpf/SLAM/vio/VIOLearning_Note_Code-master(1)/VIOLearning_Note_Code-master/ch2/vio_data_simulation-master/src/imu.cpp:56:10: error: ‘random_device’ is not a member of ‘std’

解决办法,在包含的该函数的文件中,添加头文件即可

另外一个解决办法是包含万能的头文件:

#include<bits/stdc++.h>

即可完成代码的编译。

代码的注释和理解

#include "imu.h"
#include "utilities.h"
#include<bits/stdc++.h>

// euler2Rotation:   body frame to interitail frame,对应的变换矩阵
Eigen::Matrix3d euler2Rotation( Eigen::Vector3d  eulerAngles)
{
    double roll = eulerAngles(0);
    double pitch = eulerAngles(1);
    double yaw = eulerAngles(2);

    double cr = cos(roll); double sr = sin(roll);
    double cp = cos(pitch); double sp = sin(pitch);
    double cy = cos(yaw); double sy = sin(yaw);
//取逆,获得从body系到惯性系
    Eigen::Matrix3d RIb;
    RIb<< cy*cp ,   cy*sp*sr - sy*cr,   sy*sr + cy* cr*sp,
            sy*cp,    cy *cr + sy*sr*sp,  sp*sy*cr - cy*sr,
            -sp,         cp*sr,           cp*cr;
    return RIb;
}
//欧拉角速度到body系的变换矩阵
Eigen::Matrix3d eulerRates2bodyRates(Eigen::Vector3d eulerAngles)
{
    double roll = eulerAngles(0);
    double pitch = eulerAngles(1);

    double cr = cos(roll); double sr = sin(roll);
    double cp = cos(pitch); double sp = sin(pitch);

    Eigen::Matrix3d R;
    R<<  1,   0,    -sp,
            0,   cr,   sr*cp,
            0,   -sr,  cr*cp;

    return R;
}

//初始化操作,将输入参数p赋值给param
IMU::IMU(Param p): param_(p)
{
    gyro_bias_ = Eigen::Vector3d::Zero();
    acc_bias_ = Eigen::Vector3d::Zero();
}
//添加IMU噪声参数,
void IMU::addIMUnoise(MotionData& data)
{
/*
	要得到一个我们最常需要的、符合一定分布规律的且随机质量较高的随机数,我们要做的是:
	1定义random_device对象(rd)
	2选择随机引擎(默认、线性、梅森、斐波那契)的实现类(默认),将random_device的随机结果(rd)传入作为种子
*/
    std::random_device rd;//生成一个种子
    std::default_random_engine generator_(rd());//创建一个随机引擎,以上述为种子
    std::normal_distribution<double> noise(0.0, 1.0);//正态分布模板类,均值为0,方差为1的分布 

    Eigen::Vector3d noise_gyro(noise(generator_),noise(generator_),noise(generator_));//陀螺仪噪声
//陀螺仪方差乘以3x3单位阵,陀螺仪3个方向上的噪声
    Eigen::Matrix3d gyro_sqrt_cov = param_.gyro_noise_sigma * Eigen::Matrix3d::Identity();
//给陀螺仪数据增加噪声,即陀螺仪误差模型,
//高斯白噪声从连续到离散差了个1/根号t,这里Sg为单位阵,
//gyro_sqrt_cov * noise_gyro表示陀螺方差乘以正态分布,得到以陀螺方差的高斯分布。
	//同理
    data.imu_gyro = data.imu_gyro + gyro_sqrt_cov * noise_gyro / sqrt( param_.imu_timestep ) + gyro_bias_;

    Eigen::Vector3d noise_acc(noise(generator_),noise(generator_),noise(generator_));
    Eigen::Matrix3d acc_sqrt_cov = param_.acc_noise_sigma * Eigen::Matrix3d::Identity();
    data.imu_acc = data.imu_acc + acc_sqrt_cov * noise_acc / sqrt( param_.imu_timestep ) + acc_bias_;

    // gyro_bias update陀螺仪偏差的更新
    Eigen::Vector3d noise_gyro_bias(noise(generator_),noise(generator_),noise(generator_));
    gyro_bias_ += param_.gyro_bias_sigma * sqrt(param_.imu_timestep ) * noise_gyro_bias;
    data.imu_gyro_bias = gyro_bias_;

    // acc_bias update加速度偏差的更新
    Eigen::Vector3d noise_acc_bias(noise(generator_),noise(generator_),noise(generator_));
    acc_bias_ += param_.acc_bias_sigma * sqrt(param_.imu_timestep ) * noise_acc_bias;
    data.imu_acc_bias = acc_bias_;

}

MotionData IMU::MotionModel(double t)
{

    MotionData data;
    // param
    float ellipse_x = 15;
    float ellipse_y = 20;
    float z = 1;            // z轴做sin运动
    float K1 = 10;          // z轴的正弦频率是x,y的k1倍
    float K = M_PI/ 10;    // 20 * K = 2pi   由于我们采取的是时间是20s, 系数K控制yaw正好旋转一圈,运动一周

    // translation
    // twb:  body frame in world frame
    Eigen::Vector3d position( ellipse_x * cos( K * t) + 5, ellipse_y * sin( K * t) + 5,  z * sin( K1 * K * t ) + 5);
    Eigen::Vector3d dp(- K * ellipse_x * sin(K*t),  K * ellipse_y * cos(K*t), z*K1*K * cos(K1 * K * t));              // position导数 in world frame
    double K2 = K*K;
    Eigen::Vector3d ddp( -K2 * ellipse_x * cos(K*t),  -K2 * ellipse_y * sin(K*t), -z*K1*K1*K2 * sin(K1 * K * t));     // position二阶导数

    // Rotation
    double k_roll = 0.1;
    double k_pitch = 0.2;
//顺序是ZYX
    Eigen::Vector3d eulerAngles(k_roll * cos(t) , k_pitch * sin(t) , K*t );   // roll ~ [-0.2, 0.2], pitch ~ [-0.3, 0.3], yaw ~ [0,2pi]
    Eigen::Vector3d eulerAnglesRates(-k_roll * sin(t) , k_pitch * cos(t) , K);      // euler angles 的导数

//    Eigen::Vector3d eulerAngles(0.0,0.0, K*t );   // roll ~ 0, pitch ~ 0, yaw ~ [0,2pi]
//    Eigen::Vector3d eulerAnglesRates(0.,0. , K);      // euler angles 的导数

    Eigen::Matrix3d Rwb = euler2Rotation(eulerAngles);         // body frame to world frame
    Eigen::Vector3d imu_gyro = eulerRates2bodyRates(eulerAngles) * eulerAnglesRates;   //  euler rates trans to body gyro

    Eigen::Vector3d gn (0,0,-9.81);                                   //  gravity in navigation frame(ENU)   ENU (0,0,-9.81)  NED(0,0,9,81)
    Eigen::Vector3d imu_acc = Rwb.transpose() * ( ddp -  gn );  //  Rbw * Rwn * gn = gs

    data.imu_gyro = imu_gyro;
    data.imu_acc = imu_acc;
    data.Rwb = Rwb;
    data.twb = position;
    data.imu_velocity = dp;
    data.timestamp = t;
    return data;

}

//读取生成的imu数据并用imu动力学模型对数据进行计算,最后保存imu积分以后的轨迹,
//用来验证数据以及模型的有效性。
void IMU::testImu(std::string src, std::string dist)
{
    std::vector<MotionData>imudata;
    LoadPose(src,imudata);

    std::ofstream save_points;
    save_points.open(dist);

    double dt = param_.imu_timestep;
    Eigen::Vector3d Pwb = init_twb_;              // position :    from  imu measurements
    Eigen::Quaterniond Qwb(init_Rwb_);            // quaterniond:  from imu measurements
    Eigen::Vector3d Vw = init_velocity_;          // velocity  :   from imu measurements
    Eigen::Vector3d gw(0,0,-9.81);    // ENU frame
    Eigen::Vector3d temp_a;
    Eigen::Vector3d theta;
    for (int i = 1; i < imudata.size(); ++i) {

        MotionData imupose = imudata[i];

        //delta_q = [1 , 1/2 * thetax , 1/2 * theta_y, 1/2 * theta_z]
        Eigen::Quaterniond dq;
        Eigen::Vector3d dtheta_half =  imupose.imu_gyro * dt /2.0;
        dq.w() = 1;
        dq.x() = dtheta_half.x();
        dq.y() = dtheta_half.y();
        dq.z() = dtheta_half.z();

        /// imu 动力学模型 欧拉积分
        Eigen::Vector3d acc_w = Qwb * (imupose.imu_acc) + gw;  // aw = Rwb * ( acc_body - acc_bias ) + gw
        Qwb = Qwb * dq;
        Vw = Vw + acc_w * dt;
        Pwb = Pwb + Vw * dt + 0.5 * dt * dt * acc_w;

        /// 中值积分

        // 按着imu postion, imu quaternion , cam postion, cam quaternion 的格式存储,由于没有cam,所以imu存了两次
        save_points<<imupose.timestamp<<" "
                   <<Qwb.w()<<" "
                   <<Qwb.x()<<" "
                   <<Qwb.y()<<" "
                   <<Qwb.z()<<" "
                   <<Pwb(0)<<" "
                   <<Pwb(1)<<" "
                   <<Pwb(2)<<" "
                   <<Qwb.w()<<" "
                   <<Qwb.x()<<" "
                   <<Qwb.y()<<" "
                   <<Qwb.z()<<" "
                   <<Pwb(0)<<" "
                   <<Pwb(1)<<" "
                   <<Pwb(2)<<" "
                   <<std::endl;

    }

    std::cout<<"test end"<<std::endl;

}
<think>好的,用户想用OpenCV检测花椒是否开口。首先,我需要理解花椒开口的特征。开口的花椒可能在形状上会有裂缝或者不闭合的轮廓,而闭口的花椒则是完整的。所以,关键可能在于轮廓分析。根据引用[1]提到的轮廓处理函数,比如cv2.boundingRect和cv2.minAreaRect,可以用来获取轮廓的最小外接矩形。如果开口的话,轮廓可能更复杂,或者包围盒的长宽比不同?或者可能需要计算轮廓的近似多边形,通过cv2.approxPolyDP,然后根据顶点数量来判断是否开口。比如开口的轮廓可能顶点更多,或者近似后的面积变化较大? 另外,引用[2]提到了噪声处理,比如使用均值滤波或者调整二值化的参数。花椒图像可能有椒盐噪声,所以预处理步骤很重要。可能需要先进行滤波,比如中值滤波,然后进行二值化,分割出花椒区域。二值化的参数调整会影响轮廓的提取效果,这里可能需要自适应阈值,或者使用大津法。 接下来是特征提取。开口的花椒可能在轮廓上存在凹陷,或者凸缺陷。参考OpenCV中的凸缺陷检测,cv2.convexHull和cv2.convexityDefects。计算轮廓的凸包,然后检测凸缺陷的深度,如果深度超过一定阈值,可能表示开口。另外,引用[1]中的最小外接圆,可能可以用来计算轮廓的圆形度。开口的花椒可能圆形度较低,或者与最小外接圆的面积比例较小。或者使用轮廓的面积和周长计算形状因子,比如圆形度公式4π*面积/(周长^2),开口的可能值较低。步骤大致如下:1.图像预处理:去噪,调整亮度(引用[2]中的ADJUST),二值化分割花椒。 2.轮廓提取:找到所有可能的花椒轮廓。3.轮廓分析:计算每个轮廓的凸缺陷,或者近似多边形的顶点数,或者形状因子来判断是否开口。需要验证这些方法的可行性。比如,凸缺陷检测可能适用于开口处有较深的凹陷,而近似多边形顶点数可能更多。或者,使用Hu矩等形状描述子进行模式识别。 可能遇到的问题包括光照不均导致二值化不准确,或者多个花椒粘连,轮廓分割错误。可能需要形态学操作,如开运算,来分离粘连区域。引用[2]中的积分图方法可能帮助快速计算邻域像素,用于自适应二值化。 另外,用户可能需要具体的代码示例,比如如何计算凸缺陷,或者如何提取轮廓特征。需要参考引用中的函数,比如cv2.integral、cv2.threshold等。 最后,生成相关问题需要考虑用户可能的后续需求,比如性能优化、不同光照条件处理,或者如何区分不同开口程度。</think>### 花椒开口检测算法实现步骤 #### 一、图像预处理 1. **去噪处理**:使用中值滤波消除花椒盐噪声 ```python img = cv2.medianBlur(img, 5) # 内核大小根据噪声强度调整[^2] ``` 2. **亮度调整**:通过直方图均衡化增强对比度 ```python img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_eq = cv2.equalizeHist(img_gray) ``` 3. **自适应二值化**:解决光照不均问题 ```python img_bin = cv2.adaptiveThreshold(img_eq, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) ``` #### 二、轮廓分析与特征提取 1. **轮廓检测**:提取花椒主体区域 ```python contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) ``` 2. **凸缺陷检测**:识别开口裂缝 ```python hull = cv2.convexHull(contour, returnPoints=False) defects = cv2.convexityDefects(contour, hull) for i in range(defects.shape[0]): s,e,f,d = defects[i,0] if d > 1000: # 根据实际深度阈值判断开口[^1] cv2.circle(img, tuple(contour[f][0]), 5, (0,0,255), -1) ``` 3. **形状近似分析**:通过多边形顶点数判断开口 ```python epsilon = 0.02 * cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, epsilon, True) if len(approx) > 5: # 开口轮廓顶点更多 print("检测到开口") ``` #### 三、分类判断 1. **特征融合**:结合凸缺陷深度和轮廓复杂度 $$ \text{开口概率} = \alpha \cdot \frac{\text{缺陷数量}}{\text{轮廓长度}} + \beta \cdot \frac{\text{顶点数}}{10} $$ 2. **阈值设定**:通过实验确定分类阈值 #### 完整示例代码 ```python import cv2 import numpy as np def detect_open_pepper(img_path): img = cv2.imread(img_path) img = cv2.medianBlur(img, 5) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_eq = cv2.equalizeHist(img_gray) img_bin = cv2.adaptiveThreshold(img_eq, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: hull = cv2.convexHull(cnt, returnPoints=False) if len(hull) > 3: defects = cv2.convexityDefects(cnt, hull) if defects is not None: for i in range(defects.shape[0]): s,e,f,d = defects[i,0] if d > 1000: # 深度阈值需实验确定 return True return False ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值