Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >常见的图像处理技术

常见的图像处理技术

作者头像
小白学视觉
发布于 2020-08-28 01:18:16
发布于 2020-08-28 01:18:16
2.8K00
代码可运行
举报
运行总次数:0
代码可运行

本期文章中,让我们一起来学习以下内容。

  • 通过PIL和OpenCV来使用一些常见的图像处理技术,例如将RGB图像转换为灰度图像、旋转图像、对图像进行消噪、检测图像中的边缘以及裁剪图像中的感兴趣区域。
  • 使用OpenCV中的模板匹配搜索图像中的对象。

所需安装的库:PIL、OpenCV、imutils

为什么我们需要学习图像处理技术?

深度学习对于图像的分析、识别以及语义理解具有重要意义。“图像分类”、“对象检测”、“实例分割”等是深度学习在图像中的常见应用。为了能够建立更好的训练数据集,我们必须先深入了解基本的图像处理技术,例如图像增强,包括裁剪图像、图像去噪或旋转图像等。其次基本的图像处理技术同样有助于光学字符识别(OCR)。

图像处理技术通过识别关键特征或读取图像中的文本信息,来提高图像的可解释性,以便对图像中存在的对象进行分类或检测。

图片来源于Unsplash
图片来源于Unsplash

此处提供代码和图像

导入所需的库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import cv2
from PIL import Image

首先我们使用OpenCV和PIL显示图像

使用OpenCV读取和显示图像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image = cv2.imread(r'love.jpg')
cv2.imshow("Image", image)
cv2.waitKey(0)

如果图像太大,图像的窗口将不匹配屏幕显示比例。

那么如何在屏幕上显示完整的图像?

默认情况下,显示超大图像时图像都会被裁剪,不能被完整显示出来。为了能够查

看完整图像,我们将使用OpenCV中的namedWindow(name, flag)来创建一个新的显示图像窗口。

第一个参数name是窗口的标题,将被用作标识符。 当您将flag设置为cv2.WINDOW_NORMAL时,将显示完整图像,并可以调整窗口大小。当然flag参数还有选择。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image = cv2.imread(r'love.jpg')
cv2.namedWindow('Normal Window', cv2.WINDOW_NORMAL)
cv2.imshow('Normal Window', image)
cv2.waitKey(0)

调整图像的尺寸

当我们调整图像大小时,我们可以更改图像的高度或宽度,或在保持宽高比不变的情况下同时变化高度和宽度。图片的宽高比是图片的宽度与高度的比。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image= cv2.imread(r'taj.jpg')
scale_percent =200 # percent of original size
width = int(image.shape[1] * scale_percent / 100)
height = int(image.shape[0] * scale_percent / 100)
dim = (width, height)
resized = cv2.resize(image, dim, interpolation = cv2.INTER_AREA)
cv2.imshow("Resize", resized)
cv2.waitKey(0)

使用PIL读取和显示图像

我们将使用open()加载图像,然后使用show()进行显示。

使用image.show()创建一个临时文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pil_image= Image.open(r'love.jpg')
pil_image.show("PIL Image")

如果我们对图像中目标的边缘或其他特征感兴趣,要如何对他们进行识别呢?

灰度图像常常用于识别目标物体的边缘,因为灰度图像不仅助于理解图像中对比度、阴影渐变,而且有助于理解图像特征。

与灰度图像的2D通道相比,RGB图像具有三个通道:红色,绿色和蓝色。与彩色图像相比,灰度图像每个像素的信息更少,因此灰度图像的处理时间将更快。

使用OpenCV对彩色图像进行灰度缩放

以下是使用cvtColor()将彩色图像转换为灰度图像的方法及转换结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image = cv2.imread(r'love.jpg')
gray_image= cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
cv2.namedWindow('Gray Image', cv2.WINDOW_NORMAL)
cv2.imshow('Gray Image', gray_image)
cv2.waitKey(0)
完成转换的灰度图
完成转换的灰度图

使用PIL对彩色图像进行灰度缩放

convert()提供了此图像转换的另一种方式, “ L”模式用于转换为灰度图像,“ RGB”模式用于转换为彩色图像。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pil_image= Image.open(r'love.jpg')
gray_pil=pil_image.convert('L')
gray_pil.show()

使用OpenCV进行边缘检测

我们将使用Canny算子对图像中的边缘进行检测。Canny边缘检测是通过灰度图像,使用高阶算法完成的。

