基于opencv传统数字图像处理实现车道线检测详细过程(附源码)

news2025/1/19 7:59:06

车道线检测 (Lane Detection)

1、实验内容

本实验使用数字图像处理的基本方法,构建了一个车道线检测模型。该模型可以识别图像中所有的车道线,并得到完整的车道线信息。模型在tuSimple Lane Dataset大小为100的数据子集进行了测试,达到了较好的结果。

2、实现思路

实现车道线检测,主要包含两部分操作

  1. 道路图像的处理,主要包括灰度图转换、基于高斯平滑的图像去噪、基于Canny算法的边缘提取
  2. 车道线检测方法,主要包括获取感兴趣区域(ROI)、形态学闭运算、基于Hough变换的直线检测

模型的处理流程如下,

在这里插入图片描述

2.1 道路图像处理

通过对道路图像进行处理,突出图像中的车道线部分。模型将彩色图像转化成灰度图像进行处理,目的是简化模型的复杂度,提高运行效率。

2.1.1 高斯平滑

由于光照、路面情况、拍摄质量等问题,道路图像上存在很多噪声,通过高斯滤波使图像变得平滑,减弱图像中的噪声对结果的影响,提高车道线检测模型的鲁棒性。

高斯平滑就是使用高斯滤波器与原图像进行卷积,得到平滑图像。与均值滤波类似,它们都是取滤波器窗口内像素的加权均值作为输出。高斯滤波器的权值分布满足二维高斯函数。

由于高斯平滑是线性离散滤波,因此离散形式的高斯滤波器为

本实验采用 3 × 3 3\times3 3×3 的高斯滤波器。具体实现为定义 Kernel 类实现通用的卷积操作,定义派生类 GaussianKernel 实现不同 size 和 σ \sigma σ 高斯滤波器的构建的运算,实现接口如下:

/* Kernel.h */
class Kernel
{
public:
    double **data;
    int size;
    Kernel(int size);   // 空的卷积核
    Kernel(Kernel &cp); // 拷贝构造函数
    ~Kernel();
    double *operator[](const int idx) const;
    // 卷积操作
    template<typename T1, typename T2>
    void convolve(const Img<T1> &src, Img<T2> &dst, const bool is_clip = true) const;
};

class GaussianKernel : public Kernel
{
public:
    double sigma;
    GaussianKernel(const int size, const double sigma);
    GaussianKernel(GaussianKernel &cp);
};

2.1.2 边缘提取

在实验过程中,我曾尝试采用以下方法进行边缘提取的方法。由于在图像中车道线的灰度值较大,因此我设计了一种参数自适应的阈值分割算法,把车道线从图像中抽取出来。具体方法如下:统计图像的灰度分布,选取整体灰度分布相应比例对应的灰度值作为阈值,对图像进行二值化。效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a9a0UvjK-1670900636136)(./result/image_of_readme/binary.png)]

可以发现,通过阈值分割有效的过滤掉了大部分背景,如山脉、路面、车辆,这为下面的直线检测去除了一定的干扰。但是由于部分图像存在反光或较亮区域,这导致一些车道线丢失,或特征不再明显,如下图。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N2a9RWS9-1670900636136)(./result/image_of_readme/binary_failure.png)]

虽然可以通过求图像梯度的方法将大面积的高亮度区域滤除,但是直接将原图转成二值图像处理,会丢失车道线的细节信息导致结果车道线信息不完整。因此舍弃该方案。

最终采用基于图像梯度的边缘提取方法——Canny算法。Canny主要包含三个步骤:

  1. Sobel算子:计算图像梯度
  2. 非极大值抑制:去除非边缘的噪点,细化边缘
  3. 双阈值:检测并连接边缘

(1)Sobel 算子计算图像梯度

