【OpenCV】角点检测:Harris角点及Shi-Tomasi角点检测

当一个窗口在图像上移动,在平滑区域如图(a),窗口在各个方向上没有变化。在边缘上如图(b),窗口在边缘的方向上没有变化。在角点处如图(c),窗口在各个方向上具有变化。Harris角点检测正是利用了这个直观的物理现象,通过窗口在各个方向上的变化程度,决定是否为角点。

将图像窗口平移[u,v]产生灰度变化E(u,v)

由:, 得到:

对于局部微小的移动量 [u,v],近似表达为:

其中M是 2*2 矩阵,可由图像的导数求得:

E(u,v)的椭圆形式如下图:

 

定义角点响应函数 R 为:

Harris角点检测算法就是对角点响应函数R进行阈值处理:R > threshold,即提取R的局部极大值。

 

【相关代码】

OpenCV中定义了 cornerHarris 函数:

[cpp]  view plain copy
  1. void cornerHarris( InputArray src, OutputArray dst, int blockSize,  
  2.                                 int ksize, double k,  
  3.                                 int borderType=BORDER_DEFAULT );  

可以结合 convertScaleAbs 函数,通过阈值取角点:

[cpp]  view plain copy
  1. void cornerHarris_demo( intvoid* )  
  2. {  
  3.   Mat dst, dst_norm;  
  4.   dst = Mat::zeros( src.size(), CV_32FC1 );  
  5.   /// Detector parameters  
  6.   int blockSize = 2;  
  7.   int apertureSize = 3;  
  8.   double k = 0.04;  
  9.   /// Detecting corners  
  10.   cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );  
  11.   /// Normalizing  
  12.   normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );  
  13.   convertScaleAbs( dst_norm, dst_norm_scaled );   
  14.   /// Drawing a circle around corners  
  15.   forint j = 0; j < dst_norm.rows ; j++ )  
  16.      { forint i = 0; i < dst_norm.cols; i++ )  
  17.           {  
  18.             if( (int) dst_norm.at<float>(j,i) > thresh )  
  19.               {   
  20.                 circle( dst_norm_scaled, Point( i, j ), 5,  Scalar(0), 2, 8, 0 );   
  21.                 circle(src,Point( i, j ), 5,  Scalar(255,0,0), -1, 8, 0 );  
  22.               }  
  23.           }   
  24.      }      
  25.   /// Showing the result  
  26.   imshow( corners_window, dst_norm_scaled );  
  27.   imshow( source_window, src );    
  28. }  

 
 

Shi-Tomasi 算法

Shi-Tomasi 算法是Harris 算法的改进。Harris 算法最原始的定义是将矩阵 M 的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较。后来Shi 和Tomasi 提出改进的方法,若两个特征值中较小的一个大于最小阈值,则会得到强角点。

如上面第二幅图中,对自相关矩阵 M 进行特征值分析,产生两个特征值和两个特征方向向量。因为较大的不确定度取决于较小的特征值,也就是,所以通过寻找最小特征值的最大值来寻找好的特征点也就解释的通了。
Shi 和Tomasi 的方法比较充分,并且在很多情况下可以得到比使用Harris 算法更好的结果。

 

【相关代码】

由于这种Shi-Tomasi算子与1994年在文章 Good Features to Track [1]中提出,OpenCV 实现的算法的函数名定义为 goodFeaturesToTrack:

[cpp]  view plain copy
  1. void goodFeaturesToTrack( InputArray image, OutputArray corners,  
  2.                                      int maxCorners, double qualityLevel, double minDistance,  
  3.                                      InputArray mask=noArray(), int blockSize=3,  
  4.                                      bool useHarrisDetector=falsedouble k=0.04 );  

自定义使用函数(以方便createTrackbar的响应)如下:

