YOLO 目标检测算法学习笔记(三)

YOLO-V1YOLO,全称 You Only Look Once。名字已经说明了一切! YOLO 这是一个经典的 one-stage 方法,把检测问题转换为回归问题,一个CNN就可以搞定。 YOLO 相比于 Faster R-CNN 虽然在 mAP 值上略逊一筹,但其 FPS 值是远远高于 Faster R-CNN 的,因此2016年的时,YOLO爆火。 核心思想 将输入图像分割成 SxS 个网格(如7x7),每个网格负责检测本身区域是否含有物体。 每个网格会预测 B 个边界框(在YOLO-V1中,B值等于2),边界框由四个变量表示 x、y、w、h,以及每个边界框的置信度,置信度用 c 表示。置信度表示边界框包含物体的概率。 过滤掉置信度低的边界框。 由于整个检测只需要一个前向传播,没有区域提议生成候选框的过程,所以速度非常快。 网络架构 将输入图像(在YOLO-V1中限制了输入图像的大小)进行通过卷积神经网络进行特征提取,获得 7x7x1024 的特征图,再进入全连接层,得到 1470 个特征,随后 Reshape 成 7x7x30 的特征图。 下面解释一下 7x7x30 的含义。 7x7 表示输入图像最后分割的网格大小。 30 分为 5+5+20,其中前两个5代表两个边界框的 x、y、w、h和c;最后的20表示当前格子属于数据集中的各个类别的概率。 注意,这里三个值都不是固定不变的,会由于YOLO版本的更新和训练数据集的变化而改变。 总结一下 ,如上图所示,输入图像最后会被分割成许多个网格,每个网格都包含了若干值。 S:网格边长;B:预测边界框数量;C:数据集中的类别个数。 $$ (S * S) * (B * 5 + C) $$ ...

2024年06月16日 · 1 分钟 · Cassius0924

YOLO 目标检测算法学习笔记(四)

YOLO-V2下图为YOLO-V2相较于YOLO-V1的改进点,以及改进后 mAP 值的变化。 Batch NormalizationV2 版本舍弃了 Dropout,不再有全连接层(Fully connected layers,FC)。每次卷积后都加入 Batch Normalization,对网络的每一层的输入都进行归一化,使收敛更容易。 经过 Batch Normalization 处理后的网络会提升2%的mAP值。 从现在的角度来看,Batch Normatlization 已经称为卷积神经网络处理必备处理了。 High Resolution ClassifierHigh Resolution Classifier,即高分辨率分类器,高分辨率分类器。 在 V1 版本,训练时用的是224*224分辨率的图片,测试时又使用448*448分辨率的图片,这会导致模型“水土不服”。 针对这一问题,V2 版本在模型训练时额外进行了10次448*448的微调。经过微调后,V2 版本的 mAP 值提升了约4%。 Convolutional

2024年06月16日 · 1 分钟 · Cassius0924

YOLO 目标检测算法学习笔记(一)

深度学习经典检测方法 one-stage(单阶段):YOLO系列 two-stage(双阶段):Faster-Rcnn、Mask-Rcnn系列 Faster-Rcnn:物体检测开山之作。 one-stage 单阶段检测优势:速度快,适合做实时检测任务。 缺点:效果不佳。 目标检测的两个主要指标:mAP和FPS。 mAP:检测效果的综合指标。(mAP值越大效果越好) two-stage 双阶段检测优势:效果较好。 缺点:速度较慢、不适合用于视频流的实时检测。 Mask-Rcnn是一个非常实用的通用框架(建议了解)。

2024年06月16日 · 1 分钟 · Cassius0924

基于 L2CAP 协议的蓝牙 BLE 设备通信指南

蓝牙 BLE 是什么蓝牙BLE,即蓝牙低功耗 (Bluetooth Lower Energy)是一种蓝牙通信标准,设计用于短距离通信和低功耗应用。 相比经典蓝牙,BLE 更加节能,传输距离更远,连接更快。BLE 主要用于健身设备、医疗设备、家居自动化等场景。 蓝牙 BLE 设备的连接信道L2CAP的基本概念是信道(Signaling Channel)。信道是个抽象概念,表示两个设备某个协议层之间的通道。每个信道分配一个2字节的信道ID——CID(Channel ID),每个信道功用不同,比如CID=0x0004的信道表示属性协议(Attribute Protocol)专用信道。对于BLE协议,L2CAP共有三个信道ID: 0x0004 – 属性协议 0x0005 – 低功耗信令信道 0x0006 – 安全管理协议 其他信道则用于经典蓝牙。协议复用可以理解为,不同的协议走不同的信道,互不干扰。 代码#define ATT_CID 4; // 创建 L2CAP socket int s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); // 绑定 L2CAP socket struct sockaddr_l2 bind_addr = {0}; bind_addr.l2_family = AF_BLUETOOTH; bind_addr.l2_cid = htobs(ATT_CID); // ATT 信道 CID bdaddr_t any_addr = {{0, 0, 0, 0, 0, 0}}; bacpy(&bind_addr.l2_bdaddr, &any_addr); bind_addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; int err = bind(s, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); if (err) { return -1; } // 连接 L2CAP socket struct sockaddr_l2 conn_addr = {0}; conn_addr.l2_family = AF_BLUETOOTH; conn_addr.l2_cid = htobs(ATT_CID); // ATT CID str2ba(mac_address.c_str(), &conn_addr.l2_bdaddr); conn_addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; err = connect(s, (struct sockaddr *)&conn_addr, sizeof(conn_addr)); if (err) { exit(-1); } L2CAP 数据包解析L2CAP(Logical Linked Control and Adaptation Protocol 逻辑链路控制与适配协议)工作在链路层,为上层协议提供数据通道。它支持数据分片与重组,确保数据完整可靠地传输。 ...