灰度图可以看做灰度值 h ( x , y ) h(x,y) h(x,y) 关于 ( x , y ) (x,y) (x,y) 坐标的二元函数,计算图像梯度可以通过Sobel算子计算得到。​

  • x x x 方向梯度: g r a d x ( x , y ) = ∂ h ( x , y ) ∂ x {grad}_x(x,y) = \frac{\partial h(x,y)}{\partial x} gradx(x,y)=xh(x,y)
  • y y y 方向梯度: g r a d y ( x , y ) = ∂ h ( x , y ) ∂ x {grad}_y(x,y) = \frac{\partial h(x,y)}{\partial x} grady(x,y)=xh(x,y)
  • 梯度幅度: g r a d = g r a d x 2 + g a r d y 2 grad = \sqrt{{grad_x}^2 + {gard_y}^2} grad=gradx2+gardy2
  • 梯度方向: g a r d θ = a r c t a n ( g r a d y g r a d x ) gard_\theta = arctan(\frac{grad_y}{grad_x}) gardθ=arctan(gradxgrady)

其中计算 x , y x,y x,y 方向的梯度使用Sobel算子对图像进行卷积

Sobel 算子计算梯度效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BovDpe8W-1670900636136)(./result/image_of_readme/Sobel.png)]

(2)非极大值抑制

分析上图发现,由于图像灰度存在起伏,所以有一些不是边缘的区域也存在较大的梯度。采用非极大值抑制(NMS)的方法,消除梯度图像中非边缘的噪声,并将边缘细化。

NMS实现的思路如下:计算每个中心像素点沿梯度方向邻域内各点的梯度值,如果该中心像素点的梯度值是以上像素点梯度值的局部极大值,则保留梯度,否则梯度置为零。由于邻域内在梯度方向上的点不一定是在整数坐标位置,因此需要通过插值计算邻域内梯度方向点的梯度值。实现效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4XTJjp2T-1670900636137)(./result/image_of_readme/nms.png)]

一些非边缘的噪点得到了一定程度的抑制,边缘也得到细化。

(3)双阈值检测和边缘连接

需要将得到的梯度图像进行阈值分割,得到二值图以便后续进行hough变换。采用双阈值对图像进行阈值分割,实现思路如下:

  • 当梯度值大于高阈值时,将其灰度值取为255。
  • 当梯度值小于低阈值时,将其灰度值取为0。
  • 当梯度介于两者之间是,如果该点邻域内有高阈值点,则取为255,否则取0。

双阈值处理中,高阈值将物体边缘和背景区分开,但是当高阈值较大时,可能导致边缘断断续续;此时低阈值平滑边缘轮廓,能实现较好的分割效果。同时借鉴之前尝试对灰度图做阈值分割的思路,采用整体灰度分布相应比例处的灰度值为高阈值,低阈值取高阈值的 2 3 \frac{2}{3} 32,实现效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7bCWUlC-1670900636137)(./result/image_of_readme/canny.png)]

Canny 边缘提取的实现接口如下:

#ifndef LANE_DETECTION_EDGE_DETECTION_H
#define LANE_DETECTION_EDGE_DETECTION_H

#include "Img.hpp"
#include "Kernel.h"
// 阈值分割
void TurnBinary(Img<uchar> &src, const double weight);
// 膨胀运算
void Dilation(const Img<uchar> &src, Img<uchar> &dst, int kernel_size);
// 腐蚀运算
void Erosion(const Img<uchar> &src, Img<uchar> &dst, int kernel_size);
// 遮盖无效部分
void RoiMask(Img<uchar> &src);
// Sobel 算子计算梯度
void Sobel(const Img<uchar> &src, Img<uchar> &dst, Img<double> &theta);
// 非极大值抑制
void NonMaxSuppression(const Img<uchar> &src, Img<uchar> &dst, const Img<double> &theta);
// 双阈值处理
void DoubleThreshold(Img<uchar> &image, const double weight = 0.9);
// Canny 边缘检测
void Canny(Img<uchar> &image, const double weight = 0.9);
#endif //LANE_DETECTION_EDGE_DETECTION_H

2.2 车道线检测

2.2.1 梯形 ROI mask

经过图像的边缘提取,车道线边缘已经从图像中抽取出来。观察边缘图像发现:道路两边的环境复杂,存在很多干扰车道线检测的直线边缘,如天际线、山脉边缘、电线杆、树丛等。同时考虑到道路图像中,车道线集中在图像的中间偏下区域,因此可以仅对感兴趣区域(ROI)进行处理和检测。根据车道线图像特点,采用梯形掩码获取ROI。

