PCA实现步骤及其与opencv中PCA实现方式的对比

Opencv学习笔记-----PCA原理及OpenCV实现 一、介绍            PCA(principal component analysis)就是主分量分析,是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。通过数据降维可以实现数据的压缩,同时方便数据分析和提高算法的处理速度。PCA的原理就是通过正交变换,最大化样本协方差阵的对角元素,最小化非对角元素 阅读详情

       PCA(Principal Components Analysis,中文名叫主成分分析,是数据降维很常用的算法。按照书上的说法是:寻找最小均方意义下,最能代表原始数据的投影方法。PCA的一个经典应用就是人脸识别,感兴趣的可以在网上搜eigenface。
      PCA的主要思想是寻找到数据的主轴方向,由主轴构成一个新的坐标系,这里的维数可以比原维数低,然后数据由原坐标系向新的坐标系投影,这个投影的过程就可以是降维的过程。
       原理网上一搜内容很多,这里推荐一篇讲原理讲得不错的文章: http://www.csdn123.com/html/blogs/20130320/180.htm 大家可以参考。下面着重讨论PCA的实现,由于我主要是在做图像处理时用的PCA,所以以对图像进行降维来说明。

1 对训练集图像进行处理
     读取测试集中的所以图像,然后将其保存在一个矩阵中。如果图像个数为m,图像长宽为i、j,则我们创建矩阵A(m, n = i*j)用来保存图像数据。数组的每一行表示一个图像的所有像素信息,每一列表示一个维度,也即不同图像在同一位置的像素信息,降维也即用更少的列来代表图像。
    经过对训练集的图像进行处理后,所有的图像都在表示在了一个矩阵中,我们假设这个矩阵是data。则data的维数为m*n,其中n=i*j,及n为一张图像的所以像素点。

2 求平均值mean
    在data矩阵中每一个维度上的平均值,具体方法为对data矩阵的每一列求平均值mean。如果是人脸识别的话,这一步得到的就是mean face(平均脸)。

3 每列减去均值
   将data矩阵的的每列减去该列的均值,这样每列的数据均值为0。我有用C来表示相减的值,及C=data-mean

4 计算协方差矩阵
   协方差矩阵表示不同随机变量之间的相互关系,图像中也即求任意两个像素之间的关系。如果两个随机变量的协方差为正或为负,表明两个变量之间具有相关性,如果为零表示两个变量不相关。通过计算协方差矩阵,我们就可以获得不同像素之间的关系。针对人脸识别,计算的协方差矩阵大小为n*n,其中n表示图像的像素点个数。
   计算协方差的矩阵具体操作的A = C' * C/n,这里C‘为C矩阵的转置。注意这里有个除n。在后面代码中会提到。

5  计算协方差矩阵A的特征值和特征向量
    由于协方差矩阵是实对称阵,所以可以求得其所有的特征值和特征向量,其共有n个特征值和特征向量。

6 选择主成分(投影矩阵)
    所谓主成分即是具有最大特征值的特征向量,所以我们需要将特征向量按照特征值由大到小排序,然后根据精度要求选择不同数量的特征向量,例如我们选择了前pca_dim个特征向量,通常pca_dim远小于n(在我们的人脸识别实验中,为了达到95%的精度,pca_dim只有72,而n为120*140=17040)。
    这里我们所选择的主成分实际上就是投影矩阵,我们用project_mat表示。project_mat的维度为n*pca_dim.

7 将训练集进行降维
   此步骤将原始的训练集进行降维变换,方法就是对原始矩阵用project_mat进行投影。
   原始的图像数据data是m*n的矩阵,投影后就成了n*pca_dim的矩阵(每一列都是一个特征向量)。
   特别注意这里投影时并不是想网上很多博客中所说的data*project_mat。正确的方法应该是C*project_mat,及(data-mean)*project_mat。

8 将测试集进行降维
   同步骤6相似,读取所有的测试集图像,然后对其也进行降维操作。如果测试集有M幅图像,则降维后的矩阵为M*pca_dim。
   注意对测试集进行降维时也不是直接用测试集的data*project_mat,正确的做法应该是测试集的(data-mean)*project_mat。

    下面是我写代码对PCA的实现,其中有与Opencv中自带的计算PCA方法的对比。
注意为了方便对矩阵的操作,我在代码中使用的开源的Eigen库,Eigen是个很方便的数学出来工具,尤其是对矩阵的处理。
    Eigen库的主页http://eigen.tuxfamily.org/index.php?title=Main_Page 

    使用Eigen也很简单,下载好开源包后,直接在工程的属性页面“附加包含目录”把Eigen的目录添加进去。配置好后在在代码中添加#include”Eigen/Eigen”和using namespace Eigen两行就可以使用了。

#include<iostream>
#include<fstream>
#include"Eigen/Eigen"  
#include<opencv2\opencv.hpp>
using namespace Eigen;  
using namespace std;
using namespace cv;
void BubbleSort(float *pData, int Count);//冒泡排序  
const int num = 5;    // 样本数量
const int dim = 10;    // 样本的维度(一张图片的维度)  
const int pca_dim = 4;// pca dimension of each sample  

int main()
{
	// 原始数据:每一行代表一个样本(这里为了测试时随机生成的)
	MatrixXf data =MatrixXf::Random(num, dim);
	// 求每一维度上的平均值,即每一列的平均值,最后求出来是一个行向量
	MatrixXf mean =data.colwise().mean();     
	cout<<"------------------Orignal data-------------------------\n"<<data<<endl;
	//cout<<"----------------Mean------------------\n"<<mean<<endl;

	MatrixXf C(num, dim);  // data-mean
	MatrixXf C_T(dim, num);// C的转置
	for(int i=0; i<num; i++)
	{
		C.row(i) =data.row(i)-mean;  //C= data-mean
	}
	C_T =C.transpose(); 
	/*
	协方差矩阵A的维度为dim*dim,这里除不除dim最后结果都一样,
	在书中的定义中是要除的,估计是有数学含义的。
	*/
	MatrixXf A =C_T*C;
	EigenSolver<MatrixXf> sol_A;
        sol_A.compute(A);
	//求协方差矩阵的特征值和特征向量
	MatrixXf eigenvals_A =sol_A.eigenvalues().real();
	MatrixXf eigenvecs_A =sol_A.eigenvectors().real();
	//排序
	float a[dim]={0.0};
	for(int i=0; i<dim; i++)
	{
		a[i] =eigenvals_A(i, 0);
	}
	BubbleSort(a, dim); 
	MatrixXf sorted_eigenvals_A(dim, 1);
	MatrixXf sorted_eigenvecs_A(dim, dim);
	//对特征值从大到小排序
	for(int i=0; i<dim; i++)
	{
		sorted_eigenvals_A(i, 0) =a[i];
	}
	//对应的改变特征向量的排序
	for(int i=0; i<dim; i++)
	{
		for(int j=0; j<dim; j++)
		{
			if(eigenvals_A(i, 0) == a[j])
			{
				sorted_eigenvecs_A.col(j) =eigenvecs_A.col(i);
			}
		}
	}
	
	//求PCA的投影矩阵及降维结果
	MatrixXf project_mat(dim, pca_dim); //投影矩阵
	MatrixXf res(num, pca_dim);         //最终输出,维度为num*pca_dim
	for(int i=0; i<pca_dim; i++)        //抽取主成分
	{
		project_mat.col(i) =sorted_eigenvecs_A.col(i);
	}
	
	/*
	res就是原始数据降维后的矩阵
	特别注意,这里是C*project_mat,即(data-mean)*project_mat
	在网上看到很多人这里都是直接用的data*project_mat,那样是不对的
	*/
	res =C* project_mat;    

	//-----------------------------OpenCV中的PCA--------------------------------//
	CvMat *pca_input         =cvCreateMat( num, dim, CV_32FC1);               // 输入
	CvMat *pca_avg           =cvCreateMat( 1, dim, CV_32FC1);		          // 平均值 
	CvMat *pca_eigenvalue    =cvCreateMat( 1, std::min(num, dim), CV_32FC1);  // 特征值  
	CvMat *pca_eigenvector   =cvCreateMat( std::min(num, dim), dim, CV_32FC1);// 特征向量
	CvMat *pca_eigenvector_T =cvCreateMat(dim, std::min(num, dim), CV_32FC1); // 特征向量
	CvMat *pca_output        =cvCreateMat(num, pca_dim, CV_32FC1);            // 输出
	// 数据导入
	for(int i=0; i<num; i++)
	{
		for(int j=0; j<dim; j++)
		{
			cvSetReal2D(pca_input, i, j, data(i, j));
		}
	}
	cvCalcPCA(pca_input, pca_avg, pca_eigenvalue, pca_eigenvector, CV_PCA_DATA_AS_ROW);
	

	cout<<"\n---------------Eeigen Tool降维结果-----------------"<<endl;
	cout<<res<<endl;

	cout<<"---------------OpenCV Tool降维结果---------------"<<endl;
	cvProjectPCA(pca_input, pca_avg, pca_eigenvector, pca_output);
	// 数据输出
	for(int i=0; i<num; i++)
	{
		for(int j=0; j<pca_dim; j++)
		{
			float temp =0.0;
			temp =cvGetReal2D(pca_output, i, j);
			cout<<temp<<"   ";
		}
		cout<<endl;
	}

	system("pause");
	return 0;
}
//冒泡排序算法
void BubbleSort(float *pData, int Count)  
{   
	float iTemp;  
	for(int i=1; i<Count; i++)   
	{ 
		//一共进行(count-1)轮,每次得到一个最大值   
		for(int j=Count-1; j>=i; j--) //每次从最后往前交换,得到最大值  
		{     
			if(pData[j]>pData[j-1])    
			{     
				iTemp      = pData[j-1];    
				pData[j-1] = pData[j];    
				pData[j]   = iTemp;    
			}   
		}  
	}  
} 

      最后通过对比,发现用Eigen自己实现的PCA与Opencv实现的PCA结果的数值是一样的,但是有些向量的符号相反。

     编译好的代码下载:http://download.youkuaiyun.com/detail/computerme/7497923





PS:可能有的读者发现了有些博客中讲PCA降维时,在第一步生成原始的data矩阵维度为dim*m(dim为一个图像的维度,m为训练集图片的张数)。

        如果是这种情况的话,则上面的A 应该等于 C*C' (C'是C矩阵的转置),最后求降维后的矩阵时公式也应该变为project_mat的转置乘以(data-mean)。

        总之,不管data矩阵的维度是dim*m还是m*dim,我们都要确保第四步求得的协方差A的维度是dim*dim。因为协方差矩阵表示的就是data中各维度的关系。


