Machine Learning——CV系列(一)——Python+OpenCV核心操作(4)

15 篇文章 0 订阅
13 篇文章 3 订阅

五、图像金字塔

5.1 高斯金字塔(低通)

高斯金字塔有两种形式:上采样和下采样。上采样是图片逐渐变大的过程;下采样是图片逐渐变小的过程。两种方式都会使图片越来越模糊。

import cv2

img = cv2.imread(r"13.jpg")
for i in range(3):
    cv2.imshow(f"img{i}",img)
    # img = cv2.pyrDown(img)# 12.jpg
    img = cv2.pyrUp(img)# 13.jpg

cv2.waitKey(0)

上采样
在这里插入图片描述
下采样
在这里插入图片描述

5.2 拉普拉斯金字塔(高通)

拉普拉斯金字塔需要用到高斯金字塔,公式如下:在这里插入图片描述
在这里插入图片描述
高频信号=原图-经过高斯模糊的下采样的上采样(高频信号被删除)

import cv2

img = cv2.imread(r"12.jpg")# 获得一张原图=>图0
img_down = cv2.pyrDown(img)# 首先用高斯下采样一次=>图1
img_up = cv2.pyrUp(img_down) # 然后将图1用高斯上采样一次=>图2
img_new = cv2.subtract(img, img_up)# 最后用原图0-图2得到结果
#为了更容易看清楚,做了个提高对比度的操作
img_new = cv2.convertScaleAbs(img_new, alpha=5, beta=0)
cv2.imshow("img_LP", img_new)
cv2.waitKey(0)

在这里插入图片描述

5.3 图像金字塔用途

可以将两种图片以一种良好过渡的感觉拼接起来。
应用:AI换脸。用到了金字塔。
无缝融合。

六、模板匹配

6.1 无缝融合(苹果与橘子融合的项目)

过程:
在这里插入图片描述

import cv2
import numpy as np

A = cv2.imread('21.jpg')
B = cv2.imread('22.jpg')

# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpA[i])
    L = cv2.subtract(gpA[i - 1], GE)
    lpA.append(L)



# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpB[i])
    L = cv2.subtract(gpB[i - 1], GE)
    lpB.append(L)

