算能SE5-16跑通PP-OCR实例

一、前言

1.1、硬件设备及平台

我使用的虚拟机是Ubuntu20.04 

海康摄像头的型号是:MV-CS050-10GMGC

算能平台是: SE5-16

算能的SDK版本是SDK-23.07.01

1.2、相关资料

算能官网:算能 (sophgo.com) 

算能教学视频:教学视频

SE5-15手册: SE5-16使用手册

PP-OCR例程:sophon-demo/sample/PP-OCR at release · sophgo/sophon-demo (github.com)

SophonSDK 开发指南:SophonSDK V23.07.01

基于最新SOPHONSDK快速跑通一个SoC模式(我哭死,我开发的时候怎么不出一个这样的视频):最新教学视频

1.3、重要说明

开发环境与运行环境

        开发环境:是指用于模型转换或验证以及程序编译等开发过程的环境;

        运行环境:是指在具备Sophon设备的平台上实际使用设备进行算法应用部署的运行环境。

开发环境与运行环境可能是统一的(如插有SC5加速卡的x86主机,既是开发环境又是运行环境),也可能是分离的(如使用x86主机作为开发环境转换模型和编译程序,使用SE5盒子部署运行最终的算法应用)。

PCIE模式和Soc模式

        PCIE模式:需要将PCIE加速卡插到主机中,在宿主机上安装驱动程序,然后按照指引配置docker环境,这个环境既是开发环境也是运行环境。当然,也可以基于算能提供的docker开发环境,只保留系统运行时库的相关包,并添加需要的库包以及其他程序代码,构建自己部署在生产环境中的docker镜像。

        Soc模式:需要按照指引配置docker环境,docker将工作在CModel模式,提供模型转换和程序交叉编译的开发环境;待程序编译好后,需要手动将编译好的程序拷贝到目标系统(SE5/SM5)中运行执行。

        这两个模式要先分清楚,两个模式有着不同的配置方法。如果你买的是人工智能加速卡系列,那么你就是用PCIE模式。如果你买的是智算模组系列,那么你就是用Soc模式。下文的配置都是以Soc模式为主,想看PCIE模式配置的童鞋可以溜溜球了。

1.4、整体思路

  • 通过海康的摄像头获取图片信息
  • 使用Qt写一个ui界面进行人机交互
  • 将图片信息发送给SE5平台(这里采用的是NFS挂载的方法)
  • SE5平台上完成模型的运行
  • 将识别完成的图片发送回Qt,并在窗口进行显示

二、SE5连接并配置环境

2.1、X86上位机IP设置

首先用网线把SE5的Lan口与上位机进行连接,然后在网络连接设置里修改主机的IP地址。这里的IP地址要设置成和SE5在同一个网段(SE5盒子IP:192.168.150.1),所以我们可以设置为192.168.150.2。

 2.2、连接SE5

 首先查看一下SE5的工作状态是否正常,具体可以查看官方手册  SE5-16使用手册

 一般来说绿灯常亮就是正常工作(如下图所示)

 连接方式一:在浏览器上直接进入(前提是SE5正常开启,并处在正常工作状态下)AI边缘计算盒管理后台

 连接方式二:使用SecureCRT连接,点击闪电的符号进到Quick Connect界面,输入Host为192.168.150.1,Username为linaro,密码也是linaro。

当你看到以下界面的时候就说明你已经成功连接上了SE5:

2.3、配置SE5的开发环境

2.3.1、新建一个VMware虚拟机作为 X86虚拟机

这里我使用的系统是Ubuntu20.04,所以你需要去下载一个Ubuntu20.04的光盘映像文件。这里我就不过多赘述,不懂的童鞋可以去看看这篇博客:

VMware虚拟机下安装Ubuntu20.04(保姆级教程)_ubuntu 20.04 虚拟机-CSDN博客

注意!!!新建的磁盘容量设置大一点最好不低于30GB,不然后期如果模型比较大还需要重新拓展磁盘容量,多一事不如少一事。

这里附录几个链接有需要的自己看一下:

Ubuntu20.04 更换镜像源步骤

Ubuntu20.04安装中文输入法

