案例6
import cv2
image = cv2.imread("opencv_logo.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
"""
边缘检测:边缘检测主要是寻找图像中灰度值变化明显的区域,通常用于提取图像的结构或轮廓,如常见的 Canny 边缘检测,它主要关注图像中灰度变化的边界部分。
角点检测:角点检测:角点检测则侧重于图像中局部区域的 角点,即像素强度变化较为剧烈的点,通常是图像中结构的关键部分,比如图像中的 交点、拐角 等
作用:是用于角点检测的函数。它检测并返回图像中最明显的角点。参数解释如下:
cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, mask=None, blockSize=3, useHarrisDetector=False, k=0.04)
image:输入图像,必须是灰度图像(单通道图像)。如果输入的是彩色图像,需要先转换为灰度图。
qualityLevel:最大角点数目,表示你希望检测到的最多角点数目。
qualityLevel:角点的质量阈值,用于筛选角点的质量。该值决定了什么样的角点可以被认为是“优质的”。
该值介于 0 到 1 之间,较高的值会限制返回的角点数量,只选择质量更高的角点。常见的选择值为 0.01 到 0.1。
minDistance:角点之间的最小距离。这个参数指定了相邻角点之间的最小距离,防止检测到太接近的角点。
如果设置为 10,表示每个角点之间至少要有 10 个像素的距离。这个值与图像的分辨率和需要检测的角点数量密切相关。
"""
corners = cv2.goodFeaturesToTrack(gray, 500, 0.1, 10)
# 通过 for 循环遍历检测到的每一个角点
for corner in corners:
# corner.ravel() 将角点坐标(一个二维数组)展平为一维数组,并分别赋值给 x 和 y。
x, y = corner.ravel()
cv2.circle(image, (int(x), int(y)), 3, (255, 0, 255), -1)
cv2.imshow("corners", image)
cv2.waitKey()
案例7
import cv2
import numpy as np
image = cv2.imread("poker.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 提取模板区域
template = gray[75:105, 235:265]
"""
作用:使用 OpenCV 进行 模板匹配,它的作用是通过与图像中的某个模板区域进行比较,找到模板在图像中的位置,并绘制出一个矩形框标识出该区域。
cv2.matchTemplate(image, templ, method)
image: 通常是原始的彩色图像或灰度图像,模板匹配会在图像上滑动模板来寻找匹配区域。
templ: 即你要在输入图像中查找的子图像。模板图像的尺寸通常比输入图像要小。
method: 用于指定计算模板匹配的算法。
cv2.TM_CCOEFF: 相关系数法,通过计算模板和图像区域之间的相关系数来评估匹配程度,值越大表示越相似。
cv2.TM_CCOEFF_NORMED: 归一化相关系数法,与 cv2.TM_CCOEFF 类似,但归一化处理了结果,范围通常在 -1 到 1 之间。
cv2.TM_CCORR: 相关法,计算图像区域与模板的相关性,值越大表示越相似。
cv2.TM_CCORR_NORMED: 归一化相关法,与 cv2.TM_CCORR 类似,但归一化处理了相关结果。
cv2.TM_SQDIFF: 平方差法,计算模板和图像区域之间的平方差,值越小表示越相似。
cv2.TM_SQDIFF_NORMED: 归一化平方差法,与 cv2.TM_SQDIFF 类似,但归一化处理了平方差。
返回值:
是一个与输入图像大小相同的矩阵,每个元素表示模板与该位置区域的匹配度。匹配度越高,表示模板与该位置越相似。
"""
match = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
print(match)
# where 相当于 ? : 返回 match 数组中所有匹配度大于等于 0.9 的位置的索引
locations = np.where(match >= 0.9)
print(locations)
# 绘制矩形框标记匹配区域
w, h = template.shape[0:2]
"""
[::-1] 是一种 切片操作,用于对数组进行反转。在这里,locations[::-1] 的作用是反转 locations 元组中数组的顺序:
11111111 (array([235, 235, 235, 235, 235, 236, 235, 236, 235, 236, 235, 236, 59,
60, 118, 59, 60, 118, 118, 60, 60, 117, 118, 117, 118, 61,
60, 61, 118, 118], dtype=int64), array([ 74, 75, 76, 137, 138, 138, 139, 139, 200, 200, 201, 201, 288,
288, 288, 289, 289, 289, 290, 348, 349, 349, 349, 350, 350, 407,
408, 408, 408, 409], dtype=int64))
"""
print("11111111" , locations[::-1])
"""
在 Python 中,* 是 解包运算符,它可以将一个可迭代对象解包成多个参数传递给函数。对于 zip 函数来说,它将会把 locations[::-1] 中的两个数组分开并传递给 zip:
22222222 [235 235 235 235 235 236 235 236 235 236 235 236 59 60 118 59 60 118
118 60 60 117 118 117 118 61 60 61 118 118] [ 74 75 76 137 138 138 139 139 200 200 201 201 288 288 288 289 289 289
290 348 349 349 349 350 350 407 408 408 408 409]
"""
print("22222222" , *locations[::-1])
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()
案例8
import cv2
gray = cv2.imread("opencv_logo.jpg", cv2.IMREAD_GRAYSCALE)
"""
应用了 拉普拉斯算子(Laplacian) 来检测图像的边缘。拉普拉斯算子是基于图像的二阶导数,它可以检测图像中的边缘信息(亮度变化剧烈的地方)
cv2.Laplacian(src, ddepth, ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
src:输入图像,必须是灰度图像(即单通道图像)。
ddepth:输出图像的深度。通常设为 cv2.CV_64F,表示输出为64位浮点数,允许显示大范围的值。
如果使用 cv2.CV_8U 或 cv2.CV_16S,可能会导致溢出或损失细节。
ksize:使用的 Sobel 卷积核的大小,默认值是 3。可以设置为 1, 3, 5, 7 等奇数。
scale:计算过程中对结果进行缩放的系数,默认为 1。
delta:计算过程中添加的偏移量,默认为 0。
borderType:边界像素处理方式,通常使用 cv2.BORDER_DEFAULT。
主要用于通过计算图像的二阶导数来检测图像中的边缘和纹理变化,适用于需要快速变化信息(如边缘)检测的场景。
拉普拉斯算子生成的图像通常会显示为 负值和正值的混合,这些值表示图像中亮度变化的快慢。
"""
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
"""
这里应用了 Canny 边缘检测算法。它是一种多阶段算法,通过梯度计算和双阈值策略来确定边缘。
100 和 200 是 Canny 算法的低阈值和高阈值,决定了哪些像素被认为是边缘。
cv2.Canny(image, threshold1, threshold2, apertureSize=3, L2gradient=False)
image:输入图像,必须为灰度图(单通道图像)。
threshold1:低阈值,用于边缘连接。图像中大于这个值的梯度幅值将被认为是强边缘。
100:低阈值,表示梯度幅值小于 100 的像素将不会被认为是边缘。
threshold2:高阈值。梯度幅值大于该值的像素会被认为是边缘,弱边缘则根据是否与强边缘相连来决定。
200:高阈值,表示梯度幅值大于 200 的像素将被认为是强边缘。
apertureSize:Sobel 算子的大小,默认为 3,表示使用一个 3x3 的窗口来计算梯度。
2gradient:布尔值,表示是否使用更高精度的梯度计算(L2 范数)。
默认为 False,使用标准的梯度计算方法。如果设为 True,则使用更精确的梯度幅值计算方法。
返回值:函数会返回一张与输入图像大小相同的二值图像。图像中的边缘部分会被标记为白色(255),其他部分则是黑色(0)。
为什么需要两个阈值?
高阈值:它决定了哪些像素一定是边缘,通常较高,能够有效地检测出强边缘。
低阈值:它帮助连接弱边缘像素,如果一个像素的梯度值高于低阈值并且与强边缘相连,则被认为是边缘。
"""
canny = cv2.Canny(gray, 100, 200)
cv2.imshow("gray", gray)
cv2.imshow("laplacian", laplacian)
cv2.imshow("canny", canny)
cv2.waitKey()
案例9
先了解什么是阈值?
阈值处理就是剔除图像内像素值高于一定值或者低于一定值的像素点,获得一幅有效实现前景和背景的分离的二值图像。
OpenCV 提供了函数 cv2.threshold()和函数 cv2.adaptiveThreshold(),用于实现阈值处理。
#### threshold 函数:
作用:
是 OpenCV 中用于图像阈值化处理的函数。阈值化是图像分割的一种常用方法,目的是将图像的像素值根据某个设定的阈值进行分类,通常用于将图像转换为二值图像(黑白图像)。在许多图像处理任务中,阈值化操作是非常基础且重要的步骤。
"""
retval, dst = cv2.threshold( src, thresh, maxval, type )
src:输入图像,必须为灰度图像(单通道图像)。因为阈值化操作是基于像素的灰度值来进行分类的,因此输入图像应该是灰度图。
thresh(阈值):设定的阈值。所有灰度值大于这个阈值的像素会被认为是前景(通常设为 maxval),而小于阈值的像素会被认为是背景(通常设为 0)。
maxval(最大值):阈值处理后,所有大于阈值的像素会被设置为该值。通常,maxval 设置为 255,表示白色。如果你希望将像素值限制在某个范围内,可以调整 maxval。
type(阈值类型):
cv2.THRESH_BINARY:标准的二值化,将大于阈值的像素设为 maxval,小于阈值的像素设为 0。
cv2.THRESH_BINARY_INV:反二值化,将大于阈值的像素设为 0, 小于阈值的像素设为 maxval。
cv2.THRESH_TRUNC:截断,所有大于阈值的像素被设为阈值值,而小于阈值的像素不变。
cv2.THRESH_TOZERO:大于阈值的像素保持不变,小于阈值的像素设为 0。
cv2.THRESH_TOZERO_INV:大于阈值的像素保持不变,小于阈值的像素设为 0(反转)。
返回值:
retval 是计算出的阈值,dst 是经过阈值化处理后的二值图像。
"""
adaptiveThreshold 函数:
作用:
用于执行 自适应阈值处理。自适应阈值化是一种根据图像局部区域的特征动态计算阈值的方法。它特别适用于光照不均的图像,例如在光线变化较大的区域或有阴影的图像中,通过这种方法能够得到更好的阈值化效果。
区别:
与普通的全局阈值化不同,在自适应阈值化中,每个像素的阈值是根据其周围邻域的像素值动态计算的。这样,在局部区域的阈值不同,有效解决了全局阈值在不均匀光照下的问题。
"""
dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
src:输入图像,必须是灰度图像。这个图像将被应用自适应阈值化。
maxValue:阈值化后像素的最大值。通常设置为 255,表示白色。大于阈值的像素会被设置为该值。
adaptiveMethod:自适应阈值的计算方法,常用的有两种:cv2.ADAPTIVE_THRESH_MEAN_C:使用邻域区域的平均值作为阈值。cv2.ADAPTIVE_THRESH_GAUSSIAN_C:使用邻域区域的加权平均值(高斯加权均值)作为阈值。
thresholdType:阈值类型,通常是:cv2.THRESH_BINARY:像素值大于阈值设为 maxValue,小于阈值设为 0(黑色)。cv2.THRESH_BINARY_INV:反二值化,像素值大于阈值设为 0,小于阈值设为 maxValue(白色)。
blockSize:邻域区域的大小,必须是奇数。
C:常数 C,用于调整阈值。C 会从计算出来的邻域值中减去一定的常量,通常 C 为一个小的整数。它的作用是调节阈值,使得结果更加适应实际情况。
返回值:输出图像,经过自适应阈值处理后的二值图像。
"""
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()
对阈值处理更详细的:https://blog.csdn.net/weixin_51571728/article/details/121622680?ops_request_misc=%257B%2522request%255Fid%2522%253A%252245710364-4964-407E-BA32-9B8BFF3A2E79%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=45710364-4964-407E-BA32-9B8BFF3A2E79&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-121622680-null-null.142
案例10
什么是腐蚀?什么是膨胀?
腐蚀是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的目标物。如果两目标物间有细小的连通,可以选取足够大的结构元素,将细小连通腐蚀掉。
膨胀是将目标区域接触的背景点合并到该目标物中,使目标边界向外扩张的处理。膨胀可以用来填补目标区域存在的某些空洞,也可以用来消除包含在目标区域中的小颗粒噪声。膨胀处理是腐蚀处理的对偶。
kernel是什么?
在图像处理中,kernel
(或称为结构元素)是一个小的矩阵,用来在图像中进行局部运算。它定义了某种特定操作在图像上如何应用,例如卷积、腐蚀、膨胀、边缘检测等。
常见操作中的 kernel
卷积:在卷积神经网络(CNN)中,kernel
或 滤波器
用于在图像上滑动,执行加权和操作,用于特征提取(如边缘检测、模糊、锐化等)。
形态学操作:在腐蚀、膨胀等形态学操作中,kernel
用来定义局部区域如何影响图像。例如:
在腐蚀操作中,kernel
用来决定邻域范围内的最小值。
在膨胀操作中,kernel
用来决定邻域范围内的最大值。
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 决定了操作的范围和形状。例如,一个 3x3 的 kernel 会产生较小的影响,而一个 5x5 或更大的 kernel 会产生更强的影响。
使用 np.ones((5, 5), np.uint8) 作为 kernel 会产生一个 5x5 的矩阵,其中每个元素都是 1,这意味着在执行腐蚀或膨胀操作时会考虑一个 5x5 的邻域范围,这样效果会比一个较小的结构元素更强烈。
"""
kernel = np.ones((5, 5), np.uint8)
# 腐蚀 传入二值图像和kernel 返回腐蚀后的图像
erosion = cv2.erode(binary, kernel)
#膨胀 传入二值图像和kernel 返回膨胀后的图像
dilation = cv2.dilate(binary, kernel)
cv2.imshow("binary", binary)
cv2.imshow("erosion", erosion)
cv2.imshow("dilation", dilation)
cv2.waitKey()
案例11
如何调用摄像头!
import cv2
"""
cv2.VideoCapture(0) 用于打开默认摄像头(通常是内建摄像头,编号为 0)。如果你的电脑有多个摄像头,你可以尝试使用 1、2 等其他数字来指定不同的摄像头。
capture: 用于获取摄像头的帧
"""
capture = cv2.VideoCapture(0)
"""
为什么要用while循环?
摄像头捕捉到的视频是连续的帧(图像),并且这些帧是不断变化的。为了持续获取每一帧并显示出来,必须使用一个循环。
"""
while True:
"""
capture.read() 每次读取摄像头捕获到的一帧图像。
返回值:
ret:一个布尔值,表示帧是否成功读取。
frame:读取到的图像帧,通常是一个 NumPy 数组,表示图像的像素值。
"""
ret, frame = capture.read()
cv2.imshow("camera", frame)
key = cv2.waitKey(1)
if key != -1:
break
"""
capture.release() 用于释放摄像头资源。即便程序退出或发生错误,调用 release() 确保摄像头资源被正确释放,避免锁定摄像头。
"""
capture.release()