# Now add left and right halves of images in each level
LS = []
for i, (la, lb) in enumerate(zip(lpA, lpB)):
    rows, cols, dpt = la.shape
    ls = np.hstack((la[:, 0:cols // 2], lb[:, cols // 2:]))
    LS.append(ls)

# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
    ls_ = cv2.pyrUp(ls_)
    ls_ = cv2.add(ls_, LS[i])
    # cv2.imshow(f"xxx{i}", ls_)

# image with direct connecting each half
real = np.hstack((A[:, :cols // 2], B[:, cols // 2:]))

cv2.imshow('Pyramid_blending.jpg', ls_)
cv2.imshow('Direct_blending.jpg', real)

cv2.waitKey(0)

在这里插入图片描述

七、图像直方图

直方图:衡量一张图片像素的分布规律。
意义:对图像进行"矫正"。

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('1.jpg')
# img[...,0]=0
# img[...,1]=0
cv2.imshow("...",img)

img_B = cv2.calcHist([img], [0], None, [256], [0, 256])
r'''
img是原图,channels是某一个通道,histSize是直方图有多少个区间,ranges是区间开始和结束
上面四个值都需要[]括起来,变成一个list。(本例histSize和ranges为[256], [0, 256])
mask是一个大小和image一样的np数组,其中把需要处理的部分指定为1,不需要处理的部分指定为0,
一般设置为None,表示处理整幅图像
'''
plt.plot(img_B, label='B', color='b')

img_G = cv2.calcHist([img], [1], None, [256], [0, 256])
plt.plot(img_G, label='G', color='g')
#
img_R = cv2.calcHist([img], [2], None, [256], [0, 256])
plt.plot(img_R, label='R', color='r')

plt.show()

在这里插入图片描述

7.1 直方图均衡化

可以通过方法让像素分布更加"分散"。对"整个图片"均衡。(去模糊

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('7.jpg', 0)
cv2.imshow("src", img)

his = cv2.calcHist([img], [0], None, [255], [0, 255])
plt.plot(his, label='his', color='r')
# plt.show()

dst = cv2.equalizeHist(img)
cv2.imshow("dst", dst)

cv2.imwrite("15.jpg", dst)

his = cv2.calcHist([dst], [0], None, [255], [0, 255])
plt.plot(his, label='his', color='b')
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.2 自适应均衡化

上面是对整个图片均衡,更好的方法是类似卷积一样,逐步逐步的均衡。

import cv2

img = cv2.imread('8.jpg', 0)
cv2.imshow("src", img)

dst1 = cv2.equalizeHist(img)# 可以通过调整像素分布修改图像效果
cv2.imshow("dst1", dst1)

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
r'''
clipLimit:颜色对比度的阈值
titleGridSize:进行像素均衡化的网格大小[类比卷积核]
'''
dst2 = clahe.apply(img)# 进行自适应直方图均衡化
cv2.imshow("dst2", dst2)

cv2.waitKey(0)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.3 2D直方图

在上面"直方图均衡化"中,我们是把彩色图片转换为灰度图片,可以看做是"1D直方图"。而2D直方图是取彩色图片两个通道来作为横纵坐标进行展示,很明显RGB模式并不适合,而HSV空间就比较合适了(颜色是连续的)。我们主要分析H、S通道,明度就先抛弃了。

7.4 直方图反向投影

反向投影(Back Projection):是直方图运算的逆过程。直方图运算是统计每个灰度值对应的像素个数,而反向投影则是将像素个数回送到该像素个数对应灰度区间的像素位置。

用一个简单例子来解释反向投影,假设有这么一个4×4的灰度图像:
在这里插入图片描述
将灰度分为四个区间[0-2]=1;[3-5]=2;[6-7]=3;[8-10]=4,可以统计到灰度图像在这四个区间上的灰度直方图为[4,4,6,2],就是cv2.calcHist()的结果。然后我们将这个直方图的区间上的结果[4,4,6,2]对应到图中[0-2];[3-5];[6-7];[8-10]上,即img[0,0]=1,1属于[0-2]区间,1就替换成4…以此类推,这就是直方图反投影,其本质是把直方图的结果"映射"到图像上形成一个"图像掩码"的东西,可以去提取对应特征值。
在这里插入图片描述

7.4.1 反向投影能做什么

前面讲过,反向投影是基于直方图的逆运算,而直方图则反应了图像的色彩(亮度)特征,当两幅相似的图像仅发生位置的变化而色彩(光线)几乎不变时,对应的两幅直方图相似度会很高。但直方图只是得到了特征,反向投影则是将特征"反应"到图像上,对于物体特征识别和分割有着很大的作用。

进行反向投影的一般步骤:

  • 获取直方图的源,比如我们要对手进行反向投影,那么直方图的源就是肤色的ROI
  • 获取需要反向投影的图像
  • 计算直方图,通常是在HSV模型中计算,毕竟反向投影的一大工作就是区分颜色
  • 反向投影
  • 显示
import cv2
import numpy as np

roi = cv2.imread('10.jpg')# 这是在原图截取部分的图片
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
target = cv2.imread('9.jpg')# 这是原图
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)# 转成hsv颜色空间

roihist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])## 2D直方图操作

cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX)
'''
归一化:
src=roihist:原始图像
dst=roihist:结果图像
alpha,beta=0,255:映射到结果图像中的最小值和最大值
norm_type=归一化的类型,可以取以下值:
-----------------------------------------------------------------------------------
cv2.NORM_MINMAX :数组的数值缩放到一个指定的范围,线性归一化,一般较常用
cv2.NORM_INF    :归一化数组的C-范数(绝对值的最大值)
cv2.NORM_L1     :归一化数组的L1-范数(绝对值的和)
cv2.NORM_L2     :归一化数组的(欧几里德)L2-范数
-----------------------------------------------------------------------------------
本例用的是cv2.NORM_MINMAX:归一化类型,对数组的所有值进行转化,使他们线性映射到最小值和最大值之间。归一化后数字就到[0,255]之间了,便于直方图显示。
'''
dst = cv2.calcBackProject([hsvt], [0, 1], roihist, [0, 180, 0, 256], 1)
r'''
images:输入的图像集合,需要有相同的尺寸和深度,其中深度需为CV_8U、CV_16U或CV_32F
channels:要统计哪个通道的像素,彩色图像的话就有3个通道
hist:反向投影的计算源:直方图
ranges:统计量的取值范围,注意不是纵轴的取值范围,而是横轴的取值范围比如统计量是像素,那么通常就是像素值的取值范围
scale:缩放系数,默认值为1
---------------------------------------------------------------------------
返回的是一个二值化的图,即所有类似roi的部分都变成255了,其它地方都是0(黑色)
'''
# 然后再去进行其它操作...
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
dst = cv2.filter2D(dst, -1, disc)

ret, thresh = cv2.threshold(dst, 50, 255, 0)

thresh = cv2.merge((thresh, thresh, thresh))

res = cv2.bitwise_and(target, thresh)
res = np.hstack((target, thresh, res))

cv2.imshow('img', res)
cv2.waitKey(0)

在这里插入图片描述

八、霍夫变换

图像处理中,霍夫变换用来检测任意能够用数学公式表达的形状,即使这个形状被破坏或者有点扭曲

霍夫变换是将xy坐标系转换到类似极坐标的坐标系:模长ρ和角度θ,可以用来检测"任意能用数学公式表达的形状"。在图上取多个点,将其投影到霍夫变换中,这多个点如果有公共交集,就找到了该形状的极坐标参数(即得到了模长和角度)。然后再转换为xy坐标系的一组点即轮廓。霍夫变换经常用于检测圆形和直线。

流程:

①轮廓算法检测出轮廓
②投射到Hough空间进行形状检测

原理:

(opencv里是用参数方程代替空间坐标系,ρ/θ)

空间坐标系的线对应霍夫坐标系的点
空间坐标系的点对应霍夫坐标系的线
如果空间坐标系有几点共线,在霍夫坐标系就有同一个交点
在这里插入图片描述

8.1 直线检测

import cv2
import numpy as np

image = cv2.imread("27.jpg")# 得到需要检测的原图

image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 得到灰度图像

edges = cv2.Canny(image_gray, 100, 150)# Canny描出轮廓

lines = cv2.HoughLines(edges, 1, np.pi / 180, 100)
r'''
这是找出图中的直线。关键参数四个: image, rho, theta, threshold
------------------------------------------------------------------------------
image=edges,这是传入的二值图
rho=1,指ρ的精确度(最小步长为1像素)
theta=π/180,指θ的精确度(最小角度为π/180)
threshold=300,是个经验值,指可以被认为是一个线条的最小计数值。
由于计数值的多少取决于线上的点数,所以这代表了可以被识别为线的最小长度。
------------------------------------------------------------------------------
函数输出的是(float,float)形式的ndarray,打印结果其shape应该是(N,1,2),N代表直线条数,
1代表一个直线对象(ρ,θ),2表示检测到的线(ρ,θ)中浮点值的参数。
'''
for line in lines:# 这里是循环所有找到的直线
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    # 上面四步是将极坐标转回到xy坐标系
    x1 = int(x0 + 1000 * (-b))  # 直线起点横坐标
    y1 = int(y0 + 1000 * (a))  # 直线起点纵坐标
    x2 = int(x0 - 1000 * (-b))  # 直线终点横坐标
    y2 = int(y0 - 1000 * (a))  # 直线终点纵坐标
    cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)## 描点划线

cv2.imshow("image_lines", image)# 展示结果
cv2.waitKey(0)

在这里插入图片描述

8.2 圆检测

import cv2
import numpy as np

image = cv2.imread("29.jpg")
dst = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)
circle = cv2.HoughCircles(dst, cv2.HOUGH_GRADIENT, 1, 80, param1=40, param2=20, minRadius=20, maxRadius=300)
r'''
这是在找图片中的圆,参数如下:
------------------------------------------------------------------------------
edges是灰度的轮廓,
method:使用检测方法。目前,唯一实现的方法是 CV_HOUGH_GRADIENT。
dp:累加器分辨率与图像分辨率的反比。
    如果 dp = 1,则累加器具有与输入图像相同的分辨率;
    如果 dp = 2,则累加器的宽度和高度都是一半。
minDist:检测到的圆的中心之间的最小距离。如果参数太小,除了真正的参数外,
	    可能会错误地检测到多个邻居圈;如果太大,可能会错过一些圈子。
param1:第一个方法特定的参数。在CV_HOUGH_GRADIENT表示传入Canny边缘检测的阈值
param2:第二种方法参数。在CV_HOUGH_GRADIENT的情况下,它是检测阶段的圆心的累加器阈值。
	   越小,可能会检测到越多的虚假圈子。首先返回对应于较大累加器值的圈子。
minRadius:最小圆半径。
maxRadius:最大圆半径。
返回的shape应该是(1,N,3):第一个不知道干啥的,第二个N表示找到的圆的个数,
第三个是返回每个圆的参数,分别为(x,y,半径)所以是3。
------------------------------------------------------------------------------
'''
if not circle is None:# 循环所有找到的圆
    circle = np.uint16(np.around(circle))
    for i in circle[0, :]:# 画圆
        cv2.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)

