GMM(高斯混合模型)的动态背景分割

2023-05-16

以下是GMM(高斯混合模型)的动态背景分割的实验报告以及源码,另外用到了形态学操作与多通道的处理,提升了实验结果的性能。

一.实验名称

基于混合高斯模型的动态背景分割

 

二.实验目的

探索如何对Wavingtrees等具有动态背景的数据集进行有效的建模并分割,检测前景物体。

 

三.实验原理

3.1 前言

时域中的同一个点的像素值看做是一个像素过程,由一组像素组成,如果这里只考虑灰度图的话,对于点x0y0 处于时间t 的像素历史值为

其中I 代表着图像序列,由于各种因素,环境中的背景往往不是完全不变的,下图展示在wavingtrees中两个像素点随着帧数其像素值的变化。

         

 

                                                                           图3.1 像素值变化图

从上图可以看出,我们在第一帧中选取了两个点,一个点坐标值为(11,14).位于较为远离树的位置,另一个点坐标值为(102,78)。位于树与人交叉的位置。从右上角与右下角的图表示像素值随着帧数的变化。横坐标为帧数,纵坐标为像素值的大小。可以明显的看出,随着时间的推移,即随着帧数的增加,像素点的值的分布较为分散,特别是前景与背景交叉的区域。所以单个模型,比如单个高斯模型难以适应这种场景。采用高斯混合模型就可以较好的适应这种变换。

3.2 高斯混合模型

3.2.1 背景建模

(1)高斯模型定义

鉴于由于背景环境的复杂变化,单个高斯模型难以适应,考虑对每个像素值序列X1,…,Xn 建立K 个高斯分布综合描述。当前像素值得到的概率密度函数由以下公式进行描述:

 

是该点对应的高斯模型的最大数目, 是时间 时的第 个高斯模型的权重,即当前高斯模型对于该像素点对应的所有模型占得权重, 是时间 时的第 个高斯模型的期望, 是时间 时的第 个高斯模型的协方差矩阵, 代表高斯概率密度方程:

考虑到程序的空间与时间复杂度, 的取值一般为3-5.而且协方差矩阵被简化为

因为在这里我们假设RGB三通道的数据具有互相独立而且相同的方差。虽然有些不符合现实,但是在损失了一些精度的代价下减少了程序的时间复杂度。

(2)训练过程

这里先采用若干张图片进行训练,即更新每个响度点对应的高斯混合模型的个数,高斯模型的参数等。背景建模的算法流程图如下

                                                                                   图3.2 算法流程图

在上图中,判断一个像素点是否服从高斯分布:像素值是否位于高斯分布的2.5倍标准差内。对于每个像素点对应的高斯模型,如果该像素值匹配到了某个高斯模型,则更新公式如下:

                 

 

 

对于没有匹配到的高斯模型,其方差与期望不变,权重的更新按照上述公式。其中当像素点匹配了某个高斯模型的时候 值为1,否则值为0。

如果该像素值与其对应的高斯模型都不匹配,则判断当前像素值的高斯模型个数是否已到达上限阈值K。

1.如果达到的话,侧取权重与方差比值最低的那个高斯分布重新进行初始化。权重赋予一个较低的值,这个值在程序中取得0.05.方差赋值为一个较高的值,程序中取值为30.高斯分布的期望赋值为该像素点的值。

2.如果没有达到的话。则新建一个高斯分布。初始化步骤同上。权重赋予一个较低的值,这个值在程序中取得0.05.方差赋值为一个较高的值,程序中取值为30.高斯分布的期望赋值为该像素点的值。

当前像素值与其对应的高斯模型匹配结束之后,把该像素值对应的高斯模型按照权重与方差的比例降序排列,接着对所有高斯模型对应的权重进行归一化。

 

3.2.2 前景检测

每个像素值对应的各个高斯分布的参数会一直发生改变,当一个物体趋于静止的时候,对应的像素高斯分布的方差会趋于更小,其对应的权重会趋于变得更大,相对于一个运动的物体,他一般不会匹配到像素对应的高斯模型,运动的物体会让高斯模型的方差变得更大,权重变得更低。

我们按照高斯模型的权重与方差的比值进行降序排列,由阈值T(程序中取值为0.7)选出B个高斯分布作为当前像素判断是否属于背景的模型:

                    