[cpp]  view plain copy
  1. void cornerShiTomasi_demo( intvoid* )  
  2. {  
  3.   if( maxCorners < 1 ) { maxCorners = 1; }  
  4.   /// Parameters for Shi-Tomasi algorithm  
  5.   vector<Point2f> corners;  
  6.   double qualityLevel = 0.01;  
  7.   double minDistance = 10;  
  8.   int blockSize = 3;  
  9.   bool useHarrisDetector = false;  
  10.   double k = 0.04;  
  11.   /// Copy the source image  
  12.   Mat cormat;  
  13.   /// Apply corner detection :Determines strong corners on an image.  
  14.   goodFeaturesToTrack( src_gray,   
  15.                corners,  
  16.                maxCorners,  
  17.                qualityLevel,  
  18.                minDistance,  
  19.                Mat(),  
  20.                blockSize,  
  21.                useHarrisDetector,  
  22.                k );  
  23.   /// Draw corners detected  
  24.   forint i = 0; i < corners.size(); i++ ){   
  25.       circle( dst_norm_scaled,  corners[i], 5,  Scalar(255), 2, 8, 0 );   
  26.       circle( src, corners[i], 4, Scalar(0,255,0), 2, 8, 0 );   
  27.   }  
  28.   
  29.   /// Show what you got  
  30.   imshow( corners_window, dst_norm_scaled );  
  31.   imshow( source_window, src );    
  32. }  

 
 

实践

在主函数中定义两个进度条方便调整阈值:

[cpp]  view plain copy
  1. namedWindow( source_window, CV_WINDOW_AUTOSIZE );  
  2. createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo );  
  3. createTrackbar( "Max  corners:", source_window, &maxCorners, maxTrackbar, cornerShiTomasi_demo );    
  4.   
  5. namedWindow( corners_window, CV_WINDOW_AUTOSIZE );  
  6. namedWindow( source_window, CV_WINDOW_AUTOSIZE );  
  7. imshow( source_window, src );    
  8.   
  9. cornerHarris_demo( 0, 0 );  
  10. cornerShiTomasi_demo( 0, 0 );  


这里还需要说的是OpenCV 2.4.2中给的角点检测跟踪的示例代码有些问题,是应为SURF等不再定义在 feature2d模块中,而是legacy和nonfree,所以需要加入引用:

[cpp]  view plain copy
  1. #include "opencv2/legacy/legacy.hpp"  
  2. #include "opencv2/nonfree/nonfree.hpp"  

 

角点检测结果:

蓝色实心点为Harris检测结果,绿色空心圈为goodFeaturetoTrack检测结果。

M特征值分解后每个像素点相减的图(也就是Harris阈值判断的图)如下:

黑色实心点为Harris阈值检测结果,白色空心圈为阈值为27时Shi-Tomasi检测结果。

转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7805206
源码及资料下载: http://download.csdn.net/detail/xiaowei_cqu/4466627

参考资料:

[1] Shi and C. Tomasi. Good Features to Track. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pages 593-600, June 1994.

[2] Richard Szeliski. Computer Vision: Algorithms and Applications. Springer, New York, 2010.

[3] 图像特征点提取PPT http://wenku.baidu.com/view/f61bc369561252d380eb6ef0.html 

 


角点

特征检测与匹配是Computer Vision 应用总重要的一部分,这需要寻找图像之间的特征建立对应关系。点,也就是图像中的特殊位置,是很常用的一类特征,点的局部特征也可以叫做“关键特征点”(keypoint feature),或“兴趣点”(interest point),或“角点”(conrner)。

关于角点的具体描述可以有几种:

  • 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
  • 两条及两条以上边缘的交点;
  • 图像中梯度值和梯度方向的变化速率都很高的点;
  • 角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

 

Harris角点检测



当一个窗口在图像上移动,在平滑区域如图(a),窗口在各个方向上没有变化。在边缘上如图(b),窗口在边缘的方向上没有变化。在角点处如图(c),窗口在各个方向上具有变化。Harris角点检测正是利用了这个直观的物理现象,通过窗口在各个方向上的变化程度,决定是否为角点。

将图像窗口平移[u,v]产生灰度变化E(u,v)

由:, 得到:

对于局部微小的移动量 [u,v],近似表达为:

其中M是 2*2 矩阵,可由图像的导数求得:

E(u,v)的椭圆形式如下图:

 

定义角点响应函数 R 为:

Harris角点检测算法就是对角点响应函数R进行阈值处理:R > threshold,即提取R的局部极大值。

 

【相关代码】

OpenCV中定义了 cornerHarris 函数:

[cpp]  view plain copy
  1. void cornerHarris( InputArray src, OutputArray dst, int blockSize,  
  2.                                 int ksize, double k,  
  3.                                 int borderType=BORDER_DEFAULT );  

可以结合 convertScaleAbs 函数,通过阈值取角点:

[cpp]  view plain copy
  1. void cornerHarris_demo( intvoid* )  
  2. {  
  3.   Mat dst, dst_norm;  
  4.   dst = Mat::zeros( src.size(), CV_32FC1 );  
  5.   /// Detector parameters  
  6.   int blockSize = 2;  
  7.   int apertureSize = 3;  
  8.   double k = 0.04;  
  9.   /// Detecting corners  
  10.   cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );  
  11.   /// Normalizing  
  12.   normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );  
  13.   convertScaleAbs( dst_norm, dst_norm_scaled );   
  14.   /// Drawing a circle around corners  
  15.   forint j = 0; j < dst_norm.rows ; j++ )  
  16.      { forint i = 0; i < dst_norm.cols; i++ )  
  17.           {  
  18.             if( (int) dst_norm.at<float>(j,i) > thresh )  
  19.               {   
  20.                 circle( dst_norm_scaled, Point( i, j ), 5,  Scalar(0), 2, 8, 0 );   
  21.                 circle(src,Point( i, j ), 5,  Scalar(255,0,0), -1, 8, 0 );  
  22.               }  
  23.           }   
  24.      }      
  25.   /// Showing the result  
  26.   imshow( corners_window, dst_norm_scaled );  
  27.   imshow( source_window, src );    
  28. }  

 
 

Shi-Tomasi 算法

Shi-Tomasi 算法是Harris 算法的改进。Harris 算法最原始的定义是将矩阵 M 的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较。后来Shi 和Tomasi 提出改进的方法,若两个特征值中较小的一个大于最小阈值,则会得到强角点。

如上面第二幅图中,对自相关矩阵 M 进行特征值分析,产生两个特征值和两个特征方向向量。因为较大的不确定度取决于较小的特征值,也就是,所以通过寻找最小特征值的最大值来寻找好的特征点也就解释的通了。
Shi 和Tomasi 的方法比较充分,并且在很多情况下可以得到比使用Harris 算法更好的结果。

 

【相关代码】

由于这种Shi-Tomasi算子与1994年在文章 Good Features to Track [1]中提出,OpenCV 实现的算法的函数名定义为 goodFeaturesToTrack:

[cpp]  view plain copy
  1. void goodFeaturesToTrack( InputArray image, OutputArray corners,  
  2.                                      int maxCorners, double qualityLevel, double minDistance,  
  3.                                      InputArray mask=noArray(), int blockSize=3,  
  4.                                      bool useHarrisDetector=falsedouble k=0.04 );  

自定义使用函数(以方便createTrackbar的响应)如下:

[cpp]  view plain copy
  1. void cornerShiTomasi_demo( intvoid* )  
  2. {  
  3.   if( maxCorners < 1 ) { maxCorners = 1; }  
  4.   /// Parameters for Shi-Tomasi algorithm  
  5.   vector<Point2f> corners;  
  6.   double qualityLevel = 0.01;  
  7.   double minDistance = 10;  
  8.   int blockSize = 3;  
  9.   bool useHarrisDetector = false;  
  10.   double k = 0.04;  
  11.   /// Copy the source image  
  12.   Mat cormat;  
  13.   /// Apply corner detection :Determines strong corners on an image.  
  14.   goodFeaturesToTrack( src_gray,   
  15.                corners,  
  16.                maxCorners,  
  17.                qualityLevel,  
  18.                minDistance,  
  19.                Mat(),  
  20.                blockSize,  
  21.                useHarrisDetector,  
  22.                k );  
  23.   /// Draw corners detected  
  24.   forint i = 0; i < corners.size(); i++ ){   
  25.       circle( dst_norm_scaled,  corners[i], 5,  Scalar(255), 2, 8, 0 );   
  26.       circle( src, corners[i], 4, Scalar(0,255,0), 2, 8, 0 );   
  27.   }  
  28.   
  29.   /// Show what you got  
  30.   imshow( corners_window, dst_norm_scaled );  
  31.   imshow( source_window, src );    
  32. }  

 
 

实践

在主函数中定义两个进度条方便调整阈值:

[cpp]  view plain copy
  1. namedWindow( source_window, CV_WINDOW_AUTOSIZE );  
  2. createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo );  
  3. createTrackbar( "Max  corners:", source_window, &maxCorners, maxTrackbar, cornerShiTomasi_demo );    
  4.   
  5. namedWindow( corners_window, CV_WINDOW_AUTOSIZE );  
  6. namedWindow( source_window, CV_WINDOW_AUTOSIZE );  
  7. imshow( source_window, src );    
  8.   
  9. cornerHarris_demo( 0, 0 );  
  10. cornerShiTomasi_demo( 0, 0 );  


这里还需要说的是OpenCV 2.4.2中给的角点检测跟踪的示例代码有些问题,是应为SURF等不再定义在 feature2d模块中,而是legacy和nonfree,所以需要加入引用:

[cpp]  view plain copy
  1. #include "opencv2/legacy/legacy.hpp"  
  2. #include "opencv2/nonfree/nonfree.hpp"  

 

角点检测结果:

蓝色实心点为Harris检测结果,绿色空心圈为goodFeaturetoTrack检测结果。

M特征值分解后每个像素点相减的图(也就是Harris阈值判断的图)如下:

黑色实心点为Harris阈值检测结果,白色空心圈为阈值为27时Shi-Tomasi检测结果。

转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7805206
源码及资料下载: http://download.csdn.net/detail/xiaowei_cqu/4466627

参考资料:

[1] Shi and C. Tomasi. Good Features to Track. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pages 593-600, June 1994.

[2] Richard Szeliski. Computer Vision: Algorithms and Applications. Springer, New York, 2010.

[3] 图像特征点提取PPT http://wenku.baidu.com/view/f61bc369561252d380eb6ef0.html 

 

二、opencv代码实现

harris类