cv2.imshow("circle", image)# 展示结果
cv2.waitKey(0)

在这里插入图片描述

九、分水岭算法

分水岭算法是一种经典且实用的 切割算法
分水岭算法中有一个核心思想:距离变换。

9.1 距离变换

距离变换是指把某点到某个特定区域,一般是二值化图的黑色部分,因为黑色=0,可以代表背景。然后我们定义某一个图像,或者某一个不为零的像素,其到背景0的最短距离的数值替换成像素值,那么整个图片中,越远离背景的地方就越"亮",越靠近背景的地方就越"黑"。再配合一个阈值操作,就可以找到每一个需要切割的图像的中心点了,因为中心点肯定是最亮的。

但是如果要计算最短距离,就得算出所有距离然后取min,这样计算量十分庞大。科学家想出了用腐蚀的方法来计算距离:从图形边缘开始腐蚀,每腐蚀一次,被腐蚀的点的距离就是"+1",直到把整个图形腐蚀掉,这样一遍操作,里面所有的点的距离都得到了。

我个人观点:距离变换的思想和上面图像直方图中直方图反向投影是类似的,反向投影是把该像素在整体像素分布中所占的"权重"代替原像素值;而距离变换是把该像素在黑色背景中的"海拔高度"来代替原像素值。用不同的角度去寻找图像的特征,这应该是我们可以学习的一种全新思路。

