PCL从理解到应用【06】 RANSAC原理分析 | 案例分析 | 代码实现

前言

本文分析RANSAC算法的原理,集合案例深入理解,同时提供源代码。

RANSAC,随机采样一致性,是一种迭代的算法,用于从一组包含异常值的数据中估计模型参数。

应用案例:平面拟合、线段拟合、球体拟合等。

 看看基于RANSAC的球体拟合可视化结果,如下图所示:

输出的拟合系数

Model coefficients: 1.96703 0.455202 3.86515 1.24063

对应:球体的中心(x,y,z)和半径r

一、RANSAC 原理分析

RANSAC(Random Sample Consensus,随机采样一致性)是一种迭代的算法,用于从一组包含异常值的数据中估计模型参数。

它由Fischler和Bolles于1981年提出,特别适用于在存在大量噪声或异常值的情况下,估计模型的参数。

  • 输入数据和模型

    • 输入数据集,其中包含内点(符合模型的数据点)和外点(异常值)。
    • 选择一个适合于问题的模型,例如直线、平面、变换矩阵等。
  • 迭代过程

    • 设定最大迭代次数N和误差阈值T
    • 在每次迭代中,随机选择一个最小子集的数据点(样本集),该子集应该足够小以保证计算模型参数。
    • 根据样本集计算模型参数。
  • 模型评估

    • 使用计算出的模型参数评估所有数据点,计算每个数据点与模型的误差。
    • 统计误差在阈值T内的内点数目。
    • 如果当前模型的内点数目超过之前的最佳模型,则更新最佳模型和最佳内点集。
  • 终止条件

    • 迭代达到最大次数N或者找到了足够好的模型。
  • 输出

    • 最佳模型参数和对应的内点集。

下面分析一下与RANSAC相近的算法

    算法        简介                      原理          特点 计算复杂度          优点         缺点
RANSAC 随机采样一致性算法 迭代随机采样,估计模型参数,选择内点最多的模型 通用模型估计 中等 简单易实现,对异常值鲁棒 需要设定参数,效率较低
MLESAC 基于最大似然估计的采样一致性算法 结合最大似然估计,通过最大化数据的似然估计来选择模型参数 提高了参数估计的准确性 较高 对噪声和异常值处理更好 计算复杂度高,参数选择敏感
MSAC 基于M估计的采样一致性算法 类似于RANSAC,但通过最小化所有数据点的代价函数来选择最佳模型 更好地考虑所有数据点的误差 较高 对异常值有更好的容忍度 计算复杂度相对较高
PROSAC 进步采样一致性算法 利用数据点的排序信息,优先从高质量点中选择样本集,提高采样效率 高效准确,快速收敛 较高 更快地收敛到最佳模型 需要对数据点进行排序,预处理时间较长
LMedS 最小中位数平方算法 通过最小化残差的中位数来估计模型参数 对异常值非常鲁棒 很高 对异常值非常鲁棒,不需要预设误差阈值 计算复杂度高,处理大数据集时效率较低
Theil-Sen 非参数线性回归估计 计算所有数据点对之间斜率的中位数来估计回归系数 非参数方法,特别适用于线性回归 较低 对异常值具有较强的抗干扰能力,计算简单,效率较高 主要用于线性模型,适用范围较窄

RANSAC算法广泛应用于计算机视觉和图像处理领域,如:

  • 图像拼接:在图像配准过程中,通过RANSAC算法估计变换矩阵。
  • 三维重建:用于点云配准,估计旋转和平移矩阵。
  • 平面拟合:在三维点云数据中,拟合平面或其他几何模型。

二、RANSAC常用方法

在PCL中,RANSAC(随机采样一致性)是一种常用的模型拟合算法,用于从点云数据中提取几何模型。

PCL 提供了多个与 RANSAC 相关的函数和类,用于不同类型的模型拟合

  • pcl::SampleConsensusModel:这是一个抽象基类,定义了所有采样一致性模型应实现的接口。具体的模型类继承自这个基类。
  • pcl::SampleConsensusModelPlane:用于平面模型的拟合。
  • pcl::SampleConsensusModelLine:用于线模型的拟合。
  • pcl::SampleConsensusModelCircle2D:用于二维圆模型的拟合。
  • pcl::SampleConsensusModelSphere:用于球体模型的拟合。
  • pcl::SampleConsensusModelCylinder:用于圆柱体模型的拟合。
  • pcl::SampleConsensusModelNormalPlane:用于法线约束的平面模型的拟合。
  • pcl::RandomSampleConsensus:这是 RANSAC 算法的具体实现类。可以与上述模型类结合使用。

