Opencv中Kmeans使用学习,更换证件照背景,QT界面,函数实现,C++实现

本文介绍了机器学习中的kmeans聚类算法,给出其可视化学习链接。重点展示了在opencv中用python实现照片底色更改的代码及运行结果,还提供了qt可视化的更改代码。此外,给出了c++实现方法,其效果与python一致,最后总结了涉及的知识和编写要点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

kmeans简介

kmeans是机器学习中的一种聚类算法,简单来说就是把在一个区域中的点进行分类,分类的类别由自己定。具体的数学原理大家可以在很多的blog中学习,在这里主要介绍opencv中python的实现。在这里给大家一个非常直观的链接https://www.naftaliharris.com/blog/visualizing-k-means-clustering/大家可以访问该网址。里面由DBSCAN,kmeans等算法的可视化显示,下面给出一定的截图
在这里插入图片描述通过这个可视化模型,大家可以非常好的学习kmeans和DBSCAN两种聚类算法

python代码实现

#__aditor:dwy
#__date: 2019/5/29
#!/usr/bin/env python    
# -*- coding: utf-8 -*-
import cv2 as cv
import numpy as np
img = cv.imread("tx.png")

#准备数据
color=[0,0,255]
wide = img.shape[1]
height = img.shape[0]
dims =img.shape[2]
sampleCount = wide*height
clusterCount = 4
points = np.zeros([sampleCount,dims],np.float32)#把准备好的数据存储到points中
centers = np.zeros([clusterCount,1],np.float32)
index = 0
for i in range(height):
	for j in range(wide):
		index = i*wide+j
		for n in range(dims):
			points[index][n]=img[i][j][n]
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 0.1)
ret,label,center=cv.kmeans(points,clusterCount,None,criteria,10,cv.KMEANS_PP_CENTERS)#聚类的结果在ret中,标签为label ,中心为center
mask = np.zeros((img.shape[0],img.shape[1]),np.uint8)#创建一个掩模,如果是背景则为黑,不为背景则为255
index = wide*2+4#把第二行的第四个数据作为背景的标记(通常这个区域一般为背景,也可以设置某类包含点最多的为背景)
img2=img.copy()
cindex = label[index]#创建掩模的过程
for i in range(height):
	for j in range(wide):
		index = i * wide + j
		label1 = label[index]
		if cindex==label1:
			for n in range(dims):
				img2[i][j][n]=0;
			mask[i][j]=0;
		else:
			mask[i][j]=255
structuting = cv.getStructuringElement(cv.MORPH_RECT,(11,11))#对图像进行开操作和膨胀处理
mask=cv.erode(mask,structuting)
mask=cv.GaussianBlur(mask,(9,9),0,0)#下面的循环是按照掩模复制图像,如果为0则设置成要替换的背景,如果不为0则把原图中的像素填充进去,clolr为预定的颜色
for i in range(height):
	for j in range(wide):
		if mask[i][j]==0:
			for n in range(dims):
				img2[i][j][n]=color[n]
		else:
			continue
cv.imshow("mask",img2)
cv.imshow("img",img)

cv.waitKey(0)