如果一个新的像素值服从该B 个高斯模型中的某一个,我们就认为该像素属于背景。但是如果该像素服从某个高斯分布,但是该高斯分布位于该B 个高斯模型之后,该像素仍然会被判定为前景。T的取值不宜过大,否则会产生一个多峰分布模型,背景模型如果是单峰值的话,会选出一个可能性最高的高斯分布。

3.2.3 形态学处理

背景往往不是一直不变的,有些背景可能会一直处于一种细微变化的状态,比如本实验给出的数据集wavingtrees,背景中的树一直处于在摇晃的状态,所以在检测前景的时候总是会把一些树的枝丫之类识别为前景。

为了去除一些被误识别为前景的树枝,考虑采用以下三种形态学操作。

(1)中值滤波:中值滤波常被用来处理椒盐噪声,这里的树枝可以看成是前景中的椒盐噪声。中值滤波的原理就是将当前像素值替换为周围领域像素值的中值。

(2)腐蚀:在周围都是背景的情况下,被误识别为前景的树枝可以经过腐蚀操作进行消除,但是这个操作会对前景中的人轮廓有一定的影响。

(3)膨胀:由于中值滤波或者腐蚀操作会对前景中的人造成一定的影响,即会让人的轮廓出现空洞,所以可以采用膨胀操作在一定程度上减弱这个影响。

3.2.4 三通道的考虑

这里运用的三通道其实就是在三个通道上进行背景建模与前景检测。

背景建模:每个通道的像素点都会建立数目最多为K个的高斯模型。每个通道的建模过程跟3.2.1小节与3.3.2小节描述的一样。

前景检测:原来是灰度图的单通道进行判断,其接受为前景就认为是前景,而现在对于三通道就需要三个通道都认为是前景才认为当前像素是前景。

四.实验结果

本实验采用在线训练,在线测试的方式,为了对比3.2小节描述的形态学操作与三通道的有效性。实验中做了多组对比实验。

4.1 三通道运用

不采用任何的形态学操作,运用RGB三通道与只利用单通道的效果如下图4.1所示。

                                                             

                                                                             (a)单通道            (b)多通道

                                                                                   图4.1 rgb效果对比图

在图4.1中,左边的图是仅仅考虑单通道的时候第247帧的效果,右边的图是考虑三通道之后第247帧的效果。可以明显看出考虑了三通道之后,前景中的人轮廓显得更加丰满了,而对于单通道的情况,人的轮廓中就会存在许多的空洞区域。原因就在于三通道的时候是每个通道都接受为前景才认为是前景,从而是前景的判断更加准确合理。

4.2 形态学操作

实验中考虑了两种形态学组成操作对图像进行处理。

在实验中我们对比了在考虑三通道的情况下,采用开运算,即先腐蚀后膨胀;与先进行中值滤波,在进行膨胀的效果。如下图4.2所示。

                                                          

                                                                    (a)开运算        (b)中值滤波与膨胀

                                                                           图4.2 形态学操作对比图

在上图4.2中,左边的图是第247帧采用了开运算的效果,其中核为十字架形,大小为3;右边的图为先进行中值滤波,再采用膨胀操作之后的效果,其中中值滤波的核大小为7,膨胀操作的核大小为3。从实验结果可以看出。直接利用开运算没有先进行中值滤波,再进行膨胀的效果好,前者会使人的轮廓产生一些空洞。这证明了中值滤波的效果比腐蚀的效果要好。

当形态学操作采用先进行中值滤波,后进行膨胀操作之后,对比了膨胀不同的核大小对于结果的影响。仍然采用第247帧的效果对比。

                                                          

                                                                (a)核大小为3          (b)核大小为5

                                                                                     图4.3

在图4.3中,左图表示膨胀的核大小为3,右边的图表示核的大小为5。可以看出当采用核大小为5的时候,人的轮廓显得更加丰满了。证明了核大小为5比3要好。

该实验的最后结果就是采用先进行中值滤波,后进行膨胀操作之后的效果。其中中值滤波的核大小为7,膨胀操作的核大小为5。

最后我们对比了opencv自带的createBackgroundSubtractorMOG2函数处理的效果与本实验最后得到的效果图。如下图4.4所示。

                                          

                                                      (a)本实验结果      (b)opencv(MOG2)      (c)groundtruth

                                                                                        图4.4