**************************************************************************************************************************

关注IT行业发展,关注互联网时代创业趋势,就来我们的公众号吧~~
微信公众号ID: chuangye_beginner   欢迎在公众号里与我互动
博主微博:IT修道者 
*************************************************************************************************************************

PCA原理及OpenCV实现 关于PCA的理论与公式推导网络上很多,尴尬的是本人功底有限,理论方面这里就不列出啦。下面主要从Opencv应用的角度大概来讲讲自己对PCA具体怎么实现数据集降维的理解。1、把原始数据中每个样本用一个向量表示,然后把所有样本组合起来构成一个矩阵,避免样本的单位的影响,样本集需要标准化。2、求该矩阵的协方差矩阵。(关于协方差矩阵的理解大家可以看看这篇文章)3、求步骤2中得到的协方差矩阵的特征值和特征向量。 阅读详情

相关推荐

基于OpenCV3实现人脸识别(原理篇)---PCA(Principal Component Analysis)

实践总结: 1首先了解做人脸识别的步骤 2各个算法后面的原理 3原理背后的相关知识的了解 4人脸识别项目总遇到的问题 正文 首先说关于人脸识别,用到的是OpenCV人脸识别类...

qq_37791134的博客 1万+

OpenCV PCA介绍

主成分分析(PCA)是一个统计过程,提取一个数据集最重要的特征。假设有一组2D点,如上图所示。每个维度对应一个感兴趣的特征。有些人可能会说,这些点的设置顺序是随机的。然而,如果仔细观察,会发现这里有一个很难忽略的线性模式(由蓝色线表示)。主成分分析的一个关键点是降维。降维是减少给定数据集的维数的过程。例如,在上述情况下,可以将一组点近似为一条直线,从而将给定点的维数从2D降至1D。此外还可以看到,这些点沿着蓝线变化最大,比沿着特征1或特征2轴变化更大。