1. pcl::SampleConsensusModel

pcl::SampleConsensusModel 是所有采样一致性模型的基类。

它定义了所有模型应实现的基本接口。具体的模型类会从这个基类继承并实现其方法。

2. pcl::SampleConsensusModelPlane

这个类用于平面模型的拟合。它继承自 pcl::SampleConsensusModel 并实现了平面模型的特定方法。

主要方法:

  • computeModelCoefficients(const std::vector<int> &samples, Eigen::VectorXf &model_coefficients): 计算平面模型的系数。
  • isModelValid(const Eigen::VectorXf &model_coefficients): 检查模型是否有效。

3. pcl::SampleConsensusModelLine

这个类用于线模型的拟合。它也继承自 pcl::SampleConsensusModel 并实现了线模型的特定方法。

主要方法:

  • computeModelCoefficients(const std::vector<int> &samples, Eigen::VectorXf &model_coefficients): 计算线模型的系数。
  • isModelValid(const Eigen::VectorXf &model_coefficients): 检查模型是否有效。

4. pcl::SampleConsensusModelCircle2D

这个类用于二维圆模型的拟合。它适用于在 XY 平面中的点云数据。

主要方法:

  • computeModelCoefficients(const std::vector<int> &samples, Eigen::VectorXf &model_coefficients): 计算二维圆模型的系数。
  • isModelValid(const Eigen::VectorXf &model_coefficients): 检查模型是否有效。

5. pcl::SampleConsensusModelSphere

这个类用于球体模型的拟合。它适用于三维点云数据中的球体检测。

主要方法:

  • computeModelCoefficients(const std::vector<int> &samples, Eigen::VectorXf &model_coefficients): 计算球体模型的系数。
  • isModelValid(const Eigen::VectorXf &model_coefficients): 检查模型是否有效。

6. pcl::SampleConsensusModelCylinder

这个类用于圆柱体模型的拟合。它适用于三维点云数据中的圆柱体检测。

主要方法:

  • computeModelCoefficients(const std::vector<int> &samples, Eigen::VectorXf &model_coefficients): 计算圆柱体模型的系数。
  • isModelValid(const Eigen::VectorXf &model_coefficients): 检查模型是否有效。

7. pcl::SampleConsensusModelNormalPlane

这个类用于法线约束的平面模型的拟合。它在普通的平面模型拟合基础上增加了法线约束,以提高拟合精度。

主要方法:

  • computeModelCoefficients(const std::vector<int> &samples, Eigen::VectorXf &model_coefficients): 计算带法线约束的平面模型的系数。
  • isModelValid(const Eigen::VectorXf &model_coefficients): 检查模型是否有效。

8. pcl::RandomSampleConsensus

pcl::RandomSampleConsensus 是 RANSAC 算法的具体实现类。它可以与上述各种模型类结合使用,以实现不同类型的几何模型拟合。

主要方法:

  • computeModel(int debug_verbosity_level = 0): 运行 RANSAC 算法,计算模型系数。
  • getInliers(): 获取内点集合。
  • getModelCoefficients(): 获取模型系数。

三、RANSAC优缺点分析

优点

  • 对于有大量异常值的数据集,RANSAC算法可以有效地估计模型参数。
  • 算法简单易实现,且适用于多种不同类型的模型估计问题。

缺点

  • 需要设定最大迭代次数和误差阈值,参数的选择对算法的效果有很大影响。
  • 随机采样可能导致计算时间较长,特别是在数据集较大且异常值较多的情况下。
  • 如果数据中内点比例非常低,RANSAC可能需要大量的迭代才能找到合适的模型。

用途:

  1. 平面拟合,可以用于从点云数据中提取平面。这在3D建模、建筑扫描和机器人导航中非常有用。
  2. 线条检测,在图像处理和计算机视觉中,RANSAC 可以用于从二维数据中检测直线,如道路检测、车道线识别等。
  3. 圆和球体检测,用于检测二维图像中的圆形或三维点云中的球体。这在物体识别和形状分析中很有用。
  4. 立体视觉,用于立体匹配中的基础矩阵或单应矩阵的估计。这有助于从两个视点重建3D场景。
  5. 相机标定,在相机标定中,RANSAC 可用于估计相机的内参和外参,处理噪声和异常值的影响,提高标定精度。
  6. 运动估计,用于运动估计,如在视频序列中跟踪物体的运动,估计相机运动,处理场景中的动态对象。
  7. 点云配准,在点云配准中,RANSAC 可用于估计点云之间的变换矩阵,特别是在初始对齐阶段,用于处理错误匹配。
  8. 特征匹配,可以用于图像特征匹配,如SIFT、SURF等特征点之间的匹配,通过处理错误匹配来提高匹配的可靠性。