Canny():第一个参数是输入图像,第二个和第三个参数是阈值1阈值2的值。

强度梯度大于threshold2的边缘被视为边缘,低于threshold1的边缘被视为非边缘。非边缘将被删除。两个阈值之间的任何梯度强度值都根据它们的连通性被分类为边缘或非边缘。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image= cv2.imread(r'taj.jpg')
cv2.namedWindow("Edge", cv2.WINDOW_NORMAL)
denoised_image = cv2.Canny(image, 100,200 )
cv2.imshow("Edge", denoised_image)
cv2.waitKey(0)
Canny边缘处理
Canny边缘处理

如果图像发生一定的倾斜或旋转,应该怎样进行调整?

OCR对倾斜文本的提取效果不佳,因此我们需要对原图像进行校正。可以使用OpenCV和PIL中的rotate()对图像进行角度校正。

使用OpenCV旋转图像

rotate()会依据函数中的第二个参数rotationCode的值来旋转图像。

旋转参数值有以下几种:

  • cv2.ROTATE_90_CLOCKWISE
  • cv2. ROTATE_90_COUNTERCLOCKWISE
  • cv2.ROTATE_180
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image = cv2.imread(r'love.jpg')
cv2.namedWindow("Rotated Image", cv2.WINDOW_NORMAL)
rotated_img= cv2.rotate(image,cv2.ROTATE_90_CLOCKWISE )
cv2.imshow("Rotated Image", rotated_img)
cv2.waitKey(0)
使用OpenCV将图像顺时针旋转90度
使用OpenCV将图像顺时针旋转90度

如果我们想将图像旋转特定角度怎么办?

根据特定角度旋转图像

在下面的代码中,图像以60度为增量旋转

使用 imutils中的rotate()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import imutils
import numpy as npimage = cv2.imread(r'love.jpg')# loop over the rotation angles
for angle in np.arange(0, 360, 60):
    cv2.namedWindow("Rotated", cv2.WINDOW_NORMAL)
    rotated = imutils.rotate(image, angle)
    cv2.imshow("Rotated", rotated)
    cv2.waitKey(0)
使用imutils以60度为增量旋转图像
使用imutils以60度为增量旋转图像

使用PIL旋转图像

此处使用PIL将图像旋转110度

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pil_image= Image.open(r'love.jpg')
rotate_img_pil=pil_image.rotate(110)
rotate_img_pil.show()
使用PIL将图像旋转110度
使用PIL将图像旋转110度

当图像因噪声而变差并影响图像分析时,我们应该如何提高图像质量?

使用OpenCV对图像进行除噪

噪声并不是我们想得到的信号,就图像而言,它会使图像受到干扰而失真。

使用OpenCV最小化图像中出现的噪声,首先输入含有噪声的图像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image= cv2.imread(r'taj.jpg')
cv2.namedWindow("Noised Image", cv2.WINDOW_NORMAL)
cv2.imshow("Noised Image", image)
cv2.waitKey(0)

OpenCV有多种方法可以消除图像中的噪点。我们将使用cv.fastNlMeansDenoisingColored(),来消除彩色图像中的噪点。

fastNIMeansDenoising函数的常见参数:

  • src: 源图像
  • dst: 输出与src具有相同大小和类型的图像
  • h: 调节过滤器强度。 较高的h值可以完全消除噪点和图像细节,较小的h值可以保留图像细节以及一些噪点。
  • hForColorComponents: 与h相同,但仅用于彩色图像,通常与h相同
  • templateWindowSize: 默认0(推荐7)
  • searchWindowSize: 默认0(推荐21)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image= cv2.imread(r'taj.jpg')
cv2.namedWindow("Denoised Image", cv2.WINDOW_NORMAL)
denoised_image = cv2.fastNlMeansDenoisingColored(image,None, h=5)
cv2.imshow("Denoised Image", denoised_image)
cv2.waitKey(0)

如何从图像中提取某些感兴趣的区域?

裁剪图像

裁剪图像可让我们提取图像中的兴趣区域。

我们将裁剪泰姬陵的图像,从图像中删除其他细节,使图像仅保留泰姬陵。

使用OpenCV裁剪图像

在OpenCV中裁剪是通过将图像数组切成薄片来进行的,我们先传递y坐标的起点和终点,然后传递x坐标的起点和终点。

image[y_start:y_end, x_start:x_end]

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
image= cv2.imread(r'taj.jpg')
resized_img= image[15:170, 20:200]
cv2.imshow("Resize", resized_img)
cv2.waitKey(0)