Ubuntu20.04开启root账户

Ubuntu20.04实现共享文件夹

2.3.2、下载SDK到Ubuntu20.04

去到算能官网,下载需要的版本,再将其拷贝至虚拟机中。根据你下载的版本把 SOPHONSDK 开发指南文档也下载,下载打开后直接看到3.4节配置SE5的环境。

2.3.3、根据SOPHONSDK 开发指南文档配置基础环境

2.3.3.1、解压SDK压缩包
sudo apt-get install p7zip

sudo apt-get install p7zip-full

7z x Release_<date>-public.zip

cd Release_<date>-public
2.3.3.2、tpu-mlir 环境初始化

1.    Docker 安装

若已安装docker,请跳过本节。 执行以下脚本安装 docker 并将当前用户加入 docker 组,获得 docker 执行权限。

# 安装docker
sudo apt-get install docker.io
sudo systemctl start docker
sudo systemctl enable docker
# docker命令免root权限执行
# 创建docker用户组,若已有docker组会报错,可忽略
sudo groupadd docker
# 将当前用户加入docker组
sudo usermod -aG docker $USER
# 重启docker服务
sudo service docker restart
# 切换当前会话到新group或重新登录重启会话
newgrp docker

2.    将压缩包解压到tpu-mlir

cd tpu-mlir_<date>_<hash>

mkdir tpu-mlir

tar zxvf tpu-mlir_v<x.y.z>-<hash>-<date>.tar.gz --strip-components=1 -C tpu-mlir

3.    创建docker容器并进入Docker

cd tpu-mlir

#如果当前系统没有对应的镜像,会自动从docker hub上下载;

#此处将tpu-mlir的当前目录映射到docker内的/workspace目录

#myname只是举个名字的例子, 请指定成自己想要的容器的名字

docker run --privileged --name myname -v $PWD:/workspace -it sophgo/tpuc_dev:v2.2

4.    初始化软件环境

cd /workspace/tpu-mlir

source ./envsetup.sh

请注意,如果docker stop后重新进入,则需要重新source环境变量。

2.3.3.3、tpu-nntc 环境初始化

1.    将压缩包解压到tpu-nntc

cd tpu-nntc_<date>_<hash>

mkdir tpu-nntc

tar zxvf tpu-nntc_v<x.y.z>-<hash>-<date>.tar.gz --strip-components=1 -C tpu-nntc

3.    创建docker容器并进入Docker

cd tpu-nntc

#如果当前系统没有对应的镜像,会自动从docker hub上下载;此处将tpu-nntc的上一级目录映射到docker内的/workspace目录;这里用了8001到8001端口的映射(使用ufw可视化工具会用到端口号)。

#如果端口已被占用,请根据实际情况更换为其他未占用的端口。

docker run -v $PWD/..:/workspace -p 8001:8001 -it sophgo/tpuc_dev:v2.1

4.    初始化软件环境

cd /workspace/tpu-nntc

source scripts/envsetup.sh

请注意,如果docker stop后重新进入,则需要重新source环境变量。

2.3.3.4、libsophon 环境搭建

1. 如果您使用的是Debian/Ubuntu系统,安装包由三个文件构成:sophon-driver_<x.y.z>_$arch.deb、sophon-libsophon_<x.y.z>_$arch.deb、sophon-libsophon-dev_<x.y.z>_$arch.deb

注解

其中,<x.y.z> 指版本号,$arch 指当前机器的硬件架构,使用如下命令可获取当前服务器的arch。通常x86_64机器对应的硬件架构是amd64,arm64机器对应的硬件架构是arm64。请选择您对应的安装文件进行安装。

#查询一下系统的架构,我的硬件架构是amd64

uname -m

cd libsophon_<date>_<hash>

# 安装依赖库,只需要执行一次

sudo apt install dkms libncurses5

sudo dpkg -i sophon-*.deb

# 在终端执行如下命令,或者log out再log in当前用户后即可使用bm-smi等命令

source /etc/profile
2.3.3.5、sophon-mw 环境搭建

在安装sophon-mw时,请确保已经安装libsophon。

