opencv(cpp)入门学习

本文介绍了OpenCV中如何进行图像的色彩空间转换,包括克隆、复制和赋值等操作,以及图像像素的读写、算术操作。还展示了如何使用滚动条调整图像亮度、使用键盘响应和鼠标操作进行图像处理。此外,涵盖了图像的几何变换、直方图、随机颜色生成及视频处理等技术。
摘要由CSDN通过智能技术生成

图像 色彩空间转换


图像 创建赋值

//克隆(创建另外一个Mat)
Mat m1 = src.clone();

//复制
Mat m2;
src.copyTo(m2);

//赋值:
Mat m3;
m3 = imread();
m3 = src;

//赋值:创建空白图像
Mat m4 = Mat::zeros(src.size, src.type());
Mat m5 = Mat::zeros(Size(512, 512),CV_8UC3);
Mat m6 = Mat::ones(Size(512, 512), CV_8UC3);

//赋值:C++11新增
Mat kernel = (Mat_<char>(3,3)<<0,-1,0,
    -1,5,-1,
    0,-1,0);

//赋值:通道赋值
Mat m3 = Mat::zeros(Size(512,512), CV_8UC3);
m3 = Scalar(127,127, 127);

//浅拷贝,m4和m3指向同一个对象
Mat m4 = m3;

图像 像素的读写操作


//eg1:颜色取反
// Mat image;已赋值的Mat
int w = image.cols;
int h = image.rows;
int dims = image.channels();
for(int row = 0;row < h;row++){
    for(int col = 0;col < w;col++){
        if(dims == 1){//灰度图像
            //获取该行列的像素值
            int pv = image.at<uchar>(row,col);
            image.at<uchar>(row,col) = 255 - pv;
        }
        if(dims == 3){//彩色图像
            //获取该行列的所有通道的像素值
            Vec3b bgr = image.at<Vec3b>(row,col);
            image.at<Vec3b>(row,col)[0] = 255 - bgr[0];
            image.at<Vec3b>(row,col)[1] = 255 - bgr[1];
            image.at<Vec3b>(row,col)[2] = 255 - bgr[2];
        }
    }
}

//eg2:颜色取反
// Mat image;已赋值的Mat
int w = image.cols;
int h = image.rows;
int dims = image.channels();
for(int row = 0;row < h;row++){
    //获取该行的首个元素的像素指针
    uchar * current_row = image.ptr<uchar>(row);
    for(int col = 0;col < w;col++){
        if(dims == 1){//灰度图像
            int pv = *current_row;
            *current_row++; = 255 - pv;
        }
        if(dims == 3){//彩色图像
            *current_row++; = 255 - *current_row*;
            *current_row++; = 255 - *current_row*;
            *current_row++; = 255 - *current_row*;
        }
    }

}

图像 像素的算术操作

//eg1:减法操作
//Mat image
Mat dst = image - Scalar(50,50,50);
imshow("减法操作", dst);

//eg2:除法操作
//Mat image
Mat dst = image/Scalar(2,2,2);
imshow("除法操作", dst);


//eg3:乘法操作
//Mat image
Mat m = Mat::zeros(image.size, image.type());
m = Scalar(2, 2, 2);
multiply(image, m , dst);
imshow("乘法操作", dst);

