《视觉 SLAM 十四讲》V2 第 9 讲 后端优化1 【扩展卡尔曼滤波器 EKF BA+非线性优化(Ceres、g2o)】

news2025/1/16 0:51:02

在这里插入图片描述

文章目录

  • 第9讲 后端1
      • 9.1.2 线性系统和 KF
      • 9.1.4 扩展卡尔曼滤波器 EKF 不足
    • 9.2 BA 与 图优化
      • 9.2.1 投影模型和 BA 代价函数
      • 9.2.2 BA 的求解
      • 9.2.3 稀疏性 和 边缘化
      • 9.2.4 鲁棒核函数
    • 9.3 实践: Ceres BA 【Code】
          • 本讲 CMakeLists.txt
    • 9.4 实践:g2o 求解 BA 【Code】
    • 习题

第9讲 后端1

滤波器 EKF

前端视觉里程计: 短时间内的轨迹和地图。
后端优化: 长时间内的最优轨迹和地图

9.1 概述
9.1.1 状态估计的概率解释

渐进的(Incremental): 当前的状态 只由 过去的时刻决定,甚至只由前一个决定。
批量的(Batch):不仅使用过去的信息更新自己的状态,也会用未来的信息来更新。

在这里插入图片描述
在这里插入图片描述
SfM: Structure from Motion.

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
马尔可夫性: k k k 时刻状态仅与 k − 1 k-1 k1 时刻状态 有关。 【扩展卡尔曼滤波(EKF)】
考虑 k k k 时刻状态 与 之前所有状态 的关系。 【非线性优化】

  • 视觉 SLAM 主流

9.1.2 线性系统和 KF

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

经典卡尔曼滤波:从概率角度出发的最大后验概率估计方式。

在线性高斯系统中,卡尔曼滤波器 构成了 该系统中的最大后验概率估计。
卡尔曼滤波器构成了线性系统的最优无偏估计。

在这里插入图片描述

9.1.3 非线性系统 和 EKF

把卡尔曼滤波器 的结果 扩展到 非线性系统中, 扩展卡尔曼滤波器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.1.4 扩展卡尔曼滤波器 EKF 不足

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

同等计算量的情况下, 非线性优化能取得更好的效果。
精度和鲁棒性更好。

9.2 BA 与 图优化

视觉三维重建

Bundle Adjustment (BA):从视觉图像中提炼出最优的3D模型和相机参数(内参和外差)
考虑从任意特征点 发射出来的几束光线(bundles of light rays), 它们会在几个相机的成像平面上变成像素或是检测到的特征点,如果我们调整(adjustment) 各相机姿态和各自特征点的空间位置,使得这些光纤最终收束到 相机的光心,称为 BA

其它译法: 光束法平差、捆集调整

9.2.1 投影模型和 BA 代价函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

9.2.2 BA 的求解

在这里插入图片描述

9.2.3 稀疏性 和 边缘化

在这里插入图片描述
Schur消元 Marginalization(边缘化)
在这里插入图片描述
在这里插入图片描述

9.2.4 鲁棒核函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1、构造 BA 问题
2、设置 Schur 消元
3、调用 稠密或稀疏 矩阵求解器对变量进行优化

9.3 实践: Ceres BA 【Code】

在这里插入图片描述
定义 投影误差模型
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

sudo apt-get install meshlab
本讲 CMakeLists.txt
cmake_minimum_required(VERSION 2.8)

set(CMAKE_CXX_STANDARD 17)
project(bundle_adjustment)
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "-O3 -std=c++14")

LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

Find_Package(G2O REQUIRED)
Find_Package(Eigen3 REQUIRED)
Find_Package(Ceres REQUIRED)
Find_Package(Sophus REQUIRED)
Find_Package(CSparse REQUIRED)

SET(G2O_LIBS g2o_csparse_extension g2o_stuff g2o_core cxsparse)

include_directories(${PROJECT_SOURCE_DIR} ${EIGEN3_INCLUDE_DIR} ${CSPARSE_INCLUDE_DIR})


add_library(bal_common common.cpp)