四、RANSAC案例——平面拟合

使用 PCL 中的 RANSAC 生成一个随机平面点云,进行平面拟合,并可视化结果。

  • 生成随机平面点云

    • generateRandomPlane 函数随机生成一个平面上的点云数据。
    • 平面的参数 a, b, c, d 随机生成,点的坐标 (x, y, z) 满足平面方程 ax + by + cz + d = 0
  • 执行平面拟合

    • 创建 pcl::SampleConsensusModelPlane 对象用于定义平面模型。
    • 创建 pcl::RandomSampleConsensus 对象并设置适当的距离阈值。
    • 调用 ransac.computeModel() 方法执行 RANSAC 算法,计算平面模型参数。
    • 获取内点索引和模型系数。

核心代码:

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_plane.h>
#include <cstdlib>
#include <ctime>
#include <thread> 
#include <chrono>

void generateRandomPlane(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, int num_points) {
    std::srand(std::time(nullptr));
    float a = static_cast<float>(std::rand()) / RAND_MAX;
    float b = static_cast<float>(std::rand()) / RAND_MAX;
    float c = static_cast<float>(std::rand()) / RAND_MAX;
    float d = static_cast<float>(std::rand()) / RAND_MAX;

    for (int i = 0; i < num_points; ++i) {
        pcl::PointXYZ point;
        point.x = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
        point.y = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
        point.z = -(a * point.x + b * point.y + d) / c;
        cloud->points.push_back(point);
    }
    cloud->width = static_cast<uint32_t>(cloud->points.size());
    cloud->height = 1;
    cloud->is_dense = true;
}

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    // 生成随机平面点云
    generateRandomPlane(cloud, 1000);

    // 创建平面模型对象
    pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr
        model_plane(new pcl::SampleConsensusModelPlane<pcl::PointXYZ>(cloud));

    // 创建 RANSAC 对象
    pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_plane);
    ransac.setDistanceThreshold(0.01);
    ransac.computeModel();

    // 获取内点索引
    std::vector<int> inliers;
    ransac.getInliers(inliers);

    // 输出模型系数
    Eigen::VectorXf coefficients;
    ransac.getModelCoefficients(coefficients);
    std::cout << "Model coefficients: " << coefficients[0] << " "
              << coefficients[1] << " "
              << coefficients[2] << " "
              << coefficients[3] << std::endl;

    // 创建可视化对象
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);

    // 添加原始点云到可视化窗口
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 255, 255, 255);
    viewer->addPointCloud<pcl::PointXYZ>(cloud, cloud_color, "sample cloud");

    // 可视化拟合的平面
    pcl::ModelCoefficients::Ptr plane_coefficients(new pcl::ModelCoefficients);
    plane_coefficients->values.resize(4);
    plane_coefficients->values[0] = coefficients[0];
    plane_coefficients->values[1] = coefficients[1];
    plane_coefficients->values[2] = coefficients[2];
    plane_coefficients->values[3] = coefficients[3];
    viewer->addPlane(*plane_coefficients, "plane");

    // 开始主循环
    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}

看看可视化结果,如下图所示:

输出的模型拟合系数:

Model coefficients:  0.837264 0.258466 0.481855 0.425604

对应平面的参数 a, b, c, d ,点的坐标 (x, y, z) 满足平面方程 ax + by + cz + d = 0

五、RANSAC案例——线段拟合

使用 PCL 中的 RANSAC 生成随机线段点云,进行线条拟合,并可视化结果。

  • 生成随机线段点云:创建一个函数随机生成线段上的点。
  • 执行线条拟合:使用 RANSAC 算法拟合线条模型。
  • 可视化结果:使用 PCL 的可视化工具显示点云和拟合的线条。

核心代码:

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_line.h>
#include <cstdlib>
#include <ctime>
#include <thread>
#include <chrono>
#include <random>