泠山的博客 2688

PCA基于opencv的实现和样本数小于维度的问题

PCA基于opencv的几种实现方式, 以及实现过程中发现的样本数小于维度时components个数限制问题

July's Pensieve 3563

Opencv之PCA篇

 Opencv之PCA篇PCA(principal component analysis)翻译过来就是主分量分析,是一种流行的数据降维方法。通过数据降维可以实现数据的压缩,同时方便数据分析和提高算法的处理速度。PCA的原理就是通过正交变换,最大化样本协方差阵的对角元素,最小化非对角元素。具体的介绍可以参考Shlens, J., A tutorial on principal compone

江南魅影的专栏 7827

用opencv实现的PCA算法,非API调用

理论参考文献:但此文没有代码实现,这里自己实现一下,让理解更为深刻 问题:假设在IR中我们建立的文档-词项矩阵中,有两个词项为“learn”和“study”,在传统的向量空间模型中,认为两者独立。然而从语义的角度来讲,两者是相似的,而且两者出现频率也类似,是不是可以合成为一个特征呢?        《模型选择和规则化》谈到的特征选择的问题,就是要剔除的特征主要是和类标签无关的特征。比如

fangjian1204的专栏 2344

Opencv起步之主成分分析(PCA)

早在一年前,就玩过PCA了,那个时候使用PCA做了一个人脸识别的作业。所以对于PCA的理论这里不再介绍了,直接上一个基于Opencv的PCA吧。 在Opencv中,有一个PCA类,如下: class CV_EXPORTS PCA { public: //! default constructor PCA(); //! the constructor that perfo

记录计算机应用的点点滴滴!!!!! 6386

MATLAB特征提取相关知识

文章目录一、前言二、小波变换的基本数学原理2.1小波函数2.2连续小波变换2.3离散小波变换2.4正交小波变换2.5小波函数介绍三、小波变换在MATLAB中的实现3.1小波变换3.2小波包变换 一、前言 传统的傅里叶分析中,信号是完全在频域展开,不包含任何时域信息。而小波变换具有多分辨率的特点,在时域和频域上都有表征局部信息的能力,时间窗和频率窗都可以根据信号的具体形态动态调整,在低频部分采用较低的时间分辨率,提高频率的分辨率,在高频情况下,采用较低的频率分辨率来获得精确的时间定位。 小波变换被广泛地应用

weixin_50624597的博客 1189

OpenCV主成分分析详解及编程示例

PCA的目标是通过线性变换将原始数据投影到一个新的坐标系中,使得投影后的数据具有最大的方差。通过保留较高方差的主成分,我们可以实现数据的降维,同时保留尽可能多的信息。在本文中,我们将详细介绍OpenCV中的主成分分析算法,并提供相应的编程示例。通过选择不同的主成分数量,我们可以实现数据的降维,并根据需要保留适当的信息量。请注意,PCA还可以应用于图像处理等更复杂的情况,但本文仅涵盖了基本的概念和示例。在上述代码中,我们使用了前两个主成分的主成分向量和特征值,通过矩阵乘法和加法操作来重构原始数据。

PixelInk的博客 281

OpenCV PCA

PCA(principal component analysis,主成分分析),又称为k-l变换,我想是大家用的最多的降维手段,对于PCA的理解,我想大神们都各有各的绝招,可以应用的场合也非常多。下面就介绍一下OpenCV中PCA这个类,因为常用,所以这个类相对OpenCV而言显得比较独立,放在了core这部分中。 PCA类的成员函数包括构造函数、运算符重载()、project、backPr

huangxy10的专栏 1万+

基于OpenCV的图像主成分分析

使用PCA,对单图像提取主成分分析,达到图像降维的目的,可以学习如何使用OpenCV实现PCA技术。

(八)OpenCV人脸识别_03_PCA主成分分析

PCA原理:(一个分析多维分布并且从中提取出带有最多信息量的维度子集的方法)(无监督:基于方差提取最有价值的信息) 通过对高维数据分析发现他们的相同与不同表达为一个低维数据模式 主成分不变、细微损失、高维数据到低维数据 PCA:样本数据、减去均值、计算协方差矩阵(标准差、方差越大,离散程度越大)、计算特征值与特征向量、根据特征值排序保留前K个主成分特征向量、形成新的数据样本。 输出数据 = 前K个特征向量组合 x 均值调整之后的数据 #include #include using namespace std; using namespace cv; double calcPCA(vector

OPENCV中的PCA使用

对于PCA,一直都是有个概念,没有实际使用过,今天终于实际使用了一把,发现PCA还是挺神奇的。 在OPENCV中使用PCA非常简单,只要几条语句就可以了。1、初始化数据 //每一行表示一个样本 CvMat* pData = cvCreateMat( 总的样本数, 每个样本的维数, CV_32FC1 ); CvMat* pMean = cvCreateMat(1, 样本的维数, CV_32FC1); //pEigVals中的每个数表示一个特征值 CvMat* pEigVals = cvCreateMat(1,

landsuper的专栏 5323

Spark入门:从零到能跑的实战教程

Spark 的强大在于它统一了大数据处理的多种场景,从批处理到流处理,从 SQL 到机器学习。对于初学者来说,理解 Spark 的核心理念——内存计算和分布式抽象,是最重要的一步。接着,学会用 PySpark 搭建环境,能读数据、能写 SQL,基本上就入门了。剩下的路,就是通过实战去加深理解。写到这里,相信你对 Spark 已经有了一个比较完整的认识。下一步,不妨自己动手写几个 PySpark 脚本,跑一跑日志数据,或者尝试用 Spark SQL 做一个统计。

Morpheon的博客 1367

基于opencv的pca人脸识别实现

orl人脸样本库 这里用到的ORL人脸库(Olivetti Research Laboratory人脸数据库),诞生于英国剑桥Olivetti实验室。 ORL人脸数据库由该实验室从1992年4月到1994年4月期间拍摄的一系列人脸图像组成,共有40个不同年龄、不同性别和不同种族的对象。每个人10幅图像共计400幅灰度图像组成,图像尺寸是92×112,图像背景为黑色。其中人脸部分表情和细节均有变化,例如笑与不笑、眼睛睁着或闭着,戴或不戴眼镜等,人脸姿态也有变化,其深度旋转和平面旋转可达20度,人脸尺寸也有最多

freezing_smile的博客 1696

SAR动目标检测三剑客:DPCA/ATI/STAP技术选型指南(含2023最新实验数据对比)

本文深入对比了SAR动目标检测三大主流技术DPCA、ATI与STAP的核心原理与性能差异。基于2023年最新实验数据,分析了它们在最小可检测速度、测速精度、计算复杂度及对通道失配敏感度等方面的优劣,并结合海洋监视与城市交通监控等典型场景,提供了具体的技术选型指南与工程落地考量。

m5n6o7的博客 292

Microsoft Speech SDK 使用过程中女声改为男声遇到的问题

问题将女生改为系统自带男声(Kangkang)根据上面的步骤我的播放声音是改变了,但是还是女生,是yaoyao的女生。是因为下面注册表路径中VoicePath这个配置的路径指向了yaoyao的文件。 如何使用Microsoft Speech SDK,请参考https://blog.youkuaiyun.com/daoming1112/article/details/77542562 使用系统自带男声语音,不需...

u012161365的博客 7538

OpenCV下PCA降维

这两天看了下PCA降维,用OpenCV测试了下。主要是参考[1]和[2]。根据我的理解,代码记录下。 #include #include #include #include using namespace cv; using namespace std; #define DIMENTIONS 7 #define SAMPLE_NUM 31 float Coordinat

naruto0001的专栏 5718

【WorkBuddy从入门到精通实战教程】实战案例 第 18 章 把投资分析(炒股)变成你的日常

投资本身就是一件高度信息密集、强结构化、又极度依赖判断的事:读不完的财报、理不清的行业、吵不停的多空。而整理碎片信息、拆解复杂材料、把思考过程摆到台面上,恰好是 AI 擅长的。 在一次完整的股票研究里,AI 到底能替你做掉哪些低质量的重复劳动,把精力还给判断本身。

企鹅码农的专属播客,分享10多年的实战案例和经验解读,包含YOLO、RT-DETR、AI等各个工作领域。 461

OpenCV中使用PCA

OpenCV中使用PCA    对于PCA,一直都是有个概念,没有实际使用过,今天终于实际使用了一把,发现PCA还是挺神奇的。   在OPENCV中使用PCA非常简单,只要几条语句就可以了。   1、初始化数据   //每一行表示一个样本   CvMat* pData = cvCreateMat( 总的样本数, 每个样本的维数, CV_32FC1 );   CvMat*

amanda_123的专栏 663

一文搞定 ST22 短转储 MEMORY_NO_MORE_PAGING:看懂 SAP Paging 机制,参数 rdisp/PG_SHM 与 rdisp/PG_MAXFS 怎么设才稳

SAP系统MEMORY_NO_MORE_PAGING错误通常源于Paging资源耗尽而非物理内存不足。关键排查点包括:通过ST22确认错误类型,ST02监控Paging使用情况,检查工作进程trace中的"no more free blocks"提示。解决方案建议将rdisp/PG_SHM和rdisp/PG_MAXFS设为相同值(如250000块≈2GB),使Paging完全在内存中运行。同时需优化易耗Paging的代码逻辑,如避免滥用EXTRACT命令和超大内存对象传输。典型案例如月末

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 331

SAP UI5 SimpleForm 的本质、布局选择与工程化用法:从 API 到 Fiori 规范的完整解析

SimpleForm的价值在于让开发者以“语义顺序”来思考表单:分组—行—字段,由此把更多精力放在表单信息架构与Fiori规范的落地上。当你理解了开分组、Label开新行、的断点与比例、的对齐特性、editable与的真实含义,就能据此为每个页面挑选合适的布局与参数,构建既合规又具备高可读性的企业级表单。新分组、Label新行、其他控件归当前行。SAP的断点、比例与的要点来自Fiori设计文档。SAP的适用性来自样例与课程的推荐,列表类控件不应作为其行内容。某些旧属性仅在生效,应避免误用。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 298

基于 OpenCV PCA实现过程

基于 OpenCV PCA实现过程前言PCA是一种用于数据降维的方法,常用于图像的压缩、人脸识别等。其原理并不复杂,但是其中的思想还是很有用的。详细的PCA的数学原理推荐访问https://zhuanlan.zhihu.com/p/21580949作为练手,用MATLAB和OpenCV实现PCA还是挺有帮助的,毕竟看别人的代码,总不如自己将一个算法看懂后努力去实现的收获大。目录基于 OpenCV P

healingwounds的博客 3380

OpenStack 之 Epoxy版本 部署实战

OpenStack Epoxy 是 OpenStack 的第 31 个版本,其版本号为 2025.1,于 2025 年 4 月 2 日正式发布。

求知若渴,虚心若愚。 235

opencv中PCA源码理解与训练、使用

/****************************************************************************************\ * PCA * \*****************

一休哥的专栏 4488

【知识图谱】Neo4j基本操作及数据库文件导入(graph.db.dump)

初探Neo4j导入数据备份数据客户端操作导入csv文件指定csv文件格式使用命令行导入csv文件附录 请读者参考上篇博文 Neo4j安装教程 导入数据 若开启服务,先在终端停止 Neo4j 服务 ./neo4j stop 接下来,下载射雕三部曲的数据库文件 wget https://labfile.oss.aliyuncs.com/courses/1354/graph.db.dump 下载完将出现 graph.db.dump 文件: 将数据库文件导入到 Neo4j 中 首先进入neo4j 根目录下:

全网粉丝30W+,优快云、稀土掘金人工智能领域签约作者,人工智能、大模型、Python 爬虫,商务合作,请私信沟通。 8616

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

上一篇: 有用的cmd命令
下一篇: 当科技遇上艺术
IT修道者
IT修道者 领域专家: 人工智能技术领域 领域专家: 人工智能技术领域
博客等级 码龄17年 326粉丝 95原创
评论 14
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值