opencv之图像亮度变换和形态学变换(八)
文章目录
- opencv之图像亮度变换和形态学变换(八)
- 一、图像亮度变换
-
- [1.1 亮度变换](#1.1 亮度变换)
- [1.2 线性变换](#1.2 线性变换)
- [1.3 直接像素值修改](#1.3 直接像素值修改)
- 案例
- 二、形态学变换
-
- [2.1 核](#2.1 核)
- [**2.2 腐蚀(Erosion)**](#2.2 腐蚀(Erosion))
- [**2.3 膨胀(Dilation)**](#2.3 膨胀(Dilation))
- [**2.4 开运算(Opening)**](#2.4 开运算(Opening))
- [**2.5 闭运算(Closing)**](#2.5 闭运算(Closing))
- [**2.6 礼帽运算(Top Hat)**](#2.6 礼帽运算(Top Hat))
- [**2.7 黑帽运算(Black Hat)**](#2.7 黑帽运算(Black Hat))
- [**2.8 形态学梯度(Morphological Gradient)**](#2.8 形态学梯度(Morphological Gradient))
- **核心总结**
- 案例
一、图像亮度变换
1.1 亮度变换
在讲解亮度时,需要和对比度一起来进行解释。
对比度调整:图像暗处像素强度变低,图像亮处像素强度变高,从而拉大中间某个区域范围的显示精度。
亮度调整:图像像素强度整体变高或者变低。

上图中,(a)把亮度调高,就是图片中的所有像素值加上了一个固定值;(b)把亮度调低,就是图片中的所有像素值减去了一个固定值;©增大像素对比度(白的地方更白,黑的地方更黑);(d)减小像素对比度(整幅图都趋于一个颜色);
OpenCV调整图像对比度和亮度时,公式为: g ( i , j ) = α f ( i , j ) + β g(i,j)=\alpha f(i,j)+\beta g(i,j)=αf(i,j)+β。但是不能浅显的讲 α \alpha α是控制对比度, β \beta β是控制亮度的。
对比度:需要通过 α 、 β \alpha、\beta α、β一起控制。
亮度:通过 β \beta β控制。
1.2 线性变换
使用 cv2.addWeighted()
函数,可以对图像的像素值进行加权平均,进而改变图像的整体亮度。亮度增益可以通过向每个像素值添加一个正值来实现。
cv2.addWeighted(src1, alpha, src2, beta, gamma)
-
src1
:第一张输入图像,它将被赋予权重alpha
。 -
alpha
:第一个输入图像的权重。 -
src2
:第二张输入图像,它将被赋予权重beta
。 -
beta
:第二个输入图像的权重。 -
gamma
:一个标量,将被添加到权重求和的结果上,可用于调整总体亮度。计算公式为: dst = src1 * alpha + src2 * beta + gamma
1.3 直接像素值修改
如果只需要增加或减少固定的亮度值,可以直接遍历图像像素并对每个像素值进行加减操作。
使用的API:
numpy.clip(a, a_min, a_max)
用于对数组中的元素进行限定,将超出指定范围的元素值截断至指定的最小值和最大值之间
-
a
:输入数组。 -
a_min
:指定的最小值,数组中所有小于a_min
的元素将被替换为a_min
。 -
a_max
:指定的最大值,数组中所有大于a_max
的元素将被替换为a_max
。
案例
案例一:
py
import numpy as np
import cv2 as cv
img = cv.imread("images/1.jpg")
# 使用cv2.addWeihted(src1, alpha, src2, beta, gamma)实现线性变换
"""
np.zeros_like(img) 生成与img相同形状的零矩阵
np.ones_like(img) 生成与img相同形状的1矩阵
np.full_like(img, n) 生成与img相同形状的n矩阵
"""
dst = cv.addWeighted(img, 1, np.zeros_like(img), 0, 50)
cv.imshow("dst", dst)
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()

案例二:
py
import cv2 as cv
import numpy as np
window_name = 'Trackbar'
cv.namedWindow(window_name)
# 写一个改变图像亮度的方法
def change(p):
img = cv.imread('images/1.jpg')
if img is None:
print("图像加载失败,请检查路径!")
return
# 把滑条范围映射到-255~255
p = int(p) # 确保 p 是整数
p = p / 255 * (255 - (-255)) - 255
# 亮度变换
dst = np.uint8(img + p)
dst = np.clip(dst, 0, 255)
cv.imshow(window_name, dst)
# 创建滑条
cv.createTrackbar('p', 'Trackbar', 0, 255, change)
# 初始化显示
change(0) # 初始化时调用一次,确保图像显示
cv.waitKey(0)
cv.destroyAllWindows()

二、形态学变换
形态学变换(Morphological Transformations)是一种基于形状的简单变换,它的处理对象通常是二值化图像。形态学变换有两个输入,一个输出:输入为原图像、核(结构化元素),输出为形态学变换后的图像。其基本操作有腐蚀和膨胀,这两种操作是相反的,即较亮的像素会被腐蚀和膨胀。下面我们来说一下核、腐蚀与膨胀的概念。
2.1 核
自适应二值化中,我们已经接触过核了,还记得吗?就是那个在原图中不断滑动计算的3*3的小区域,那其实就是一个3*3的核。
核(kernel)其实就是一个小区域,通常为3*3、5*5、7*7大小,有着其自己的结构,比如矩形结构、椭圆结构、十字形结构,如下图所示。通过不同的结构可以对不同特征的图像进行形态学操作的处理。
2.2 腐蚀(Erosion)
- 作用:收缩白色区域(前景),消除小噪点、细线
- 原理 :结构元素覆盖区域内有黑即黑(取最小值)
- 效果:目标"变瘦",边缘平滑
2.3 膨胀(Dilation)
- 作用:扩展白色区域,填补空洞、断裂
- 原理 :结构元素覆盖区域内有白即白(取最大值)
- 效果:目标"变胖",轮廓连通
2.4 开运算(Opening)
- 操作:先腐蚀后膨胀
- 作用:消除孤立噪点、分离粘连物体
- 特点:保留原主体,去除小干扰
2.5 闭运算(Closing)
- 操作:先膨胀后腐蚀
- 作用:填充内部孔洞、闭合缝隙
- 特点:平滑轮廓,保持主体完整性
2.6 礼帽运算(Top Hat)
- 公式:原图 - 开运算结果
- 作用:提取比背景亮的细节(如微小亮斑)
- 应用:背景均匀时的前景增强
2.7 黑帽运算(Black Hat)
- 公式:闭运算结果 - 原图
- 作用:提取比背景暗的细节(如暗色缺陷)
- 应用:检测深色区域或空洞
2.8 形态学梯度(Morphological Gradient)
- 公式:膨胀图 - 腐蚀图
- 作用:突出边缘轮廓
- 效果:类似边缘检测,但更平滑
核心总结
操作 | 关键作用 | 典型应用场景 |
---|---|---|
腐蚀 | 消除噪点、细化物体 | 去除胡椒噪声 |
膨胀 | 连接断裂、填充孔洞 | 文字修复 |
开运算 | 去噪+保形 | 分离粘连细胞 |
闭运算 | 补洞+平滑 | 填充指纹断裂 |
礼帽 | 提取亮细节 | 显微图像亮斑提取 |
黑帽 | 提取暗细节 | 工业缺陷检测 |
形态学梯度 | 边缘增强 | 目标轮廓提取 |
注:所有操作均依赖**结构元素(核)**的形状和大小选择!
案例
案例一:腐蚀和膨胀
py
import cv2 as cv
import numpy as np
long = cv.imread("images/long.png")
# 定义一个5×5的卷积核
kernel = np.ones((5,5),np.uint8)
# 腐蚀操作cv.erode(src, kernel, dst, anchor, iterations, borderType, borderValue)
# iterations表示迭代次数
dst_erode = cv.erode(long,kernel,iterations=1)
# 膨胀操作cv.dilate(src, kernel, dst, anchor, iterations, borderType, borderValue)
dst_dilate = cv.dilate(long,kernel,iterations=5)
cv.imshow("long",long)
cv.imshow("dst_erode",dst_erode)
cv.imshow("dst_dilate",dst_dilate)
cv.waitKey(0)
cv.destroyAllWindows()

案例二:
py
import cv2 as cv
import numpy as np
car = cv.imread("images/car4.png")
car = cv.resize(car,(640,480))
# 定义一个5×5的卷积核
kernel = np.ones((5,5),np.uint8)
# 开运算 cv.morphologyEx(src,op,kernel) # 先腐蚀再膨胀
open = cv.morphologyEx(car,cv.MORPH_OPEN,kernel)
# 闭运算 cv.morphologyEx(src,op,kernel) # 先膨胀再腐蚀
close = cv.morphologyEx(car,cv.MORPH_CLOSE,kernel)
# 显示图像
cv.imshow("car",car)
cv.imshow("open",open)
cv.imshow("close",close)
cv.waitKey(0)
cv.destroyAllWindows()

案例三:
py
import cv2 as cv
import numpy as np
car = cv.imread("images/car4.png")
car = cv.resize(car,(640,480))
# 定义一个5×5的卷积核
kernel = np.ones((5,5),np.uint8)
# 礼帽运算cv.morphologyEx(src,op,kernel) 原图减"开运算"
dst_top = cv.morphologyEx(car,cv.MORPH_TOPHAT,kernel)
# 黑帽运算cv.morphologyEx(src,op,kernel) "闭运算"的结果图与原图像之差
dst_black = cv.morphologyEx(car,cv.MORPH_BLACKHAT,kernel)
cv.imshow("car",car)
cv.imshow("dst_top",dst_top)
cv.imshow("dst_black",dst_black)
cv.waitKey(0)
cv.destroyAllWindows()

案例四:
py
import cv2 as cv
import numpy as np
car = cv.imread("images/car4.png")
car = cv.resize(car,(640,480))
# 定义一个5×5的卷积核
kernel = np.ones((5,5),np.uint8)
# 形态学梯度 cv2.morphologyEx(src,op,kernel) 像素点在膨胀后的图像值与其在腐蚀后的图像值之差
gradient = cv.morphologyEx(car,cv.MORPH_GRADIENT,kernel)
cv.imshow("gradient",gradient)
cv.imshow("car",car)
cv.waitKey(0)
cv.destroyAllWindows()