//eg4:加法扩展
//Mat image
Mas dst = Mat::zeros(image.size, image.type());
Mas m = Mat::zeros(image.size, image.type());
m = Scalar(50,50,50);
//加法
int w = image.cols;
int h = image.rows;
int dims = image.channels();
for(int row = 0;row < h;row++){
    for(int col = 0;col < w;col++){
        if(dims == 1){//灰度图像
            //获取该行列的像素值
            // int pv = image.at<uchar>(row,col);
            // image.at<uchar>(row,col) = 255 - pv;
        }
        if(dims == 3){//彩色图像
            //获取该行列的所有通道的像素值
            Vec3b p1 = image.at<Vec3b>(row,col);
            Vec3b p2 = m.at<Vec3b>(row,col);
            dst.at<Vec3b>(row,col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
            dst.at<Vec3b>(row,col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
            dst.at<Vec3b>(row,col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
        }
    }
}

//eg5:api
Mas dst = Mat::zeros(image.size, image.type());
Mas m = Mat::zeros(image.size, image.type());
m = Scalar(50,50,50);
add(image, m, dst);//加法
// subtract(image, m, dst);//减法
// divide(image, m, dst);//除法
imshow("运算操作", dst);

滚动条操作演示 调整图像亮度

//回调函数,亮度回调值
static void on_track(int,void*){
    Mas dst = Mat::zeros(image.size, image.type());
    Mas m = Mat::zeros(image.size, image.type());
}

namedWindow("亮度调整", WINDOW_AUTOSIZE);
int max_value = 100;
int lightness = 50;
createTrackbar("Value", "亮度调整", &lightness, max_value, on_track);
on_track(50,0);//设置一个默认值

滚动条操作演示-参数传递度

//回调函数,亮度回调值
static void onLightness(int b, void* userdata) {
    Mat image = *((Mat*)userdata);
    Mat dst = Mat::zeros(image.size(), image.type());
    Mat m = Mat::zeros(image.size(), image.type());
    addWerghted(image,1.0,m,0,b,dst);
    imshow("亮度与对比度调整",dst);
}

//回调函数,亮度与对比度调整
static void onContrast(int b, void* userdata) {
    Mat image = *((Mat*)userdata);
    Mat dst = Mat::zeros(image.size(), image.type());
    Mat m = Mat::zeros(image.size(), image.type());
    doublt contrast = b / 100.0;
    addWerghted(image,contrast,m,0.0,0,dst);
    imshow("亮度与对比度调整",dst);
}
   

void tracking_bar_demo(Mat &image){
    namedWindow("亮度调整", WINDOW_AUTOSIZE);
    int max_value = 100;
    int lightness = 50;
    int contrast_value = 100;
    createTrackbar("Value", "亮度与对比度调整", &lightness, max_value, onLightness,(void*)(&image));
    createTrackbar("Contrast Bar", "亮度与对比度调整", &contrast_value, max_value200, onContrast,(void*)(&image));
    on_lightness(50,&image);
}

键盘响应操作 waitKey

void key_demo(Mat &image){
    Mat dst;

    //监听键盘操作
    while(true){
        char c = waitKey(10);
        std::cout << c << std::endl;
    }
}

openCV自带颜色表操作 applyColorMap

void colorStyleDemo(Mat &image){
    int colormap[]= {
        COLORMAP_AUTUMN,
        COLORMAP_BONE,
        COLORMAP_JET,
        COLORMAP_WINTER,
        COLORMAP_RAINBOW,
        COLORMAP_OCEAN,
        COLORMAP_SUMMER,
        COLORMAP_SPRING,
        COLORMAP_COOL,
        COLORMAP_PINK,
        COLORMAP_HOT,
        COLORMAP_PARULA,
        COLORMAP_MAGMA,
        COLORMAP_INFERNO,
        COLORMAP_PLASMA,
        COLORMAP_VIRIDIS,
        COLORMAP_CIVIDIS,
        COLORMAP_TWILIGHT,
        COLORMAP_TWILIGHT_SHIFTED
    };

    Mat dst;
    int index = 0;
    while(true){
        int c = waitKey(2000);
        if(c == 27){//退出
            break;
        }
        applyColorMap(image, dst, colormap[index%19]);
        index++;
        imshow("颜色风格", dst);
    }   
}

rectangle 图像像素的逻辑操作

void bitWiseDemo(Mat &image){
    Mat m1 = Mat::zero(Size(256,256),CV_8UC3);
    Mat m2 = Mat::zero(Size(256,256),CV_8UC3);
    rectangle(m1,//图像对象
    Rect(100,100,80,80),//位置
    Scalar(255,255,0),//bgr
    -1,     //-1:绘制、2:描边
    LINE_8,
    0);
    rectangle(m2,Rect(150,150,80,80),Scalar(0,255,255),-1,LINE_8,0);
    imshow("m1",m1);
    imshow("m2",m2);

    Mat dst;
    bitwise_and(m1,m2,dst);
    //bitwise_or(m1,m2,dst);//或
    //bitwise_nor(m1,m2,dst);//非
    //dst = ~image;//非
    imshow("像素位操作",dst);
}

通道分离和合并


void channels_demo(Mat &image){

    //通道分离
    std::vector<Mat> mv;
    split(image,mv);
    imshow("蓝色",mv[0]);
    imshow("绿色",mv[1]);
    imshow("红色",mv[2]);

    //通道合并
    Mat dst;
    mv[1] = 0;
    mv[2] = 0;
    merge(mv,dst);
    imshow("蓝色",dst);

    int from_to[] = {0,2,//0通道换到2通道
                    1,1,
                    2,0};
    mixChannels(&image,1,&dst,1,
            from_to,
            3);//3对交换的通道
    imshow("通道混合",dst);
}

图像色彩空间转换

void inrange_demo(Mat &image){
    Mat hsv;
    //转换色彩空间
    cvtColor(image,hsv,COLOR_BGR2HSV);

    //提取
    Mat mask;
    inRange(hsv,Scalar(35,43,46),Scalar(77,255,255),mask);
    //eg1:显示

    Mat redback = Mat::zeros(image.size(),image.type());
    redback = Scalar(40,40,200);
    //取反
    bitwise_not(mask,mask);
    //eg2:显示
    imshow("mask",mask);

    image.copyTo(redback,mask);
    //eg3:roi区域提取
}

图像像素值统计

void pixel_statistic_demo(Mat &iamge){
    int minv,max;
    Point minLoc,maxLoc;
    std::vector<Mat> mv;
    //通道分离
    split(image,mv);
    for (int i = 0; i < mv.size(); ++i) {
        minMaxLoc(mv[i],&minv,&maxv,&minLoc,&maxLoc,Mat());
        std::cout << "No. channels:" 
        << i << "min value" << minv
        << "max value:" << maxv << std::endl;
    }
    Mat mean,stddev;
    Mat redback = Mat::zeros(image.size().image.type());
    meanStdDev(redback,mean,stddev);
    imshow("redback",redback);
    std::cout << "means:" << mean << std::endl;
    std::cout << "stddev:" << stddev << std::endl;
}

算出的方差

判断图像对比度差异大小(方差、对比度成正比)

图像几何形状绘制

//图像几何形状绘制
void drawing_demo(Mat &image){
    Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.width = 250;
    rect.height = 300;
    Mat bg = Mat::zeros(image.size(), image.type());
    //绘制矩形
    rectangle(bg, rect, Scalar(0, 0, 255), -1, 8, 0);
    //绘制圆
    circle(bg, Point(350, 400), 15, Scalar(255, 0, 0), -1, 8, 0);
    //绘制线
    line(bg, Point(100, 100), Point(350, 400), Scalar(0, 255, 0), 4, LINE_AA, 0);
    //绘制椭圆
    RotatedRect rrt;
    rrt.center = Point(200, 200);
    rrt.size = Size(100, 200);
    rrt.angle = 90.0;
    ellipse(bg, rrt, Scalar(0, 255, 255), 2, 8);
    //图像合并
    Mat dst;
    addWeighted(image, 0.7, bg, 0.3, 0, dst);
    imshow("绘制演示", bg);
}

随机数与随机颜色


//eg1:随机数与随机颜色
void random_drawing(Mat &image){

    Mat canvas = Mat::zeros(Size(512,512),image.type());
    int w = canvas.cols;
    int h = canvas.rows;
    //定义随机对象
    RNG rng(12345);
    while(true){
        int c = waitKey(10);
        if(c == 27){//退出
            break;
        }
        //设置随机值
        int x1 = rng.uniform(0,w);
        int y1 = rng.uniform(0,h);
        int x2 = rng.uniform(0,w);
        int y2 = rng.uniform(0,h);
        int b = rng.uniform(0,255);
        int g = rng.uniform(0,255);
        int r = rng.uniform(0,255);

        //绘制线
        line(bg, Point(100, 100), Point(350, 400), Scalar(b, g, r),
         1, LINE_AA, 0);

         ishow("随机绘制演示",canvas);
    }

多边填充与绘制


//多边形填充与绘制
void polyline_drawing_demo(){
    Mat canvas = Mat::zeros(Size(512,512),CV_8UC3);
    Point p1(100,100);
    Point p1()100,100;Point p2(350, 100);
    Point p3(450, 280);
    Point p4(320, 450);
    Point p5(80, 400);
    std::vector<Point> pts;
    pts.push back(p1);
    pts.push back(p2);
    pts.push back(p3);
    pts.push back(p4);
    pts.push back(p5);
    //fillPoly(canvas, pts, Scalar(255, 0, 255), 8, 0);
    //polylines(canvas, pts, true, Scalar(0, 0, 255), 2, LINE AA, 0); 
    std::vector<std::vector<Point>> contours;
    contours.push back(pts);
    drawContours(canvas, contours, -1, Scalar(255, 0, 0), -1);
    imshow("多边形绘制"canvas);
}

鼠标操作与响应



//eg1
Point sp;
Point ep;
Mat temp;
static void on_draws(int event,int x,int y,int flags,void *userdata){
    
    Mat image = *((Mat*)userdata);

    switch(event){
        case EVENT_LBUTTONDOWN:
        {
            sp.x = x;
            sp.y = y;
            std::cout << "start point:" << sp << endl;
        }
        break;
        case EVENT_LBUTTONUP:
        {
            ep.x = x;
            ep.y =  y;
            int dx = ep.x - sp.x;
            int dy = ep.y - sp.y;
            if(dx - 0 && dy > 0){
                Rect box(sp.x,sp.y,dx,dy);
                imshow("roi区域",image(box));
                rectangle(image, box, Scalar(0,0,255),2,8,0);
                imshow("鼠标绘制",image);
                sp.x = -1;
                sp.y = -1;
            }
        }
        break;
        case EVENT_MOUSEMOVE:
        {
            if(sp.x - 0 && sp.y > 0){
                ep.x = x;
                ep.y =  y;
                int dx = ep.x - sp.x;
                int dy = ep.y - sp.y;
                if(dx - 0 && dy > 0){
                    Rect box(sp.x,sp.y,dx,dy);
                    temp.copyTo(image);
                    rectangle(image, box, Scalar(0,0,255),2,8,0);
                    imshow("鼠标绘制",image);
                }
            }
        }
        break;
        default:
        break;
    }  
}

//鼠标操作与响应
void mouse_drawing_demo(Mat &image){
    namedWindow("鼠标绘制",WINDOW_AUTOSIZE);
    //设置鼠标事件回调函数
    setMouseCallback("鼠标绘制",on_draws,(void*)&image);
    imshow("鼠标绘制",image);
    temp = image.clone();
}

图像像素类型转换与归一化

//图像数据归一化
void norm_demo(Mat &image){
    Mat dst;
    std::cout << image.type() << endl;
    //图像像素类型转换
    image.convertTo(image, CV_32F);
    std::cout << image.type() << endl;
    //图像数据归一化
    normalize(image, dst, 1.0, 0, NORM_MINMAX);
    cout << dst.type() << endl;
    imshow("图像数据归一化", dst);
}

图像放缩与插值


//图像的放缩与插值
void resize_demo(Mat &image){
    Mat zoomin,zoomout;
    int h = image.rows;
    int w = image.clos;
    //缩小
    resize(image,zoomout,Size(w/2,h/2),0,0,INTER_LINEAR);
    imshow("zoomout",zoomout);

    //放大
    resize(image,zoomin,Size(w*1.5,h*1.5),0,0,INTER_LINEAR);
    imshow("zoomin", zoomin);
}

图像旋转

eg1:flip


//图像旋转
void flip_demo(Mat &image){
    Mat dst;
    //flip(image,dst,0);//上下旋转
    //flip(image,dst,1);//左右旋转
    flip(image,dst,-1);//180°旋转
    imshow("图像旋转",dst);
}

eg2:warpAffine

void rotate_demo(Mat &image){
    Mat dst,M;
    int w = image.cols;
    int h = image.rows;
    M = getRotationMatrix2D(Point2f(w/2,h/2),45,1.0);
    double cos = abs(M.at<double>(0,0));
    double sin = abs(M.at<double>(0,1));
    int nw = cow*w + sin*h;
    int nh = sin*w + cos*h;
    M.at<double>(0,2) += (nw/2 - w/2);
    M.at<double>(1,2) += (nh/2-h/2);
    warpAffine(image,dst,M,Size(nw,nh),INTER_LINEAR,0,Scalar(255,255,0));
    imshow("旋转演示",dst);
}

视频文件摄像头使用


//视频文件摄像头使用
void video_demo(){

    //打开摄像头:默认摄像头
    VideoCapture capture(0);

    Mat frame;
    while(true){
        //读码摄像头数据
        capture.read(frame);
        
        //旋转Mat图像:1左右旋转
        flip(frame,frame,1);
        if(frame.empty()){
            break;
        }
        imshow("frame",frame);
        //TODO:do something...
        //获取键盘事件
        int c = waitKey(1);
        if(c == 27){//退出
            break;
        }
    }

    //关闭摄像头
    capture.release();
}

视频处理与保存

//视频文件摄像头使用
void video_demo(){

    //打开摄像头:默认摄像头
    VideoCapture capture(0);

    //摄像头的视频属性
    int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);
    int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);
    int frame_count = capture.get(CAP_PROP_FRAME_COUNT);
    double fps = capture.get(CAP_PROP_FPS);

    cout << "frame_width:" << frame_width << endl;
    cout << "frame_height:" << frame_height << endl;
    cout << "frame_count:" << frame_count << endl;
    cout << "fps:" << fps << endl;
    
    //打开VideoWrite
    VideoWrite writer("D:/test.mp4",
                    cpature.get(CAP_PROP_FOURCC),
                    fps,
                    Size(frame_width,frame_height),
                    true);
    Mat frame;
    while(true){
        //读码摄像头数据
        capture.read(frame);
        
        //旋转Mat图像:1左右旋转
        flip(frame,frame,1);
        if(frame.empty()){
            break;
        }
        imshow("frame",frame);
        writer.write(frame);
        //TODO:do something...
        //获取键盘事件
        int c = waitKey(1);
        if(c == 27){//退出
            break;
        }
    }

    //关闭摄像头
    capture.release();
    //关闭视频保存对象
    writer.release();
}

图像直方图

void showHistogram(cv::Mat &src)
{//通道分离
   vector<Mat> bgr_plane;
   split(src,bgr_plane) ;// 定义参数恋量
   const int channels[1] = {0};
   int bins[1] = { 256};
   float hranges[2] = {0,255};
   const float* ranges[1] = { hranges };
   Mat b_hist;
   Mat g_hist;
   Mat r_hist;// 计算Blue,Green,Red通道的直方图
   calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins,ranges);
   calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins,ranges);
   calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
   //显示直方图
   int hist_w = 512;
   int hist_h = 400;
   int bin_w = cvRound((double)hist_w / bins[0]);
   Mat histImage = Mat::zeros (hist_h, hist_w, CV_8UC3);
   // 归一化直方图数据
   normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
   normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
   normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
   // 绘制直方图曲线
   for (int i = 1;i < bins[0]; i++) {
       line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
       line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
       line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
   }
   // 显示直方图
   namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
   imshow("Histogram Demo", histImage);
}

) {
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at(i - 1))),
Point(bin_w*(i), hist_h - cvRound(b_hist.at(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at(i - 1))),
Point(bin_w*(i), hist_h - cvRound(g_hist.at(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at(i - 1))),
Point(bin_w*(i), hist_h - cvRound(r_hist.at(i))), Scalar(0, 0, 255), 2, 8, 0);
}
// 显示直方图
namedWindow(“Histogram Demo”, WINDOW_AUTOSIZE);
imshow(“Histogram Demo”, histImage);
}













  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程目的:OpenCV是应用非常广泛的开源视觉处理库,在图像处理、计算机视觉和自动驾驶中有着非常重要的作用。课程设计特色:(课程当前为第一期)1、C++与Python双语教学Python语言是在计算机视觉中应用最多的一种语言,在工作中,深度学习模型的训练基本上都是使用Python语言编写的训练代码。OpenCV在这个过程中用于图像的预处理(例如图像读取、数据增强)和后处理,还可以用于显示处理的结果,功能强大,使用方便。但是在功能的部署的时候,不管是部署在服务端还是PC端,开发语言基本上用的是C++,所以如何有效的使用OpenCV进行模型或者功能的部署尤为重要。C++语言应用的好坏,在面试中可以看出一个面试者的工程实践能力的强弱,两种语言的开发掌握好了可以使工作如虎添翼。2、全模块讲解我出版了一本图书《学习OpenCV4:基于Python的算法实战》,虽然这本书是写的基于Python的算法实战,但是实际上这本书有详细的介绍算法的C++接口,还有一些C++方向的案例,是以Python为主。图书出版的时候就想双语写作,只是限于篇幅没有成行。本课程不仅采用双语教学,更是对C++的每个模块都做讲解,我们知道,很多的书其实只讲imgproc,如果你翻开一本书图像的形态学运算和图像滤波都是作为独立章节讲解的,那么这本书基本上就可以确定是只是讲解了imgproc模块,但是其他的模块在工作中也有很重要的作用。例如:core模块定义了C++的基本数据结构和基本运算(如四则运算);highgui模块是可视化与交互的模块;feature2d是特征点与特征匹配相关算法所在的模块;ml是机器学习相关的模块;dnn是深度学习相关的模块,可以使用OpenCV进行深度学习模型的部署。这些是很多的书和课程都不会讲的。3、讲解细致本课程会从环境搭建开始讲解,环境搭建尤为重要。从我多年的授课经验总结来看,如果只是给了代码,很多的入门用户环境问题处理不好的话,后面的学习很难进行下去,甚至会丧失学习的信心。4、会讲解C++和Python的开发语法问题是入门用户的一大难关,特别是C++语言。大学只是教授了C语言相关的内容,C++很多同学只懂一点皮毛,所以写代码步履维艰,我们在讲解代码的过程中会顺带讲解C++和Python的内容。我们还会讲解编译相关知识,还有库的装载与链接,这些是学校里不会教的,目前也几乎没有课程讲解。5、讲师经验丰富我讲解过C++和OpenCV的多个课程,广受学员好评。我出版过两本图书《深度学习计算机视觉实战》和《学习OpenCV4》,两本书都是细致入微的讲解,主要针对的就是初学者,所以能够很好的处理课程的难易程度。6、讲义准备充分讲义准备的充分细致,标识清楚明确,重点和疑难点突出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值