文章目录
一、OpenCV常用函数
以下是一些常用的 OpenCV 图像处理函数的详细信息,包括参数、返回值及示例:
1. cv2.imread()
- 功能:读取图像文件。
- 参数:
filename
:图像文件的路径(字符串)。flags
:读取标志,默认值为cv2.IMREAD_COLOR
,可选值包括:cv2.IMREAD_GRAYSCALE
:以灰度模式读取。cv2.IMREAD_UNCHANGED
:包含 alpha 通道的读取。
- 返回值:图像数组(如果读取失败,则返回
None
)。
示例:
import cv2
img = cv2.imread('image.png', cv2.IMREAD_COLOR)
if img is None:
print("图像加载失败")
2. cv2.imshow()
- 功能:显示图像。
- 参数:
winname
:窗口名称(字符串)。mat
:要显示的图像(numpy 数组)。
- 返回值:无。
示例:
cv2.imshow('Display Image', img)
3. cv2.imwrite()
- 功能:保存图像到文件。
- 参数:
filename
:保存的文件名(字符串)。img
:要保存的图像(numpy 数组)。
- 返回值:布尔值,表示保存是否成功。
示例:
success = cv2.imwrite('output.png', img)
if success:
print("图像保存成功")
4. cv2.resize()
- 功能:调整图像大小。
- 参数:
src
:输入图像(numpy 数组)。dsize
:目标尺寸(),设置为(0, 0)
时可用fx
和fy
缩放因子。fx
:水平方向的缩放因子(浮点数)。fy
:垂直方向的缩放因子(浮点数)。
- 返回值:调整后的图像(numpy 数组)。
示例:
resized_img = cv2.resize(img, (200, 300)) # 直接指定尺寸
resized_img = cv2.resize(img, (0, 0), fx=2, fy=2) # 使用缩放因子
5. cv2.add()
- 功能:像素级别相加两张图像。
- 参数:
src1
:第一张输入图像(numpy 数组)。src2
:第二张输入图像(numpy 数组)。
- 返回值:相加后的图像(numpy 数组)。
示例:
result_img = cv2.add(img1, img2)
cv2.addWeighted
6. cv2.waitKey()
- 功能:等待键盘输入。
- 参数:
delay
:等待时间(毫秒),如果为0
,则无限等待。
- 返回值:按下键的 ASCII 码(整数)。
示例:
cv2.waitKey(0) # 等待任意键
7. cv2.destroyAllWindows()
- 功能:关闭所有创建的窗口。
- 参数:无。
- 返回值:无。
示例:
cv2.destroyAllWindows()
8. cv2.cvtColor()
- 功能:转换图像颜色空间。
- 参数:
src
:输入图像(numpy 数组)。code
:颜色转换代码,例如:cv2.COLOR_BGR2GRAY
:从 BGR 转换为灰度。cv2.COLOR_GRAY2BGR
:从灰度转换为 BGR。
- 返回值:转换后的图像(numpy 数组)。
示例:
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
这些函数构成了 OpenCV 的基础,适用于各种图像处理任务。
二、阈值与平滑处理
1、图像阈值
二值化操作(cv2.threshold
)
cv2.threshold
是 OpenCV 中用于图像阈值处理的函数,常用于图像二值化。以下是详细信息:
函数概述
-
功能:
-
参数:
src
:输入图像(灰度图像,numpy 数组)。thresh
:阈值,低于此值的像素将被设为maxval
,高于此值的像素将被设为0
或255
(根据类型)。maxval
:用于设置高于阈值的像素的值,通常为255
。type
:阈值类型,可以是以下值之一:cv2.THRESH_TRUNC
:截断。cv2.THRESH_TOZERO
:大于阈值的值保持不变,其他设置为0
。cv2.THRESH_TOZERO_INV
:小于阈值的值设置为0
。
-
返回值:一个元组,包含两个元素:
示例代码
import cv2
# 读取图像并转换为灰度图
img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
# 应用阈值处理
thresh_value = 128
max_value = 255
retval, binary_img = cv2.threshold(img, thresh_value, max_value, cv2.THRESH_BINARY)
# 显示结果
cv2.imshow('Binary Image', binary_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
使用场景
阈值处理广泛应用于图像分割、边缘检测和特征提取等任务,可以帮助突出目标物体并减少背景干扰。
2、平滑处理
平滑操作(滤波
)
# 均值滤波
# 简单的平均卷积操作
blur = cv2.blur(img, (3, 3)) # 是将每个像素的值替换为该像素邻域内像素值的平均值
# 方框滤波
# 基本和均值一样,可以选择归一化
box = cv2.boxFilter(img,-1,(3,3), normalize=True) # 越界就取255
# normalize=True: 如果设置为 True,表示对核的输出结果进行归一化处理,即计算区域内的像素平均值。如果设置为 False,将计算区域内像素的总和。
# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian = cv2.GaussianBlur(img, (5, 5), 1)
# 中值滤波
# 相当于用中值代替
median = cv2.medianBlur(img, 5) # 中值滤波
res = np.hstack((blur,aussian,median))
三、形态学操作
1、腐蚀操作
腐蚀操作 (cv2.erode
)
- 功能:缩小图像中的白色区域,去除小的噪声。
- 参数:
src
:输入图像(通常是二值图像)。kernel
:结构元素,用于腐蚀操作(numpy 数组)。iterations
:迭代次数,默认值为 1。
- 返回值:腐蚀后的图像(numpy 数组)。
- 原始图像:在整个腐蚀过程中,所有像素点的判断都是基于输入的原始图像数据。更新每个像素点时使用的是原始未更新的像素点数据。
示例:
# 用于对二值化图像或者灰度图像的形态学处理。腐蚀操作可以去除小的白噪点或在二值图像中缩小前景物体,通常用于形态学操作如物体检测和图像预处理。
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)# 在每个像素位置,将卷积核覆盖在图像上,如果卷积核下方的所有像素值都为1,则保留该像素的值,否则将该像素值设为0。
# 这会使得前景区域(亮色部分)变小,或去掉小的噪声点。
2、膨胀操作
膨胀操作 (cv2.dilate
)
- 功能:放大图像中的白色区域,填补小的空洞。
- 参数:
src
:输入图像(通常是二值图像)。kernel
:结构元素(numpy 数组)。iterations
:迭代次数,默认值为 1。
- 返回值:膨胀后的图像(numpy 数组)。
示例:
kernel = np.ones((3,3),np.uint8)
dige_dilate = cv2.dilate(dige_erosion,kernel,iterations = 1)
3、开运算&闭运算
开运算 (cv2.morphologyEx
)
- 功能:
- 参数:
src
:输入图像(通常是二值图像)。op
:操作类型,设置为cv2.MORPH_OPEN
。kernel
:结构元素(numpy 数组)。
- 返回值:开运算后的图像(numpy 数组)。
示例:
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
闭运算 (cv2.morphologyEx
)
- 功能:
- 参数:
src
:输入图像(通常是二值图像)。op
:操作类型,设置为cv2.MORPH_CLOSE
。kernel
:结构元素(numpy 数组)。
- 返回值:闭运算后的图像(numpy 数组)。
示例:
kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
4、梯度运算
# 梯度=膨胀-腐蚀
pie = cv2.imread('pie.png')
kernel = np.ones((7,7),np.uint8)
dilate = cv2.dilate(pie,kernel,iterations = 5)
erosion = cv2.erode(pie,kernel,iterations = 5)
gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
5、礼帽与黑帽
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)
6、常用操作用途
在图像处理中,开运算、闭运算、礼帽操作 和 黑帽操作 都是基于 形态学操作 的方法,常用于图像的预处理,尤其是在去噪、增强图像特征、分割等任务中。
1. 开运算(Opening Operation)
- 效果:去除图像中的小亮点(噪声),保持较大物体的形状和边界完整。
- 应用场景:适用于消除小的白色噪点,但不影响整体的形态。
公式:开运算 = 腐蚀 + 膨胀
- 腐蚀:先将图像的前景区域缩小,去除小的噪声点。
- 膨胀:在腐蚀之后,再恢复物体的形状。
实际效果:
- 如果图像中有一些孤立的小亮点噪声,开运算会去掉它们,而不会对较大的物体产生明显影响。
2. 闭运算(Closing Operation)
- 效果:填补图像中的小黑洞,闭合前景物体内的小裂缝或孔洞,同时保留物体的整体形状。
- 应用场景:用于去除前景物体内部的小黑洞,或者连接断开的物体。
公式:闭运算 = 膨胀 + 腐蚀
- 膨胀:先扩展图像的前景,填补小黑点或缝隙。
- 腐蚀:然后恢复图像物体的边界,避免过度扩展。
实际效果:
- 如果图像中有一些小的黑色缝隙或空洞,闭运算可以填补这些区域,同时保持物体的边缘完整。
3. 礼帽操作(Top-hat Operation)
- 效果:突出图像中比周围亮的小区域,可以用于提取局部亮的细节。
- 应用场景:在图像中寻找比背景亮的物体,适合提取局部亮的特征,如字符识别、车牌识别等。
公式:礼帽 = 原图像 - 开运算
实际效果:
- 提取出那些比周围背景亮的小物体,能够增强图像中高亮部分的对比度。
4. 黑帽操作(Black-hat Operation)
- 效果:突出图像中比周围暗的小区域,用于提取局部暗的细节。
- 应用场景:在图像中寻找比背景暗的物体,适合提取局部暗的特征。
公式:黑帽 = 闭运算 - 原图像
实际效果:
- 提取图像中比背景暗的区域,增强局部阴影或黑暗区域的细节。
总结表格:
应用实例:
- 开运算:用于去除图片中的小白色噪点,如在车牌识别前处理照片。
- 闭运算:用于填补图像中的小黑色空洞,如在医学图像中填补细胞内部的小缺口。
- 礼帽操作:可以用于增强图像中的亮斑点特征,如识别图片中的小亮点。
- 黑帽操作:适合用于提取图片中的暗区域特征,如在摄影后期处理中突出阴影部分。
这些操作可以结合图像处理任务的不同需求来灵活使用,优化图像质量或提取特定区域特征。
四、图像梯度计算
1、sobel算子
cv2.Sobel
-
功能:计算图像的梯度,用于边缘检测。
-
参数:
src
:输入图像(灰度图像)。ddepth
:输出图像的深度,通常使用cv2.CV_64F
。
dx
:x方向的导数阶数(0表示不计算x方向的导数)。dy
:y方向的导数阶数(0表示不计算y方向的导数)。ksize
:Sobel算子的大小,通常为1、3、5、7。scale
:缩放因子(可选)。delta
:加到结果上的值(可选)。
-
返回值:计算后的梯度图像(numpy 数组)。
import cv2
img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) # x方向的梯度
sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3) # y方向的梯度
cv2.convertScaleAbs
梯度取绝对值
sobelx = cv2.convertScaleAbs(sobelx)
# 这个函数将 sobelx 中的 64 位浮点数转换为 8 位无符号整数(uint8),方便后续的图像显示。
# 它通过取绝对值 (abs),确保负值被转换为正值。
# 并将结果缩放到 0-255 的范围,适合显示和处理。
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
# 将 sobelx 和 sobely 按 1:1 的比例加权合并,生成一个新的图像 sobelxy,包含了水平和垂直边缘的信息。
sobel_combined = cv2.magnitude(sobel_x, sobel_y) # 结合 x 和 y 方向的梯度
2、Scharr算子和laplacian算子
cv2.Scharr
- 功能:与 Sobel 类似,但使用更高阶的核,通常能提供更好的边缘检测效果。
- 参数:
- 与
cv2.Sobel
相同。 ksize
默认值为 -1,表示使用 Scharr 算子。
- 与
- 返回值:计算后的梯度图像(numpy 数组)。
scharr_x = cv2.Scharr(img, cv2.CV_64F, 1, 0) # x方向的梯度
scharr_y = cv2.Scharr(img, cv2.CV_64F, 0, 1) # y方向的梯度
scharr_combined = cv2.magnitude(scharr_x, scharr_y)
cv2.Laplacian
- 功能:计算图像的拉普拉斯变换,用于边缘检测。
- 参数:
src
:输入图像(灰度图像)。ddepth
:输出图像的深度,通常使用cv2.CV_64F
。ksize
:拉普拉斯算子的大小,通常为1、3、5、7。scale
:缩放因子(可选)。delta
:加到结果上的值(可选)。
- 返回值:计算后的拉普拉斯图像(numpy 数组)。
laplacian = cv2.Laplacian(img, cv2.CV_64F, ksize=3)
#不同算子的差异
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
laplacian = cv2.Laplacian(img,cv2.CV_64F) # 对噪音点敏感
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show(res,'res')
五、边缘检测
canny边缘检测
1) 使用高斯滤波器,以平滑图像,滤除噪声。
2) 计算图像中每个像素点的梯度强度和方向。
3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
4) 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
5) 通过抑制孤立的弱边缘最终完成边缘检测。
Canny边缘检测是一种经典且高效的边缘检测算法,整个流程可以分为五个主要步骤,每个步骤都承担着不同的任务,确保检测到准确且连续的边缘。以下是对整个流程的总结:
1. 高斯滤波器去噪
==使用高斯滤波器对输入图像进行平滑处理,目的是减小噪声的影响。==噪声对边缘检测有很大的干扰,所以通过高斯滤波器可以去除图像中的大部分噪声,同时保留主要的图像结构。
2. 计算梯度强度和方向
==通过Sobel算子或者类似的方法,计算图像中每个像素点的梯度强度和方向。==梯度强度代表像素点亮度变化的幅度,梯度方向指向亮度变化最快的方向。在这一步中,你将得到每个像素点的梯度大小和梯度方向,这是判断边缘的重要依据。
3. 非极大值抑制
非极大值抑制是这一过程的关键:
- 对每个像素点,沿着其梯度方向(通常取0°, 45°, 90°, 135°)检查该方向上的相邻像素点。
- 如果当前像素的梯度强度大于其梯度方向上两个相邻像素的强度,则保留这个像素,认为它可能是边缘的一部分。
- 否则,抑制该像素,将其梯度强度设为0,消除杂散响应(非边缘像素)。
这一过程通过去除多余的边缘点,使得保留下来的边缘变得更细、更精确。
4. 双阈值检测
在非极大值抑制之后的图像中,边缘像素被细化,但还需要双阈值检测通过设置两个阈值(高阈值和低阈值)来进行分类:
- 强边缘:梯度强度高于高阈值的像素点直接保留。
- 弱边缘:梯度强度介于低阈值和高阈值之间的像素,需要进一步判断。
- 非边缘:梯度强度低于低阈值的像素点被直接舍弃。
5. 抑制孤立弱边缘,完成边缘检测
==为了确保最终的边缘是连续的,弱边缘像素点需要进一步通过连接性判断。如果弱边缘像素与强边缘相连,则保留该弱边缘,认为它是边缘的一部分;否则,舍弃该弱边缘,认为它不是边缘。==这样可以有效减少孤立的、无意义的弱边缘,使得边缘检测结果更加可靠。
整体总结:
- 高斯滤波器平滑图像,减少噪声干扰。
- 计算梯度强度和方向,标记出可能的边缘位置。
- 非极大值抑制通过保留局部最大梯度强度的像素,确保边缘清晰且细化。
- 双阈值检测进一步筛选强边缘和弱边缘,并通过阈值分割图像中的边缘像素。
- 抑制孤立弱边缘,通过连接性检查,保留真正的边缘,丢弃不连贯的噪声边缘。
这个五步流程使得Canny边缘检测能够在噪声环境下仍然检测出精确、连续的边缘,并广泛应用于各种图像处理任务中。
六、图像金字塔与轮廓检测
1、上下采样都会损失信息吗
是的,上下采样都会不同程度地损失信息,但损失的类型和程度有所不同。
1. 下采样(Downsampling)
- 下采样是通过的一种操作。常见的下采样方法包括跳过某些像素、平均池化、最大池化等。
- 下采样的目的是减少图像的分辨率以适应特定任务(如多尺度分析),但不可避免地会丢失部分信息。
示例:
- 降采样步长较大的话,图像会失去更多的细节。比如,将 100x100 的图像直接缩小到 50x50 像素,原本相邻的像素点会被合并或舍弃,导致细节消失。
2. 上采样(Upsampling)
-
上采样是将低分辨率图像扩大到高分辨率的过程。这种操作,常用的方法有双线性插值、双三次插值等。
-
上采样不会增加图像的真实信息,相反,它会基于现有的低分辨率信息进行插值,因而
-
尽管上采样扩大了图像尺寸,但由于缺少新的原始信息,这种操作也无法恢复因下采样而丢失的细节。
-
将 50x50 的图像放大到 100x100 时,新增的像素点会基于现有像素进行插值,但这些新像素点的值并不代表图像的真实细节,可能会造成图像模糊或不准确。
3. 减少损失的方式
在上下采样过程中,尽管信息损失不可避免,但有一些方法可以减少损失的影响:
- 平滑处理:在下采样之前对图像进行平滑处理(如高斯滤波)可以去除一些噪声,保留较为重要的低频信息。
- 超分辨率技术:上采样时引入如深度学习的超分辨率算法,可以在放大图像时生成较为自然和清晰的高分辨率图像,减少虚假信息。
- 多尺度金字塔:使用图像金字塔技术,能够在不同尺度下保留部分细节,便于多尺度图像分析。
总结:
- 下采样时,图像的细节会丢失,特别是高频信息。
- 上采样时,无法恢复丢失的细节,可能引入插值误差或伪影。
- 无论是上下采样,信息损失是不可避免的,但可以通过一些方法尽量减少损失或降低其对图像质量的影响。
2、实际流程
cv2.pyrUp
&cv2.pyrDown
down=cv2.pyrDown(img)
up2=cv2.pyrUp(up)
3、轮廓检测
cv2.findContours
cv2.drawContours
轮廓检测与边缘检测区别🛫
边缘检测和轮廓检测虽然都是图像处理中的重要步骤,但它们在目的和处理方式上有显著的区别。
简单来说,边缘检测可以用于找出图像中的所有边缘,而轮廓检测则通过这些边缘来识别和重构图像中的形状和物体。
4、轮廓特征与预测
轮廓近似
cnt = contours[0]
# 计算轮廓的周长,并计算多边形逼近的精度
epsilon = 0.10 * cv2.arcLength(cnt, True) #epsilon 是一个浮点数,表示多边形逼近的精度。值越小,逼近的曲线越接近原始轮廓;值越大,逼近的曲线越简单。
# 使用多边形逼近算法简化轮廓
approx = cv2.approxPolyDP(cnt, epsilon, True)
# 复制原图像,防止对原图进行修改
draw_img = img.copy()
# 在图像上绘制简化后的轮廓
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
# 显示结果
cv_show(res, 'res')
外接矩形
# 获取外接矩形坐标和尺寸
# cv2.boundingRect(cnt) 计算轮廓 cnt 的最小外接矩形,返回 (x, y, w, h),其中 (x, y) 是矩形左上角的坐# 标,w 是宽度,h 是高度。
x, y, w, h = cv2.boundingRect(cnt)
# 在图像上绘制外接矩形
# 在原图 img 上绘制外接矩形,使用绿色 (0, 255, 0),线条宽度为 2。
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 显示结果
cv_show(img, 'img')
外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,'img')
5、模版匹配
模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度.这个差别程度的计算方法在opencv里有6种, 然后将每次计算的结果放入一个矩阵里,作为结果输出。
cv2.matchTemplate
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
res
中的值代表模板匹配的得分。
参数cv2.TM_SQDIFF
:
- TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
- TM_CCORR:计算相关性,计算出来的值越大,越相关
- TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
- TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
- TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
- TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
- 归一化的更可靠
- https://docs.opencv.org/3.3.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(min_val,' ', max_val, min_loc, max_loc) # 39168.0 74403584.0 (107, 89) (159, 62)
cv2.rectangle
cv2.rectangle(image, pt1, pt2, color, thickness)
是 OpenCV 中用于在图像上绘制矩形的函数。这个函数常用于标记图像中的特定区域,或在图像处理和计算机视觉任务中可视化结果。
函数定义:
cv2.rectangle(image, pt1, pt2, color, thickness)
参数说明:
- image(输入图像):
- 要在其上绘制矩形的图像。可以是彩色图像(BGR格式)或灰度图像。
- pt1(矩形的一个顶点):
- 一个元组,表示矩形左上角的坐标,如
(x1, y1)
。
- 一个元组,表示矩形左上角的坐标,如
- pt2(矩形的另一个顶点):
- 一个元组,表示矩形右下角的坐标,如
(x2, y2)
。
- 一个元组,表示矩形右下角的坐标,如
- color(颜色):
- 矩形的颜色,通常以 BGR 格式指定,例如,红色可以表示为
(0, 0, 255)
。
- 矩形的颜色,通常以 BGR 格式指定,例如,红色可以表示为
- thickness(线宽):
- 矩形边框的线宽,单位为像素。如果设置为
cv2.FILLED
,则矩形将被填充。
- 矩形边框的线宽,单位为像素。如果设置为
for meth in methods:
img2 = img.copy()
# 匹配方法的真值
method = eval(meth) # methods 是一个包含匹配方法名的列表(如 cv2.TM_CCOEFF, cv2.TM_SQDIFF 等)。通过 eval(meth) 将字符串转换为实际的 OpenCV 方法。
print (method)
# 使用 cv2.matchTemplate() 进行模板匹配,res 是匹配结果图像。模板匹配的结果是一个灰度图,越亮的地方表示匹配度越高(对于大多数方法)。
res = cv2.matchTemplate(img, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 画矩形
# 根据匹配区域的左上角 top_left 位置以及模板的宽高 (w, h) 计算矩形的右下角 bottom_right,然后使用 cv2.rectangle() 在图像 img2 上绘制匹配区域。
cv2.rectangle(img2, top_left, bottom_right, 255, 2)
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.xticks([]), plt.yticks([]) # 隐藏坐标轴
plt.subplot(122), plt.imshow(img2, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
匹配多个对象
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]): # *号表示可选参数
bottom_right = (pt[0] + w, pt[1] + h)
cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)
cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)
loc[::-1]
:
- 这个操作将
loc
中的数组顺序反转,使得 y 坐标在前,x 坐标在后。这是因为在绘制矩形时,我们需要先给出左上角的点(x,y)。
七、直方图与傅里叶变换
1、直方图
cv2.calcHist
cv2.calcHist
是 OpenCV 中==用于计算图像直方图的函数。==直方图是表示图像中像素值分布的图形,可以用于图像分析、增强和比较。
函数定义:
cv2.calcHist(images, channels, mask, histSize, ranges)
参数说明:
- images(输入图像):
- 输入图像的列表。通常传入一张图像或多张图像的列表。
- channels(通道):
- 指定计算直方图的通道索引。例如,对于彩色图像,通常可以使用
0
(蓝色通道)、1
(绿色通道)、2
(红色通道)来计算各个通道的直方图。
- 指定计算直方图的通道索引。例如,对于彩色图像,通常可以使用
- mask(掩膜):
- 可选参数,用于指定计算直方图的区域。如果为
None
,则计算整个图像的直方图。
- 可选参数,用于指定计算直方图的区域。如果为
- histSize(直方图大小):
- 指定直方图的 bin 数(即区间的数量),通常是一个整数。例如,常用的值为
256
,表示像素值范围 [0, 255] 的直方图。
- 指定直方图的 bin 数(即区间的数量),通常是一个整数。例如,常用的值为
- ranges(范围):
- 指定像素值的范围。对于灰度图像,通常是
[0, 256]
;对于彩色图像,可以分别为每个通道设置范围。
- 指定像素值的范围。对于灰度图像,通常是
返回值:
- 返回计算得到的直方图,通常是一个 Numpy 数组,表示各个 bin 的像素计数。
img = cv2.imread('cat.jpg',0) #0表示灰度图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
hist.shape # (256, 1)
2、均衡化
cv2.equalizeHist
img.ravel()
img.ravel()
将图像展平成一维数组。通常图像是二维(灰度图)或三维(彩色图)的矩阵,ravel()
会将这些像素值压缩成一维的形式,便于进行直方图统计。
img = cv2.imread('clahe.jpg',0) #0表示灰度图 #clahe
plt.hist(img.ravel(),256)
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
res = np.hstack((img,equ))
cv_show(res,'res')
cv2.createCLAHE
(自适应均衡化)
cv2.createCLAHE
是 OpenCV 中用于创建自适应直方图均衡化(CLAHE,Contrast Limited Adaptive Histogram Equalization)对象的函数。CLAHE 是传统直方图均衡化的改进版本,能够有效避免均衡化过程中出现的过度对比增强问题,特别适合处理局部对比度不足的图像。
函数定义:
cv2.createCLAHE(clipLimit=40.0, tileGridSize=(8, 8))
参数说明:
clipLimit
(对比度限制):- CLAHE 的核心参数之一,用于限制对比度增强的程度。如果某个局部区域的像素值超过
clipLimit
,则会进行剪裁。较高的clipLimit
会产生更强的对比度增强,默认值为 40.0。
- CLAHE 的核心参数之一,用于限制对比度增强的程度。如果某个局部区域的像素值超过
tileGridSize
(网格大小):- 图像被划分为多个小块,每个小块都进行独立的直方图均衡化。
tileGridSize
参数定义了这些小块的大小,通常是一个 2D 的元组(x, y)
,默认为(8, 8)
。值越大,小块区域越大,均衡化效果更接近全局均衡化。
- 图像被划分为多个小块,每个小块都进行独立的直方图均衡化。
返回值:
- 返回一个 CLAHE 对象,该对象可以用来对图像执行自适应直方图均衡化。
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_clahe = clahe.apply(img)
# res_clahe = clahe.apply(img) 是使用创建的 CLAHE 对象对输入图像进行自适应直方图均衡化的操作。这个函数# # 将对图像的对比度进行增强,以改善其可视效果,特别是在局部对比度不足的区域。
res = np.hstack((img,equ,res_clahe))
cv_show(res,'res')
3、傅里叶变换(了解即可)
1、图像中的高低频❤️
,它是信号处理中的重要工具。
2、傅里叶变换
基本概念:
傅里叶变换是将信号或图像分解为不同频率的正弦波的和。对于图像而言,傅里叶变换可以帮助我们分析图像中不同频率成分的分布。
- 时域/空域:信号或图像的常规表示方式。对于图像来说,就是每个像素点的亮度值。
- 频域:信号或图像的频率表示方式。它反映了图像中变化快的区域(高频)和变化慢的区域(低频)。通过傅里叶变换,我们可以将图像从像素空间转换到频率空间。
。比如,图像中细小的纹理、边缘等都是高频成分,而大的平滑区域则为低频成分。
公式解释:
离散傅里叶变换(DFT)的公式如下:
$
F(u,v) = \sum_{x=0}{N-1}f(x,y)\cdot e^{-j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)}
$
其中:
- ( f(x, y) ) 是输入的图像(空间域)。
- ( F(u, v) ) 是傅里叶变换后的频域表示。
- ( M ) 和 ( N ) 是图像的宽度和高度。
- ($ e^{-j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)} $) 是复指数,用于将空间域数据映射到频域。
复数表示中的实部和虚部的意义:
-
实部 (Real Part) 和 虚部 (Imaginary Part) 是傅里叶变换的结果之一,它们分别表示频率成分的振幅和相位。
- 实部:对应频率分量的振幅。
- 虚部:对应频率分量的相位。
图像的频域表示为复数形式,其中频率信息的大小存储在实部和虚部中。为了可视化频域信息,通常会计算频率的幅度谱(Magnitude Spectrum),这是实部和虚部的组合,即:
$
\text{Magnitude} = \sqrt{\text{Re}^2 + \text{Im}^2}
$
3. **傅里叶反变换 **
傅里叶变换的逆操作叫做傅里叶反变换,它将频域信息重新转换回时域或空域。通过反变换,可以从频率信息恢复原始图像。
离散傅里叶反变换(IDFT)的公式为:
$
f(x, y) = \frac{1}{MN} \sum_{u=0}^{M-1} \sum_{v=0}^{N-1} F(u,v) \cdot e^{j2\pi\left(\frac{ux}{M} + \frac{vy}{N}\right)}
$
通过这个公式,频率域的数据 ( F(u,v) ) 可以还原成图像域数据 ( f(x,y) )。
傅里叶变换和反变换的作用:
4. 低通滤波和高通滤波
傅里叶变换能够将图像信息分解为频率成分,因此可以通过对频域中不同频率成分的操作,实现不同的滤波器功能,如低通滤波和高通滤波。
低通滤波器(Low-Pass Filter, LPF):
==低通滤波器允许低频成分通过,抑制高频成分。==低频成分通常包含图像的主要轮廓、整体形状等信息,而高频成分则包含边缘、细节等信息。
-
低通滤波作用:去除图像中的高频噪声,平滑图像。
应用场景:在图像降噪、去除小细节、模糊化处理时,常用低通滤波器。
高通滤波器(High-Pass Filter, HPF):
高通滤波器允许高频成分通过,抑制低频成分。高频成分通常包含图像中的边缘、纹理等细节信息。
低通和高通滤波与傅里叶变换的关系:
- 在频域中,通过低通滤波器可以抑制频谱中的高频部分,只保留频谱中的低频区域(通常位于频谱的中心)。
- 通过高通滤波器,可以抑制频谱中的低频部分,突出高频区域(通常位于频谱的边缘)。
总结:
- 傅里叶变换 (DFT) 将图像从空间域(像素值)转换到频域(频率信息),其中频域包含了图像的低频(平滑区域)和高频(边缘、纹理)成分。
- 傅里叶反变换 (IDFT) 则将频域信息重新转换回空间域,恢复图像。
- 低通滤波器允许低频信号通过,可以去除高频噪声,平滑图像。
- 高通滤波器允许高频信号通过,可以增强图像的边缘和细节。
傅里叶变换为我们提供了分析和处理图像的频率成分的手段。通过它,我们可以方便地进行滤波、去噪、增强等操作,帮助在不同的任务中处理图像。
5、傅里叶处理中的函数
这几个函数在图像处理和频域分析中非常重要,尤其是在进行傅里叶变换和频域滤波时。下面是对它们的详细解释:
1. cv2.dft
-
定义:计算离散傅里叶变换(DFT)。
-
函数签名:
cv2.dft(src, flags=cv2.DFT_COMPLEX_OUTPUT)
-
参数:
src
:输入图像,通常是浮点型的单通道或多通道图像。flags
:可选参数,指定输出格式,cv2.DFT_COMPLEX_OUTPUT
表示输出复数结果。
-
返回值:返回的结果是一个复数数组,包含频域信息。
2. np.fft.fftshift
-
定义:
-
函数签名:
np.fft.fftshift(x)
-
参数:
x
:输入的傅里叶变换结果。
-
返回值:返回中心化后的频谱数组,使低频和高频成分更易于可视化。
-
用途:在进行傅里叶变换后,低频成分通常位于图像的角落,使用
fftshift
可以将其移动到图像中心,以便更好地分析频域信息。
3. cv2.magnitude
-
定义:。
-
函数签名:
cv2.magnitude(x, y)
-
参数:
x
:复数的实部。y
:复数的虚部。
-
返回值:返回的幅值图像,表示频域中每个点的强度。
-
用途:在频域分析中,使用
cv2.magnitude
可以提取频率分量的强度信息。
4. cv2.idft
-
定义:计算逆离散傅里叶变换(IDFT),将频域信息转换回空间域。
-
函数签名:
cv2.idft(dft, flags=cv2.DFT_SCALE)
-
参数:
dft
:输入的复数频域数组。flags
:可选参数,cv2.DFT_SCALE
用于缩放输出,使其与输入图像的大小相同。
-
返回值:返回的结果是恢复的图像(空间域)。
-
用途:
cv2.idft
用于从频域重建图像,通常在频域处理后进行。
6、实例
img = cv2.imread('lena.jpg',0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2) # 中心位置
# 低通滤波
'''
mask:创建一个和图像同样大小的全零矩阵(相当于掩膜),用于滤波操作。
mask[crow-30:crow+30, ccol-30:ccol+30] = 1:在图像中心区域(30x30的正方形区域)设置为1,代表低通滤波器会保留该区域的频率信息,
而外部区域(高频部分)会被滤除。
'''
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# IDFT
fshift = dft_shift*mask # 将掩膜应用到傅里叶变换后的频谱上,过滤掉高频部分,只保留中心低频成分。
f_ishift = np.fft.ifftshift(fshift) # 将频谱反转回原始位置(频谱移回左上角),为反傅里叶变换做准备。
img_back = cv2.idft(f_ishift) # 进行反傅里叶变换,将频率域信息转换回空间域。
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1]) # 计算反变换后的图像的幅度,恢复图像数据。
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()
img = cv2.imread('lena.jpg',0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2) # 中心位置
# 高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0
# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])
plt.show()