使用PIL裁剪图像

PIL的crop()允许我们裁剪图像的矩形区域。crop()的参数是矩形左上角和右下角的像素坐标。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pil_image = Image.open(r'taj.jpg')

# Get the Size of the image in pixels 
width, height = pil_image.size

# Setting the cropped image co-ordinates
left = 3
top = height /25
right = 200
bottom = 3 * height / 4

# Crop the  image based on the above dimension 
cropped_image = pil_image.crop((left, top, right, bottom))

# Shows the image in image viewer 
cropped_image.show()

模板匹配

我们可以提供模板和OpenCV中的matchTemplate()在图像中搜索该模板并提取其位置。

这个模板会像卷积神经网络一样在整个图像上滑动,并尝试将模板与输入图像进行匹配。

minMaxLoc()用于获取最大值/最小值,它是通过矩形的左上角开始沿着宽度和高度获取值。

模板匹配有6种方法:

  • cv2.TM_SQDIFF
  • cv2.TM_SQDI
  • cv2.TM_C
  • cv2.TM_CCORR_NORMED
  • cv2.TM_CCOEFF
  • cv2.TM_CCOEFF_NORMED

在下面的示例中,我们将从主图中裁剪一小部分创建模板。

用于模板匹配的方法是TM_CCOEFF_NORMED。匹配的阈值设置为0.95。当匹配概率大于0.95时,该函数将会在与该匹配相对应的区域周围绘制一个矩形。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread(r'love.jpg',0)cv2.imshow("main",img)
cv2.waitKey(0)template = cv2.imread(r'template1.png',0)
cv2.imshow("Template",template)
cv2.waitKey(0)w, h = template.shape[::-1]
methods = [ 'cv2.TM_CCOEFF_NORMED']for meth in methods:
    
    method = eval(meth)# Apply template Matching
    res = cv2.matchTemplate(img,template,method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    threshold=0.95
    loc=np.where(res>threshold)
    if len(loc[0])>0:# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
        if method in [ cv2.TM_SQDIFF_NORMED]:
            top_left = min_loc
        bottom_right = (top_left[0] + w, top_left[1] + h)cv2.rectangle(img,top_left, bottom_right,100,20)plt.subplot(121),plt.imshow(res,cmap = 'gray')
        plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
        plt.subplot(122),plt.imshow(img,cmap = 'gray')
        plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
        plt.suptitle(meth)plt.show()
    else:
        print("Template not matched")

结论

我们所讨论的最常见图像处理技术可用于分析图像,例如图像分类,目标检测以及OCR。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小白学视觉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
[图像处理] Python+OpenCV实现车牌区域识别
这里原理推荐我以前C++图像处理的文章,如下:https://blog.csdn.net/column/details/eastmount-mfc.html
Ai学习的老章
2019/04/23
4.7K0
[图像处理] Python+OpenCV实现车牌区域识别
【OpenCV图像处理基础与OCR应用】
在现代计算机视觉中,OpenCV是一款非常流行且强大的工具库。它不仅支持基本的图像处理操作,还能与深度学习模型结合应用,解决实际问题。OCR(光学字符识别)是计算机视觉中的一个重要应用领域,广泛用于文档扫描、车牌识别、手写识别等。本文将带你从基础的图像处理开始,逐步了解OCR技术的原理,并结合OpenCV实现简单的OCR预处理流程。
机器学习司猫白
2025/03/09
3350
02: 基本元素-图片
大部分人可能都知道电脑上的彩色图是以RGB(红-绿-蓝,Red-Green-Blue)颜色模式显示的,但OpenCV中彩色图是以B-G-R通道顺序存储的,灰度图只有一个通道。
CodecWang
2021/12/07
3370
02: 基本元素-图片
Opencv第一个程序:显示图片
使用cv2.imread()函数读取图像。第二个参数是一个标识,它用来指定图像的读取方式。
李小白是一只喵
2020/04/23
1.1K0
Opencv第一个程序:显示图片
使用OpenCV调用摄像头,显示图片,获取视频并保存
友情链接:https://blog.csdn.net/u012348774/article/details/78255130
种花家的奋斗兔
2020/11/13
4.3K0
Python数字图像处理-3种图像读取方式总结
学习数字图像处理,第一步就是读取图像。这里我总结下如何使用 opencv3,scikit-image, PIL 图像处理库读取图片并显示。
嵌入式视觉
2022/09/05
1.6K0
Python数字图像处理-3种图像读取方式总结
OpenCV入门教程1-常用函数
工作的原因,最近开始涉及到很多图像处理的工作,所以决定开辟一个新专栏:OpenCV入门教程系列。
皮大大
2024/06/20
4740
快乐学AI系列——计算机视觉(1)图像处理基础
图像处理是计算机视觉领域的一个基础部分,是对图像进行数字化处理的过程。下面是几个图像处理的基础知识点:
MATRIX.矩阵之芯
2023/03/29
9730
快乐学AI系列——计算机视觉(1)图像处理基础
【OpenCV】Chapter1.图像的基本操作
扩展使用: 可以通过cv2.namedWindow和cv2.resizeWindow来指定窗口显示尺寸。
zstar
2022/09/21
1.1K0
6个案例手把手教你用Python和OpenCV进行图像处理
导读:图像是由若干个像素组成的,因此,图像处理可以看作计算机对像素的处理。在面向Python的OpenCV中,可以通过位置索引的方式对图像内的像素进行访问和处理。
IT阅读排行榜
2020/08/28
1.9K0
6个案例手把手教你用Python和OpenCV进行图像处理
基于OpenCV的图像分割处理!
图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。它不仅可以极大的压缩数据量,而且也大大简化了分析和处理步骤,因此在很多情况下,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。
Datawhale
2020/07/09
3.7K0
基于OpenCV的图像分割处理!
[python opencv 计算机视觉零基础到实战] 八、ROI泛洪填充
ROI指的是region of Interest,翻译过来就是你所感兴趣的区域。弱在一张图片中,你感兴趣的是某一个区域,那么这个区域就可以称为ROI。我们通过一些方法选取了该区域后,可以进行操作;例如颜色填充、图像变换等编辑。
1_bit
2021/01/14
7540
[python opencv 计算机视觉零基础到实战] 八、ROI泛洪填充
[Python图像处理] 七.图像阈值化处理及民族服饰实验对比
该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类、目标检测应用。
Eastmount
2021/12/02
6680
[Python图像处理] 七.图像阈值化处理及民族服饰实验对比
Python+OpenCV的图像读取、显示、保存
一、图像的读取 图像的读取主要函数是cv2.imread()。 函数格式:Mat cv::imread (const String & filename, int flags = IMREAD_COLOR) 功能:读取图片文件。 参数: windows位图:后缀名为bmp JPEG文件:后缀名为jpeg/jpg JPEG2000:后缀名为jp2 便携式网络图像文件:后缀名为png TIFF文件:后缀名为tiff/tif 参数二是整型的flag,标志,默认值为IMREAD_COLOR,取值有如下几种: IMREAD_UNCHANGED:如果设置,则按原样返回加载的图像(带有Alpha通道,否则会被裁剪)。 IMREAD_GRAYSCALE:如果设置,总是将图像转换为单通道灰度图像读入。 IMREAD_COLOR:如果设置,总是将图像转换为3通道BGR彩色图像读入。 IMREAD_ANYDEPTH:如果设置,当输入具有相应深度时返回16位/ 32位图像,否则将其转换为8位。 IMREAD_ANYCOLOR:如果设置,图像将以任何可能的颜色格式读取。 IMREAD_LOAD_GDAL:如果设置,总是使用GDAL驱动程序加载图像。 IMREAD_REDUCED_GRAYSCALE_2:如果设置,总是将图像转换为单通道灰度图像,图像尺寸减小1/2。 IMREAD_REDUCED_COLOR_2:如果设置,总是将图像转换为3通道BGR彩色图像,图像尺寸减小1/2。 IMREAD_REDUCED_GRAYSCALE_4:如果设置,总是将图像转换为单通道灰度图像,图像尺寸减小1/4。 IMREAD_REDUCED_COLOR_4:如果设置,总是将图像转换为3通道BGR彩色图像,图像尺寸减小1/4。 IMREAD_REDUCED_GRAYSCALE_8:如果设置,总是将图像转换为单通道灰度图像,图像尺寸减小1/8。 IMREAD_REDUCED_COLOR_8:如果设置,总是将图像转换为3通道BGR彩色图像,图像尺寸减小1/8 常用的是前三种。因为flags是整型,所以传入数值也行: flags >0:等同于IMREAD_COLOR。 flags =0:等同于 IMREAD_GRAYSCALE。 flags <0: 等同于IMREAD_UNCHANGED。 通常是给1、0、-1,给其他整型也是可以的。 返回值:Mat类型。从opencv2开始,用于存放图像的数据类型就是Mat, 二、图像的显示 图像读取后,下一步就是再把图像显示出来,主要函数有:cv2.namedWindows()、cv2.imshow()。再另外再介绍三个函数cv2.waitKey()、cv2.destroyWindow()、cv2.destroyAllWindows()。 2.1 cv2.namedWindows函数介绍 void cv::namedWindow (const String & winname,int flags = WINDOW_AUTOSIZE ) 功能:创建一个窗口。 参数:参数一是winname,给创建的窗口起一个名字,以后通过这个名字调用该窗口;参数二整型的flags,定义窗口的属性,默认值是WINDOW_AUTOSIZE,其他取值如下所示: WINDOW_NORMAL:用户可以调整窗口大小(不受约束)/也可以使用将全屏窗口切换为正常大小。 WINDOW_AUTOSIZE:用户无法调整窗口大小,窗口大小随显示图像的大小而变化。 WINDOW_OPENGL:带有opengl支持的窗口。 WINDOW_FULLSCREEN:将窗口更改为全屏。 WINDOW_FREERATIO:不遵循图像的比例调整图像后在窗口显示 WINDOW_KEEPRATIO:根据图像的比例调整图像后在窗口中显示 2.2 cv2.imshow函数介绍 void cv::imshow (const String & winname, InputArray mat ) 功能:在指定窗口显示图像。 参数:参数一是窗口名;参数二设置为要显示的图像。 注意此函数之后应该跟随函数waitKey,指定窗口显示多少毫秒。 2.3 cv2.waitKey函数介绍 int cv::waitKey (int delay = 0) 功能:等待按键或延迟多少毫秒。 参数:整型的delay,默认值是0。设置为0表示永久等待按键,设置为非零,表示延迟delay毫秒。该函数仅在创建至少一个窗口并且窗口处于活动状态时才起作用。 2.4 cv2.destroyWind
菲宇
2019/11/12
4K0
[Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理
该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~
Eastmount
2021/12/02
3.1K0
[Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理
[python opencv 计算机视觉零基础到实战] 十三 直方图颜色提鲜
图像直方图均衡化主要是对图像中的少数灰度进行压缩,扩展该值的范围,以致于让这个图的对比度调高,使当前图像变得更加清晰。在一张图片中,若整体偏亮,直方图的值应该是在偏右侧,就可能会产生过渡曝光;若一张图像的直方图整体偏暗就会导致直方图呈现数值整体偏左,可能会造成过暗不清晰,所以一张图是否看起来舒服应该在直方图中的布局显示会相对于均衡。
1_bit
2022/01/06
5620
[python opencv 计算机视觉零基础到实战] 十三 直方图颜色提鲜
OpenCV学习笔记(Python)
警告: 就算图像的路径是错的, OpenCV 也不会提醒你的,但是当你使用命 令print img时得到的结果是None。
一点儿也不潇洒
2018/08/07
3.8K0
OpenCV学习笔记(Python)
OpenCV Python 系列教程 4 - OpenCV 图像处理(上)
HSV 的色相范围为 [0,179],饱和度范围为 [0,255],值范围为 [0,255]。不同的软件使用不同的规模。
机器视觉CV
2019/07/15
3.1K0
OpenCV Python 系列教程 4 - OpenCV 图像处理(上)
Opencv 图像处理:图像基础操作与灰度转化
Opencv读取图像是以BGR读取的,但是许多包是RGB读取,因此有些情况下需要转化。
timerring
2022/11/02
2K0
Opencv 图像处理:图像基础操作与灰度转化
[python opencv 计算机视觉零基础到实战] 七、逻辑运算与应用
在上一节中,我们了解了基本的图像运算,这一节将了解在opencv将两张图片进行逻辑运算。逻辑运算在编程中较为常见的一种基本运算,在此不在进行赘述。我们首先了解一下opencv中的逻辑与运算,opencv中逻辑与运算与我们基本的逻辑与运算一致,也就是1 and 1为1,1 and 0 为0。我们可以通过一个小示例来直观的感受opencv的and运算方式。
1_bit
2021/01/14
1.1K0
[python opencv 计算机视觉零基础到实战] 七、逻辑运算与应用
推荐阅读
相关推荐
[图像处理] Python+OpenCV实现车牌区域识别
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验