观察图像选取了(400, 0) (220, 420) (200, 860), (400, 1280)四个点作为 mask 的角点。mask图像如下

在这里插入图片描述

ROI 如下:

在这里插入图片描述

2.2.2 hough 变换检测直线

hough变换是一种目标检测的方法,可以检测出有明确表达式的图形。hough 变换的基本原理:利用两个不同坐标系之间的变换来检测图像中的直线。将图像空间中的直线映射到参数空间的一个点,然后对参数空间中的点进行累计投票,进而得到参数空间中的峰值点,该峰值点就对应空间坐标系中的真实存在的直线参数。

hough变换中,直线采用极坐标方程表示,因为参数 θ \theta θ r r r 的范围有限,便于以相同步长进行离散化

实现思路:

  • 初始化参数空间(二维矩阵)
  • 遍历空间坐标系的每个非零像素点,为所有可能经过该点的直线的参数进行投票。
  • 找出参数空间中大于指定阈值的参数点

hough 变换效果如下图:
在这里插入图片描述

可以线由于车道线存在一定的弧度并非严格地直线,且存在一定宽度,导致每条车道线都会检测出多条对应直线。可以采用聚类的方法对检测出的直线进行聚类,以得到更精准的效果。

2.2.3 车道线聚类

由于 k-means 等聚类算法复杂度较高,影响车道线检测的实时性。所以我设计了一种高效的聚类方案。具体思路如下:根据以两个直线的角度参数距离为相似度函数,遍历hough变换检测出的所有直线参数,如果相似度高于阈值,则认为属于同一类别,该类别大小加一;如果相似度低于阈值,则认为属于不同类别,与下一个类中心点进行比较。如果没有相似的

伪代码如下:

params; 	// hough 变换得到参数列表
clusters; 	// 聚类列表
flag; 		// 标记是否新建类
for param in params
{
    flag = true;
    for cluster in clusters
    {
		if is_similar(param, cluster)	// 如果相似则添加到该类中
        {
            flag = false;
            update(cluster);
            break;
        }
    }
    if flag	// 与现有的所有类都不同
        clusters.append(param);	// 添加新类
}

这里相似度函数采用两条直线的角度参数的差值。

一开始选择的更新聚类中心的方法,是取同一类别的平均值,效果不佳。经过尝试最后采用取每个类别的初始值为中心点,实现较好的效果。示例如下:

在这里插入图片描述

评测结果对比:

中心点AccuracyFPFN
数据均值0.57400.70580.7533
聚类初始值0.75390.50250.5242

分析原因:由于车道线有一定弧度,导致前半部分和后半部分的车道线参数差距较大。如果降低判定相似的标准,就会导致本不相似的直线求均值,从而使Accuracy较低;如果提高相似的标准就会,导致聚类得到类别很多,从而FP较大;因此采用加权均值更新聚类中心点并不理想。

按照车道线聚类结果中每个类别的大小,对聚类结果进行排序,选择所有聚类结果中规模最大的4个类作为最终确定的直线参数。

代码接口如下:

// 相似函数
bool is_similar(pair<int, int> &l1, pair<int, int> &l2);
// 更新类中心点
void update_cluster(pair<int, int> &line, pair<pair<int, int>, int> &cluster);
// 直线聚类
void lines_cluster(vector<pair<int, int>> &lines);
// hough变换
void HoughTransform(Img<uchar> &src, vector<pair<int, int>> &lines, int threshold);

2.3 输出结果

函数接口如下:

/* 根据车道线的参数,获取坐标向量 */
void GetLanes(Img<uchar> &src, vector<pair<int, int>> &params, vector<vector<int>> &lanes);
/* 将检测结果写入json文件 */
void WriteJson(string &raw_file, vector<vector<int>> &lanes, double run_time, ofstream &of);
/* 展示车道线检测结果 */
void polyLanes(const string &path, vector<vector<int>> &lanes, int delay);

通过 GetLanes 将每个直线参数转换成直线坐标,WriteJson 函数将结果写入json文件,polyLanes 可视化展示车道线。