2024年06月16日 · 3 分钟 · Cassius0924

解决VScode远程开发C++项目时无代码提示问题

简单粗暴,给本地主机和远程主机都安装上C/C++插件即可。

2024年06月16日 · 1 分钟 · Cassius0924

三维重建笔记——从变换矩阵中提取并分析平移量

在编写点云变换和姿态估计代码时,我们经常需要从结果的变换矩阵中提取平移信息,并分析平移量的大小,帮助判断结果的准确性。 本文将介绍如何从变换矩阵中提取平移向量,并计算其欧几里得长度。 提取平移向量假设我们通过某种姿态估计算法得到了一个4x4的变换矩阵 result.transformation_ ,其中包含了旋转和平移信息。 我们可以通过以下代码提取出平移部分:(以Open3D为例) core::Tensor translation = result.transformation_.Slice(0, 0, 3).Slice(1, 3, 4); Slice(0,0,3);表示从矩阵的第0维(行),第0行开始,取3行,即前3行;Slice(1,3,4);表示从矩阵的第1维(列),第3列开始,取1列,即第4列。 最后获得一个3x1的平移向量,包含x、y、z三个方向的平移量。 计算欧几里得长度有了平移向量后,我们可以计算其欧几里得长度,表示平移量的大小: double translation_norm = std::sqrt((translation * translation).Sum({0, 1}).Item<double>()); std::sqrt计算平方根,translation * translation 计算向量每个元素的平方,Sum 聚合,最终得到平移向量的L2范数,即欧几里得长度。 分析平移量通过提取并计算平移向量的模长,我们可以分析相机或物体的移动距离,以及姿态估计结果的准确性。 如果 translation_norm 的值过大,可能表示估计存在误差,需要反复优化算法。 设置不同的阈值可以根据实际场景需求,判断平移量是否在允许的范围内。 以上是从变换矩阵中提取和利用平移信息的简单示例,可以提供点云变换和姿态估计任务有用的辅助分析。

2024年06月16日 · 1 分钟 · Cassius0924

通过 frp 内网穿透实现异地 SSH 连接(反向代理)

起因是我放假回家,想在家里通过 SSH 连接放在学校的无显示器的 Linux,但是学校的 Linux 是内网,无法直接连接,且无显示器无法使用向日葵等远程桌面软件,所以想到了使用 frp 的反向代理功能实现内网穿透,进而实现异地 SSH 连接。 前提 一台具有公网 IP 的服务器(阿里云、腾讯云等) 配置远程主机我们需要有三台主机,分别是:自己的电脑、远程 Linux 主机和具有公网 IP 的服务器。 只需要在远程 Linux 和具有公网 IP 的服务器上配置 frp 即可。 首先在远程 Linux 上下载 frp,Github 下载地址。下载远程主机对应的版本,我这里是 ARM64 架构的 Linux,所以下载 frp_0.51.2_linux_arm64.tar.gz。 下载完毕后解压: tar -xvf frp_0.51.2_linux_arm64.tar.gz cd frp_0.51.2_linux_arm64 远程 Linux 为客户端,所以只需要保留 frpc* 文件即可,frps可以删除。 rm frps* 修改frpc.ini,只需要将server_addr修改为服务器的 IP 地址即可,local_ip不变。server_port和remote_port一般不变,若与其他服务冲突了可以修改。 vim frpc.ini #:wq 退出 配置服务器同样下载好对应系统版本的 frp,解压后删除frpc*文件。 rm frpc* 修改frpc.ini,确保bind_port与 frpc 客户端,即远程主机的server_port一致。 再前往阿里云或腾讯云官网配置服务器防火墙规则,开放服务器的 6000 和 7000 端口(若修改了则开放修改后的端口)。 ...

2024年06月16日 · 1 分钟 · Cassius0924

C++ Copy&Swap 惯用法指南