下面是代码运行的结果
在这里插入图片描述左边是更换前的代码,右边是更换后的代码。
为了更好的使用该方法,本文提供qt可视化的更改代码

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'D:\My code\Python\PYQT\Background\background.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralWidget = QtWidgets.QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.gridLayout_4 = QtWidgets.QGridLayout(self.centralWidget)
        self.gridLayout_4.setObjectName("gridLayout_4")
        self.widget_2 = QtWidgets.QWidget(self.centralWidget)
        self.widget_2.setObjectName("widget_2")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.widget_2)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.label_2 = QtWidgets.QLabel(self.widget_2)
        self.label_2.setObjectName("label_2")
        self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1)
        self.label_4 = QtWidgets.QLabel(self.widget_2)
        self.label_4.setObjectName("label_4")
        self.gridLayout_2.addWidget(self.label_4, 0, 1, 1, 1)
        self.before = QtWidgets.QLabel(self.widget_2)
        self.before.setText("")
        self.before.setObjectName("before")
        self.gridLayout_2.addWidget(self.before, 1, 0, 1, 1)
        self.after = QtWidgets.QLabel(self.widget_2)
        self.after.setText("")
        self.after.setObjectName("after")
        self.gridLayout_2.addWidget(self.after, 1, 1, 1, 1)
        self.gridLayout_2.setRowStretch(0, 1)
        self.gridLayout_2.setRowStretch(1, 9)
        self.gridLayout_4.addWidget(self.widget_2, 0, 0, 1, 1)
        self.widget_3 = QtWidgets.QWidget(self.centralWidget)
        self.widget_3.setObjectName("widget_3")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_3)
        self.horizontalLayout.setObjectName("horizontalLayout")
        spacerItem = QtWidgets.QSpacerItem(148, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.widget = QtWidgets.QWidget(self.widget_3)
        self.widget.setObjectName("widget")
        self.gridLayout = QtWidgets.QGridLayout(self.widget)
        self.gridLayout.setObjectName("gridLayout")
        self.loadImage = QtWidgets.QPushButton(self.widget)
        self.loadImage.setObjectName("loadImage")
        self.gridLayout.addWidget(self.loadImage, 0, 0, 1, 1)
        self.colorchoose = QtWidgets.QComboBox(self.widget)
        self.colorchoose.setObjectName("colorchoose")
        self.colorchoose.addItem("")
        self.colorchoose.addItem("")
        self.colorchoose.addItem("")
        self.colorchoose.addItem("")
        self.colorchoose.addItem("")
        self.colorchoose.addItem("")
        self.colorchoose.addItem("")
        self.gridLayout.addWidget(self.colorchoose, 0, 1, 1, 1)
        self.change = QtWidgets.QPushButton(self.widget)
        self.change.setObjectName("change")
        self.gridLayout.addWidget(self.change, 0, 2, 1, 1)
        self.pushButton_2 = QtWidgets.QPushButton(self.widget)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)
        self.pushButton_4 = QtWidgets.QPushButton(self.widget)
        self.pushButton_4.setObjectName("pushButton_4")
        self.gridLayout.addWidget(self.pushButton_4, 1, 1, 1, 1)
        self.pushButton_5 = QtWidgets.QPushButton(self.widget)
        self.pushButton_5.setObjectName("pushButton_5")
        self.gridLayout.addWidget(self.pushButton_5, 1, 2, 1, 1)
        self.horizontalLayout.addWidget(self.widget)
        self.groupBox = QtWidgets.QGroupBox(self.widget_3)
        self.groupBox.setObjectName("groupBox")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.label_5 = QtWidgets.QLabel(self.groupBox)
        self.label_5.setObjectName("label_5")
        self.gridLayout_3.addWidget(self.label_5, 0, 0, 1, 1)
        self.red = QtWidgets.QLineEdit(self.groupBox)
        self.red.setText("")
        self.red.setObjectName("red")
        self.gridLayout_3.addWidget(self.red, 0, 1, 1, 1)
        self.label_7 = QtWidgets.QLabel(self.groupBox)
        self.label_7.setObjectName("label_7")
        self.gridLayout_3.addWidget(self.label_7, 1, 0, 1, 1)
        self.green = QtWidgets.QLineEdit(self.groupBox)
        self.green.setText("")
        self.green.setObjectName("green")
        self.gridLayout_3.addWidget(self.green, 1, 1, 1, 1)
        self.label_6 = QtWidgets.QLabel(self.groupBox)
        self.label_6.setObjectName("label_6")
        self.gridLayout_3.addWidget(self.label_6, 2, 0, 1, 1)
        self.blue = QtWidgets.QLineEdit(self.groupBox)
        self.blue.setText("")
        self.blue.setObjectName("blue")
        self.gridLayout_3.addWidget(self.blue, 2, 1, 1, 1)
        self.gridLayout_3.setColumnStretch(0, 1)
        self.gridLayout_3.setColumnStretch(1, 2)
        self.horizontalLayout.addWidget(self.groupBox)
        spacerItem1 = QtWidgets.QSpacerItem(148, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)
        self.gridLayout_4.addWidget(self.widget_3, 1, 0, 1, 1)
        self.textBrowser = QtWidgets.QTextBrowser(self.centralWidget)
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(12)
        self.textBrowser.setFont(font)
        self.textBrowser.setObjectName("textBrowser")
        self.gridLayout_4.addWidget(self.textBrowser, 2, 0, 1, 1)
        self.gridLayout_4.setRowStretch(0, 3)
        self.gridLayout_4.setRowStretch(1, 1)
        self.gridLayout_4.setRowStretch(2, 1)
        MainWindow.setCentralWidget(self.centralWidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label_2.setText(_translate("MainWindow", "处理前图像"))
        self.label_4.setText(_translate("MainWindow", "处理后图像"))
        self.loadImage.setText(_translate("MainWindow", "导入图片"))
        self.colorchoose.setItemText(0, _translate("MainWindow", "蓝色"))
        self.colorchoose.setItemText(1, _translate("MainWindow", "白色"))
        self.colorchoose.setItemText(2, _translate("MainWindow", "红色"))
        self.colorchoose.setItemText(3, _translate("MainWindow", "灰色"))
        self.colorchoose.setItemText(4, _translate("MainWindow", "紫色"))
        self.colorchoose.setItemText(5, _translate("MainWindow", "黄色"))
        self.colorchoose.setItemText(6, _translate("MainWindow", "绿色"))
        self.change.setText(_translate("MainWindow", "确认更改"))
        self.pushButton_2.setText(_translate("MainWindow", "待添加功能"))
        self.pushButton_4.setText(_translate("MainWindow", "待添加功能"))
        self.pushButton_5.setText(_translate("MainWindow", "待添加功能"))
        self.groupBox.setTitle(_translate("MainWindow", "RGB通道"))
        self.label_5.setText(_translate("MainWindow", "    R"))
        self.label_7.setText(_translate("MainWindow", "    G"))
        self.label_6.setText(_translate("MainWindow", "    B"))
        self.textBrowser.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'宋体\'; font-size:12pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'SimSun\';\">以后还有什么图像处理相关的内容可以在此基础上扩展,RGB通道可以更改到任意背景颜色</span></p></body></html>"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())


界面布局代码部分文件命名为Ui_background.py为后一个文件导入方便

# -*- coding: utf-8 -*-

"""
Module implementing MainWindow.
"""

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from Ui_background import Ui_MainWindow   #如果此处的ui文件命名不同请改命名
import cv2 as cv
import numpy as np
import os


class MainWindow(QMainWindow, Ui_MainWindow):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.color = [0, 0, 0]
        self.target =True 
        self.i=0
        self.newname =''
        self.file_name=""
        self.file_type =""
    
    @pyqtSlot()
    def on_loadImage_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        
        self.file_name, self.file_type = QFileDialog.getOpenFileName(self,"打开文件","D:/","All Files (*);")

        ##"open file Dialog "为文件对话框的标题,第三个是打开的默认路径,第四个是文件类型过滤器
        img = cv.imread(self.file_name, -1)


        if (img.shape[2] == 3):#bgr到rgb转换的显示
            qimg = cv.cvtColor(img, cv.COLOR_BGR2RGB)
            qimg = QImage(qimg.data, qimg.shape[1], qimg.shape[0], qimg.shape[1]*qimg.shape[2],QImage.Format_RGB888)
            self.before.setPixmap(QPixmap.fromImage(qimg))
        else:
            qimg = QImage(img.data, img.shape[1], img.shape[0],QImage.Format_Grayscale8)
            self.before.setPixmap(QPixmap.fromImage(qimg))
    
        

    
    @pyqtSlot(str)
    def on_colorchoose_currentIndexChanged(self, p0):
        """
        Slot documentation goes here.
        
        @param p0 DESCRIPTION
        @type str
        """
        # TODO: not implemented yet
        current = self.colorchoose.currentText()
        if self.target:
            if current=="红色":
                self.color =[0, 0, 255]
                self.newname= '_red'
            elif current=="白色":
                self.color =[255, 255, 255]
                self.newname= '_white'
            elif current=="蓝色":
                self.color =[255, 0, 0]
                self.newname= '_blue'
            elif current=="绿色":
                self.color =[0, 255, 0]
                self.newname= '_green'
            elif current=="黄色":
                self.color=[0, 255, 255]
                self.newname= '_yellow'
            elif current=="紫色":
                self.color=[255, 0, 255]
                self.newname= '_violet'
            elif current=="灰色":
                self.color=[96, 96, 96]
                self.newname= '_gray'
    
    @pyqtSlot()
    def on_change_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        if self.red.text()!="":
            self.red1 =int(self.red.text())
            self.green1 =int(self.green.text())
            self.blue1 =int(self.blue.text())
            self.color = [self.blue1, self.green1,self.red1]
            self.newname='_define'
            print(self.color)
            self.target = False
        img =cv.imread(self.file_name, -1)

        if (img is None):
            print(1)
            self.textBrowser.setText("打开图片失败,请重新加载")
        else:
            # 准备数据
            wide = img.shape[1]
            height = img.shape[0]
            dims = img.shape[2]
            sampleCount = wide * height
            clusterCount = 4
            points = np.zeros([sampleCount, dims], np.float32)
            centers = np.zeros([clusterCount, 1], np.float32)
            index = 0
            for i in range(height):
                for j in range(wide):
                    index = i * wide + j
                    for n in range(dims):
                        points[index][n] = img[i][j][n]
            criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 0.1)
            ret, label, center = cv.kmeans(points, clusterCount, None, criteria, 10, cv.KMEANS_PP_CENTERS)
            mask = np.zeros((img.shape[0], img.shape[1]), np.uint8)
            index = wide * 2 + 4
            img2 = img.copy()
            cindex = label[index]
            for i in range(height):
                for j in range(wide):
                    index = i * wide + j
                    label1 = label[index]
                    if cindex == label1:
                        for n in range(dims):
                            img2[i][j][n] = 0;
                        mask[i][j] = 0;
                    else:
                        mask[i][j] = 255
            structuting = cv.getStructuringElement(cv.MORPH_RECT, (13, 13))
            mask =cv.dilate(mask,structuting)
            mask = cv.erode(mask, structuting)
            structuting2 = cv.getStructuringElement(cv.MORPH_RECT, (9, 9))
            mask = cv.erode(mask, structuting2)
            cv.waitKey(10)
            mask = cv.GaussianBlur(mask, (9, 9), 0, 0)
            for i in range(height):
                for j in range(wide):
                    if mask[i][j] == 0:
                        for n in range(dims):
                            img2[i][j][n] =  self.color[n]
                    else:
                        continue
            img2 = cv.GaussianBlur(img2, (3, 3), 0, 0)
            if (img2.shape[2] == 3):
                qimg = cv.cvtColor(img2, cv.COLOR_BGR2RGB)
                qimg = QImage(qimg.data, qimg.shape[1], qimg.shape[0], qimg.shape[1] * qimg.shape[2],
                              QImage.Format_RGB888)
                self.after.setPixmap(QPixmap.fromImage(qimg))
            else:
                qimg = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_Grayscale8)
                self.after.setPixmap(QPixmap.fromImage(qimg))
            (fathername, filename) = os.path.split(self.file_name)#读取文件的父目录,文件名
            (name, type) = os.path.splitext(filename)#分开文件名后缀名
            name=fathername+"/"+name+self.newname+type
            print(name)
            cv.imwrite(name,img2)
            write = "the image has been saved in:"+name
            self.textBrowser.setText(write)

        
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ui = MainWindow()
    ui.show()
    sys.exit(app.exec_())
    

