🏠大家好,我是Yui_💬
🍑如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🚀如有不懂,可以随时向我提问,我会全力讲解~
🔥如果感觉博主的文章还不错的话,希望大家关注、点赞、收藏三连支持一下博主哦~!
🔥你们的支持是我创作的动力!
🧸我相信现在的努力的艰辛,都是为以后的美好最好的见证!
🧸人的心态决定姿态!
💬欢迎讨论:如有疑问或见解,欢迎在评论区留言互动。
👍点赞、收藏与分享:如觉得这篇文章对您有帮助,请点赞、收藏并分享!
🚀分享给更多人:欢迎分享给更多对编程感兴趣的朋友,一起学习!
本文是基于哔哩哔哩OpenCV入门课程的内容加上我个人的理解而来。
本篇文章的主要内容:
阅读本篇文章,你需要具备python的基本语法的学习。如果你并没有学习过python,可以去看我的python专栏:python
本文的内容:图片的读取,RGB彩色通道,区域裁剪,绘制图像1和文字,均值滤波,特征提取,模板匹配,梯度算法,阈值算法,形态学操作,摄像头的读取。
文章目录
- 1. 背景
- 2. 安装OpenCV库
- 3. Hello World示例
- 4.图像的彩色通道
- 5. 图像的裁剪
- 6.绘制功能
- `np.zeros`函数
- `cv2.rectangle`函数
- `cv2.rectangle`函数
- `cv2.circle`函数
- `cv2.putText`函数
- 7. 均值滤波
- `cv2.GaussianBlur`函数
- `cv2.medianBlur`函数
- 8.图像特征提取
- `cv2.goodFeaturesToTrack`函数
- 9. 模板匹配
- `cv2.matchTemplate`函数
- `np.where`函数
- 10. 图像梯度算法
- 10.1 `cv2.Laplacian`函数
- 10.2 `cv2.Canny`函数
- 11.阈值算法
- 11.1 `cv2.threshold`函数
- 11.1.1 `cv2.THRESH_BINARY`
- 11.1.2 `cv2.THRESH_BINARY + cv2.THRESH_OTSU`
- 11.2 `cv2.adaptiveThreshold`函数
- 12. 腐蚀与膨胀
- 12.1 `np.ones`函数
- 12.2 `cv2.erode`函数
- 12.3 `cv2.dilate`函数
- 13.调用摄像头
- 14. 总结
1. 背景
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,最初由英特尔于1999年发布,现已成为计算机视觉领域的一个重要工具。它以C++为核心语言开发,并提供了多种语言的绑定,包括Python、Java、C等,适用于多种操作系统,如Windows、Linux和macOS。
2. 安装OpenCV库
在Windows终端输入:
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
这是用清华的镜像源,下载起来会快很多。
验证是否下载成功:
打开编辑器,查看安装OpenCV的版本
import cv2
print(cv2.__version__)
我的版本是4.10.0
本片文章,将用到四张图片,图中的4张图片。
3. Hello World示例
import cv2
image = cv2.imread("opencv_logo.jpg")
print(image.shape)#打印维度
读取的图片数据会存储在image变量里,且为一个numpy数组类型。
打印结果
(250, 250, 3)
其中,(250,250)分别位图片像素的横行和纵列,最后一个3为,图片的3原色彩色通道。
打开画图板验证:
得到结果确实如此。
下面我们把读取到的图片打印到显示屏当中。
import cv2
image = cv2.imread("opencv_logo.jpg")
print(image.shape)
cv2.imshow("Image", image)
cv2.waitKey()
cv2.imshow('Image',image)
,用于在一个新窗口显示图像,第一个参数是窗口的名称,第二个参数是要显示的图像。
cv2.waitKey()
等待用户输入任意键,确保图像窗口不会立即关闭。
4.图像的彩色通道
在数字图像处理中,彩色图像通常由三个颜色通道组成:红色(Red)、绿色(Green)和蓝色(Blue),这三个通道也被称为RGB通道。每个通道代表图像在该颜色上的强度分布。
在OpenCV中,图像是以BGR格式存储的,而不是常见的RGB格式。这意味着第一个通道是蓝色,第二个通道是绿色,第三个通道是红色。
对于OpenCV来说,存储一张彩色图片等同于存储3张灰度图片,它们被存储在OpenCV图像数据的第3个维度上,灰度范围是0-255
。当显示器需要渲染一张图片时,计算机会依次取出图像数据中的3张灰度图在把它们分别投影到显示器的蓝色、绿色和红色的led芯片上。
下面开始让显示屏上显示这3张灰度图以及原图:
import cv2
# 读取图像
image = cv2.imread("opencv_logo.jpg")
# 显示原始图像和各个通道
cv2.imshow("Original Image", image)
cv2.imshow("Blue Channel", image[:, :, 0])
cv2.imshow("Green Channel", image[:, :, 1])
cv2.imshow("Red Channel", image[:, :, 2])
# 等待按键,然后关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
OpenCV同时还提供一种彩色图像的灰度变换算法,可以把3个彩色通道的图像做平方和加权平均。
import cv2
# 读取图像
image = cv2.imread("opencv_logo.jpg")
# 显示原始图像和各个通道
cv2.imshow("Blue Channel", image[:, :, 0])
cv2.imshow("Green Channel", image[:, :, 1])
cv2.imshow("Red Channel", image[:, :, 2])
#显示灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray", gray)
# 等待按键,然后关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到gray是BGR3原色的平均,而且它也描述了图案的明暗分布,在计算机视觉邻域我们通常把这个变换后的图像gray
称为称为灰度图。
大量的图像算法都是基于灰度图来操作的
5. 图像的裁剪
import cv2
image = cv2.imread("opencv_logo.jpg")
crop = image[10:170,40:200]
cv2.imshow("Crop", crop)
cv2.waitKey(0)
运行代码
可以看到,部分代码被提取出来了。
下面我将打开,Windows中的画图来进行讲解:
对于OpenCV索引的顺序是先横行后纵列
也就是说:索引10:170
对应的是第10横行到第170横行,对应的40:200
就是第40纵列到第200纵列。这个索引顺序可能与某些图像处理工具是不同的,比如加州理工大学基于MATLAB
的图像处理包为相反顺序。
6.绘制功能
本次代码需要引入numpy
工具包,实际上opencv的图像数据是numpy数组数据结构。
import cv2
import numpy as np
image = np.zeros([300,300,3],dtype=np.uint8)#利用numpy创建一个黑色画布
cv2.line(image,(100,200),(250,250),(255,0,0),2)
cv2.rectangle(image,(30,100),(60,150),(0,255,0),2)
cv2.circle(image,(150,100),20,(0,0,255),3)
cv2.putText(image,"Hello World",(100,50),0,1,(255,255,255),2,1)
cv2.imshow("Image",image)
cv2.waitKey(0)
下面我会开始介绍代码中出现的函数。
np.zeros
函数
np.zeros([300,300,3],dtype=np.uint8)
创建一个300*300像素的黑色画布,并初始化所有像素值为0(也就是黑色)。
np.zeros
:NumPy库中的一个函数,用于创建一个指定形状和数据类型的全零数组。[300,300,3]
:这是数组的形状。这里表示一个300x300像素的图像,每个像素有3个通道(BGR颜色通道)。dtype=np.uint8
:指定数组的数据类型为无符号8位整数(unsigned 8-bit integer),这是图像处理中常用的数据类型,因为每个像素的BGR值通常在0到255之间。
cv2.rectangle
函数
cv2.rectangle(image,(30,100),(60,150),(0,255,0),2)
cv2.line
是 OpenCV 库中的一个函数,用于在图像上绘制一条直线。
image
:要在其上绘制直线的图像。(100, 200)
:直线的起点坐标。(250, 250)
:直线的终点坐标。(255, 0, 0)
:直线的颜色,这里是蓝色。2
:直线的粗细。
cv2.rectangle
函数
cv2.rectangle(image,(30,100),(60,150),(0,255,0),2)
cv2.rectangle
是 OpenCV 库中的一个函数,用于在图像上绘制一个矩形
image
:要在其上绘制矩形的图像。(30, 100)
:矩形左上角的坐标。(60, 150)
:矩形右下角的坐标。(0, 255, 0)
:矩形的颜色,这里是绿色。2
:矩形边框的粗细。
cv2.circle
函数
cv2.circle
是 OpenCV 库中的一个函数,用于在图像上绘制一个圆形。
cv2.circle(image,(150,100),20,(0,0,255),3)
image
:要在其上绘制圆形的图像。(150, 100)
:圆心的坐标。20
:圆的半径。(0, 0, 255)
:圆的颜色,这里是红色。3
:圆边框的粗细。
cv2.putText
函数
cv2.putText
是 OpenCV 库中的一个函数,用于在图像上绘制文本。
cv2.putText(image,"Hello World",(100,50),0,1,(255,255,255),2,1)
image
:要在其上绘制文本的图像。"Hello World"
:要绘制的文本内容。(100, 50)
:文本左下角的坐标。cv2.FONT_HERSHEY_SIMPLEX
:字体类型。1
:字体比例因子。(255, 255, 255)
:文本的颜色,这里是白色。2
:文本线条的粗细。cv2.LINE_AA
:文本线条的类型,抗锯齿线。
7. 均值滤波
本次代码会使用的到飞机素材。
该图片是一张噪点十分多的图片,下面我会用滤波器对其进行处理。
import cv2
image = cv2.imread('plane.jpg')
gauss = cv2.GaussianBlur(image, (5, 5), 0)#高斯滤波
median = cv2.medianBlur(image, 5)#均值滤波
cv2.imshow('Original', image)
cv2.imshow('Gaussian Blur', gauss)
cv2.imshow('Median Blur', median)
cv2.waitKey(0)
可以看到无论是高斯滤波器还是均值滤波器都使得图片的噪点噪点减少,不过也破坏了些图像细节。
实际的处理中,我们很难遇到噪点这么严重的图片,更多情况下,我们会遇到干净背景中的少数几个噪点,使用均值滤波把它消除。
cv2.GaussianBlur
函数
cv2.GaussianBlur
是 OpenCV 库中的一个函数,用于对图像应用高斯模糊。
cv2.GaussianBlur(image, (5, 5), 0)
image
:输入图像。(5, 5)
:高斯核的大小,表示核的宽度和高度均为 5。0
:高斯核在 X 方向上的标准差,设为0
表示自动计算。
cv2.medianBlur
函数
cv2.medianBlur
是 OpenCV 库中的一个函数,用于对图像应用中值滤波(Median Blur)。中值滤波是一种非线性滤波方法,它通过将每个像素的值替换为其邻域内像素值的中值来工作。这种方法对于去除椒盐噪声(salt-and-pepper noise)特别有效。
cv2.medianBlur(image, 5)
image
:输入图像。5
:滤波器的大小,表示邻域的大小为 5×55×5。
8.图像特征提取
import cv2
image = cv2.imread('opencv_logo.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray, 500, 0.1, 10)
for corner in corners:
x,y = corner.ravel()#是 NumPy 数组的一个方法,用于将多维数组展平成一维数组。
cv2.circle(image,(int(x),int(y)),3,(255,0,255),-1)
cv2.imshow('Corners', image)
cv2.waitKey(0)
我们看到识别出来的特征都是图案的转角,转交是最简单的图像特征,提取转角的算法都是非常高效的。
cv2.goodFeaturesToTrack
函数
cv2.goodFeaturesToTrack(gray, 500, 0.1, 10)
gray
:需要检测角点的灰度图像。500
:最大角点数,即函数最多会返回500个角点。0.1
:质量等级,表示角点的最小可接受质量。该值越小,检测到的角点越多,但质量可能较低。10
:最小距离,表示检测到的任意两个角点之间的最小像素距离。该值越大,检测到的角点越分散。
函数返回一个包含检测到的角点的数组,每个角点由其坐标(x, y)表示。
9. 模板匹配
模板匹配我们会用到扑克那张图片,来匹配扑克中的菱形。
import cv2
import numpy as np
image = cv2.imread("poker.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
template = gray[75:105, 235:265] #该区域刚好包含一个菱形
match = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
locations = np.where(match >= 0.9)#找出匹配系数大于0.9的匹配点
w, h = template.shape[0:2] #求出模板的长和宽,方便后续标记图片。
for p in zip(*locations[::-1]):
x1, y1 = p[0], p[1]
x2, y2 = x1 + w, y1 + h
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imshow("image", image)
cv2.waitKey()
我们这里使用的匹配算法是大小敏感的,如果想要把图片中的菱形都匹配出来,可以放到缩小图像多次来匹配。
cv2.matchTemplate
函数
cv2.matchTemplate
函数在提供的代码中用于在灰度图像gray
中查找与模板template
最匹配的区域.
- cv2.matchTemplate函数会在输入图像(gray)中滑动模板(template)
- 并计算每个位置与模板的匹配程度,返回一个匹配程度的矩阵
- cv2.TM_CCOEFF_NORMED是一种匹配方法,它通过归一化相关系数来衡量匹配程度
np.where
函数
np.where(match >= 0.9)
是 NumPy 库中的一个函数调用,用于根据条件 match >= 0.9
查找数组 match
中满足条件的元素的索引
match
:这是一个二维数组,由cv2.matchTemplate
函数返回,表示输入图像中每个位置与模板的匹配程度。match >= 0.9
:这是一个布尔数组,表示match
中每个元素是否大于等于 0.9。np.where(match >= 0.9)
:这个函数调用返回一个元组,包含两个数组,分别表示满足条件的元素的行索引和列索引。
10. 图像梯度算法
我们前面学的特征点提取与图像匹配这些算法的背后都使用的图像梯度。
图像梯度就是图像的明暗变化,比如我们可以分别计算沿水平和垂直方向的明暗变化,再其这俩个变化的平方和就得到了梯度,它和地理上的梯度是一样的,只不过地面的高低起伏变成了图像的明暗变化。
import cv2
gray = cv2.imread("opencv_logo.jpg", cv2.IMREAD_GRAYSCALE)
laplacian = cv2.Laplacian(gray, cv2.CV_64F)#拉普拉斯算子
canny = cv2.Canny(gray, 100, 200)
cv2.imshow("gray", gray)
cv2.imshow("laplacian", laplacian)
cv2.imshow("canny", canny)
cv2.waitKey()
拉普拉斯算子给出了图像明暗变化的趋势,比如均一的背景区域变成了黑色,有明暗变化的部分,比如边缘就变成了白色,我们知道一个几何图形的变化往往有剧烈的明暗变化,所以梯度算法也常常用于检测边缘。
conny
边缘检测,在conny
算法中我们使用一个梯度区间来定义边缘,比如梯度区间100到200,如果某个像素的梯度大于200,那么可以确定它是一个边缘,因为它周围的明暗变化足够强烈。反过来,如果梯度小于100,那么可以确定它不是一个边缘,因为他周围没有明暗变化,如果梯度在100到200之间,那么就要看这个像素是否和已知的边缘像素相连,如果和某个已知的边缘像素连载一起,那么我们判定它是边缘,否则不是。
这个过程有点像扫雷,先确定一些显而易见的像素,剩下的像素由确定好的像素来辅助判断。
![[Pasted image 20250127213341.png]]
10.1 cv2.Laplacian
函数
Laplacian 算子是图像处理中的一种二阶微分算子,用于检测图像中的边缘。 它通过计算图像灰度值的二阶导数来确定边缘的位置。 在 OpenCV 中,cv2.Laplacian 函数用于计算图像的 Laplacian 变换。
Laplacian 算子的工作原理是:
- 计算图像中每个像素点的二阶导数。
- 二阶导数的正值表示图像在该点的亮度从暗到亮的变化,负值表示从亮到暗的变化。
- 边缘通常发生在二阶导数的绝对值较大的地方。
cv2.Laplacian(gray, cv2.CV_64F)
- gray: 输入的灰度图像。
- cv2.CV_64F: 指定输出图像的深度,这里是 64 位浮点型。
10.2 cv2.Canny
函数
cv2.Canny
是 OpenCV 中用于边缘检测的函数,它实现了 Canny 边缘检测算法。Canny 边缘检测是一种多阶段的算法,旨在检测图像中的边缘,并尽量减少噪声和虚假边缘的数量。
Canny 边缘检测算法通常包括以下步骤:
- 高斯滤波:首先,图像通过高斯滤波器进行平滑处理,以减少噪声。
- 梯度计算:然后,计算图像的梯度强度和方向,通常使用 Sobel 算子。
- 非极大值抑制:在梯度方向上进行非极大值抑制,以细化边缘。
- 双阈值检测:使用两个阈值(低阈值和高阈值)来确定哪些边缘是强边缘,哪些是弱边缘。
- 边缘跟踪:通过连接强边缘和与其相连的弱边缘来形成最终的边缘图。
cv2.Canny(gray, 100, 200)
gray
:输入的灰度图像。Canny 算法通常在灰度图像上执行,因为彩色图像中的颜色信息对于边缘检测不是必需的,并且可能会引入额外的复杂性。100
:这是 Canny 算子的低阈值。低于此阈值的边缘将被忽略。200
:这是 Canny 算子的高阈值。高于此阈值的边缘将被视为强边缘,并且可能会触发与其相连的弱边缘的检测。
11.阈值算法
阈值算法也叫二值化算法,它把灰度图像分为黑与白。
阈值的阈是门槛的意思,通俗的讲,门槛下面是黑色,门槛上面是白色,我们常说世界是复杂的,充满灰色地带,但是在阈值算法的观点中,世界是简单的,非黑即白。
import cv2
gray = cv2.imread("bookpage.jpg", cv2.IMREAD_GRAYSCALE)
ret, binary = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
binary_adaptive = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)
ret1, binary_otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow("gray", gray)
cv2.imshow("binary", binary)
cv2.imshow("adaptive", binary_adaptive)
cv2.imshow("otsu", binary_otsu)
cv2.waitKey()
11.1 cv2.threshold
函数
cv2.threshold
是 OpenCV 中用于图像二值化的函数。它将输入图像转换为二值图像,根据指定的阈值将像素分为两类:前景和背景。
工作原理
- 固定阈值:
cv2.threshold
使用一个固定的阈值来分割图像。在这个例子中,阈值被设置为10。 - 二值化:所有灰度值大于10的像素将被设置为255(白色),而所有灰度值小于或等于10的像素将被设置为0(黑色)。
11.1.1 cv2.THRESH_BINARY
cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
gray
:输入的灰度图像。10
:这是阈值。所有大于这个值的像素将被设置为最大值(通常是255),而所有小于或等于这个值的像素将被设置为0。255
:这是最大值,用于设置前景像素的值。cv2.THRESH_BINARY
:这是阈值类型。在这种情况下,它表示如果像素值大于阈值,则将其设置为最大值,否则设置为0。
11.1.2 cv2.THRESH_BINARY + cv2.THRESH_OTSU
Otsu 方法(也称为大津法)是一种自动确定图像二值化阈值的算法。它适用于双峰图像(即图像的直方图有两个峰值),并且能够有效地处理光照不均匀的情况。Otsu 方法通过最大化类间方差来选择最佳阈值,从而将图像分为前景和背景两部分。
gray
:输入的灰度图像。0
:这里的阈值参数设置为0,意味着不使用固定阈值,而是让算法自动计算阈值。255
:这是最大值,用于设置前景像素的值。cv2.THRESH_BINARY + cv2.THRESH_OTSU
:这是阈值类型。cv2.THRESH_BINARY
表示二值化类型,而cv2.THRESH_OTSU
是一个标志位,表示使用 Otsu 方法来自动计算阈值。
11.2 cv2.adaptiveThreshold
函数
cv2.adaptiveThreshold
是 OpenCV 中的一个函数,用于根据图像的小区域计算阈值,以实现自适应的二值化。这种方法特别适合于光照不均匀的图像,因为它会在不同的局部区域内分别计算阈值。
工作原理
- 局部阈值计算:对于图像中的每个像素,函数会考虑其周围的一个小区域(由邻域大小决定),并计算该区域的加权平均值(或加权中值)。
- 二值化:然后,将这个局部阈值与像素的实际值进行比较。如果像素值大于局部阈值减去常数 C,则将该像素设置为最大值,否则设置为0。
cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)
gray
:输入的灰度图像。255
:这是用于设置前景像素的最大值。cv2.ADAPTIVE_THRESH_GAUSSIAN_C
:这是自适应方法。ADAPTIVE_THRESH_GAUSSIAN_C
表示阈值是邻域像素的加权和,权重为一个高斯窗口。cv2.THRESH_BINARY
:这是阈值类型。THRESH_BINARY
表示如果计算的局部阈值大于像素值,则将该像素设置为0(黑色),否则设置为最大值(白色)。115
:这是邻域大小,用于计算局部阈值的窗口大小。它必须是奇数,例如 11x11 或 15x15 的区域。1
:这是常数 C,从计算的局部均值或加权均值中减去。这个常数可以用来微调阈值。
12. 腐蚀与膨胀
import cv2
import numpy as np
gray = cv2.imread("opencv_logo.jpg", cv2.IMREAD_GRAYSCALE)
_, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(binary, kernel)
dilation = cv2.dilate(binary, kernel)
cv2.imshow("binary", binary)
cv2.imshow("erosion", erosion)
cv2.imshow("dilation", dilation)
cv2.waitKey()
cv2.THRESH_BINARY_INV
:这是阈值类型。THRESH_BINARY_INV
表示反向二值化,即如果像素值大于阈值,则将其设置为0(黑色),否则设置为最大值(白色)。
12.1 np.ones
函数
np.ones()
是 NumPy 库中的一个函数调用,用于创建一个指定形状和数据类型的数组,其中所有元素都初始化为1。
参数说明
- 形状参数
(5, 5)
:
- 这个参数定义了数组的维度。在这个例子中,
(5, 5)
表示创建一个二维数组,具有5行5列。
- 数据类型参数
np.uint8
:
- 这个参数指定了数组中元素的数据类型。
np.uint8
是无符号8位整型,其取值范围是0到255。 - 使用
np.uint8
数据类型可以节省内存,并且在处理图像时非常常见,因为大多数图像格式使用8位像素值。
返回值
函数返回一个二维数组,所有元素都被初始化为1,且数据类型为np.uint8
。
12.2 cv2.erode
函数
cv2.erode
是 OpenCV 库中的一个函数,用于对图像进行腐蚀操作。腐蚀操作是一种形态学操作,它可以消除图像中的小物体、在纤细点分离物体、平滑较大物体的边界同时并不明显改变其面积。
12.3 cv2.dilate
函数
cv2.dilate
是 OpenCV 库中的一个函数,用于对图像进行膨胀操作。膨胀操作是一种形态学操作,它可以扩大图像中的物体、填补物体内部的空洞、平滑物体的边界同时可能会增加其面积。
13.调用摄像头
import cv2 # 导入OpenCV库
# 创建VideoCapture对象,参数0表示默认摄像头
capture = cv2.VideoCapture(0)
# 开始一个无限循环,用于持续捕获视频帧
while True:
ret, frame = capture.read() # 读取摄像头的一帧
if not ret: # 如果读取失败,跳出循环
break
cv2.imshow("camera", frame) # 显示捕获到的帧
key = cv2.waitKey(1) # 等待用户按键,参数1表示等待1毫秒
if key != -1: # 如果用户按下了键,跳出循环
break
capture.release() # 释放摄像头资源
cv2.destroyAllWindows() # 关闭所有OpenCV窗口
14. 总结
OpenCV是一个集轻量、高效、开源与一身的被使用最广泛的计算机视觉工具,非常值得程序员的学习。