在图4.4中,仍然是展示第247帧的效果。左边的图是本实验最后得到的最好结果图,中间的图是opencv自带的MOG2函数得到的效果图。右边的图是groundtruth。可以看出本实验得到的效果图已经和后面两张图非常类似,这就证明了本实验的算法的有效性。不过其实也可以看出,由本实验得出的图由于采用了膨胀操作,导致人的轮廓有些略大。

五.实验总结

建立高斯混合模型可以较为有效的分割出背景与前景。得到了像素值在时间域上的拟合分布情况。运用高斯混合模型在wavingtrees上取得了较好的结果。

实验中运用的形态学操作一定程度上消除了被检测为前景的树,三通道在一定程度上消除了被误检测为背景的人的轮廓,使得人的轮廓更加的清晰。这都证明了实验中形态学操作与三通道运用的有效性。

但是从实验中也可以看出高斯混合模型对于这种动态背景还是不鲁棒的,仅仅是wavingtrees中背景中的树的轻微晃动,就会出现把树误检测为前景的情况,将前景中的人误检测为背景。这些情况在没有添加形态学操作与三通道的时候尤为明显。所以可以推断当背景发现较为明显的变化时,比如物体突然移动,光照突然变化。高斯混合模型都是无法适应这种变换的。

 

实验报告以及完成源码,数据集:https://download.csdn.net/download/breeze_blows/11975860

核心源代码:

import cv2
import numpy as np
import glob

GMM_MAX_COMPONT = 5
SIGMA = 30
gmm_thr_sumw = 0.6
train_num = 2
WEIGHT = 0.05
T = 0.7
alpha = 0.005
eps = pow(10, -10)
channel = 3
GMM_MAX_COMPONT = GMM_MAX_COMPONT
m_weight = [[] for i in range(GMM_MAX_COMPONT*channel)]#怎么先对numpy初始化为一维数组,后续在对每个元素重新复制为数组呢
m_mean = [[] for i in range(GMM_MAX_COMPONT*channel)]
m_sigma = [[] for i in range(GMM_MAX_COMPONT*channel)]
m_fit_num = None

def init(img):
    row, col, channel = img.shape
    global m_fit_num
    for i in range(GMM_MAX_COMPONT*channel):
        m_weight[i] = np.zeros((row, col), dtype='float32')
        m_mean[i] = np.zeros((row, col), dtype='float32')
        m_sigma[i] = np.ones((row, col), dtype='float32')
        m_sigma[i] *= SIGMA

    m_fit_num = np.zeros((row, col), dtype='int32')