实现部分
最后的实现效果如下图
在这里插入图片描述只需要更改下拉框的参数便可以实现底色的改变。如果有需要的也可以用pyinstall 去打包py文件成可以执行的exe文件。
如果需要打包好的文件可以在下方留言,看到的话可以发给你

c++实现

int kmeans_picture()
{
	Mat src = imread("tx.png");
	Mat img2 = src.clone();
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("input image", WINDOW_AUTOSIZE);
	imshow("input image", src);

	Scalar colorTab[] = {
		Scalar(0, 0, 255),
		Scalar(0, 255, 0),
		Scalar(255, 0, 0),
		Scalar(0, 255, 255),
		Scalar(255, 0, 255)
	};
	int width = src.cols;
	int height = src.rows;
	int dims = src.channels();//获取图像的要素
    // 初始化定义,准备数据阶段,把数据展开成width *height行的数据
	int sampleCount = width*height;
	int clusterCount = 4;//分类的组别
	Mat points(sampleCount, dims, CV_32F, Scalar(10));//重新生成分类的数组
	Mat labels;
	Mat centers(clusterCount, 1, points.type());

	// RGB 数据转换到样本数据
	//int index = 0;
	//for (int row = 0; row < height; row++) {
	//	for (int col = 0; col < width; col++) {
	//		index = row*width + col;
	//		Vec3b bgr = src.at<Vec3b>(row, col);
	//		points.at<float>(index, 0) = static_cast<int>(bgr[0]);
	//		points.at<float>(index, 1) = static_cast<int>(bgr[1]);
	//		points.at<float>(index, 2) = static_cast<int>(bgr[2]);
	//	}
	//}
	//指针索引方法
	int index = 0;
	for (int row = 0; row < height; row++)
	{
		
		for (int col = 0; col < width; col++)
		{
			index = row*width + col;
			uchar *p = src.ptr<uchar>(row,col);
			points.at<float>(index, 0) = static_cast<int>(p[0]);
			points.at<float>(index, 1) = static_cast<int>(p[1]);
			points.at<float>(index, 2) = static_cast<int>(p[2]);
		}
	}

	// 运行K-Means
	TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
	kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);

	Mat mask = Mat::zeros(src.size(), CV_8UC1);
	index = src.rows * 2 + 2;
	int cindex = labels.at<int>(index, 0);//背景设置为0
	height = src.rows;
	width = src.cols;

	for (int row = 0;row<height;row++)
	{
		for (int col = 0;col<width;col++)
		{
			index = row*width + col;
			int label = labels.at<int>(index, 0);
			if (label == cindex)
			{
				img2.at<Vec3b>(row, col)[0] = 0;
				img2.at<Vec3b>(row, col)[1] = 0;
				img2.at<Vec3b>(row, col)[2] = 0;
				mask.at<uchar>(row, col) = 0;
			}
			else
			{
				mask.at<uchar>(row, col) = 255;
			}
		}
	}

	//腐蚀
	Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
	erode(mask, mask, k);
	imshow("win4", mask);

	//高斯模糊
	GaussianBlur(mask, mask, Size(3, 3), 0, 0);
	imshow("win5", mask);

	//通道混合
	RNG rng(12345);
	Vec3b color;
	color[0] = rng.uniform(0, 255);
	color[1] = rng.uniform(0, 255);
	color[2] = rng.uniform(0, 255);
	Mat result(src.size(), src.type());

	double d1 = 0.0;
	int r = 0, g = 0, b = 0;
	int r1 = 0, g1 = 0, b1 = 0;
	int r2 = 0, g2 = 0, b2 = 0;


	for (int row = 0; row < height;row++)
	{
		for (int col = 0;col<width;col++)
		{
			int m = mask.at<uchar>(row, col);
			if (m == 255)
			{
				result.at<Vec3b>(row, col) = src.at<Vec3b>(row, col);//前景
			}
			else if (m == 0)
			{
				result.at<Vec3b>(row, col) = color;//背景
			}
			else
			{
				d1 = m / 255.0;
				b1 = src.at<Vec3b>(row, col)[0];
				g1 = src.at<Vec3b>(row, col)[1];
				r1 =src.at<Vec3b>(row, col)[2];

				b2 = color[0];
				g2 = color[1];
				r2 = color[2];

				b = b1*d1 + b2*(1.0 - d1);
				g = g1*d1 + g2*(1.0 - d1);
				r = r1*d1 + r2*(1.0 - d1);

				result.at<Vec3b>(row, col)[0] = b;
				result.at<Vec3b>(row, col)[1] = g;
				result.at<Vec3b>(row, col)[2] = r;
			}
		}
	}

	//输出
	imshow("win2", mask);
	imshow("win3", img2);
	imshow("win6", result);
	//保存处理后的图片
	waitKey(0);
	imwrite("result-2.jpg", result);
	}

效果和python的结果是一致的

小结

1本节主要用kmeans实现了照片底色的更改,主要涉及到了python的一些基础知识和opencv的使用
2.本节给出了python和c++两种方法的使用,也给出了基于界面的编写。大家可以参考一下如何在qt的lable控件中显示图片

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值