字符识别opencv2.4.13-vs2013 C++实现全部代码

最近用opencv做一个字符识别的例子。参考了CSDN上的文档,把全部代码写下来了。训练100000个样本时候准确率超90%。主要用来识别0-9数字。

详细原理参考了

https://www.cnblogs.com/ronny/p/opencv_road_more_01.html

这位大佬写的文章。

代码如下:可以直接写一个main函数跑,转载请注明,请勿商用。

#include "opencv2\opencv.hpp"  
#include "iostream""    
#include "string"
#include "stdafx.h"
#include "targetver.h"
#include "opencv2\highgui.hpp"
#include "opencv2\ml.hpp"  
#include "opencv2\imgproc.hpp"

using namespace std;
using namespace cv;
/*梯度特征法
void calcGradientFeat(const Mat& imgSrc, vector<float>& feat)
 {
        float sumMatValue(const Mat& image); // 计算图像中像素灰度值总和 
    
         Mat image;
         cvtColor(imgSrc, image, CV_BGR2GRAY);
         resize(image, image, Size(8, 16));
    
           // 计算x方向和y方向上的滤波 
        float mask[3][3] = { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };
        Mat y_mask = Mat(3, 3, CV_32F, mask) / 8;
        Mat x_mask = y_mask.t(); // 转置 
        Mat sobelX, sobelY;
    
        filter2D(image, sobelX, CV_32F, x_mask);
        filter2D(image, sobelY, CV_32F, y_mask);
    
        sobelX = abs(sobelX);
        sobelY = abs(sobelY);
    
        float totleValueX = sumMatValue(sobelX);
        float totleValueY = sumMatValue(sobelY);
    
            // 将图像划分为4*2共8个格子,计算每个格子里灰度值总和的百分比 
            for (int i = 0; i < image.rows; i = i + 4)
            {
                for (int j = 0; j < image.cols; j = j + 4)
                    {
                       Mat subImageX = sobelX(Rect(j, i, 4, 4));
                        feat.push_back(sumMatValue(subImageX) / totleValueX);
                        Mat subImageY = sobelY(Rect(j, i, 4, 4));
                         feat.push_back(sumMatValue(subImageY) / totleValueY);
                     }
             }
 }
float sumMatValue(const Mat& image)
{
     float sumValue = 0;
     int r = image.rows;
       int c = image.cols;
        if (image.isContinuous())
            {
                c = r*c;
                 r = 1;
             }
         for (int i = 0; i < r; i++)
             {
                const uchar* linePtr = image.ptr<uchar>(i);
                 for (int j = 0; j < c; j++)
                   {
                        sumValue += linePtr[j];
                    }
           }
         return sumValue;
}
*/
int main(){
    CvANN_MLP bp;
    int times = 0;
    int r, t;
    Mat imgfeatures(100000, 128, CV_32F);
    Mat inputs;
    Mat outputs = cv::Mat::zeros(cv::Size(10, 100000), CV_32F); // 全零矩阵
    CvANN_MLP_TrainParams params;
    cout << "开始训练请输入0" << endl;
    cout << "直接测试请输入1" << endl;
    int scan;
    cin >> scan;
    if (scan == 0){
        while (times < 100000){
            r = rand() % 10;
            t = rand() % 50 + 1;
            char filename[100];
            sprintf_s(filename, "G:\\opencv\\字符识别\\charSamples\\%d\\字符%d (%d).png", r, r, t);
            Mat SrcImg, ResImg;
            SrcImg = cv::imread(filename, 1);//导入图片
            if (SrcImg.empty())//读取失败时
            {
                cout << "Could not open or find the image" << std::endl;
                return -1;
            }
            cvtColor(SrcImg, ResImg, CV_BGR2GRAY);
            resize(ResImg, ResImg, Size(8, 16), 0, 0, CV_INTER_LINEAR);
            Mat imgfeature(1, 128, CV_32F);
            //Laplacian(ResImg, ResImg, ResImg.depth(), 3, 1);
            int p = 0;
            for (int i = 0; i < ResImg.rows; i++)
            {
                for (int j = 0; j < ResImg.cols; j++)
                {
                    imgfeature.at<float>(0, p) = ResImg.at<unsigned char>(i, j);
                    //auto a = ResImg.at<unsigned char>(i, j);
                    p++;
                }
            }
            for (int i = 0; i < imgfeature.cols; i++)
            {
                imgfeatures.at<float>(times, i) = imgfeature.at<float>(0, i);
            }
            outputs.at<float>(times, r) = 1;
            times++;
        }
        Mat layerSizes = (Mat_<int>(1, 5) << 128, 16, 16, 16, 10);
        bp.create(layerSizes, CvANN_MLP::SIGMOID_SYM, 1, 1);
        //CvANN_MLP_TrainParams params;
        params.train_method = CvANN_MLP_TrainParams::BACKPROP;//训练算法设置为随机序列反向传播 
        //该系数乘以计算出的权值梯度,推荐值为0.1。  
        params.bp_dw_scale = 0.1;
        //该系数乘以前两次迭代的权值之差,平滑权值的随机影响,取值从0-1(0对应的特征被disable)或更大,0.1左右已经足够了。  
        params.bp_moment_scale = 0.1;
        params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 5000, 0.01);
        int nSamples = 100000;//设置样本个数
        int ndims = 128;//特征向量维数
        int nClass = 10;//类别数
        inputs = imgfeatures;
        /*for (int i = 0; i < 2000; i++)
        {
        outputs.at<float>(i, r) = 1;
        }*/
        //outputs.at<float>(times, r) = 1;
        cout << "the net is training...." << endl;
        bp.train(inputs, outputs, Mat(), Mat(), params);
        bp.save("bp.xml");//保存训练结果  
        cout << "the net has trained over" << endl;
        Mat input, Resinput;
        Mat bpinput(1, 128, CV_32F);
        Mat output(1, 10, CV_32F);
        input = imread("G:\\opencv\\字符识别\\charSamples\\5\\字符5 (2).png", 1);
        cvtColor(input, Resinput, CV_BGR2GRAY);
        resize(Resinput, Resinput, Size(8, 16), 0, 0, CV_INTER_LINEAR);
        int p1 = 0;
        for (int i = 0; i < Resinput.rows; i++)
        {
            for (int j = 0; j < Resinput.cols; j++)
            {
                bpinput.at<float>(0, p1) = Resinput.at<unsigned char>(i, j);
                //auto a = ResImg.at<unsigned char>(i, j);
                p1++;
            }
        }
        bp.predict(bpinput, output);
        float max = 0;
        int flag;
        for (int i = 0; i < output.cols; i++)
        {
            if (max < output.at<float>(0, i))
            {
                max = output.at<float>(0, i);
                flag = i;
            }
        }
        switch (flag)
        {
        case 0: cout << "0" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 1: cout << "1" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 2: cout << "2" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 3: cout << "3" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 4: cout << "4" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 5: cout << "5" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 6: cout << "6" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 7: cout << "7" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 8: cout << "8" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 9: cout << "9" << endl;
            cout << output.at<float>(0, 9) << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 10: cout << "A" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 11: cout << "B" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 12: cout << "C" << endl;
            break;
        case 13: cout << "D" << endl;
            break;
        case 14: cout << "E" << endl;
            break;
        case 15: cout << "F" << endl;
            break;
        case 16: cout << "G" << endl;
            break;
        case 17: cout << "H" << endl;
            break;
        case 18: cout << "J" << endl;
            break;
        case 19: cout << "K" << endl;
            break;
        case 20: cout << "L" << endl;
            break;
        case 21: cout << "M" << endl;
            break;
        case 22: cout << "N" << endl;
            break;
        case 23: cout << "P" << endl;
            break;
        case 24: cout << "Q" << endl;
            break;
        case 25: cout << "R" << endl;
            break;
        case 26: cout << "S" << endl;
            break;
        case 27: cout << "T" << endl;
            break;
        case 28: cout << "U" << endl;
            break;
        case 29: cout << "V" << endl;
            break;
        case 30: cout << "W" << endl;
            break;
        case 31: cout << "X" << endl;
            break;
        case 32: cout << "Y" << endl;
            break;
        case 33: cout << "Z" << endl;
            break;
        default:
            break;
        }
    }
    else if (scan == 1)
    {
        CvANN_MLP bp;
        CvANN_MLP_TrainParams params;
        Mat layerSizes = (Mat_<int>(1, 5) << 128, 16, 16, 16, 10);
        bp.create(layerSizes, CvANN_MLP::SIGMOID_SYM, 1, 1);
        //CvANN_MLP_TrainParams params;
        params.train_method = CvANN_MLP_TrainParams::BACKPROP;//训练算法设置为随机序列反向传播 
        //该系数乘以计算出的权值梯度,推荐值为0.1。  
        params.bp_dw_scale = 0.1;
        //该系数乘以前两次迭代的权值之差,平滑权值的随机影响,取值从0-1(0对应的特征被disable)或更大,0.1左右已经足够了。  
        params.bp_moment_scale = 0.1;
        params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 5000, 0.01);
        bp.load("bp.xml");
        Mat input, Resinput;
        Mat bpinput(1, 128, CV_32F);
        Mat output(1, 10, CV_32F);
        input = imread("G:\\opencv\\字符识别\\charSamples\\9\\字符9 (13).png", 1);
        cvtColor(input, Resinput, CV_BGR2GRAY);
        resize(Resinput, Resinput, Size(8, 16), 0, 0, CV_INTER_LINEAR);
        int p1 = 0;
        for (int i = 0; i < Resinput.rows; i++)
        {
            for (int j = 0; j < Resinput.cols; j++)
            {
                bpinput.at<float>(0, p1) = Resinput.at<unsigned char>(i, j);
                //auto a = ResImg.at<unsigned char>(i, j);
                p1++;
            }
        }
        bp.predict(bpinput, output);
        float max = 0;
        int flag;
        for (int i = 0; i < output.cols; i++)
        {
            if (max < output.at<float>(0, i))
            {
                max = output.at<float>(0, i);
                flag = i;
            }
        }
        switch (flag)
        {
        case 0: cout << "0" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 1: cout << "1" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 2: cout << "2" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 3: cout << "3" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 4: cout << "4" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 5: cout << "5" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 6: cout << "6" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 7: cout << "7" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 8: cout << "8" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 9: cout << "9" << endl;
            cout << output.at<float>(0, 9) << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 10: cout << "A" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 11: cout << "B" << endl;
            cout << output.at<float>(0, 0) << endl;
            cout << output.at<float>(0, 1) << endl;
            cout << output.at<float>(0, 2) << endl;
            cout << output.at<float>(0, 3) << endl;
            cout << output.at<float>(0, 4) << endl;
            cout << output.at<float>(0, 5) << endl;
            cout << output.at<float>(0, 6) << endl;
            cout << output.at<float>(0, 7) << endl;
            cout << output.at<float>(0, 8) << endl;
            cout << output.at<float>(0, 9) << endl;
            break;
        case 12: cout << "C" << endl;
            break;
        case 13: cout << "D" << endl;
            break;
        case 14: cout << "E" << endl;
            break;
        case 15: cout << "F" << endl;
            break;
        case 16: cout << "G" << endl;
            break;
        case 17: cout << "H" << endl;
            break;
        case 18: cout << "J" << endl;
            break;
        case 19: cout << "K" << endl;
            break;
        case 20: cout << "L" << endl;
            break;
        case 21: cout << "M" << endl;
            break;
        case 22: cout << "N" << endl;
            break;
        case 23: cout << "P" << endl;
            break;
        case 24: cout << "Q" << endl;
            break;
        case 25: cout << "R" << endl;
            break;
        case 26: cout << "S" << endl;
            break;
        case 27: cout << "T" << endl;
            break;
        case 28: cout << "U" << endl;
            break;
        case 29: cout << "V" << endl;
            break;
        case 30: cout << "W" << endl;
            break;
        case 31: cout << "X" << endl;
            break;
        case 32: cout << "Y" << endl;
            break;
        case 33: cout << "Z" << endl;
            break;
        default:
            break;
        }
    }
    else
        exit(-1);
    system("pause");
    return 0;
}

转载请注明!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值