[cpp]  view plain copy
  1. #ifndef HARRIS_H  
  2. #define HARRIS_H  
  3. #include "opencv2/opencv.hpp"  
  4.   
  5. class harris  
  6. {  
  7. private:  
  8.     cv::Mat  cornerStrength;  //opencv harris函数检测结果,也就是每个像素的角点响应函数值  
  9.     cv::Mat cornerTh; //cornerStrength阈值化的结果  
  10.     cv::Mat localMax; //局部最大值结果  
  11.     int neighbourhood; //邻域窗口大小  
  12.     int aperture;//sobel边缘检测窗口大小(sobel获取各像素点x,y方向的灰度导数)  
  13.     double k;  
  14.     double maxStrength;//角点响应函数最大值  
  15.     double threshold;//阈值除去响应小的值  
  16.     int nonMaxSize;//这里采用默认的3,就是最大值抑制的邻域窗口大小  
  17.     cv::Mat kernel;//最大值抑制的核,这里也就是膨胀用到的核  
  18. public:  
  19.     harris():neighbourhood(3),aperture(3),k(0.01),maxStrength(0.0),threshold(0.01),nonMaxSize(3){  
  20.   
  21.     };  
  22.   
  23.     void setLocalMaxWindowsize(int nonMaxSize){  
  24.         this->nonMaxSize = nonMaxSize;  
  25.     };  
  26.   
  27.     //计算角点响应函数以及非最大值抑制  
  28.     void detect(const cv::Mat &image){  
  29.             //opencv自带的角点响应函数计算函数  
  30.             cv::cornerHarris (image,cornerStrength,neighbourhood,aperture,k);  
  31.             double minStrength;  
  32.             //计算最大最小响应值  
  33.             cv::minMaxLoc (cornerStrength,&minStrength,&maxStrength);  
  34.   
  35.             cv::Mat dilated;  
  36.             //默认3*3核膨胀,膨胀之后,除了局部最大值点和原来相同,其它非局部最大值点被  
  37.             //3*3邻域内的最大值点取代  
  38.             cv::dilate (cornerStrength,dilated,cv::Mat());  
  39.             //与原图相比,只剩下和原图值相同的点,这些点都是局部最大值点,保存到localMax  
  40.             cv::compare(cornerStrength,dilated,localMax,cv::CMP_EQ);  
  41.     }  
  42.   
  43.     //获取角点图  
  44.     cv::Mat getCornerMap(double qualityLevel) {  
  45.             cv::Mat cornerMap;  
  46.             // 根据角点响应最大值计算阈值  
  47.             threshold= qualityLevel*maxStrength;  
  48.             cv::threshold(cornerStrength,cornerTh,  
  49.             threshold,255,cv::THRESH_BINARY);  
  50.             // 转为8-bit图  
  51.             cornerTh.convertTo(cornerMap,CV_8U);  
  52.             // 和局部最大值图与,剩下角点局部最大值图,即:完成非最大值抑制  
  53.             cv::bitwise_and(cornerMap,localMax,cornerMap);  
  54.             return cornerMap;  
  55.     }  
  56.   
  57.     void getCorners(std::vector<cv::Point> &points,  
  58.             double qualityLevel) {  
  59.             //获取角点图  
  60.             cv::Mat cornerMap= getCornerMap(qualityLevel);  
  61.             // 获取角点  
  62.             getCorners(points, cornerMap);  
  63.     }  
  64.   
  65.     // 遍历全图,获得角点  
  66.     void getCorners(std::vector<cv::Point> &points,  
  67.     const cv::Mat& cornerMap) {  
  68.   
  69.             forint y = 0; y < cornerMap.rows; y++ ) {  
  70.                     const uchar* rowPtr = cornerMap.ptr<uchar>(y);  
  71.                     forint x = 0; x < cornerMap.cols; x++ ) {  
  72.                     // 非零点就是角点  
  73.                           if (rowPtr[x]) {  
  74.                                 points.push_back(cv::Point(x,y));  
  75.                           }  
  76.                      }  
  77.                 }  
  78.           }  
  79.   
  80.     //用圈圈标记角点  
  81.     void drawOnImage(cv::Mat &image,  
  82.     const std::vector<cv::Point> &points,  
  83.             cv::Scalar color= cv::Scalar(255,255,255),  
  84.             int radius=3, int thickness=2) {  
  85.                     std::vector<cv::Point>::const_iterator it=points.begin();  
  86.                     while (it!=points.end()) {  
  87.                     // 角点处画圈  
  88.                     cv::circle(image,*it,radius,color,thickness);  
  89.                     ++it;  
  90.             }  
  91.     }  
  92.   
  93. };  
  94.   
  95. #endif // HARRIS_H  
相关测试代码:

[cpp]  view plain copy
  1. cv::Mat  image, image1 = cv::imread ("test.jpg");  
  2.    //灰度变换  
  3.    cv::cvtColor (image1,image,CV_BGR2GRAY);  
  4.   
  5.   
  6.    // 经典的harris角点方法  
  7.    harris Harris;  
  8.    // 计算角点  
  9.    Harris.detect(image);  
  10.    //获得角点  
  11.    std::vector<cv::Point> pts;  
  12.    Harris.getCorners(pts,0.01);  
  13.    // 标记角点  
  14.    Harris.drawOnImage(image,pts);  
  15.   
  16.    cv::namedWindow ("harris");  
  17.    cv::imshow ("harris",image);  
  18.    cv::waitKey (0);  
  19.    return 0;  