9.2 分水岭算法原理

**分水岭算法,顾名思义,就是用"水"来分割"山岭"。这里的山就是距离变换后的二值化图,水就是用来切割并标记的工具。**我简单说一下我的理解:首先背景是黑色的,高度为0,不同的边缘有不同的高度。然后开始灌水,一开始水都是在最底层,互相独立不连通,随着水高度越来越高,有些低洼的地方就被漫过,水就汇合了,每汇合一次,就在那个地方标一个"-1",这样直到淹没整个图,所有的轮廓都被标注出来了。由于一开始背景黑色就是0,所以只要找出小于0的就是轮廓了。

import numpy as np
import cv2

img = cv2.imread('30.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
# 上面3步是得到二值化后的图片thresh
# noise removal
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 上面2步是对二值化图片进行开操作,为了去除周边背景的噪点
# sure background area
sure_bg = cv2.dilate(opening, kernel, iterations=3) # 膨胀操作,突出背景
# sure_bg = opening

dist_transform = cv2.distanceTransform(opening, 1, 5)
r'''
这一步叫距离变换,配合下面阈值操作,可以得到每个切割图像的大致中心点位置,
相当于进行了先验处理。
参数:
-----------------------------------------------------------------------
src=opening   :传入的二值图
distance_type :计算距离的公式,参看"轮廓"中=>3-4:凸包和凸性检测中cv2.fitLine()下的解释
mask_size     :尺寸。就是cv2.erode(img, kernel)中kernel的大小
     cv2.DIST_MASK_3 = 3
     cv2.DIST_MASK_5 = 5
     cv2.DIST_MASK_PRECISE = 0
-----------------------------------------------------------------------
'''
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)

# Marker labelling
ret, markers1 = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers1 + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0

markers3 = cv2.watershed(img, markers)# 这就是分水岭算法
img[markers3 == -1] = [0, 0, 255]