// 生成随机点云,并添加散乱的噪声
void generateRandomPointCloudWithScatterNoise(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, int num_points, float noise_stddev, int num_noise_points) {
    std::srand(std::time(nullptr));
    // 随机生成线段的两个端点
    pcl::PointXYZ point1, point2;
    point1.x = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    point1.y = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    point1.z = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    point2.x = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    point2.y = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    point2.z = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;

    // 创建一个正态分布生成器,用于添加噪声
    std::default_random_engine generator;
    std::normal_distribution<float> distribution(0.0, noise_stddev);

    // 生成线段上的随机点
    for (int i = 0; i < num_points; ++i) {
        float t = static_cast<float>(std::rand()) / RAND_MAX;
        pcl::PointXYZ point;
        point.x = point1.x + t * (point2.x - point1.x) + distribution(generator);
        point.y = point1.y + t * (point2.y - point1.y) + distribution(generator);
        point.z = point1.z + t * (point2.z - point1.z) + distribution(generator);
        cloud->points.push_back(point);
    }

    // 添加散乱的噪声点
    for (int i = 0; i < num_noise_points; ++i) {
        pcl::PointXYZ noise_point;
        noise_point.x = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
        noise_point.y = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
        noise_point.z = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
        cloud->points.push_back(noise_point);
    }

    cloud->width = static_cast<uint32_t>(cloud->points.size());
    cloud->height = 1;
    cloud->is_dense = true;
}

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    // 生成带有散乱噪声的随机点云
    generateRandomPointCloudWithScatterNoise(cloud, 1000, 0.05f, 200);

    // 创建线段模型对象
    pcl::SampleConsensusModelLine<pcl::PointXYZ>::Ptr
        model_line(new pcl::SampleConsensusModelLine<pcl::PointXYZ>(cloud));

    // 创建 RANSAC 对象
    pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_line);
    ransac.setDistanceThreshold(0.05);
    ransac.computeModel();

    // 获取内点索引
    std::vector<int> inliers;
    ransac.getInliers(inliers);

    // 输出模型系数
    Eigen::VectorXf coefficients;
    ransac.getModelCoefficients(coefficients);
    std::cout << "Model coefficients: " << coefficients[0] << " "
              << coefficients[1] << " "
              << coefficients[2] << " "
              << coefficients[3] << " "
              << coefficients[4] << " "
              << coefficients[5] << std::endl;

    // 创建可视化对象
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);

    // 添加原始点云到可视化窗口
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 255, 255, 255);
    viewer->addPointCloud<pcl::PointXYZ>(cloud, cloud_color, "sample cloud");

    // 可视化拟合的线条
    pcl::ModelCoefficients::Ptr line_coefficients(new pcl::ModelCoefficients);
    line_coefficients->values.resize(6);
    line_coefficients->values[0] = coefficients[0];
    line_coefficients->values[1] = coefficients[1];
    line_coefficients->values[2] = coefficients[2];
    line_coefficients->values[3] = coefficients[3];
    line_coefficients->values[4] = coefficients[4];
    line_coefficients->values[5] = coefficients[5];
    viewer->addLine(*line_coefficients, "line");

    // 开始主循环
    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}
  • 生成随机点云并添加散乱噪声

    • generateRandomPointCloudWithScatterNoise 函数随机生成线段上的点,并在每个点的坐标上添加噪声。
    • 同时,生成一些散乱的噪声点,分布在整个空间中。
  • 执行线条拟合

    • 创建 pcl::SampleConsensusModelLine 对象用于定义线条模型。
    • 创建 pcl::RandomSampleConsensus 对象并设置适当的距离阈值(这里设置为 0.05,以考虑添加的噪声)。
    • 调用 ransac.computeModel() 方法执行 RANSAC 算法,计算线条模型参数。
    • 获取内点索引和模型系数。

看看可视化结果,如下图所示:

输出的拟合系数

Model coefficients: 6.4163 6.92066 2.9858 0.919972 -0.385063 0.0733363

对应:线段的两个端点(x1,y1,z1),(x2,y2,z2)

六、RANSAC案例——球体拟合

使用 PCL 中的 RANSAC 生成随机点云,进行球体检测,并可视化结果。

  • 生成随机球体点云并添加噪声

    • generateRandomSphereWithNoise 函数随机生成球体上的点。
    • 首先随机生成球体的中心和半径,然后在球体表面生成随机点,并在每个点的坐标上添加噪声。
    • 噪声是通过正态分布生成的,标准差由 noise_stddev 参数指定。
  • 执行球体检测

    • 创建 pcl::SampleConsensusModelSphere 对象用于定义球体模型。
    • 创建 pcl::RandomSampleConsensus 对象并设置适当的距离阈值(这里设置为 0.05,以考虑添加的噪声)。
    • 调用 ransac.computeModel() 方法执行 RANSAC 算法,计算球体模型参数。
    • 获取内点索引和模型系数。