def train_gmm(imgs):
    row, col, channel = imgs.shape
    B, G, R = cv2.split(imgs)
    m_mask = np.zeros((row,col), dtype=np.uint8)
    m_mask[:] = 255
    for i in range(row):
        for j in range(col):
            cnt = 0
            for c, img in enumerate((B,G,R)):
                # img = imgs[:,:,c]
                # img = B.copy()
                num_fit = 0
                for k in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                    if m_weight[k][i][j] != 0:
                        delta = abs(img[i][j]-m_mean[k][i][j])
                        if float(delta) < 2.5*m_sigma[k][i][j]:
                            m_weight[k][i][j] = (1-alpha)*m_weight[k][i][j] + alpha*1
                            m_mean[k][i][j] = (1-alpha)*m_mean[k][i][j] +alpha*img[i][j]
                            m_sigma[k][i][j] = np.sqrt((1-alpha)*m_sigma[k][i][j]*m_sigma[k][i][j]+alpha*(img[i][j]-m_mean[k][i][j])*(img[i][j]-m_mean[k][i][j]))

                            num_fit += 1

                        else:
                            m_weight[k][i][j] *= (1-alpha)

                for ii in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                    for jj in range(ii + 1, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                        if (m_weight[ii][i][j] / m_sigma[ii][i][j]) <= (m_weight[jj][i][j] / m_sigma[jj][i][j]):
                            m_sigma[ii][i][j], m_sigma[jj][i][j] = m_sigma[jj][i][j], m_sigma[ii][i][j]
                            m_weight[ii][i][j], m_weight[jj][i][j] = m_weight[jj][i][j], m_weight[ii][i][j]
                            m_mean[ii][i][j], m_mean[jj][i][j] = m_mean[jj][i][j], m_mean[ii][i][j]

                if num_fit == 0:
                    if 0==m_weight[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j]:
                        for kk in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                            if (0 == m_weight[kk][i][j]):
                                m_weight[kk][i][j] = WEIGHT
                                m_mean[kk][i][j] = img[i][j]
                                m_sigma[kk][i][j] = SIGMA
                                break
                    else:
                        m_weight[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j] = WEIGHT
                        m_mean[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j] = img[i][j]
                        m_sigma[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j] = SIGMA

                weight_sum = 0
                for nn in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                    if m_weight[nn][i][j] != 0:
                        weight_sum += m_weight[nn][i][j]
                    else:
                        break

                weight_scale = 1.0/(weight_sum+eps)
                weight_sum = 0
                for nn in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                    if m_weight[nn][i][j] != 0:
                        m_weight[nn][i][j] *= weight_scale
                        weight_sum += m_weight[nn][i][j]
                        if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                            cnt += 1
                            break
                        if weight_sum > T:
                            if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                                cnt += 1
                            break
                    else:
                        break


            if cnt == channel:
                m_mask[i][j] = 0

    # cv2.imshow('img_gray', img)
    m_mask = cv2.medianBlur(m_mask, 7)
    # kernel_e = np.ones((3, 3), np.uint8)
    # m_mask = cv2.erode(m_mask, kernel_e)
    kernel_d = np.ones((5, 5), np.uint8)
    m_mask = cv2.dilate(m_mask, kernel_d)
    # element = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))  # 形态学去噪
    # m_mask = cv2.morphologyEx(m_mask, cv2.MORPH_OPEN, element)  # 开运算去噪
    return m_mask
    # cv2.imshow('img_mask', m_mask)
    # cv2.waitKey(1)

def test_img(imgs):
    row, col, channel = imgs.shape
    B, G, R = cv2.split(imgs)
    m_mask = np.zeros((row, col), dtype=np.uint8)
    m_mask[:] = 255
    for i in range(row):
        for j in range(col):
            cnt = 0
            for c, img in enumerate((B, G, R)):
                weight_sum = 0
                for nn in range(c * GMM_MAX_COMPONT, c * GMM_MAX_COMPONT + GMM_MAX_COMPONT):
                    if m_weight[nn][i][j] != 0:
                        weight_sum += m_weight[nn][i][j]
                        if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                            cnt += 1
                            break
                        if weight_sum > T:
                            if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                                cnt += 1
                            break
                    else:
                        break

            if cnt == channel:
                m_mask[i][j] = 0

    m_mask = cv2.medianBlur(m_mask, 7)
    kernel_d = np.ones((5, 5), np.uint8)
    m_mask = cv2.dilate(m_mask, kernel_d)

    return m_mask


import time

if __name__ == '__main__':
    data_dir = 'D:/images/'
    file_list = glob.glob('D:/images/b*.bmp')
    i = -1
    for file in file_list:
        # print(file)
        i += 1
        img = cv2.imread(file)
        # img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
        if i == 0:
            init(img)

        if i <= 200:
            t1 = time.time()
            m_mask = train_gmm(img)
            # cv2.imwrite("./rgb_morphologyEx3_MORPH_ELLIPSE/{}.jpg".format(i), m_mask)
            t2 = time.time()
            print(t2-t1)
        if i == 286:
            j = 0
            for temp_file in file_list:
                temp_img = cv2.imread(temp_file)
                m_mask = test_img(temp_img)
                cv2.imwrite("./rgb_mb7_dila5_train200/{:0>5d}.jpg".format(j), m_mask)
                j += 1

参考:

https://blog.csdn.net/zouxy09/article/details/9622401

https://blog.csdn.net/lwx309025167/article/details/78513437#commentBox

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GMM(高斯混合模型)的动态背景分割 的相关文章

  • D435i标定摄像头和IMU笔记一(配置环境篇)

    IntelRealSense D435i摄像头和IMU标定笔记一 xff08 配置环境篇 xff09 一 标定方案二 环境要求三 环境配置3 1 基本环境安装3 1 1 for ubuntu16 043 1 2 for ubuntu18 0
  • D435i标定摄像头和IMU笔记二(RGB摄像头标定篇)

    D435i标定摄像头和IMU教程二 xff08 RGB摄像头标定篇 xff09 一 文件准备二 录制摄像头标定rosbag三 开始标定四 标定结果 参考视频 D435i标定摄像头和IMU笔记一 xff08 配置环境篇 xff09 D435i
  • D435i标定摄像头和IMU笔记三(IMU标定篇)

    D435i标定摄像头和IMU笔记三 xff08 IMU标定篇 xff09 一 RealSense官网驱动标定IMUbias和三个轴的对齐1 1 驱动安装1 2 标定 二 港科大imu utils标定IMU随机游走2 1 环境及文件准备2 2
  • D435i标定摄像头和IMU笔记四(RGB摄像头和IMU联合标定篇)

    D435i标定摄像头和IMU教程四 xff08 RGB摄像头和IMU联合标定篇 xff09 一 前提二 准备标定文件 2 1 标定板yaml文件2 2 相机标定yaml文件2 3 imu标定yaml文件2 4 录制rosbag文件2 5 标
  • D435i标定摄像头和IMU笔记二-2(RGB+双目多摄像头标定篇)

    D435i标定摄像头和IMU笔记二 2 xff08 RGB 43 双目多摄像头标定篇 xff09 一 文件准备二 标定准备三 开始标定四 标定结果 参考视频 D435i标定摄像头和IMU笔记一 xff08 配置环境篇 xff09 D435i
  • D435i标定摄像头和IMU笔记四-2(双目摄像头与IMU联合标定篇)

    D435i标定摄像头和IMU笔记四 2 xff08 双目摄像头与IMU联合标定篇 xff09 一 前提二 文件准备2 1 标定板文件checkerboard yaml xff08 前面多次用到 xff09 xff1a 2 2 imu标定结果
  • px4+vins+ego单机鲁棒飞行一(px4+mavros篇)

    px4 43 vins 43 ego单机鲁棒飞行一 xff08 px4 43 mavros篇 xff09 一 mavors安装二 mavros中的重要插件Plugins三 mavros中的重要topic四 mavros中的tf树五 px4校
  • ardupilot在Linux上设置SITL(FlightGear)

    本页介绍如何在Linux上设置SITL xff08 软件在环路中 xff09 特定命令在Ubuntu上从12 10到16 04进行了测试 概观 SITL模拟器允许您在没有任何硬件的情况下运行Plane xff0c Copter或Rover
  • px4+vins+ego单机鲁棒飞行二(外部位姿估计篇)

    px4 43 vins 43 ego单机鲁棒飞行二 xff08 外部位姿估计篇 xff09 一 使用px4的EKF2 xff08 扩展卡尔曼 xff09 估计测试过程及结果 xff1a 二 使用px4的LPE估计测试过程及结果 xff1a
  • px4+vins+ego单机鲁棒飞行三(realsense_ros配置及经验篇)

    px4 43 vins 43 ego单机鲁棒飞行三 xff08 realsense ros配置及经验篇 xff09 一 驱动及realsense ros安装二 参数设置三 经验 一 驱动及realsense ros安装 D435i标定摄像头
  • px4+vins+ego单机鲁棒飞行四(PX4飞控日志分析篇)

    px4 43 vins 43 ego单机鲁棒飞行四 xff08 PX4飞控日志分析篇 xff09 一 FlightPlot安装二 记录日志二 取出日志三 分析日志 一 FlightPlot安装 参考博客 参考视频 二 记录日志 在QGC中参
  • px4+vins+ego单机鲁棒飞行二-1(更改px4外部视觉估计固件)

    px4 43 vins 43 ego单机鲁棒飞行二 1 xff08 更改px4外部视觉估计固件 xff09 一 EKF2源码 获取视觉里程计信息二 EKF2源码 设置外部视觉数据三 源码中对位置的发送四 测试 前提 xff1a 固件1 11
  • px4+vins+ego单机鲁棒飞行五(坐标系变换篇)

    px4 43 vins 43 ego单机鲁棒飞行五 xff08 坐标系变换篇 xff09 一 齐次矩阵变换原理二 无人机上利用旋转矩阵求飞机中心位置 一 齐次矩阵变换原理 参考一 参考二 二 无人机上利用旋转矩阵求飞机中心位置 首先写出相机
  • 编译多版本opencv,并在cmakelists中链接

    编译多版本opencv xff0c 并在cmakelists中链接 一 下载二 编译三 链接四 替代系统的 xff08 可选 xff0c 但不建议 xff09 五 链接了 xff0c 但无法找到 一 下载 github链接 自己选择版本 x
  • CMakeLists笔记

    CMakeLists笔记 一 路径名二 函数三 常用 一 路径名 PROJECT SOURCE DIR xff1a 一般为catkin ws src xff0c 是cmakelists的绝对路径PROJECT BINARY DIR xff1
  • 源码编译安装openvino

    源码编译安装openvino 1 原地升级cmake2 编译opencv4 5 33 下载openvino4 配置usb规则 参考博客 交叉编译方式 1 原地升级cmake 方法一 xff1a 下载3 19 0中的CMake 3 19 0
  • 【ros】读取串口数据

    文章目录 一 自定义 gnrmc msg二 代码三 结果四 注意点 有时候 有的设备是通过串口发送数据 xff0c 想要在 ros 中 xff0c 读取串口数据 xff0c 记录一下操作 xff1a 一 自定义 gnrmc msg 首先需要
  • Android守护进程

    守护进程 守护进程 一直在后台运行的进程 本文主要讲解一些android比较常用的守护进程的方法 实现思想 1 保活 xff0c 通过提高进程优先级 xff0c 降低进程被杀死的概率 2 拉起 xff0c 进程被杀死后 xff0c 进行拉起
  • ros package 由于依赖 msg 导致编译问题解决

    文章目录 1 问题2 解决 1 问题 经常我们会自定义一些 msg 给其他的 package 使用 如果正常写 CmakeLists txt 在编译的时候 就会提示没有找到依赖的 msg 需要先编译 msg 的 package 再编译其他的
  • 使用Docker部署软件运行环境

    什么是docker xff1f Docker是基于Go语言进行开发实现 xff0c 一个开源的应用容器引擎 采用Linux内核的cgroup xff0c namespace xff0c 以及AUFS类的Union FS等技术 xff0c 对

随机推荐

  • 【控制control】四足机器人运动学、动力学模型

    系列文章目录 提示 xff1a 这里可以添加系列文章的所有文章的目录 xff0c 目录需要自己手动添加 TODO 写完再整理 文章目录 系列文章目录前言一 四足机器人实际模型的物理难点二 四足机器人运动学模型1 方法一 xff1a DH法建
  • 【项目解读】fast_planner工程解读

    系列文章目录 提示 xff1a 这里可以添加系列文章的所有文章的目录 xff0c 目录需要自己手动添加 TODO 写完再整理 文章目录 系列文章目录前言一 规划系统运行逻辑 业务部分 1 Fast planner node cpp 程序入口
  • IMU方向位姿估计

    系列文章目录 提示 xff1a 这里可以添加系列文章的所有文章的目录 xff0c 目录需要自己手动添加 TODO 写完再整理 文章目录 系列文章目录前言一 方法一 xff1a IMU方向位姿可以直接从IMU本身提供的专有算法中获得 xff0
  • 【autoware的仿真平台】

    系列文章目录 提示 xff1a 这里可以添加系列文章的所有文章的目录 xff0c 目录需要自己手动添加 TODO 写完再整理 文章目录 系列文章目录前言一 仿真的必要性及常见的仿真工具介绍二 gazebo仿真插件介绍及源码解析1 gazeb
  • 【机械臂、无人机规控篇】(8)机械臂轨迹规划、跟踪控制方向

    系列文章目录 提示 xff1a 这里可以添加系列文章的所有文章的目录 xff0c 目录需要自己手动添加 TODO 写完再整理 文章目录 系列文章目录前言一 机械臂的规划控制和无人的规划控制的异同点分析1 规划的异同分析2 控制的异同分析 二
  • 微信支付——支付签名验证失败的坑

    只讲几个微信支付开发中的签名问题 xff08 JAVA版的公众号支付 xff09 第一个是获取订单数据时生成 xff0c 然后通过这些数据生成预支付订单 xff08 通过 统一下单 方法取得 xff09 xff0c 微信官方返回一串xml数
  • c++的多重继承

    一 前言 每个类只继承一个父辈 xff0c 在现实世界中事情通常是这样的 xff0c 但是有一些类却代表两个类的合成 例如两用沙发 xff0c 它是一张床 xff0c 也是一个沙发 二 示例代码 xff0c 用作下面提出问题使用 span
  • 学习 STM32之九轴姿态传感器(BWT901CL)串口通信读取数据

    由于个人应用到3轴传感器 xff0c 所以买了直接买了一个9轴的 xff0c 用于学习STM32Core平台串口2连接维特智能串口Normal协议 xff0c 然后通过串口1直接打印数据 xff0c 接收传感器数据和与传感器进行通信 xff
  • 用遗传算法求解旅行商问题

    以下是用遗传算法解决旅行商问题的实验报告 1 问题描述 旅行商问题 xff08 Travelling Salesman Problem 简记TSP xff0c 亦称货郎担问题 xff1a 设有n个城市和距离矩阵D 61 dij xff0c
  • 学习LLC谐振变换电路的工作原理

    五 学习LLC谐振变换电路的工作原理 在具有电阻R 电感L和电容C元件的交流电路中 xff0c 电路两端的电压与其中电流相位一般是不同的 如果调节电路元件 xff08 L或C xff09 的参数或电源频率 xff0c 可以使它们相位相同 x
  • 关于电赛应该了解的事

    2021年1月31日 xff0c 全国大学生电子设计竞赛组委会向各赛区组委会 各有关高校下发 关于组织2021年全国大学生电子设计竞赛的通知 xff0c 正式启动2021年全国竞赛组织工作 电赛越来越近 xff0c 很多大一大二的同学还没有
  • stm32的基本学习路径---新手指南

    心得 xff1a 本人学习STM32的时候有一些跟风的因素 xff0c 自以为学的芯片越多就越厉害 61 61 其实 xff0c 学习嵌入式重要的是整体的工程思想和项目经验积累 xff0c 说到底这些芯片 xff0c 我感觉学习起来都差不多
  • 初学stm32建议的---实用开发板推荐

    STM32编程作为一项实操性很强的技能 xff0c 所以要多实操 初学的话 xff0c 我觉得书籍就暂时先不买吧 xff0c 先考虑入手一块STM32开发板 xff0c 然后跟着开发板的教程走 几年前 xff0c 做STM32的教程有很多家
  • 嵌入式操作系统-ucos是什么?

    一句话概括ucos系统 xff1a 一款源代码开放的 xff0c 抢占式多任务实时操作系统 其在整个嵌入式产品的架构中的角色和主要功能代码如下图所示 xff1a ucos 系统建立了用户程序和底层硬件之间沟通的渠道 通过ucos系统的管理和
  • 自学stm32,需要会到什么程度能找到一份工作?

    我是从大一就开始接触单片机 xff0c 学过很多类型的单片机 从最简单的51单片机 xff08 stc xff0c atmel intel等类型都用过 xff09 到国内现在最火的stm32 xff08 推荐正点原子 xff0c 后期很多项
  • 学习STM32的寄存器版本好还是库函数版本好

    我个人认为 xff0c 在回答这个问题之前 xff0c 你得先问清楚自己 xff0c 我学习stm32 或者再往更深的地方走 xff0c 我学习单片机 xff0c 究竟是为了什么 xff1f 你现在是处于什么状态 xff1f 你是学生还是已
  • proteus 8 打开proteus 7版本仿真文件的两个方法

    Proteus版本一直在更新 xff0c 其中常见的大版本Proteus 7 和Proteus 8兼容是有问题的 xff0c Proteus是向上兼容的 xff0c 高版本可以打开低版本的仿真 xff0c 低版本打不开高版本的 Proteu
  • stm32 单片机主要优点有哪些?

    51单片机之所以成为经典 xff0c 成为易上手的单片机主要有以下特点 xff1a 特性 xff1a 1 从内部的硬件到软件有一套完整的按位操作系统 xff0c 称作位处理器 xff0c 处理对象不是字或字节而是位 不但能对片内某些特殊功能
  • openmv入门之路

    如果你发现OpenCV函数繁多 xff01 xff01 xff01 如果你发现OpenCV配置繁琐 xff01 xff01 xff01 如果你发现自己买不起miniPC xff01 xff01 xff01 请选择OpenMV来完成你的项目吧
  • GMM(高斯混合模型)的动态背景分割

    以下是GMM xff08 高斯混合模型 xff09 的动态背景分割的实验报告以及源码 xff0c 另外用到了形态学操作与多通道的处理 xff0c 提升了实验结果的性能 一 实验名称 基于混合高斯模型的动态背景分割 二 实验目的 探索如何对W