cv2.imshow("img", img)
cv2.waitKey(0)

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenCV 3 is a state-of-the-art computer vision library that allows a great variety of image and video processing operations. Some of the more spectacular and futuristic features such as face recognition or object tracking are easily achievable with OpenCV 3. Learning the basic concepts behind computer vision algorithms, models, and OpenCV’s API will enable the development of all sorts of real-world applications, including security and surveillance. Starting with basic image processing operations, the book will take you through to advanced computer vision concepts. Computer vision is a rapidly evolving science whose applications in the real world are exploding, so this book will appeal to computer vision novices as well as experts of the subject wanting to learn the brand new OpenCV 3.0.0. You will build a theoretical foundation of image processing and video analysis, and progress to the concepts of classification through machine learning, acquiring the technical know-how that will allow you to create and use object detectors and classifiers, and even track objects in movies or video camera feeds. Finally, the journey will end in the world of artificial neural networks, along with the development of a hand-written digits recognition application. What You Will Learn Install and familiarize yourself with OpenCV 3’s Python API Grasp the basics of image processing and video analysis Identify and recognize objects in images and videos Detect and recognize faces using OpenCV Train and use your own object classifiers Learn about machine learning concepts in a computer vision context Work with artificial neural networks using OpenCV Develop your own computer vision real-life application
OpenCV(Open Source Computer Vision Library)是一款开源的计算机视觉库,专门为图像和视频处理任务设计,广泛应用于学术研究、工业应用以及个人项目中。以下是关于OpenCV的详细介绍: 历史与发展 起源:OpenCV于1999年由英特尔公司发起,旨在促进计算机视觉技术的普及和商业化应用。该项目旨在创建一个易于使用、高效且跨平台的库,为开发者提供实现计算机视觉算法所需的基础工具。 社区与支持:随着时间的推移,OpenCV吸引了全球众多开发者和研究人员的参与,形成了活跃的社区。目前,OpenCV由非盈利组织OpenCV.org维护,并得到了全球开发者、研究机构以及企业的持续贡献和支持。 主要特点 跨平台:OpenCV支持多种操作系统,包括但不限于Windows、Linux、macOS、Android和iOS,确保代码能够在不同平台上无缝运行。 丰富的功能:库中包含了数千个优化过的函数,涵盖了计算机视觉领域的诸多方面,如图像处理(滤波、形态学操作、色彩空间转换等)、特征检测与描述(如SIFT、SURF、ORB等)、物体识别与检测(如Haar级联分类器、HOG、DNN等)、视频分析、相机校正、立体视觉、机器学习(SVM、KNN、决策树等)、深度学习(基于TensorFlow、PyTorch后端的模型加载与部署)等。 高效性能:OpenCV代码经过高度优化,能够利用多核CPU、GPU以及特定硬件加速(如Intel IPP、OpenCL等),实现高速图像处理和实时计算机视觉应用。 多语言支持:尽管OpenCV主要使用C++编写,但它提供了丰富的API绑定,支持包括C、Python、Java、MATLAB、JavaScript等多种编程语言,方便不同领域的开发者使用。 开源与免费:OpenCV遵循BSD开源许可证发布,用户可以免费下载、使用、修改和分发库及其源代码,无需担心版权问题。 架构与核心模块 OpenCV的架构围绕核心模块构建,这些模块提供了不同层次的功能: Core:包含基本的数据结构(如cv::Mat用于图像存储和操作)、基本的图像和矩阵操作、数学函数、文件I/O等底层功能。 ImgProc:提供图像预处理、滤波、几何变换、形态学操作、直方图计算、轮廓发现与分析等图像处理功能。 HighGui:提供图形用户界面(GUI)支持,如图像和视频的显示、用户交互(如鼠标事件处理)以及简单的窗口管理。 VideoIO:负责视频的读写操作,支持多种视频格式和捕获设备。 Objdetect:包含预训练的对象检测模型(如Haar级联分类器用于人脸检测)。 Features2D:提供特征点检测(如SIFT、ORB)与描述符计算、特征匹配与对应关系估计等功能。 Calib3d:用于相机标定、立体视觉、多视图几何等问题。 ML:包含传统机器学习算法,如支持向量机(SVM)、K近邻(KNN)、决策树等。 DNN:深度神经网络模块,支持导入和运行预训练的深度学习模型,如卷积神经网络(CNN)。 应用领域 OpenCV广泛应用于: 科研与教育:作为计算机视觉教学和研究的基础工具,OpenCV简化了算法原型开发与验证过程。 工业自动化:在视觉检测、机器人导航、产品质量控制等工业场景中,OpenCV用于实时图像分析与决策。 安防监控:用于人脸识别、行人检测、行为分析等智能监控系统。 医疗影像分析:在医疗领域,OpenCV可用于医学图像处理、病灶检测、诊断辅助等应用。 自动驾驶:在车辆视觉感知系统中,OpenCV用于道路标志识别、障碍物检测、车道线识别等任务。 多媒体应用:如图像编辑软件、AR/VR应用、游戏开发等,利用OpenCV进行图像和视频处理。 物联网与嵌入式系统:在资源受限的嵌入式设备上,OpenCV提供轻量级的计算机视觉解决方案。 学习与社区资源 OpenCV拥有丰富的官方文档、教程、示例代码以及活跃的开发者社区,包括GitHub、StackOverflow、官方论坛等,为学习和使用OpenCV提供了有力支持。此外,有许多书籍、在线课程、博客文章和研讨会专门讲解OpenCV的使用和计算机视觉技术。 综上所述,OpenCV作为一款功能强大、高效、跨平台且开源的计算机视觉库,为开发者提供了实现各类图像和视频处理任务所需的工具箱,其广泛的应用领域和活跃的社区支持使之成为计算机视觉领域不可或缺的开发工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wa1tzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值