形态学(Morphology)是基于数学形态学理论的一类图像处理操作,广泛应用在目标提取、噪声去除、轮廓强化、背景分离等视觉场景中。顶帽(Top-hat)与黑帽(Black-hat)是形态学中两个非常重要的变换,通过与开运算、闭运算的组合,可用于突出图像中的细节、增强局部区域的亮暗结构。
形态学基础
1. 腐蚀(Erosion)
将结构元素(kernel)在图像上滑动,使前景区域"缩小"。
2. 膨胀(Dilation)
将结构元素覆盖到图像,使前景区域"扩大"。
3. 开运算(Opening)
先腐蚀,再膨胀
消除小的亮噪声、分离粘连物体。
数学形式:
Open(I) = Dilate(Erode(I))
4. 闭运算(Closing)
先膨胀,再腐蚀
填补小黑洞、连接断裂区域。
数学形式:
Close(I) = Erode(Dilate(I))
顶帽和黑帽正是基于这两个操作构建的。
顶帽(Top-hat)操作原理
1. 数学定义
顶帽操作定义为:

即:
原图 - 开运算后的图
2. 直观理解
开运算会消除图像中 比结构元素(kernel)小的亮区域。
顶帽结果 = 原图中 所有被开运算去掉的小亮结构。
因此,顶帽能够突出:
- 小的、孤立的亮点
- 局部过亮细节
- 线状或点状稀疏高光
它常用于:
- 光照不均场景下的亮点提取
- 文本增强(白底黑字)
- 医学图像的小亮特征检测
- 车牌、道路高光线增强
3. 形象例子
如果原图是:
背景(暗) + 小亮点对象
而开运算的输出类似:
背景(暗)
那么顶帽 = 小亮点部分。
黑帽(Black-hat)操作原理
1. 数学定义
黑帽操作定义为:

即:
闭运算的图 - 原图
2. 直观理解
闭运算会消除图像中 比结构元素小的暗区域(黑区域)。
黑帽得到的就是:
- 原图中被闭运算"填补"的那部分暗细节
- 即局部的小黑区域、暗凹痕、小黑线条
黑帽适合提取:
- 文本阴影等暗字条(黑底白字也适用)
- 图像中暗线、暗点
- 医学图像中黑色微结构
- 背景不均时的暗区域补偿
OpenCV 中的顶帽与黑帽 API
OpenCV 提供统一函数 cv2.morphologyEx():
python
dst = cv2.morphologyEx(src, op, kernel)
其中:
- 顶帽:
cv2.MORPH_TOPHAT - 黑帽:
cv2.MORPH_BLACKHAT
示例
提取亮细节与暗细节
python
import cv2
import numpy as np
# --------------------------------------------
# 1. 构建一张带亮点、暗点、亮线、暗线的测试图
# --------------------------------------------
img = np.full((400, 400), 150, dtype=np.uint8) # 灰度背景(150)
# 添加亮点
cv2.circle(img, (100, 100), 5, 255, -1)
cv2.circle(img, (150, 250), 8, 255, -1)
# 添加暗点
cv2.circle(img, (300, 100), 6, 50, -1)
cv2.circle(img, (250, 300), 8, 30, -1)
# 添加亮线
cv2.line(img, (50, 350), (350, 350), 255, 3)
# 添加暗线
cv2.line(img, (50, 50), (350, 50), 30, 3)
# --------------------------------------------
# 2. 定义结构元素
# --------------------------------------------
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (31, 31))
# --------------------------------------------
# 3. 顶帽和黑帽操作
# --------------------------------------------
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
# --------------------------------------------
# 4. 显示效果
# --------------------------------------------
cv2.imshow("Synthetic Original", img)
cv2.imshow("Top-hat (highlight bright details)", tophat)
cv2.imshow("Black-hat (highlight dark details)", blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()
执行结果:

自动补偿光照不均
python
import cv2
import numpy as np
# --------------------------------------------------------------
# 1. 自定义构建一张具有光照不均 + 图案的测试图片
# --------------------------------------------------------------
def create_test_image():
# 基础灰度背景
h, w = 400, 400
img = np.full((h, w), 120, dtype=np.uint8)
# 构造光照梯度(左上亮、右下暗)
grad_x = np.linspace(50, -50, w)
grad_y = np.linspace(50, -50, h)
gradient = np.add.outer(grad_y, grad_x).astype(np.int16)
img = np.clip(img + gradient, 0, 255).astype(np.uint8)
# 添加亮点
cv2.circle(img, (100, 200), 15, 255, -1)
cv2.circle(img, (300, 100), 10, 230, -1)
# 添加暗点
cv2.circle(img, (200, 300), 15, 20, -1)
cv2.circle(img, (100, 100), 10, 50, -1)
# 添加亮线 / 暗线
cv2.line(img, (50, 350), (350, 350), 255, 4)
cv2.line(img, (50, 50), (350, 50), 40, 4)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# --------------------------------------------------------------
# 2. 光照校正(你的原函数)
# --------------------------------------------------------------
def correct_illumination(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 结构元素越大,越能提取"整体光照趋势"
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (51, 51))
bg = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)
# 背景图差值(顶帽思想)
corrected = cv2.normalize(gray - bg, None, 0, 255, cv2.NORM_MINMAX)
return corrected
# --------------------------------------------------------------
# 3. 测试
# --------------------------------------------------------------
img = create_test_image() # 自动生成测试图
result = correct_illumination(img)
cv2.imshow("Synthetic Original", img)
cv2.imshow("Corrected Illumination", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
执行结果:

总结
- 顶帽 = 原图 - 开运算
- 黑帽 = 闭运算 - 原图
- 顶帽突出小的亮细节
- 黑帽突出小的暗细节
- 内核大小决定"多大算细节"
- 顶帽用于亮点、亮线增强
- 黑帽用于暗点、暗线增强
- OCR、医学、检测、图像增强常用
- 两者可结合使用改善光照不均和细节