PCL点云库安装与案例实践手册

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:PCL是一个专门处理3D点云数据的C++开源库,适用于3D计算机视觉、机器人等领域。本教程详细指导如何在不同操作系统上安装PCL 1.8版本及其依赖项,并通过案例实践来学习点云数据的处理,包括读取、显示、滤波、聚类和表面重建等操作。

1. PCL点云库概览

点云是三维空间中散乱分布的一组数据点集合,它广泛应用于机器人、计算机视觉、3D打印和增强现实等众多领域。PCL(Point Cloud Library)是一个开源的大型跨平台机器视觉库,专注于点云处理,提供了从基本数据类型到复杂算法在内的多种工具。

PCL库的优点包括:
- 跨平台性 :能够在不同的操作系统上运行,如Windows, Linux, Mac OS等。
- 丰富功能 :拥有滤波、特征提取、表面重建、数据集处理等多种功能。
- 模块化 :便于进行模块化开发,开发者可以根据需要选择合适的模块进行编程。

PCL库的构建依赖于许多其他开源库,例如Boost、Eigen、VTK等。它还提供了大量的示例和应用程序,供初学者学习和高级用户深入研究。接下来的章节将会详细介绍如何在不同系统上安装和配置PCL库,以及如何利用它进行点云数据的处理。

2. 系统需求与依赖项检查

2.1 确定系统兼容性

2.1.1 PCL支持的操作系统

PCL(Point Cloud Library)是一个开源的库,主要支持Linux操作系统。不过,通过社区的努力,PCL也能在Windows和Mac OS X平台上进行编译和使用。详细的兼容性信息如下:

  • Linux : PCL在Linux系统上支持度最好,包括Ubuntu、Fedora、Debian等多种发行版。大多数Linux发行版都有现成的PCL软件包,可以通过包管理器直接安装。

  • Windows : PCL官方提供了预编译的二进制包和Windows安装程序,可以方便地在Windows系统上进行安装。不过,建议使用Visual Studio作为开发环境,并配置CMake构建系统。

  • Mac OS X : 可以通过Homebrew或者MacPorts包管理器来安装PCL。此外,也可以从源代码编译安装。

2.1.2 确认硬件要求

在安装和使用PCL之前,需要确认你的计算机硬件满足以下基本要求:

  • 处理器 : 至少为双核处理器,建议使用四核以上处理器以获得更好的体验。
  • 内存 : 至少需要4GB RAM,但为了处理大型点云数据,8GB或更多会更加理想。
  • 磁盘空间 : 安装PCL及其依赖项会占用几GB的空间,额外还需要空间来存储点云数据。
  • 显卡 : 如果需要使用PCL的可视化模块,具备支持OpenGL的显卡将会提高性能。

2.2 检查依赖库和工具

2.2.1 必要的编译器和开发工具

为了成功编译PCL,你需要准备好以下的编译器和开发工具:

  • CMake : 是PCL推荐的构建系统,用于生成项目文件和管理构建过程。
  • 编译器 : 对于Linux系统,GCC和Clang都是可选的。在Windows上,推荐使用Microsoft Visual Studio的编译器。
  • Git : 如果你打算从源代码编译PCL,你将需要Git来克隆仓库。

2.2.2 第三方库的安装与配置

PCL库有多个依赖的第三方库,这些库支持PCL的众多功能。必须安装和配置这些依赖库,以下是一些关键的第三方库:

  • Boost : 提供C++标准库的扩展功能,是许多其他库的依赖项。
  • Eigen : 一个高效的数学库,用于线性代数运算。
  • FLANN : 快速近似最近邻搜索库,用于大数据集的快速搜索。
  • VTK : 可视化工具库,为PCL提供三维可视化功能。
  • OpenNI : 提供了对Kinect等深度相机的支持。

表2.1列出了部分关键依赖库及其功能说明:

依赖库 功能说明
Boost C++标准库的扩展
Eigen 高效的数学线性代数库
FLANN 快速近似最近邻搜索库
VTK 三维数据可视化工具库
OpenNI 深度相机数据读取及处理库