add_executable(bundle_adjustment_ceres bundle_adjustment_ceres.cpp)
target_link_libraries(bundle_adjustment_ceres ${CERES_LIBRARIES} bal_common)


add_executable(bundle_adjustment_g2o bundle_adjustment_g2o.cpp)
target_link_libraries(bundle_adjustment_g2o 
                    ${G2O_LIBS} 
                    g2o_solver_csparse g2o_csparse_extension
                    ${Sophus_LIBRARIES}
                    bal_common)  

mkdir build && cd build
cmake ..
make 
./bundle_adjustment_ceres ../problem-16-22106-pre.txt
byzanz-record -x 72 -y 64 -w 1848 -h 893  -d 20 --delay=5 -c  /home/xixi/myGIF/test.gif

在这里插入图片描述

byzanz-record -x 72 -y 64 -w 1848 -h 893  -d 30 --delay=5 -c  /home/xixi/myGIF/test.gif

在这里插入图片描述
bundle_adjustment_ceres.cpp

#include <iostream>
#include <ceres/ceres.h>
#include "common.h"
#include "SnavelyReprojectionError.h"

using namespace std;

void SolveBA(BALProblem &bal_problem);

int main(int argc, char **argv) {
    if (argc != 2) {
        cout << "usage: bundle_adjustment_ceres bal_data.txt" << endl;
        return 1;
    }

    BALProblem bal_problem(argv[1]);
    bal_problem.Normalize();
    bal_problem.Perturb(0.1, 0.5, 0.5);
    bal_problem.WriteToPLYFile("initial.ply");
    SolveBA(bal_problem);
    bal_problem.WriteToPLYFile("final.ply");

    return 0;
}

void SolveBA(BALProblem &bal_problem) {
    const int point_block_size = bal_problem.point_block_size();
    const int camera_block_size = bal_problem.camera_block_size();
    double *points = bal_problem.mutable_points();
    double *cameras = bal_problem.mutable_cameras();

    // Observations is 2 * num_observations long array observations
    // [u_1, u_2, ... u_n], where each u_i is two dimensional, the x
    // and y position of the observation.
    const double *observations = bal_problem.observations();
    ceres::Problem problem;

    for (int i = 0; i < bal_problem.num_observations(); ++i) {
        ceres::CostFunction *cost_function;

        // Each Residual block takes a point and a camera as input
        // and outputs a 2 dimensional Residual
        cost_function = SnavelyReprojectionError::Create(observations[2 * i + 0], observations[2 * i + 1]);

        // If enabled use Huber's loss function.
        ceres::LossFunction *loss_function = new ceres::HuberLoss(1.0);

        // Each observation corresponds to a pair of a camera and a point
        // which are identified by camera_index()[i] and point_index()[i]
        // respectively.
        double *camera = cameras + camera_block_size * bal_problem.camera_index()[i];
        double *point = points + point_block_size * bal_problem.point_index()[i];

        problem.AddResidualBlock(cost_function, loss_function, camera, point);
    }

    // show some information here ...
    std::cout << "bal problem file loaded..." << std::endl;
    std::cout << "bal problem have " << bal_problem.num_cameras() << " cameras and "
              << bal_problem.num_points() << " points. " << std::endl;
    std::cout << "Forming " << bal_problem.num_observations() << " observations. " << std::endl;

    std::cout << "Solving ceres BA ... " << endl;
    ceres::Solver::Options options;
    options.linear_solver_type = ceres::LinearSolverType::SPARSE_SCHUR;
    options.minimizer_progress_to_stdout = true;
    ceres::Solver::Summary summary;
    ceres::Solve(options, &problem, &summary);
    std::cout << summary.FullReport() << "\n";
}

9.4 实践:g2o 求解 BA 【Code】

在这里插入图片描述
报错:

/home/xixi/Downloads/slambook2-master/ch9/bundle_adjustment_g2o.cpp:10:10: fatal error: sophus/se3.hpp: No such file or directory
   10 | #include "sophus/se3.hpp"
      |          ^~~~~~~~~~~~~~~~

在这里插入图片描述
SO3d 去掉 d 。 共3个
报错2:

