上一期【人工智能-14】OpenCV梯度处理、边缘检测、绘制轮廓、凸包检测、轮廓特征查找
文章目录
一、直方图均衡化
直方图均衡化是一种用于增强图像对比度的数字图像处理技术,通过调整图像的灰度值分布,使原本集中在较窄灰度区间的像素值扩展到更宽的区间,从而让图像的明暗差异更明显。
1.为什么要用
很多图像(如逆光拍摄、低光照环境下的图像)存在灰度值集中的问题,导致对比度低、细节模糊。直方图均衡化能通过优化灰度分布,让图像中暗的部分更暗、亮的部分更亮,突出细节信息,便于后续的图像分析或视觉观察。
2.这个用了什么技术
核心是基于图像的灰度直方图(统计每个灰度值出现的频率)。通过构建灰度值的累积分布函数,将原始图像的灰度值映射到新的灰度区间:频率高的灰度区间被 “拉伸”,频率低的区间被 “压缩”,最终使灰度分布更均匀。
3.自适应直方图均衡化
dst = cv.equalizeHist(imgGray)
imgGray为需要直方图均衡化的灰度图,返回值为处理后的图像
优点:实现简单,计算效率高;能有效提升整体对比度,对多数低对比度图像效果明显。
缺点:可能过度增强图像中的噪声(尤其是暗部噪声);对局部对比度提升有限,可能导致部分区域细节丢失(如过亮或过暗区域)。
4. 对比度受限的自适应直方图均衡化
因为全局调整亮度和对比度的原因,脸部太亮,大部分细节都丢失了。自适应均衡化就是用来解决这一问题的:它在每一个小区域内(默认8×8)进行直方图均衡化。当然,如果有噪点的话,噪点会被放大,需要对小区域内的对比度进行了限制,所以这个算法全称叫:对比度受限的自适应直方图均衡化(Contrast Limited Adaptive Histogram Equalization, CLAHE)。
- 图像分块(Tiling):
- 图像首先被划分为多个不重叠的小块(tiles)。这样做的目的是因为在全局直方图均衡化中,单一的直方图无法反映图像各个局部区域的差异性。通过局部处理,AHE能够更好地适应图像内部的不同光照和对比度特性。(tiles 的 大小默认是 8x8)
- 计算子区域直方图:
- 对于每个小块,独立计算其内部像素的灰度直方图。直方图反映了该区域内像素值的分布情况。
- 子区域直方图均衡化:
- 对每个小块的直方图执行直方图均衡化操作。这涉及重新分配像素值,以便在整个小块内更均匀地分布。均衡化过程会增加低频像素的数量,减少高频像素的数量,从而提高整个小块的对比度。
- 对比度限制(Contrast Limiting):
- 如果有噪声的话,噪声会被放大。为了防止过大的对比度增强导致噪声放大,出现了限制对比度自适应直方图均衡化(CLAHE)。CLAHE会在直方图均衡化过程中引入一个对比度限制参数。当某一小块的直方图在均衡化后出现极端值时,会对直方图进行平滑处理(使用线性或非线性的钳制函数),确保对比度增强在一个合理的范围内。
- 重采样和邻域像素融合:
- 由于小块之间是不重叠的,直接拼接经过均衡化处理的小块会产生明显的边界效应。因此,在CLAHE中通常采用重采样技术来消除这种效应,比如通过双线性插值将相邻小块的均衡化结果进行平滑过渡,使最终图像看起来更为自然和平滑。
- 合成输出图像:
- 将所有小块均衡化后的结果整合在一起,得到最终的自适应直方图均衡化后的图像。
clahe = cv2.createCLAHE(clipLimit=None, tileGridSize=None)
- clipLimit(可选):对比度限制参数,用于控制直方图均衡化过程中对比度增强的程度。如果设置一个大于1的值(如2.0或4.0),CLAHE会限制对比度增强的最大程度,避免过度放大噪声。如果不设置,OpenCV会使用一个默认值。
- tileGridSize(可选):图像分块的大小,通常是一个包含两个整数的元组,如
(8, 8)
,表示将图像划分成8x8的小块进行独立的直方图均衡化处理。分块大小的选择会影响到CLAHE的效果以及处理速度。
创建CLAHE对象后,可以使用 .apply()
方法对图像进行CLAHE处理:
img=clahe.apply(image)
- image:要均衡化的图像。
- img均衡后的图像
二、模板匹配
模板匹配是一种在较大的源图像中查找与较小模板图像最相似区域的技术。它通过在源图像上滑动模板(就像卷积操作),逐像素位置计算模板与源图像对应区域的相似度(或差异度),并找出相似度最高(或差异度最低)的位置,这个位置就被认为是模板在源图像中出现的位置。
1.什么时候用
当需要在图像中定位已知的子图像(模板)时使用,例如:
在工业检测中定位零件或标记。
在视频监控中查找特定物体(如人脸、车辆)。
在游戏中查找UI元素。
在文档图像中查找特定符号或标志。
2.用了什么技术
核心是计算相似度/差异度度量。OpenCV提供了多种计算方法:
平方差匹配: 计算模板和源图像对应区域像素值差的平方和。值越小,匹配越好。
归一化平方差匹配: 对平方差进行归一化处理,使其结果在0到1之间,更鲁棒于光照变化。
相关匹配: 计算模板和源图像对应区域的互相关。值越大,匹配越好。
归一化相关匹配: 对相关匹配进行归一化处理,使其结果在-1到1之间,对光照变化鲁棒性更强。
相关系数匹配: 计算模板和源图像对应区域的相关系数(类似于统计中的相关系数)。值越大(接近1),匹配越好。
归一化相关系数匹配: 对相关系数匹配进行归一化,使其结果在-1到1之间。
算法在源图像上逐像素(或按步长)移动模板,在每个位置计算选定的度量值,最终生成一个结果矩阵(result),该矩阵的每个点存储了该位置匹配的得分(或差值)。
res=cv2.matchTemplate(image, templ, method)
image:原图像,这是一个灰度图像或彩色图像(在这种情况下,匹配将在每个通道上独立进行)。
templ:模板图像,也是灰度图像或与原图像相同通道数的彩色图像。
method:匹配方法,可以是以下之一:
- cv2.TM_CCOEFF(相关系数匹配)
- cv2.TM_CCOEFF_NORMED(归一化相关系数匹配)
- cv2.TM_CCORR(相关匹配)
- cv2.TM_CCORR_NORMED(归一化相关匹配)
- cv2.TM_SQDIFF(平方差匹配)
- cv2.TM_SQDIFF_NORMED(归一化平方差匹配)
- 这些方法决定了如何度量模板图像与原图像子窗口之间的相似度。
返回值res
函数在完成图像模板匹配后返回一个结果矩阵,这个矩阵的大小与原图像不相同。矩阵的每个元素表示原图像中相应位置与模板图像匹配的相似度。
匹配方法不同,返回矩阵的值的含义也会有所区别。以下是几种常用的匹配方法及其返回值含义:
cv2.TM_SQDIFF
或cv2.TM_SQDIFF_NORMED
:返回值越接近0,表示匹配程度越好。最小值对应的最佳匹配位置。
cv2.TM_CCORR
或cv2.TM_CCORR_NORMED
:返回值越大,表示匹配程度越好。最大值对应的最佳匹配位置。
cv2.TM_CCOEFF
或cv2.TM_CCOEFF_NORMED
:返回值越大,表示匹配程度越好。最大值对应的最佳匹配位置。
绘制
找的目标图像中匹配程度最高的点,我们可以设定一个匹配阈值来筛选出多个匹配程度高的区域。
- loc=np.where(array > 0.8) #loc包含array中所有大于0.8的元素索引的数组
np.where(condition) 是 NumPy 的一个函数,当条件为真时,返回满足条件的元素的索引。
- *zip(loc)
*loc
是解包操作,将loc
中的多个数组拆开,作为单独的参数传递给zip
。zip
将这些数组按元素一一配对,生成一个迭代器,每个元素是一个元组,表示一个坐标点。
x=list([[1,2,3,4,3],[23,4,2,4,2]])
print(list(zip(*x)))#[(1, 23), (2, 4), (3, 2), (4, 4), (3, 2)]
3.优点和缺点
优点:
概念简单,易于理解和实现。
当模板在源图像中存在且仅发生平移(没有旋转、缩放、透视变形)且光照变化不大时,效果通常很好。
可以直接得到匹配位置的精确坐标。
缺点:
计算量大: 尤其当源图像和模板都很大时,逐像素滑动计算非常耗时。
对几何变换敏感: 对模板的旋转、缩放、倾斜等几何变换极其敏感,匹配效果会急剧下降。
对光照和外观变化敏感: 如果模板和源图像中目标区域的光照条件或视角(导致外观变化)不同,匹配效果会很差。
可能产生多个峰值: 如果图像中有多个相似区域或存在重复模式,结果矩阵可能会有多个局部最大值/最小值,需要额外的策略(如阈值)来确定最佳匹配。
只能找到平移: 本身不提供关于旋转或缩放的信息。
三、霍夫变换
霍夫变换是一种用于检测图像中特定形状(主要是直线、圆,也可扩展检测椭圆等)的技术。它的强大之处在于对噪声和部分遮挡具有鲁棒性,即使目标形状不是连续的或者有断裂,也能检测出来。
1.为什么要用
直接在图像中检测由边缘点组成的几何形状(如直线、圆)很困难,因为边缘点可能不连续或受噪声干扰。霍夫变换能通过参数空间的聚集特性,有效提取完整的几何形状,适用于车道线检测、物体轮廓提取等场景。
2.用了什么技术
核心思想是将图像空间中的形状检测问题转换到参数空间中进行投票。
直线检测:
通常先对图像进行边缘检测(如Canny),得到二值边缘图。
在图像空间中,一条直线可以用 ρ = xcosθ + ysinθ 表示(ρ是原点到直线的垂直距离,θ是该垂直线与x轴的夹角)。
对于边缘图像上的每个边缘点(x, y),它在参数空间(ρ, θ)中对应一条正弦曲线(所有可能的穿过该点的直线)。
构造一个累加器数组(参数空间网格),遍历所有边缘点,对每个点对应的参数空间曲线上的所有(ρ, θ)点进行投票(累加器值加1)。
在累加器数组中寻找局部峰值(投票数高的点),这些峰值对应的(ρ, θ)参数就代表了图像空间中存在的直线。
圆检测:
同样需要边缘图。
一个圆可以用 (x - a)² + (y - b)² = r² 表示(圆心(a, b),半径r)。
对于每个边缘点(x, y),它可能位于许多不同圆心和半径的圆上。这些可能的圆构成一个三维参数空间(a, b, r)。
对每个边缘点,遍历所有可能的半径r,计算满足方程的可能圆心(a, b)(也是一个圆),并在三维累加器数组的对应(a, b, r)位置投票。
在三维累加器中寻找峰值,峰值对应的(a, b, r)就是检测到的圆。
优点: 即使图像中的直线/圆是断裂的(只要断裂点不多),或者存在噪声,多个边缘点贡献的投票最终也能在参数空间中累积出峰值。部分遮挡的目标也能被检测出来。
标准霍夫直线变换
计算图像中的每一个点,计算量比较大,另外它得到的是整一条线(r和θ),并不知道原图中直线的端点。
lines=cv2.HoughLines(image, rho, theta, threshold)
image
:输入图像,通常为二值图像,其中白点表示边缘点,黑点为背景。rho
:r的精度,以像素为单位,表示霍夫空间中每一步的距离增量, 值越大,考虑越多的线。theta
:角度θ的精度,通常以弧度为单位,表示霍夫空间中每一步的角度增量。值越小,考虑越多的线。threshold
:累加数阈值,只有累积投票数超过这个阈值的候选直线才会被返回。
返回值:cv2.HoughLines
函数返回一个二维数组,每一行代表一条直线在霍夫空间中的参数 (rho, theta)
。
统计概率霍夫直线变换
这是一种改进的霍夫变换,它在获取到直线之后,会检测原图中在该直线上的点,并获取到两侧的端点坐标,然后通过两个点的坐标来计算该直线的长度,通过直线长度与最短长度阈值的比较来决定该直线要不要被保留。
lines=cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=0, maxLineGap=0)
image
:输入图像,通常为二值图像,其中白点表示边缘点,黑点为背景。rho
:极径分辨率,以像素为单位,表示极坐标系中的距离分辨率。theta
:极角分辨率,以弧度为单位,表示极坐标系中角度的分辨率。threshold
:阈值,用于过滤掉弱检测结果,只有累计投票数超过这个阈值的直线才会被返回。lines
(可选):一个可初始化的输出数组,用于存储检测到的直线参数。minLineLength
(可选):最短长度阈值,比这个长度短的线会被排除。maxLineGap
(可选):同一直线两点之间的最大距离。当霍夫变换检测到一系列接近直角的线段时,这些线段可能是同一直线的不同部分。maxLineGap
参数指定了在考虑这些线段属于同一直线时,它们之间最大可接受的像素间隔。
返回值lines:cv2.HoughLinesP
函数返回一个二维数组,每个元素是一个包含4个元素的数组,分别表示每条直线的起始点和结束点在图像中的坐标(x1, y1, x2, y2)。
霍夫圆变换
circles=cv2.HoughCircles(image, method, dp, minDist, param1, param2)
image
:输入图像,通常是灰度图像。method
:使用的霍夫变换方法:霍夫梯度法,可以是cv2.HOUGH_GRADIENT
,这是唯一在OpenCV中用于圆检测的方法。dp
:累加器分辨率与输入图像分辨率之间的降采样比率,用于加速运算但不影响准确性。设置为1表示霍夫梯度法中累加器图像的分辨率与原图一致minDist
:检测到的圆心之间的最小允许距离,以像素为单位。在霍夫变换检测圆的过程中,可能会检测到许多潜在的圆心。minDist
参数就是为了过滤掉过于接近的圆检测结果,避免检测结果过于密集。当你设置一个较小的minDist
值时,算法会尝试找出尽可能多的圆,即使是彼此靠得很近的圆也可能都被检测出来。相反,当你设置一个较大的minDist
值时,算法会倾向于只检测那些彼此间存在一定距离的独立的圆。param1
和param2
:这两个参数是在使用cv2.HOUGH_GRADIENT
方法时的特定参数,分别为:param1
(可选):阈值1,决定边缘强度的阈值。param2
:阈值2,控制圆心识别的精确度。较大的该值会使得检测更严格的圆。param2
通常被称为圆心累积概率的阈值。在使用霍夫梯度方法时,param2
设置的是累加器阈值,它决定了哪些候选圆点集合被认为是有效的圆。较高的param2
值意味着对圆的检测更严格,只有在累加器中积累了足够高的响应值才认为是真实的圆;较低的param2
值则会降低检测的门槛,可能会检测到更多潜在的圆,但也可能包含更多的误检结果。
返回值:cv2.HoughCircles
返回一个二维numpy数组,包含了所有满足条件的圆的参数。
3.优点和缺点
优点:
对噪声和部分遮挡鲁棒: 是其主要优势,能检测不连续或不完美的形状。
能检测多个实例: 可以在同一幅图像中检测多条直线/多个圆。
缺点:
计算复杂度高: 尤其是圆检测(三维参数空间),计算量和内存消耗都很大。直线检测(二维)相对好一些。
参数敏感: 需要谨慎设置累加器网格的分辨率(ρ/θ/r的步长)和检测阈值(峰值的最小投票数)。参数设置不当会导致漏检或误检。
只能检测参数化形状: 基本霍夫变换只能检测能用少量参数描述的简单形状(直线、圆)。虽然可以扩展(如广义霍夫变换),但会更复杂。
精度受限: 检测精度受限于累加器网格的分辨率。
四、图像亮度变换
图像亮度变换是调整图像明暗程度的技术,通过修改像素的灰度值(或 RGB 值),使图像整体变亮、变暗,或针对局部区域调整亮度。
1.为什么要用
解决图像光照不均的问题,比如矫正过暗(逆光)或过亮(曝光过度)的图像,使图像更符合人眼视觉习惯,或为后续处理(如目标检测、分割)提供更合适的输入。
2.用了什么技术
主要通过像素值的映射实现,常见方式包括:
**线性变换:**对每个像素的灰度值乘以系数(调整亮度)加常数(调整偏移),如新值 = 系数×原值 + 常数;
使用 cv2.addWeighted()
函数,可以对图像的像素值进行加权平均,进而改变图像的整体亮度。亮度增益可以通过向每个像素值添加一个正值来实现。
cv2.addWeighted(src1, alpha, src2, beta, gamma)
src1
:第一张输入图像,它将被赋予权重alpha
。alpha
:第一个输入图像的权重。src2
:第二张输入图像,它将被赋予权重beta
。beta
:第二个输入图像的权重。gamma
:一个标量,将被添加到权重求和的结果上,可用于调整总体亮度。计算公式为: dst = src1 * alpha + src2 * beta + gamma
**非线性变换:**如伽马校正(通过幂函数调整,解决相机传感器的非线性响应)、对数变换(压缩高亮度区域,扩展低亮度区域)、直接像素修改等。
如果只需要增加或减少固定的亮度值,可以直接遍历图像像素并对每个像素值进行加减操作。
使用的API:
numpy.clip(a, a_min, a_max)
用于对数组中的元素进行限定,将超出指定范围的元素值截断至指定的最小值和最大值之间
a
:输入数组。a_min
:指定的最小值,数组中所有小于a_min
的元素将被替换为a_min
。a_max
:指定的最大值,数组中所有大于a_max
的元素将被替换为a_max
。
3.优点和缺点
优点:操作简单,计算高效;能快速改善图像的视觉效果,适应不同光照条件。
缺点:简单的全局变换可能导致细节丢失(如过亮区域的高光溢出、过暗区域的暗部丢失);难以处理复杂的局部光照不均问题。
五、形态学变换
形态学变换是一组基于形状的图像处理操作,通常应用于二值图像(前景白色/1,背景黑色/0),但也可扩展到灰度图像。它们利用一个称为结构元素的小模板(或核)在图像上移动,并根据结构元素与图像区域的交集情况来修改图像的形状(如边界、孔洞、凸起)。
1.为什么使用
为了分析和操纵图像中对象的形状结构:
去除噪声: 消除小的白点(椒盐噪声)或小黑洞。
分离对象: 断开细小的连接。
连接对象: 弥合狭窄的断裂。
增强对象边界。
提取骨架、凸壳、边界等形状特征。
填充对象内部的小孔洞。
为后续处理(如轮廓分析、目标识别)准备更“干净”的二值图像。
2.用了什么技术
核心是结构元素和集合操作:
结构元素 (SE): 一个小矩阵(通常为矩形、圆形、十字形),定义了一个邻域形状和一个原点(锚点)。它定义了操作的局部范围和形状影响。
基本操作:
腐蚀 (Erosion):
结构元素在图像上滑动。
输出像素值:只有当结构元素完全包含在目标对象(白色区域)内时,锚点位置的输出才为白色(前景),否则为黑色(背景)。
效果: 白色区域(前景)被“腐蚀”变小,小的白点消失,断开细连接。
膨胀 (Dilation):
结构元素在图像上滑动。
输出像素值:只要结构元素与目标对象(白色区域)有交集(至少一个像素重叠),锚点位置的输出就为白色(前景)。
效果: 白色区域(前景)被“膨胀”变大,小的黑洞被填充,弥合窄断裂。
组合操作 (由基本操作组合而成):
开运算 (Opening): 开运算 = 先腐蚀,后膨胀
效果: 消除小的白噪声点(被腐蚀掉且膨胀不回来),平滑物体轮廓,断开细连接,基本保持原物体大小不变。
闭运算 (Closing): 闭运算 = 先膨胀,后腐蚀
效果: 填充物体内部小的黑洞(被膨胀填满且腐蚀不掉),弥合狭窄的断裂和小缺口,平滑轮廓,基本保持原物体大小不变。
其他高级操作: 形态学梯度(膨胀-腐蚀)、顶帽变换(原图-开运算)、黑帽变换(闭运算-原图)等。
import cv2 as cv
import numpy as np
# 读取图像
car = cv.imread('../images/car.png',cv.IMREAD_GRAYSCALE)
# 二值化
_,car = cv.threshold(car,127,255,cv.THRESH_BINARY_INV)
# 定义核
kernel = np.ones((5,5),np.uint8)
# 腐蚀 对白色腐蚀
erosion = cv.erode(car,kernel,iterations=1)
cv.imshow('erosion', erosion)
# 膨胀 对白色膨胀
dilation = cv.dilate(car,kernel,iterations=1)
cv.imshow('dilation', dilation)
# 开运算 先腐蚀后膨胀
opening = cv.morphologyEx(car, cv.MORPH_OPEN, kernel)
cv.imshow('opening', opening)
# 闭运算 先膨胀后腐蚀
closing = cv.morphologyEx(car, cv.MORPH_CLOSE, kernel)
cv.imshow('closing', closing)
# 礼帽运算 原图与开运算差
topht = cv.morphologyEx(car, cv.MORPH_TOPHAT, kernel)
cv.imshow('topht', topht)
# 黑帽运算 闭运算与原图差
blackhat = cv.morphologyEx(car, cv.MORPH_BLACKHAT, kernel)
cv.imshow('blackhat', blackhat)
# 形态学梯度 膨胀与腐蚀的差
gradient = cv.morphologyEx(car, cv.MORPH_GRADIENT, kernel)
cv.imshow('gradient', gradient)
cv.waitKey(0)
cv.destroyAllWindows()
3.优点和缺点
优点:
对二值图像处理效果显著且高效。
能有效去除特定类型的噪声(椒盐噪声、小孔洞)。
能操纵对象形状结构(连接、分离、填充孔洞、平滑边界)。
理论基础坚实(集合论、格论)。
操作可组合,通过不同顺序组合基本操作实现复杂效果。
选择合适的结构元素形状和大小可以控制操作的局部性和方向性。
缺点:
主要针对二值图像设计,在灰度图像上应用需要推广(如灰度腐蚀/膨胀)。
结果高度依赖于结构元素的选择(形状、大小)。 选择不当可能导致期望效果不佳或破坏目标形状。
本质是局部操作,对全局形状的理解有限。
可能会轻微改变目标对象的尺寸(腐蚀缩小,膨胀放大,开闭运算基本保持但细微变化)。
对于复杂形状或密集粘连的对象,可能难以完美分离或保持细节。