相关测试结果:


三、改进的Harris角点检测

    从经典的Harris角点检测方法不难看出,该算法的稳定性和k有关,而k是个经验值,不好把握,浮动也有可能较大。鉴于此,改进的Harris方法()直接计算出两个特征值,通过比较两个特征值直接分类,这样就不用计算Harris响应函数了。

    另一方面,我们不再用非极大值抑制了,而选取容忍距离:容忍距离内只有一个特征点。
    该算法首先选取一个具有最大   最小特征值的点(即:max(min(e1,e2)),e1,e2是harris矩阵的特征值)作为角点,然后依次按照最大最小特征值顺序寻找余下的角点,当然和前一角点距离在容忍距离内的新角点呗忽略。

    opencv测试该算法代码如下:

[cpp]  view plain copy
  1.     cv::Mat  image, image1 = cv::imread ("test.jpg");  
  2.     //灰度变换  
  3.     cv::cvtColor (image1,image,CV_BGR2GRAY);  
  4.     // 改进的harris角点检测方法  
  5.     std::vector<cv::Point> corners;  
  6.     cv::goodFeaturesToTrack(image,corners,  
  7.     200,  
  8.     //角点最大数目  
  9.     0.01,  
  10.     // 质量等级,这里是0.01*max(min(e1,e2)),e1,e2是harris矩阵的特征值  
  11.     10);  
  12.     // 两个角点之间的距离容忍度  
  13.     harris().drawOnImage(image,corners);//标记角点  
    测试结果如下:


四、FAST角点检测

    算法原理比较简单,但实时性很强。

    该算法的角点定义为:若某像素点圆形邻域圆周上有3/4的点和该像素点不同(编程时不超过某阈值th),则认为该点就是候选角点。opencv更极端,选用半径为3的圆周上(上下左右)四个点,若超过三个点和该像素点不同,则该点为候选角点。

    和Harris算法类似,该算法需要非极大值抑制。

opencv代码:

[cpp]  view plain copy
  1. cv::Mat  image, image1 = cv::imread ("test.jpg");  
  2. cv::cvtColor (image1,image,CV_BGR2GRAY);  
  3. //快速角点检测  
  4. std::vector<cv::KeyPoint> keypoints;  
  5. cv::FastFeatureDetector fast(40,true);  
  6. fast .detect (image,keypoints);  
  7. cv::drawKeypoints (image,keypoints,image,cv::Scalar::all(255),cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);  


测试结果如下:

Shi-Tomasi角点检测算法是一种经典的角点检测算法,它可以在图像中找到具有最大角度的角点。在OpenCV中,可以使用cv.goodFeaturesToTrack()函数进行Shi-Tomasi角点检测。 函数原型: ``` cv.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]]) ``` 参数说明: - image:输入图像,必须是单通道8位或32位浮点型图像。 - maxCorners:检测到的最大角点数。 - qualityLevel:角点的最小质水平,范围为0到1,表示角点的最小可接受质。 - minDistance:角点之间的最小欧几里得距离。 - corners:输出角点的坐标。 - mask:用于限制检测区域的掩码图像。 - blockSize:计算图像梯度的邻域大小。 - useHarrisDetector:如果为true,则使用Harris角点检测算法。 - k:Harris角点检测算法的自由参数。 示例代码: ```python import cv2 as cv import numpy as np img = cv.imread('test.jpg') gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) corners = cv.goodFeaturesToTrack(gray, 100, 0.01, 10) corners = np.int0(corners) for corner in corners: x, y = corner.ravel() cv.circle(img, (x, y), 3, (0, 0, 255), -1) cv.imshow('img', img) cv.waitKey(0) cv.destroyAllWindows() ``` 效果如下图所示: ![shi-tomasi角点检测示例](https://img-blog.csdn.net/20180313173704656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ29vZGllX2Jsb2c=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/75)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值