/usr/local/include/g2o/stuff/tuple_tools.h:41:46: error: ‘tuple_size_v’ is not a member of ‘std’; did you mean ‘tuple_size’?
   41 |       f, t, i, std::make_index_sequence<std::tuple_size_v<std::decay_t<T>>>());

改动3:
在这里插入图片描述
第143-147行 更换成下述代码

    std::unique_ptr<g2o::BlockSolverX::LinearSolverType> linearSolver (new g2o::LinearSolverCSparse<g2o::BlockSolverX::PoseMatrixType>());

    std::unique_ptr<g2o::BlockSolverX> solver_ptr (new g2o::BlockSolverX(std::move(linearSolver)));
    g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(std::move(solver_ptr));

其它问题: 链接库的问题, 看 CMakeLists.txt

cd build
cmake ..
make 
./bundle_adjustment_g2o ../problem-16-22106-pre.txt
byzanz-record -x 72 -y 64 -w 1848 -h 893  -d 30 --delay=5 -c  /home/xixi/myGIF/test.gif

在这里插入图片描述

byzanz-record -x 72 -y 64 -w 1848 -h 893  -d 20 --delay=5 -c  /home/xixi/myGIF/test.gif

在这里插入图片描述

bundle_adjustment_g2o.cpp

#include <g2o/core/base_vertex.h>
#include <g2o/core/base_binary_edge.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/solvers/csparse/linear_solver_csparse.h>
#include <g2o/core/robust_kernel_impl.h>
#include <iostream>

#include "common.h"
#include "sophus/se3.h"

using namespace Sophus;
using namespace Eigen;
using namespace std;

/// 姿态和内参的结构
struct PoseAndIntrinsics {
    PoseAndIntrinsics() {}

    /// set from given data address
    explicit PoseAndIntrinsics(double *data_addr) {
        rotation = SO3::exp(Vector3d(data_addr[0], data_addr[1], data_addr[2]));
        translation = Vector3d(data_addr[3], data_addr[4], data_addr[5]);
        focal = data_addr[6];
        k1 = data_addr[7];
        k2 = data_addr[8];
    }

    /// 将估计值放入内存
    void set_to(double *data_addr) {
        auto r = rotation.log();
        for (int i = 0; i < 3; ++i) data_addr[i] = r[i];
        for (int i = 0; i < 3; ++i) data_addr[i + 3] = translation[i];
        data_addr[6] = focal;
        data_addr[7] = k1;
        data_addr[8] = k2;
    }

    SO3 rotation;
    Vector3d translation = Vector3d::Zero();
    double focal = 0;
    double k1 = 0, k2 = 0;
};

/// 位姿加相机内参的顶点,9维,前三维为so3,接下去为t, f, k1, k2
class VertexPoseAndIntrinsics : public g2o::BaseVertex<9, PoseAndIntrinsics> {
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;

    VertexPoseAndIntrinsics() {}

    virtual void setToOriginImpl() override {
        _estimate = PoseAndIntrinsics();
    }

    virtual void oplusImpl(const double *update) override {
        _estimate.rotation = SO3::exp(Vector3d(update[0], update[1], update[2])) * _estimate.rotation;
        _estimate.translation += Vector3d(update[3], update[4], update[5]);
        _estimate.focal += update[6];
        _estimate.k1 += update[7];
        _estimate.k2 += update[8];
    }

    /// 根据估计值投影一个点
    Vector2d project(const Vector3d &point) {
        Vector3d pc = _estimate.rotation * point + _estimate.translation;
        pc = -pc / pc[2];
        double r2 = pc.squaredNorm();
        double distortion = 1.0 + r2 * (_estimate.k1 + _estimate.k2 * r2);
        return Vector2d(_estimate.focal * distortion * pc[0],
                        _estimate.focal * distortion * pc[1]);
    }

    virtual bool read(istream &in) {}

    virtual bool write(ostream &out) const {}
};

class VertexPoint : public g2o::BaseVertex<3, Vector3d> {
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;

    VertexPoint() {}

    virtual void setToOriginImpl() override {
        _estimate = Vector3d(0, 0, 0);
    }

    virtual void oplusImpl(const double *update) override {
        _estimate += Vector3d(update[0], update[1], update[2]);
    }