1.    如果您使用的是Debian/Ubuntu系统,安装包由四个文件构成,分别为:sophon-mw-sophon-ffmpeg_<x.y.z>_$arch.deb、sophon-mw-sophon-ffmpeg-dev_<x.y.z>_$arch.deb、sophon-mw-sophon-opencv_<x.y.z>_$arch.deb、sophon-mw-sophon-opencv-dev_<x.y.z>_$arch.deb,请选择您对应的安装文件参考如下步骤进行安装:

cd sophon-mw_<date>_<hash>

# 必须先安装sophon-mw-sophon-ffmpeg,再安装sophon-mw-sophon-opencv

sudo dpkg -i sophon-mw-sophon-ffmpeg_<x.y.z>_*.deb sophon-mw-sophon-ffmpeg-dev_<x.y.z>_*.deb

sudo dpkg -i sophon-mw-sophon-opencv_<x.y.z>_*.deb sophon-mw-sophon-opencv-dev_<x.y.z>_*.deb

# 在终端执行如下命令,或者log out再log in当前用户后即可使用安装的工具

source /etc/profile
2.3.3.6、交叉编译环境搭建

如果您希望使用SophonSDK搭建交叉编译环境,您需要用到gcc-aarch64-linux-gnu工具链,再将程序所依赖的头文件和库文件打包到soc-sdk目录中。

1.    首先安装工具链:

sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

2.    解压sophon-img包里的libsophon_soc_<x.y.z>_aarch64.tar.gz,将lib和include的所有内容拷贝到soc-sdk文件夹。

cd sophon-img_<date>_<hash>

# 创建依赖文件的根目录

mkdir -p soc-sdk

# 解压sophon-img release包里的libsophon_soc_${x.y.z}_aarch64.tar.gz,其中x.y.z为版本号

tar -zxf libsophon_soc_<x.y.z>_aarch64.tar.gz

# 将相关的库目录和头文件目录拷贝到依赖文件根目录下

cp -rf libsophon_soc_<x.y.z>_aarch64/opt/sophon/libsophon-<x.y.z>/lib ${soc-sdk}

cp -rf libsophon_soc_<x.y.z>_aarch64/opt/sophon/libsophon-<x.y.z>/include ${soc-sdk}

3.  解压sophon-mw包里的sophon-mw-soc_<x.y.z>_aarch64.tar.gz,将sophon-mw下lib和include的所有内容拷贝到soc-sdk文件夹。

cd sophon-mw_<date>_<hash>

# 解压sophon-mw包里的sophon-mw-soc_<x.y.z>_aarch64.tar.gz,其中x.y.z为版本号

tar -zxf sophon-mw-soc_<x.y.z>_aarch64.tar.gz

# 将ffmpeg和opencv的库目录和头文件目录拷贝到依赖文件根目录下

cp -rf sophon-mw-soc_<x.y.z>_aarch64/opt/sophon/sophon-ffmpeg_<x.y.z>/lib ${soc-sdk}

cp -rf sophon-mw-soc_<x.y.z>_aarch64/opt/sophon/sophon-ffmpeg_<x.y.z>/include ${soc-sdk}

cp -rf sophon-mw-soc_<x.y.z>_aarch64/opt/sophon/sophon-opencv_<x.y.z>/lib ${soc-sdk}

cp -rf sophon-mw-soc_<x.y.z>_aarch64/opt/sophon/sophon-opencv_<x.y.z>/include ${soc-sdk}
2.3.3.7、验证

您可以执行以下命令,验证开发环境中的交叉编译工具链是否配置成功:

which aarch64-linux-gnu-g++

# 终端输出内容

# /usr/bin/aarch64-linux-gnu-g++

如果终端输出了aarch64编译的路径,则说明交叉编译工具链正确,开发环境是可以正常使用的。

2.3.4、环境配置-SoC

2.3.4.1、开发环境配置

对于SoC模式,模型转换也需要在docker开发容器中完成;C/C++程序建议在x86主机上使用交叉编译工具链编译生成可执行文件后,再拷贝到SoC目标平台运行。docker开发容器的配置参照前述章节相关内容。

注意:

1.    请先使用 bm_version 命令查看微服务器中的SDK版本与当前SDK版本是否一致,如果不一致,请参考《 SOPHON BSP开发参考手册 》中的 软件安装 章节对微服务器进行软件更新。

2.    SE微服务器目前已经不再预置人脸抓拍应用gate,gate应用也将不再维护。后续我们也会将SE微服务器的默认系统升级为Ubuntu 20.04,并自带一个web界面用于查询和配置基础信息;同时使用qt编写了一个简易的界面以方便用户配置IP,您可以连接HDMI接口到显示器查看,并使用键鼠一体的套装进行相应操作。

3.    SE微服务器自带的操作系统并没有桌面系统,您需要使用ssh登录到微服务器终端内进行操作开发。

2.3.4.2、运行环境配置

对于SoC平台,内部已经集成了相应的libsophon、sophon-opencv和sophon-ffmpeg运行库包,位于/opt/sophon/下。只需设置环境变量即可。

# 设置环境变量
export PYTHONPATH=$PYTHONPATH:/opt/sophon/sophon-opencv_<x.y.z>/opencv-python

2.4、SE5的软件更新

        通过ssh连接到SE5,输入bm_version可以看到当前SE5的SDK版本。这里有要求要和虚拟机的SDK版本一致,如果不至于需要对SE5进行软件升级,这里我采用最简单也是最稳妥的SD卡更新。其他办法可以参考使用文档

        首先我们需要一张啥也没有的SD卡,将SDK的镜像文件拷贝过去。镜像文件在你下载的SDK包中的sophon-img文件夹内,参照我的就是在D:\文件\VM_Share\SophonSDK\Release_230701-public\sophon-img_20230810_221353内。

        将上图的sdcard压缩包全部解压至SD卡内,然后把SE5关机并断电,打开SE5背面的SD卡盖子安装好SD后,直接上电即可。更新完后一样通过ssh连接到SE5,输入bm_version查看SDK版本是否一致。

三、PP-OCR环境配置与跑通

        这里简单介绍一下PP-OCR,主要用在识别文字,支持中英文数字组合识别、竖排文本识别、长文本识别。 

3.1、 PP-OCR例程下载

1、先进入到算能的github库去下载全部的例程sophgo/sophon-demo (github.com)

 2、在sophon-demo-release\sample里面可以找到PP-OCR的源代码,其他的例程也是同理。

3、将sophon-demo-release整个文件夹拷贝至虚拟机中,这里我用的是WinSCP,你也可以使用共享文件夹等其他的方法。

3.2、准备模型与数据

1、直接使用算能提供的脚本下载,最简单,最省事。在sophon-demo-release/sample/PP-OCR/scripts目录下提供了相关模型和数据的下载脚本download.sh。

# 安装unzip,若已安装请跳过,非ubuntu系统视情况使用yum或其他方式安装
sudo apt install unzip
chmod -R +x scripts/
./scripts/download.sh

  • 我这里已经安装过了,所以他会说文件存在。
  • 下载完的文件会在sophon-demo-release/sample/PP-OCR/datasets目录下找到。
  • 下载的模型包括:
├── BM1684
│   ├── ch_PP-OCRv3_cls_fp32.bmodel # 使用TPU-MLIR编译,用于BM1684的FP32 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_det_fp32.bmodel # 使用TPU-MLIR编译,用于BM1684的FP32 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_rec_fp32.bmodel # 使用TPU-MLIR编译,用于BM1684的FP32 BModel,由batch_size=1和batch_size=4的模型combine得到。
├── BM1684X
│   ├── ch_PP-OCRv3_cls_fp16.bmodel # 使用TPU-MLIR编译,用于BM1684X的FP16 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_cls_fp32.bmodel # 使用TPU-MLIR编译,用于BM1684X的FP32 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_det_fp16.bmodel # 使用TPU-MLIR编译,用于BM1684X的FP16 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_det_fp32.bmodel # 使用TPU-MLIR编译,用于BM1684X的FP32 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_rec_fp16.bmodel # 使用TPU-MLIR编译,用于BM1684X的FP16 BModel,由batch_size=1和batch_size=4的模型combine得到。
│   ├── ch_PP-OCRv3_rec_fp32.bmodel # 使用TPU-MLIR编译,用于BM1684X的FP32 BModel,由batch_size=1和batch_size=4的模型combine得到。
├── onnx # 原始模型的onnx版本
└── paddle # 原始模型的paddlepaddle版本
  • 下载的数据包括:
├── cali_set_det # 检测模型量化用的数据集
├── cali_set_rec # 分类、识别模型量化用的数据集
├── fonts # 字体
├── ppocr_keys_v1.txt # 汉字集合
├── train_full_images_0 # ICDAR-2019训练集
└── train_full_images_0.json # ICDAR-2019 ground truth文件

2、您也可以自己准备模型和数据集,并参考3.3模型编译进行模型转换。建议使用TPU-MLIR编译BModel,Paddle模型在编译前要导出成onnx模型。具体可参考Paddle部署模型导出Paddle2ONNX文档

3.3、模型编译

我这里直接使用下载好的BModel,如果需要自己进行模型编译可以参考一下官方的例程https://github.com/sophgo/sophon-demo/tree/release/sample/PP-OCR#4-%E6%A8%A1%E5%9E%8B%E7%BC%96%E8%AF%91

3.4、推理测试 

这里有两种测试方法,分别是C++和Python。下面我用C++例程实现, Python的例程可以参考以下文档:Python例程

3.4.1、 交叉编译环境搭建

之前我们在2.3.3.6、交叉编译环境搭建 已经实现了libsophon、sophon-ffmpeg、sophon-opencv的安装,但是我们还需要安装一个sophon-sail,步骤如下:

  1. sophon-sail源码在我们下载的SDK文件夹中。解压sophon-sail源码并进入其源码目录。

  2. 创建编译文件夹build,并进入build文件夹

  3. 执行编译命令
    注意:这里的路径一定要确定好,后面如果有报错90%都是这里出来问题

    DCMAKE_TOOLCHAIN_FILE:就是在你解压的sophon-sail文件夹下的cmake文件夹,cmake后面的路径不用管,只需确定一下前面的。因为当前是在build文件夹内,所以我们要返回上一层的路径,故这里的路径要写成../camke/.......

    DLIBSOPHON_BASIC_PATH: 这里有个坑啊,这里的libsophon并不是我们之前2.3.3.4、libsophon 环境搭建 配置的那个。我因为这个问题卡了好久,后来才发现是在sophon-img中的libsophon_soc才是对的

    DFFMPEG_BASIC_PATH和DOPENCV_BASIC_PATH:就是之前在2.3.3.6、交叉编译环境搭建 的soc-sdk文件夹内

    cmake -DBUILD_TYPE=soc -DBUILD_PYSAIL=OFF \
        -DCMAKE_TOOLCHAIN_FILE=../cmake/BM168x_SOC/ToolChain_aarch64_linux.cmake \
        -DLIBSOPHON_BASIC_PATH=/home/zkh/sophon/SophonSDK/Release_230701-public/sophon-img_20230810_221353/libsophon_soc_0.4.9_aarch64/opt/sophon/libsophon-0.4.9 \
        -DFFMPEG_BASIC_PATH=/home/zkh/sophon/SophonSDK/Release_230701-public/sophon-mw_20230807_032400/sophon-mw-soc_0.7.0_aarch64/opt/sophon/sophon-ffmpeg_0.7.0 \
        -DOPENCV_BASIC_PATH=/home/zkh/sophon/SophonSDK/Release_230701-public/sophon-mw_20230807_032400/sophon-mw-soc_0.7.0_aarch64/opt/sophon/sophon-opencv_0.7.0 ..
    make sail
  4. 安装SAIL动态库及头文件,程序将自动在源码目录下创建‘build_soc’,编译结果将安装在‘build_soc’下面

    make install
  5. 将‘build_soc’文件夹下的‘sophon-sail’拷贝至目标SOC的‘/opt/sophon’目录下,即可在soc上面进行调用。拷贝的方法这里就不做介绍了,可以用WinSCP等一系列的方法。

  6. 在SE5上设置一下环境变量

    sudo echo "export LD_LIBRARY_PATH=/opt/sophon/sophon-sail/lib/:$LD_LIBRARY_PATH" >> ~/.bashrc
    source ~/.bashrc

 3.4.2、使用交叉编译工具链编译生成可执行文件

  1. 在sophon-demo-release/sample/PP-OCR/cpp文件夹内编写cmake 
    cd cpp/ppocr_bmcv
    mkdir build && cd build
    #请根据实际情况修改-DSDK的路径,需使用绝对路径。
    cmake -DTARGET_ARCH=soc -DSDK=/home/zkh/sophon/SophonSDK/Release_230701-public/sophon-img_20230810_221353/soc-sdk .. 
    make
    
  2. 编译完成后,会在ppocr_bmcv目录下生成ppocr_bmcv.soc。


     
  3. 将ppocr_bmcv.soc以及所需要的模型models和datasets打包在一个文件夹内,并拷贝到SE5平台上。模型路径在sophon-demo-release/sample/PP-OCR/

 3.4.3、跑通PP-OCR

  1. 参数说明:可执行程序默认有一套参数,请注意根据实际情况进行传参,以ppocr_bmcv.pcie为例,具体参数说明如下:
    # 注意:CPP传参与python不同,需要用等于号,例如./ppocr_bmcv.pcie --bmodel=xxx
    Usage: ppocr_bmcv.pcie [params] 
    
            --batch_size (value:4)
                    ppocr system batchsize
            --bmodel_cls (value:../../models/BM1684X/ch_PP-OCRv3_cls_fp32.bmodel)
                    cls bmodel file path, unsupport now.
            --bmodel_det (value:../../models/BM1684X/ch_PP-OCRv3_det_fp32.bmodel)
                    det bmodel file path
            --bmodel_rec (value:../../models/BM1684X/ch_PP-OCRv3_rec_fp32.bmodel)
                    rec bmodel file path
            --dev_id (value:0)
                    TPU device id
            --rec_thresh (value:0.5)
                    recognize threshold
            --help (value:true)
                    print help information.
            --input (value:../../datasets/cali_set_det)
                    input path, images directory
            --labelnames (value:../../datasets/ppocr_keys_v1.txt)
                    class names file path
  2. 测试图片
    图片测试实例如下,支持对整个图片文件夹进行测试。注意:这里的BModel模型选择要选择相对应的芯片,例如SE5就是BM1684而不是BM1684X。
    测试结束后,会将预测的图片保存在results/images下,预测的结果保存在results/ 下,同时会打印预测结果、推理时间等信息。(PS:下面的代码要在SE5上运行哦)

    ./ppocr_bmcv.soc --input=./datasets/train_full_images_0 \
                      --batch_size=4 \
                      --bmodel_det=./models/BM1684/ch_PP-OCRv3_det_fp32.bmodel \
                      --bmodel_rec=./models/BM1684/ch_PP-OCRv3_rec_fp32.bmodel \
                      --labelnames=./datasets/ppocr_keys_v1.txt
  3. 结果展示
    跑完的图片会保存在/PP-OCR/results/images目录下。

四、海康摄像头环境配置

 4.1、硬件连接

  • 将电脑的网口线接到路由器LAN口(此时电脑的IP为192.168.150.2)
  • 将SE5的Lan口接到路由器 LAN口(此时SE5的IP为192.168.150.1)
  • 将虚拟机的网络设置到NAT模式,IP设置为192.168.150.3
  • 将海康摄像头接到路由器 LAN口
  • 至此你就搭建了一个自己的局域网,摄像头、SE5都可以和虚拟机进行数据交互

 4.2、MVS安装

 4.3、linux下海康威视工业相机的sdk二次开发

【精选】Linux环境中对海康威视工业相机SDK进行二次开发(QT+CMake+Opencv+海康SDK)_linux下海康威视工业相机的sdk二次开发-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_45445740/article/details/122026207

五、整体PPOCR工程的实现

5.1、NFS挂载
Ubuntu 系统上NFS的安装与使用 - 知乎 (zhihu.com)icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/606174368?utm_id=0

5.2、整体项目演示

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值