核心代码:

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_sphere.h>
#include <cstdlib>
#include <ctime>
#include <thread>
#include <chrono>
#include <random>

// 生成随机球体点云,并添加噪声
void generateRandomSphereWithNoise(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, int num_points, float noise_stddev) {
    std::srand(std::time(nullptr));
    // 随机生成球体的中心和半径
    pcl::PointXYZ center;
    center.x = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    center.y = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    center.z = 10.0f * static_cast<float>(std::rand()) / RAND_MAX;
    float radius = 5.0f * static_cast<float>(std::rand()) / RAND_MAX + 1.0f; // 半径在 1.0 到 6.0 之间

    // 创建一个正态分布生成器,用于添加噪声
    std::default_random_engine generator;
    std::normal_distribution<float> distribution(0.0, noise_stddev);

    // 生成球体上的随机点,并添加噪声
    for (int i = 0; i < num_points; ++i) {
        float theta = 2.0f * M_PI * static_cast<float>(std::rand()) / RAND_MAX;
        float phi = M_PI * static_cast<float>(std::rand()) / RAND_MAX;
        pcl::PointXYZ point;
        point.x = center.x + radius * std::sin(phi) * std::cos(theta) + distribution(generator);
        point.y = center.y + radius * std::sin(phi) * std::sin(theta) + distribution(generator);
        point.z = center.z + radius * std::cos(phi) + distribution(generator);
        cloud->points.push_back(point);
    }

    cloud->width = static_cast<uint32_t>(cloud->points.size());
    cloud->height = 1;
    cloud->is_dense = true;
}

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    // 生成带噪声的随机球体点云
    generateRandomSphereWithNoise(cloud, 1000, 0.05f);

    // 创建球体模型对象
    pcl::SampleConsensusModelSphere<pcl::PointXYZ>::Ptr
        model_sphere(new pcl::SampleConsensusModelSphere<pcl::PointXYZ>(cloud));

    // 创建 RANSAC 对象
    pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_sphere);
    ransac.setDistanceThreshold(0.05);
    ransac.computeModel();

    // 获取内点索引
    std::vector<int> inliers;
    ransac.getInliers(inliers);

    // 输出模型系数
    Eigen::VectorXf coefficients;
    ransac.getModelCoefficients(coefficients);
    std::cout << "Model coefficients: " << coefficients[0] << " "
              << coefficients[1] << " "
              << coefficients[2] << " "
              << coefficients[3] << std::endl;

    // 创建可视化对象
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);

    // 添加原始点云到可视化窗口
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 255, 255, 255);
    viewer->addPointCloud<pcl::PointXYZ>(cloud, cloud_color, "sample cloud");

    // 可视化拟合的球体
    pcl::ModelCoefficients::Ptr sphere_coefficients(new pcl::ModelCoefficients);
    sphere_coefficients->values.resize(4);
    sphere_coefficients->values[0] = coefficients[0];
    sphere_coefficients->values[1] = coefficients[1];
    sphere_coefficients->values[2] = coefficients[2];
    sphere_coefficients->values[3] = coefficients[3];
    viewer->addSphere(*sphere_coefficients, "sphere");

    // 开始主循环
    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}

看看可视化结果,如下图所示:

输出的拟合系数

Model coefficients: 1.96703 0.455202 3.86515 1.24063

对应:球体的中心(x,y,z)和半径r

分享完成~

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 02:50:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 02:50:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 02:50:03       58 阅读
  4. Python语言-面向对象

    2024-07-17 02:50:03       69 阅读

热门阅读

  1. powerShell相关

    2024-07-17 02:50:03       16 阅读
  2. Set接口

    2024-07-17 02:50:03       17 阅读
  3. 【Pandas】-Series数据类型

    2024-07-17 02:50:03       25 阅读
  4. 高程值的二维数组生成tiff栅格文件格式

    2024-07-17 02:50:03       27 阅读
  5. C#WPF DialogHost.Show 弹出对话框并返回数据

    2024-07-17 02:50:03       20 阅读
  6. QSFPDD光模块文档解析

    2024-07-17 02:50:03       21 阅读
  7. 【Python 项目】照片马赛克 - 3

    2024-07-17 02:50:03       24 阅读
  8. 如何衡量机器学习分类模型(python)

    2024-07-17 02:50:03       22 阅读
  9. Backend - Dockerfile 镜像档

    2024-07-17 02:50:03       24 阅读
  10. SQL进阶--条件分支

    2024-07-17 02:50:03       22 阅读
  11. workingset protection/detection on the anonymous LRU list

    2024-07-17 02:50:03       21 阅读