Copy&Swap 是什么Copy&Swap 是一种 C++ 中常用的编程技巧,用于实现类的赋值运算符(operator=)。 实现传统写法先看看未使用 Copy&Swap 的赋值运算符写法: #include <iostream> #include <vector> class OldAClass { private: int _count; std::string _str; std::vector<int> _vec; public: OldAClass() : _count(0), _vec(10) {} // 拷贝构造函数 和 拷贝赋值运算符 OldAClass(OldAClass &a) : _count(a._count), _str(a._str), _vec(a._vec) { std::cout << "Copy constructor called\n"; } OldAClass &operator=(OldAClass &a) { std::cout << "Copy Assignment operator called\n"; if (this != &a) { //判断传入的 a 是否是自己 _count = a._count; _str = a._str; _vec = a._vec; } return *this; } // 移动构造函数 和 移动赋值运算符 OldAClass(OldAClass &&a) noexcept : _count(a._count), _str(std::move(a._str)), _vec(std::move(a._vec)) { std::cout << "Move constructor called\n"; } OldAClass &operator=(OldAClass &&a) noexcept { std::cout << "Move Assignment operator called\n"; if (this != &a) { _count = a._count; _str = std::move(a._str); _vec = std::move(a._vec); } return *this; } }; 可以看到,这种写法需要重复写两次赋值运算符,并且每次都需要判断传入的参数是否是自己,而且代码重复度高。 Copy&Swap 写法class AClass { private: int _count; std::string _str; std::vector<int> _vec; public: AClass() : _count(0), _vec(10) {} static void swap(AClass &a, AClass &b) { std::swap(a._count, b._count); std::swap(a._str, b._str); std::swap(a._vec, b._vec); } // 拷贝构造函数 AClass(AClass &a) : _count(a._count), _str(a._str), _vec(a._vec) { std::cout << "Copy constructor called\n"; } // 移动构造函数 AClass(AClass &&a) noexcept { std::cout << "Move constructor called\n"; swap(*this, a); } // 赋值运算符 AClass &operator=(AClass a) { // 注意这里的参数是值传递,会调用拷贝构造函数 std::cout << "Assignment operator called\n"; swap(*this, a); return *this; } }; 这种写法只需要写一次赋值运算符,代码更简洁,而且不需要判断传入的参数是否是自己。 ...

2024年01月15日 · 2 分钟

Jetson (Ubuntu Arm64) 安装 Bazel

简介本文旨在帮助用户在 Jetson 上的 Ubuntu Arm64 系统上安装 Bazel。Bazel 是一个开源的构建工具,它专注于构建和测试大型软件项目,并且被广泛应用于机器学习和深度学习领域。通过使用 Bazel,您可以更高效地管理和构建您的项目。 步骤 1:安装OpenJDK在开始安装 Bazel 之前,我们需要安装 OpenJDK。在终端中执行以下命令: sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get install openjdk-11-jdk 步骤 2:下载 Bazel 安装包在安装 OpenJDK 之后,我们需要下载 Bazel 的安装包。在终端中执行以下命令: wget https://github.com/bazelbuild/bazel/releases/download/6.2.1/bazel-6.2.1-dist.zip 或者,您也可以从 Bazel 的 Github 仓库下载最新版本的安装包。(必须下载dist.zip文件) 步骤 3:安装 Bazel下载完成后,我们可以使用以下命令来安装 Bazel: unzip bazel-6.2.1-dist.zip -d bazel-6.2.1 bash./compile.sh sudo cp output/bazel /usr/local/bin 步骤 4:验证安装安装完成后,我们可以验证 Bazel 是否成功安装。在终端中执行以下命令: bazel version 如果一切正常,您应该能够看到如下输出:

2023年06月14日 · 1 分钟 · Cassius0924

Ubuntu 安装 Protobuf 指南

Protobuf(Protocol Buffers)是一种轻量级的数据交换格式,常用于高效地序列化结构化数据。本指南将介绍如何在 Ubuntu 上安装 Protobuf。 步骤 1:更新系统在安装 Protobuf 之前,我们首先需要确保系统已经更新到最新版本。打开终端并执行以下命令: sudo apt update sudo apt upgrade 这将更新系统的软件包并安装最新的安全补丁。 步骤 2:安装编译工具和依赖项在安装 Protobuf 之前,我们需要安装一些编译工具和依赖项。执行以下命令来安装它们: sudo apt install build-essential autoconf libtool 这些工具和依赖项将帮助我们编译和构建 Protobuf。 步骤 3:下载和编译 Protobuf 首先,我们需要下载 Protobuf 的源代码。这里选择下载v3.20.3版本的Protobuf源码压缩包。(必须下载-all压缩包) 解压压缩包 tar -zxvf protobuf-all-3.20.3.tar.gz 这将克隆 Protobuf 的源代码到当前目录。 进入克隆下来的 Protobuf 目录: cd protobuf-all-3.20.3 在源代码目录中,运行以下命令来生成配置文件和构建系统: ./autogen.sh 接下来,我们需要运行 configure 脚本来配置编译选项。可以使用以下命令进行配置: ./configure 配置完成后,我们可以使用以下命令编译和安装 Protobuf: sudo make sudo make check #这一步可能会报错,解决方法见下文 sudo make install sudo ldconfig 编译过程可能需要一些时间,请耐心等待。 步骤 4:验证安装安装完成后,我们可以验证 Protobuf 是否成功安装。执行以下命令来检查 Protobuf 的版本信息: ...

2023年06月12日 · 1 分钟 · Cassius0924