实现效果如下:

在这里插入图片描述

3、 实现说明

3.1 Img 模板类存储图像

由于只允许使用OpenCV进行图像的读写操作,因此本实验构建了 Img 模板类,作为图像存储和操作的基本数据结构,代码接口如下:

template<typename T>
class Img
{
public:
    T **data;   // 存放数据
    int rows;   // 图像的行数
    int cols;   // 图像的列数

    Img(int rows, int cols); /* 构造空值图像 */
    Img(const char *path);   /* 读入图像:灰度图 */
    Img(Img &cp);            /* Img类的复制构造函数 */
    ~Img();

    T *operator[](const int idx) const;
    Img &operator=(const Img &cp);

    cv::Mat toMat() const;                        /* 将图像转换成 cv::Mat */
    void show(const char *name, int delay) const; /* 展示图片 */
};

展示图片的plotLanes函数也使用了 OpenCV 框架对图像进行展示。

3.2 main 函数

int main()
{
    // 获取所有图片的路径
    vector<string> file_names;
    get_image_names("../data/selected test data", file_names);
    // 输出文件流接口
    ofstream out;
    out.open("../result/predict.json", ios::out);
    // 记录 run_time 运行时间
    clock_t begin_time, end_time;
    // 车道线检测
    for (auto &path : file_names)
    {
        begin_time = clock();
        Img<uchar> src(path.data());
        Img<uchar> dst(src.rows, src.cols);
        Img<uchar> dst_close(src.rows, src.cols);
        Img<double> theta(src.rows, src.cols);

        // 高斯滤波
        GaussianKernel filter(3, 1);
        filter.convolve(src, dst, true);
        // Canny 边缘检测
        Canny(dst, 0.97);
        // 获取图像 Roi
        RoiMask(dst);
        // hough 变换
        vector<pair<int, int>> lanes_param;
        HoughTransform(dst, lanes_param, 100);
        // 将车道线转成标准格式
        vector<vector<int>> lanes;
        GetLanes(dst, lanes_param, lanes);
        end_time = clock();
        // 将预测结果保存在 json 文件中
        string raw_path = path;
        raw_path.replace(raw_path.find("../data/selected test data"), 26, "clips");
        WriteJson(raw_path, lanes, double(end_time - begin_time) / CLOCKS_PER_SEC, out);
        // 绘图展示检测出的直线
        polyLanes(path, lanes, lanes_param, 100);
        cout << lanes_param.size() << endl;
    }
    out.close();
    return 0;
}

3.3 项目文件树结构:

│  .gitignore
│  CMakeLists.txt
│  evaluate.py	# 评测脚本
│  main.cpp		# 主函数
│  README.md
│
├─result
│     predict.json	# 预测结果
├─data
│  │  data_process.py	# 数据预处理脚本
│  │  groundtruth.json	# 真实值
│  │
│  └─selected test data	# 待处理图像
│      ├─0531
│      └─0601
│
├─include
│      Edge.h	# 边缘检测
│      Hough.h	# hough 变换
│      Img.hpp	# Img 模板类
│      Kernel.h	# Kernel 滤波器
│      SaveResult.h	# 输出结果接口
│
└─source
       Edge.cpp
       Hough.cpp
       Kernel.cpp
       SaveResult.cpp

4、 实验结果

经过运行 TuSimple Lane Detection 项目的测评脚本,得到在数据子集上检测结果如下:

AccuracyFPFN
0.75390.50250.5242

实现了较好的测评效果。同时检测每张图像约用时0.4秒。

5、 实验总结及改进

实验过程中尝试了很多方案,如采用形态学运算,提高车道线的完整性;通过阈值分割,去除背景和干扰物;采用均值作为聚类中心等。由于方案设计上的主观缺陷和检测任务的存在的光照不均、环境复杂等客观因素,以上方案均被舍弃。最终经过实践得到了一种鲁棒性较好,效果较优的车道线检测方案。

通过查阅相关资料,我了解到更多车道线检测的改进算法,例如可以通过最大类间方差法(OTSU)进行阈值分割、动态ROI区域等。可以通过以上算法进一步提高模型精度和性能。