接下来,我们将详细介绍如何从源代码克隆PCL仓库,并准备编译环境。

3. PCL源码下载与解压

3.1 选择PCL版本和下载方式

3.1.1 官网下载与镜像站点选择

PCL库(Point Cloud Library)是一个开源库,提供大量用于点云处理和分析的算法,广泛应用于3D重建、机器人、计算机视觉等领域。在开始点云处理之前,首先需要获取PCL的源码。一个常见的获取方式是通过PCL的官方网站下载,或者使用镜像站点加速下载过程。

通过官网(http://pointclouds.org/)下载时,可以直观地看到当前版本号以及历史版本的链接。官方建议下载稳定版本(Release),而对于开发者来说,下载开发版本(Development)可以获得最新的功能和修复,但可能不够稳定。

另外,由于网络环境的不同,直接从官网下载可能会遇到速度慢或者连接不稳定的情况。此时,可以考虑使用镜像站点,这些站点通常由社区或学术机构维护,可以提供更稳定快速的下载服务。例如,中国的清华大学和中科大都有提供PCL库的镜像服务。用户可以根据自己的地理位置选择最佳的镜像站点进行下载。

3.1.2 Git仓库克隆方法

除了通过官方网站下载源码包,另一种获取PCL源码的方式是使用Git进行克隆。Git是一种版本控制工具,广泛应用于软件的开发和维护中,可以帮助用户追踪和管理源码的变化。使用Git克隆PCL源码不仅可以获取最新的版本,而且当PCL有更新时,用户可以通过简单的命令更新到最新。

使用Git克隆PCL源码的方法如下:

  1. 确保系统已安装Git。在终端执行 git --version 检查是否已安装Git。
  2. 执行克隆命令: git clone https://github.com/PointCloudLibrary/pcl.git
  3. 克隆完成后,会在当前目录下生成一个名为 pcl 的文件夹,里面包含PCL的全部源码。

此外,用户还可以指定特定的分支或标签来克隆,例如,如果你想克隆某个特定的稳定版本,可以使用 git clone -b pcl-1.8 https://github.com/PointCloudLibrary/pcl.git 这样的命令。

3.2 源码的解压与准备

3.2.1 文件解压步骤

如果用户选择下载的是压缩包形式的PCL源码,那么在使用之前需要进行解压。以下是解压源码包的基本步骤:

  1. 下载对应操作系统的PCL源码压缩包。
  2. 找到下载的压缩包文件,例如 pcl-pcl-1.8.1.tar.gz
  3. 右键点击压缩包并选择解压缩选项,或者使用命令行工具进行解压。例如,在Linux或MacOS下,可以在终端使用命令:
tar -zxvf pcl-pcl-1.8.1.tar.gz

这个命令会将 pcl-pcl-1.8.1.tar.gz 解压缩到当前目录,解压缩后会在当前目录生成一个名为 pcl-pcl-1.8.1 的文件夹。

3.2.2 目录结构和文件说明

解压PCL源码后,打开 pcl-pcl-1.8.1 文件夹,可以看到PCL源码的目录结构。PCL项目是按照模块化的方式组织的,以下是一些主要目录和文件的功能说明:

  • apps/ :包含PCL的示例程序和应用程序。
  • common/ :公共的头文件和源文件,这些文件被其他模块共享。
  • io/ :负责点云的输入/输出(IO),包括常见的点云文件格式。
  • kdtree/ :包含KD-树实现,用于高效空间搜索。
  • search/ :搜索相关的类和结构。
  • filters/ :过滤操作,如去除噪声、下采样等。
  • features/ :特征提取,包括法线、关键点、表面特征等。
  • recognition/ :识别相关算法,如对象识别、场景理解等。
  • registration/ :用于点云配准的算法,包括ICP等。

在每个子目录下通常都有 include 文件夹存放头文件, src 文件夹存放源代码。了解这些目录和文件有助于后续的开发和学习。

通过理解PCL源码的结构和组成,可以帮助开发者更好地定位和利用PCL库中的资源,为接下来的编译和安装打下良好的基础。

4. 构建目录创建与CMake配置

4.1 创建构建目录

4.1.1 目录命名规范

在进行PCL编译之前,我们首先需要创建一个构建目录。构建目录的命名规范通常遵循简单的命名原则,如以“build”为前缀来区分源码目录和构建目录。例如,如果您当前的工作目录是 PCL-1.8.1 ,那么构建目录可以命名为 PCL-1.8.1/build 。这样做有助于在项目中维护清晰的文件结构,便于项目管理和版本控制。

4.1.2 目录创建步骤

创建构建目录可以通过命令行来完成。在您的终端中,导航到PCL源码所在的目录,然后输入以下命令来创建构建目录:

mkdir build
cd build

这里我们使用了 mkdir 命令创建一个新的目录,然后用 cd 命令切换到该目录。在创建构建目录时,您应该确保自己具有相应目录的写权限,否则创建过程会失败。

4.2 CMake配置与选项

4.2.1 CMake界面介绍

CMake是一个跨平台的自动化构建系统。它使用CMakeLists.txt文件来指定项目的构建规则。在构建目录中运行CMake将生成特定平台上的构建文件,如Makefile或Visual Studio解决方案文件。

要开始配置PCL,需要运行CMake的图形界面或者使用命令行。在构建目录中,您可以启动CMake GUI并指定源码路径和构建路径。在CMake GUI中,您还需要点击“Configure”按钮,选择适合您的生成器,例如Unix Makefiles或Visual Studio。这将生成一个初始的构建系统文件。

4.2.2 常用配置选项解析

在配置过程中,CMake会显示一系列的配置选项。下面是其中几个重要的选项及其解释:

  • BUILD_SHARED_LIBS :这个选项用于设置是否构建共享库。设置为 ON 构建共享库,设置为 OFF 构建静态库。
  • CMAKE_BUILD_TYPE :这个选项用于设置构建类型,可以是 Debug Release MinSizeRel 或者 RelWithDebInfo 。在调试时通常使用 Debug 类型。
  • BUILD麸ystems :这个选项用于指定是否构建PCL的全部模块,包括可选模块。

在配置时,您可能会遇到需要设置第三方依赖项的路径。如果CMake不能自动找到这些依赖项,您需要手动指定它们的位置。例如,如果系统中已安装了Eigen和Boost,但CMake未能自动检测到,那么需要手动设置 EIGEN3_INCLUDE_DIR Boost_INCLUDE_DIR

为了在命令行中执行CMake配置,可以使用以下命令:

cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON ..

在该命令中, -DCMAKE_BUILD_TYPE=Release 指定了构建类型为Release, -DBUILD_SHARED_LIBS=ON 告诉CMake构建共享库。最后的 .. 代表CMake将从上级目录寻找CMakeLists.txt文件。

完成这些步骤后,CMake会生成Makefile或相应的构建文件。您可以通过运行 make 命令(在Unix系统上)或在Visual Studio中打开生成的解决方案文件来开始编译过程。

在接下来的章节中,我们将进一步探讨PCL的编译与安装流程,以及如何通过编写一个简单的点云处理程序来验证安装是否成功。

5. PCL编译与安装流程

5.1 编译前的准备工作

5.1.1 清理旧编译文件

在编译PCL之前,清理之前的编译文件是一个好习惯。这可以防止旧文件对新编译造成干扰。例如,在构建目录下使用 make clean cmake --build . --target clean 命令可以清除大部分编译产物。如果有必要,可以手动删除构建目录。

cd pcl_build_directory
make clean
# 或者
cmake --build . --target clean

5.1.2 检查编译环境

确保系统中已经安装了所有必需的依赖项。在Linux系统上,可以通过运行以下命令来检查是否安装了所有必要的开发工具和库:

sudo apt-get update
sudo apt-get install build-essential cmake cmake-gui

还要检查是否安装了用于PCL编译的其他依赖库,例如OpenNI、Boost、VTK等。这可以通过简单的包管理器命令来完成:

sudo apt-get install libopenni-dev libboost-all-dev libvtk5-dev

在编译之前,这些检查确保了编译环境的干净和完整性。

5.2 编译和安装步骤

5.2.1 使用CMake进行编译

在完成上述准备工作之后,可以开始使用CMake进行编译。通常的做法是创建一个新的构建目录(如果尚未创建),然后从该目录调用CMake。例如:

mkdir pcl_build
cd pcl_build
cmake ../pcl_source_dir
make -j$(nproc)

这里 ../pcl_source_dir 是PCL源码所在的目录, $(nproc) 会自动使用可用的CPU核心数来加速编译过程。

5.2.2 安装PCL库到系统

一旦编译成功完成,接下来就是安装PCL库到系统中。这通常通过以下命令完成:

sudo make install

这会将编译好的PCL库和相关的头文件安装到系统的标准库目录下(如 /usr/local/lib /usr/local/include )。安装后,PCL就可以在任何项目中使用了。

章节小结

本章节介绍了如何准备编译环境,清理旧编译文件,检查编译环境的完整性,并且详细阐述了使用CMake进行PCL编译以及安装PCL到系统中的具体步骤。下文将介绍如何验证PCL的安装以及如何编写并运行第一个简单的点云处理程序。

6. 安装验证与简单程序编写

安装和验证PCL(Point Cloud Library)是一个确保环境正确配置以及验证安装成功的过程。在这一章节中,我们将引导读者完成PCL库的安装验证,并指导如何编写一个简单的点云处理程序。此章节将分为两个主要部分:首先是通过安装验证方法来确认PCL库是否安装成功;然后是带领读者进入实际编程,编写第一个点云处理程序。

6.1 安装验证方法

6.1.1 命令行测试工具使用

安装成功后,可以通过编译并运行PCL自带的测试程序来进行验证。这些测试程序通常会检测核心库功能是否正常工作。首先,确保已经将PCL的库目录添加到了系统的环境变量中,或者在命令行中指定了正确的库路径。

打开终端或命令提示符窗口,导航到PCL的 bin 目录下。在该目录中,PCL已经提供了一系列的测试和示例程序。例如,可以尝试运行下面的命令,以测试点云的IO功能是否正常工作:

cd /path/to/pcl/bin
./pcl_io -f /path/to/your/pointcloud.pcd

上述命令尝试加载并显示名为 pointcloud.pcd 的点云文件。如果文件加载成功并正确显示,表明PCL的IO模块安装正确。

6.1.2 示例程序运行验证

除了使用测试工具之外,我们也可以通过运行PCL提供的示例程序来进一步验证安装。这些示例程序覆盖了PCL的大部分功能模块。通过编译和运行这些示例,你可以检查PCL的各个模块是否已经正确安装。

首先,需要编译示例程序。如果你已经按照前面章节的指示配置好了CMake和构建目录,那么在构建目录中使用以下命令来编译示例:

cd /path/to/pcl/build
cmake ..
make

接下来,尝试运行一个简单的点云过滤示例:

./examples/segmentation/extract_indices.out

这个程序应该会提示你输入点云文件和索引文件的路径,然后它会从点云中提取出指定的点。如果能够看到处理结果,说明PCL的核心模块安装无误。

6.2 编写第一个点云处理程序

6.2.1 简单的点云显示程序

现在,我们已经验证了PCL安装无误,接下来可以开始编写自己的点云处理程序了。首先从一个简单的点云显示程序开始,这个程序会读取一个PCD(Point Cloud Data)文件,并使用PCL的 visualization 模块将其显示出来。

下面是一个简单的点云显示程序的代码:

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>

int main(int argc, char** argv)
{
  // 创建点云对象
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

  // 读取PCD文件
  if (pcl::io::loadPCDFile<pcl::PointXYZ>("input.pcd", *cloud) == -1)
  {
    PCL_ERROR("Couldn't read file input.pcd \n");
    return (-1);
  }

  // 创建一个可视化对象
  pcl::visualization::PCLVisualizer viewer("PCL点云显示窗口");
  // 简单视图设置
  viewer.setBackgroundColor (0, 0, 0);
  viewer.addPointCloud (cloud, "sample cloud");
  viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
  viewer.addCoordinateSystem (1.0);
  viewer.initCameraParameters ();

  // 等待直到可视化窗口关闭。
  while (!viewer.wasStopped ())
  {
    viewer.spinOnce (100); // 更新可视化窗口
  }

  return 0;
}

在上述代码中,首先我们包含了必要的头文件,然后在 main 函数中定义了点云对象,并尝试从文件 input.pcd 加载点云数据。一旦成功加载,程序会初始化一个PCL视觉化对象,并设置背景颜色。然后,将点云数据添加到视图中,并设置了点的大小。最后,程序进入了一个循环,等待用户停止可视化窗口。

6.2.2 程序编译与运行

接下来,需要将上述代码编译成可执行文件。可以使用CMake来完成这个任务。首先,在构建目录中创建一个新的 CMakeLists.txt 文件,并添加如下内容:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(pcl_simple_example)

find_package(PCL 1.8 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable(pcl_simple_example pcl_simple_example.cpp)
target_link_libraries(pcl_simple_example ${PCL_LIBRARIES})

这个 CMakeLists.txt 文件首先声明了项目名和最低CMake版本要求,然后找到PCL库,包括了必要的头文件和库文件。之后,它定义了一个可执行文件,并将其链接到了PCL的库文件。

现在,可以使用CMake来配置和编译我们的程序:

cd /path/to/pcl/build
cmake ..
make

编译完成后,运行程序:

./pcl_simple_example

如果一切顺利,你会看到一个窗口,其中显示了从 input.pcd 文件中读取的点云数据。

通过编写并运行上述程序,我们不仅验证了PCL库的安装,也完成了点云处理的基础学习之旅。接下来的章节中,我们将继续深入学习更多PCL库的高级功能。

7. PCD文件与案例操作

7.1 PCD文件格式解析

点云数据(PCD)文件格式是点云库(PCL)中最常见和广泛使用的数据格式之一,用于存储和交换点云数据。它不仅格式简单、易于读写,而且可以包含点云的各种属性信息,如颜色、强度等。

7.1.1 PCD文件结构和属性

PCD文件通常以“#”开头的注释行开始,这些行提供了文件的版本信息、字段名称、数据类型和点云属性等元数据。紧接着是一系列数据行,其中包含了点云的实际数据。下面是一个简单的PCD文件结构示例:

# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z rgb
SIZE 4 4 4 4
TYPE F F F I
WIDTH 5
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 5
DATA ascii
0.1 0.2 0.3 1.0
0.2 0.3 0.4 1.0
0.3 0.4 0.5 1.0
0.4 0.5 0.6 1.0
0.5 0.6 0.7 1.0

在这个例子中:

  • VERSION 表明了PCD文件的版本。
  • FIELDS 定义了点云数据包含的字段,本例中包括了 x y z 坐标以及颜色 rgb
  • SIZE 列出了每个字段占用的字节数。
  • TYPE 指明了字段的数据类型,例如 F 表示浮点数, I 表示整数。
  • WIDTH HEIGHT 表示点云数据的宽度和高度,对于一般点云数据来说, HEIGHT 通常为1。
  • VIEWPOINT 是可选的,用于指定视角信息,但不是所有PCL算法都需要此信息。
  • POINTS 表明了点云中点的数量。
  • DATA 后面跟的是数据格式,可以是 ascii binary

7.1.2 PCD文件读写操作

PCL提供了一系列的函数用于读取和写入PCD文件,以下是一个简单的示例,展示如何使用PCL API读写PCD文件:

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

int main()
{
    // 创建一个PointCloud对象,模板类型对应于点云数据类型
    pcl::PointCloud<pcl::PointXYZRGB> cloud;

    // 读取PCD文件
    if (pcl::io::loadPCDFile<pcl::PointXYZRGB>("input.pcd", cloud) == -1)
    {
        PCL_ERROR("Couldn't read file input.pcd \n");
        return (-1);
    }

    // 打印从文件中读取的点云的宽度、高度和点的数量
    std::cout << "Loaded "
              << cloud.width * cloud.height
              << " data points from input.pcd with the following fields: "
              << std::endl;

    for (size_t i = 0; i < cloud.points.size(); ++i)
        std::cout << "    " << cloud.points[i].x
                  << " " << cloud.points[i].y
                  << " " << cloud.points[i].z << std::endl;

    // 创建一个PointCloud对象用于存储数据
    pcl::PointCloud<pcl::PointXYZRGB> cloud_write;

    // 添加数据到cloud_write
    cloud_write = cloud;

    // 写入PCD文件
    pcl::io::savePCDFileASCII("output.pcd", cloud_write);

    return 0;
}

这段代码首先定义了一个 PointCloud 类型的变量 cloud 用于存储点云数据,然后使用 loadPCDFile 函数读取名为 input.pcd 的文件,并检查读取是否成功。接着代码遍历点云并打印点数据。之后,将读取的数据保存到 cloud_write 变量中,并使用 savePCDFileASCII 函数将点云数据写入到名为 output.pcd 的文件中。

7.2 案例实操:点云数据处理

在本小节中,我们将通过一个实际的案例来展示如何使用PCL库处理点云数据。这个案例将包括读取PCD文件、进行基本的滤波操作,并将处理后的点云保存到新的PCD文件中。

7.2.1 实际案例介绍

假设我们有一组从激光扫描仪获取的点云数据,该数据受到噪声的影响,需要使用滤波器进行清理。这里我们选择使用体素网格滤波(VoxelGrid)来减少数据量并去除噪声。

7.2.2 案例步骤和结果展示

以下是案例的详细步骤:

  1. 读取PCD文件 :使用PCL的读取函数从文件中加载点云数据。
  2. 滤波处理 :创建一个 VoxelGrid 滤波器对象,设置体素大小,并应用滤波器到点云数据。
  3. 保存处理后的点云 :将经过滤波处理的点云保存到新的PCD文件中。

下面是一个简单的C++代码示例,展示如何实现上述步骤:

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>

int main()
{
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);

    // 读取点云数据
    if (pcl::io::loadPCDFile<pcl::PointXYZRGB>("input.pcd", *cloud) == -1)
    {
        PCL_ERROR("Couldn't read file input.pcd \n");
        return (-1);
    }

    // 创建体素网格滤波器对象
    pcl::VoxelGrid<pcl::PointXYZRGB> sor;
    sor.setInputCloud(cloud);
    sor.setLeafSize(0.01f, 0.01f, 0.01f);
    sor.filter(*cloud_filtered);

    // 保存滤波后的点云到PCD文件
    pcl::io::savePCDFileASCII("output.pcd", *cloud_filtered);

    return 0;
}

代码开始时定义了两个 PointCloud 类型的智能指针 cloud cloud_filtered ,分别用于存储原始和滤波后的点云数据。通过调用 loadPCDFile 函数读取点云数据,并创建 VoxelGrid 滤波器对象 sor 。设置体素网格的大小后,将原始点云数据通过 setInputCloud 方法设置给滤波器,然后执行滤波操作 filter 。最终,将处理后的点云数据保存到名为 output.pcd 的文件中。

通过本章节的学习,您已经掌握了PCD文件的基本结构、属性及读写操作,并通过实际案例熟悉了点云数据的基本处理流程。这些知识将为以后更深入的点云处理工作打下坚实的基础。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:PCL是一个专门处理3D点云数据的C++开源库,适用于3D计算机视觉、机器人等领域。本教程详细指导如何在不同操作系统上安装PCL 1.8版本及其依赖项,并通过案例实践来学习点云数据的处理,包括读取、显示、滤波、聚类和表面重建等操作。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值