    virtual bool read(istream &in) {}

    virtual bool write(ostream &out) const {}
};

class EdgeProjection :
    public g2o::BaseBinaryEdge<2, Vector2d, VertexPoseAndIntrinsics, VertexPoint> {
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;

    virtual void computeError() override {
        auto v0 = (VertexPoseAndIntrinsics *) _vertices[0];
        auto v1 = (VertexPoint *) _vertices[1];
        auto proj = v0->project(v1->estimate());
        _error = proj - _measurement;
    }

    // use numeric derivatives
    virtual bool read(istream &in) {}

    virtual bool write(ostream &out) const {}

};

void SolveBA(BALProblem &bal_problem);

int main(int argc, char **argv) {

    if (argc != 2) {
        cout << "usage: bundle_adjustment_g2o bal_data.txt" << endl;
        return 1;
    }

    BALProblem bal_problem(argv[1]);
    bal_problem.Normalize();
    bal_problem.Perturb(0.1, 0.5, 0.5);
    bal_problem.WriteToPLYFile("initial.ply");
    SolveBA(bal_problem);
    bal_problem.WriteToPLYFile("final.ply");

    return 0;
}

void SolveBA(BALProblem &bal_problem) {
    const int point_block_size = bal_problem.point_block_size();
    const int camera_block_size = bal_problem.camera_block_size();
    double *points = bal_problem.mutable_points();
    double *cameras = bal_problem.mutable_cameras();

    // pose dimension 9, landmark is 3
    /*typedef g2o::BlockSolver<g2o::BlockSolverTraits<9, 3>> BlockSolverType;
    typedef g2o::LinearSolverCSparse<BlockSolverType::PoseMatrixType> LinearSolverType;
    // use LM
    auto solver = new g2o::OptimizationAlgorithmLevenberg(
        g2o::make_unique<BlockSolverType>(g2o::make_unique<LinearSolverType>()));*/
    
    std::unique_ptr<g2o::BlockSolverX::LinearSolverType> linearSolver (new g2o::LinearSolverCSparse<g2o::BlockSolverX::PoseMatrixType>());

    std::unique_ptr<g2o::BlockSolverX> solver_ptr (new g2o::BlockSolverX(std::move(linearSolver)));
    g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(std::move(solver_ptr));

    g2o::SparseOptimizer optimizer;
    optimizer.setAlgorithm(solver);
    optimizer.setVerbose(true);

    /// build g2o problem
    const double *observations = bal_problem.observations();
    // vertex
    vector<VertexPoseAndIntrinsics *> vertex_pose_intrinsics;
    vector<VertexPoint *> vertex_points;
    for (int i = 0; i < bal_problem.num_cameras(); ++i) {
        VertexPoseAndIntrinsics *v = new VertexPoseAndIntrinsics();
        double *camera = cameras + camera_block_size * i;
        v->setId(i);
        v->setEstimate(PoseAndIntrinsics(camera));
        optimizer.addVertex(v);
        vertex_pose_intrinsics.push_back(v);
    }
    for (int i = 0; i < bal_problem.num_points(); ++i) {
        VertexPoint *v = new VertexPoint();
        double *point = points + point_block_size * i;
        v->setId(i + bal_problem.num_cameras());
        v->setEstimate(Vector3d(point[0], point[1], point[2]));
        // g2o在BA中需要手动设置待Marg的顶点
        v->setMarginalized(true);
        optimizer.addVertex(v);
        vertex_points.push_back(v);
    }

    // edge
    for (int i = 0; i < bal_problem.num_observations(); ++i) {
        EdgeProjection *edge = new EdgeProjection;
        edge->setVertex(0, vertex_pose_intrinsics[bal_problem.camera_index()[i]]);
        edge->setVertex(1, vertex_points[bal_problem.point_index()[i]]);
        edge->setMeasurement(Vector2d(observations[2 * i + 0], observations[2 * i + 1]));
        edge->setInformation(Matrix2d::Identity());
        edge->setRobustKernel(new g2o::RobustKernelHuber());
        optimizer.addEdge(edge);
    }

    optimizer.initializeOptimization();
    optimizer.optimize(40);

    // set to bal problem
    for (int i = 0; i < bal_problem.num_cameras(); ++i) {
        double *camera = cameras + camera_block_size * i;
        auto vertex = vertex_pose_intrinsics[i];
        auto estimate = vertex->estimate();
        estimate.set_to(camera);
    }
    for (int i = 0; i < bal_problem.num_points(); ++i) {
        double *point = points + point_block_size * i;
        auto vertex = vertex_points[i];
        for (int k = 0; k < 3; ++k) point[k] = vertex->estimate()[k];
    }
}