6、 运行方法

  1. 编译(Windows 10):

    • cmake version 3.19.3
    • GNU Make version 4.2.1
    • OpenCV version 4.5.1

    在 powershell 中执行以下命令:
    (1)生成 debug 版本:

    mkdir debug # 创建编译目录
    cd debug
    cmake -G "MinGW Makefiles" ..   # 生成 Makefile
    mingw32-make    # 使用 MinGW 编译代码
    

    (2)生成 release 版本

    mkdir release
    cd release
    cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release ..  
    mingw32-make
    
  2. 运行

    在 debug / release 目录中双击 lane_detection.exe 即可运行

  3. 测评

    cd ..
    python evaluate.py ./result/predict.json ./data/groundtruth.json
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/84883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

餐饮门店数字化转型|餐厅管理系统小程序

餐饮行业规模非常庞大&#xff0c;每年都有大量公司或个体户入局&#xff0c;国内各类美食非常多&#xff0c;不同品类菜品都有大量需求&#xff0c;以前几乎在业的餐饮门店&#xff0c;只要运营得当&#xff0c;挣多挣少总归是有利的&#xff0c;也能很好的生存下去&#xff0…

nodejs+vue大学生交流互动论坛网站系统

目 录 1 概述 1 1.1课题背景及意义 1 1.2 国内外研究现状 1 1.3 本课题主要工作 2 2 系统开发环境 3 前端技术&#xff1a;nodejsvueelementui 前端&#xff1a;HTML5,CSS3、JavaScript、VUE 系统分为不同的层次&#xff1a;视图层&#xff08;vue页面&…

【云计算与大数据技术】Bloom Filter、LSM树、Merkle哈希树、Cuckoo哈希等数据结构的讲解(图文解释 超详细)

一、重要数据结构与算法 分布式存储系统中存储大量的数据,同时需要支持大量的上层读/写操作&#xff0c;为了实现高吞吐量&#xff0c;设计和实现一个良好的数据结构能起到相当大的作用 这是以下三个数据库使用的数据结构&#xff0c;一个良好的数据结构对于分布式系统来说有…

Swift 周报 第十九期 |技术汇总

前言 本期是 Swift 编辑组自主整理周报的第十期&#xff0c;每个模块已初步成型。各位读者如果有好的提议&#xff0c;欢迎在文末留言。 欢迎投稿或推荐内容。目前计划每两周周一发布&#xff0c;欢迎志同道合的朋友一起加入周报整理。 十期磨一剑&#xff0c;废铁亦有形&am…

使用TensorFlow Probability实现最大似然估计

TensorFlow Probability是一个构建在TensorFlow之上的Python库。它将我们的概率模型与现代硬件(例如GPU)上的深度学习结合起来。 极大似然估计 最大似然估计是深度学习模型中常用的训练过程。目标是在给定一些数据的情况下&#xff0c;估计概率分布的参数。简单来说&#xff0…

开源依赖项管理指南

就像人际关系中人与人之间的关系一样&#xff0c;软件生态系统中包含一个庞大的关系网络。其中一些联系非常深入&#xff0c;而有一些关系则更为表面。但实际上&#xff0c;现代基于开源的软件开发涉及一个极其庞大的依赖关系树&#xff0c;依赖关系层层叠加&#xff0c;同时涉…

喜讯丨创新微MinewSemi的MS11SF1系列荣获2022中国IoT创新奖—产品金狮奖

北京时间2022年12月8日&#xff0c;由知名电子科技媒体“电子发烧友”举办的2022第九届中国IoT大会在深圳圆满落幕&#xff0c;创新微MinewSemi凭借高性能、低功耗的WiFiBLE Combo 模块—MS11SF1系列&#xff0c;在众多参会嘉宾和行业主流媒体的共同见证下&#xff0c;荣获2022…

卷积神经网络中卷积的作用与原理

目录 前言 卷积的作用 卷积的参数 卷积核大小&#xff08;kernel_size&#xff09; 填充&#xff08;padding&#xff09; same valid full 卷积核算子&#xff08;operator&#xff09; Robert 算子 Prewitt算子 Sobel 算子 Laplance 算子 卷积核深度与个数&…

【C++进阶】哈希(万字详解)—— 运用篇(下)

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

[附源码]Python计算机毕业设计电子工厂进销存管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

为什么要把测试环境的告警当成生产环境的告警处理?是一个哲学问题,还是一个技术问题?...

开发不愿意了一个后端服务通常有三个环境&#xff1a;测试环境&#xff0c;预发布环境&#xff0c;生产环境。运维在给测试环境增加告警规则和告警路由时&#xff0c;开发人员反对。这很容易理解&#xff0c;如果真把告警规则配置到测试环境&#xff0c;他们可能无时不刻地收到…

Web GIS开发教程

Web GIS开发教程 非程序员的基本 Web GIS 开发 课程英文名&#xff1a;Web GIS development course 此视频教程共4.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 下载地址 课程编号&#xff1a;355 百度网盘地址&#xff1a;https://p…

杭州联合银行 x 袋鼠云:打造智能标签体系,助力银行大零售业务转型

“智能标签平台上线后&#xff0c;支行及业务部门已创建多个客群用于营销&#xff0c;为我行客户精细化管理打下了良好基础。” 2021 年&#xff0c;联合银行就已搭建了大数据基础平台&#xff0c;围绕平台搭建了数据研发平台、大数据调度平台及大数据服务平台&#xff0c;提高…

(附源码)Python飞机票销售系统 毕业设计 141432

摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息存…

Vue组件的嵌套关系,父组件传递子组件 ,事件总线,Provide,inject,作用域插槽,具名插槽非props的attribute ,子组件传递父组件

组件化 – 组件间通信 认识组件的嵌套 ◼ 前面我们是将所有的逻辑放到一个App.vue中:  在之前的案例中,我们只是创建了一个组件App;  如果我们一个应用程序将所有的逻辑都放在一个组件中,那么这个组件就会变成非常的臃 肿和难以维护;  所以组件化的核心思想应该是对…

【YOLOv5】记录YOLOv5的学习过程

以下记录的是Ubuntu20.04版本&#xff0c;其他Ubuntu版本也相差不大~ 一、安装pytorch GPU版本、显卡驱动、CUDA、cuDNN 下载pytorch GPU版本&#xff1a; 最新版本链接&#xff1a;Start Locally | PyTorch 历史版本链接&#xff1a;Previous PyTorch Versions | PyTorch…

MySQL——内置函数

文章目录内置函数日期函数字符串函数数学函数其他函数内置函数 日期函数 基本使用&#xff1a; 可以进行运算&#xff1a; 在日期基础上加时间 在日期基础上减时间 计算两个日期相差的天数 案例1&#xff1a; 建一张表&#xff0c;记录生日 案例2&#xff1a; 创建一…

设计有趣的轻巧真无线,体积小续航长,南卡小音舱上手

大家平时都会听听音乐、玩玩游戏&#xff0c;这时候就需要用到蓝牙耳机&#xff0c;特别是在户外接打电话时&#xff0c;戴上一副耳机都会方便很多。最近发现了一款南卡小音舱Lite2&#xff0c;这些天用过之后感觉它质量不错&#xff0c;做得十分小巧&#xff0c;日常携带特别方…

Postman带sessionId的post请求访问失败

Postman带sessionId的post请求访问失败1、Python 调用过程2、Postman 错误示例3、Postman 正确示例4、总结使用 Python 访问一个数据接口&#xff0c;调用是正常的&#xff0c;但是使用 Postman 进行访问时出错了&#xff0c;搞了两天&#xff0c;后面发现很简单&#xff0c;故…

如何理解FFT中时间窗与RBW的关系

作为一种常用的频谱分析工具&#xff0c;快速傅里叶变换(FFT) 实现了时域到频域的转换&#xff0c;是数字信号分析中最常用的基本功能之一。FFT 频谱分析是否与传统的扫频式频谱仪类似&#xff0c;也具有分辨率带宽(RBW) 的概念&#xff1f;如果具有RBW &#xff0c;那么FFT 的…