在这里插入图片描述
在这里插入图片描述

习题

在这里插入图片描述

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

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

相关文章

FTP(数据共享)

1. 软件下载 到官方网站下载FileZilla的服务端和客户端程序 网站:FileZilla - The free FTP solution 自行下载即可 2. 服务器安装与配置 2.1 安装 安装的过程非常简单&#xff0c;直接下一步就可以了&#xff0c;需要说明的是&#xff0c;下图中的端口指的是FileZill…

GCC内联汇编及其在Linux内核中的使用

1. 概述 学习 GCC 内联汇编又多了一个好处。现在让我们深入内核&#xff0c;看看一些事情是如何实际工作的。 GNU C 编译器允许您将汇编语言代码嵌入到 C 程序中。 本教程解释了如何在 ARM 架构上做到这一点(译注&#xff1a;因此&#xff0c;若要测试本文档中使用的例子&…

Android MediaMetadataRetriever setDataSource failed: status = 0xFFFFFFEA

Android MediaMetadataRetriever setDataSource抛错&#xff1a; java.lang.RuntimeException: setDataSource failed: status 0xFFFFFFEA 原因是 setDataSource(String path) path指向的视频文件大小为0或者是破损视频资源。 Android AppGlideModule,DataFetcher,ModelLoad…

力扣刷题 day48:10-18

1.4的幂 给定一个整数&#xff0c;写一个函数来判断它是否是 4 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 整数 n 是 4 的幂次方需满足&#xff1a;存在整数 x 使得 n 4x 方法一&#xff1a;不断除以4 #方法一&#xff1a;不断除…

windows本地文件上传linux 或 linux输入rz命令后出现receive.**B0100000023be50

这种现象需要客户端支持&#xff0c;或者使用Xshell工具等 但是有一种简单的方法&#xff0c;使用 sftp rootip地址 // 比如 sftp root127.0.0.2 当然&#xff0c;你要记得登录远程节点的密码&#xff1a;

什么是gpt?国内怎么用?

近年来&#xff0c;人工智能技术在国内迅猛发展&#xff0c;成为推动社会进步的重要力量。在这个数字化时代&#xff0c;智能助手在生活中的应用越来越广泛。其中&#xff0c;OpenAI的ChatGPT作为一种先进的自然语言处理模型&#xff0c;为用户提供了强大的智能对话体验。但是O…

什么是网络爬虫,爬虫的机制是那些

网络爬虫&#xff08;也称为网页蜘蛛、网络机器人或网页追逐者&#xff09;是一种按照预设规则&#xff0c;自动抓取万维网信息的程序或脚本。它们广泛应用于搜索引擎、数据挖掘、竞争情报、价格监测等各种互联网应用中。 爬虫机制是爬虫程序或机器人用来访问、抓取、索引以及…

智慧人防三维数字沙盘系统

1&#xff09;系统架构设计 智慧人防三维数字沙盘系统软件是深圳易图讯科技有限公司(www.3dgis.top)基于WebGL、WEBGIS平台引擎自主研发&#xff0c;以二三维地理空间场景为电子沙盘展示平台&#xff08;支持导入3DMAX、BIM、无人机倾斜等三维模型&#xff09;&#xff0c;以二…

【小黑嵌入式系统第二课】嵌入式系统的概述(二)——外围设备、处理器、ARM、操作系统

上一课&#xff1a; 【小黑嵌入式系统第一课】嵌入式系统的概述&#xff08;一&#xff09;——概念、特点、发展、应用 下一课&#xff1a; 【小黑嵌入式系统第三课】嵌入式系统硬件平台&#xff08;一&#xff09;——概述、总线、存储设备&#xff08;RAM&ROM&FLASH…

好用的办公软件有哪些

日常的工作难免和各种各样的软件打交道&#xff0c;除了传统的Office三件套&#xff0c;小编日常还在用着其他的办公软件&#xff0c;借此跟各位分享其中比较好用、堪称办公神器的8款软件&#xff01; 1.WPS office 2.office2007 3.EasyConnect 4.ToDesk 5.Photoshop 6.A…

DAY 1 QT 创建QQ界面

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//创建一个窗口&#xff0c;改变窗口标签名和窗口标签图标this -> resize(640,500);//设置窗口界面大小this -> setWindowTitle("QQ登录");//设置窗口标题this -> s…

linux手动安装scapy2.5

手动安装scap2.5&#xff0c;或者其他版本 当然如果有网络的话&#xff0c;可以直接安装最新版本(如果本地python版本支持的话)&#xff1a; pip install scapy查看python版本与scapy版本支持关系&#xff1a; 下载安装包 scapy2.5地址&#xff1a;scapy2.5.0 scapy历史地址…

SpringCloud微服务(注册发现Nacos、服务调用SSM、网关gateway)项目环境搭建(项目概况,SSM细节总结)

目录 1.nacos环境搭建nacos安装 2.项目主体结构6.2)表结构分析6.4)**运营端微服务搭建**6.4)登录功能实现 7)接口工具postman、swagger、knife4j7.1)postman7.2)swagger7.3)knife4j 8)网关9)前端集成9.1)前端项目部署思路9.2)配置nginx 1.nacos环境搭建 nacos安装 ①&#xf…

asp.net特色商品购物网站系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net特色商品购物网站系统 是一套完善的web设计管理系统&#xff0c;系统采用mvc模式&#xff08;BLLDALENTITY&#xff09;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 vs2010&#xff0c;数据库为sqlserver2008&a…

压缩图片怎么压缩?压缩图片的步骤

网页设计师或开发人员&#xff0c;可能需要将网页中使用的电脑图片压缩&#xff0c;通过减小图片文件大小&#xff0c;可以加快网页加载速度&#xff0c;提升用户体验&#xff0c;减少带宽消耗&#xff0c;那么除了下载安装图片压缩&#xff08;https://www.yasuotu.com&#x…

PG集合查询

1.运算符 1.1 union并集 连接上下语句 union distinct连接并且去重 all不去重 1.2 intersect交集 上下交集 distinct连接并且去重 all不去重 1.3 except除外 上面除了下面 distinc去重 all不去重

机器学习基础之《回归与聚类算法(4)—逻辑回归与二分类(分类算法)》

一、什么是逻辑回归 1、逻辑回归&#xff08;Logistic Regression&#xff09;是机器学习中的一种分类模型&#xff0c;逻辑回归是一种分类算法&#xff0c;虽然名字中带有回归&#xff0c;但是它与回归之间有一定的联系。由于算法的简单和高效&#xff0c;在实际中应用非常广…

【FPGA零基础学习之旅#15】串口接收模块设计与验证(工业环境)

&#x1f389;欢迎来到FPGA专栏~串口接收模块设计与验证&#xff08;工业环境&#xff09; ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如…

【ArcGIS微课1000例】0075:将AutoCAD(Dwg、Dxf)文件转换为shp、KML(kml、kmz)文件

文章目录 1. 加载DWG2. 导出为shp3. 投影变换4. 转为kml1. 加载DWG 打开ArcMap,点击添加符号: 选择地形图dwg数据,全选图层,也可以选择需要的图层。 提示位置的空间参考,点击确定即可。 加载效果。 2. 导出为shp 接下来我们演示将面状数据转为shp,选择Polygon图层,右键…

SD卡与NAND flash的差异

SD卡与普通的NAND Flash相比&#xff0c;具有以下优势和劣势&#xff1a; 优势&#xff1a; 可移动性&#xff1a;SD卡是一种可移动存储介质&#xff0c;可以轻松插入和拔出支持SD卡接口的设备&#xff0c;如相机、手机、笔记本电脑等。这使得SD卡成为方便携带和共享数据的理想…