提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一,简介
在图像中,高光区域指的是那些亮度极高、细节信息极少的区域,这些区域通常呈现出纯白色或接近白色。这是因为高光区域反射了大部分入射光,使得图像传感器捕捉到的信息非常有限。高光区域可能是由多种因素引起的:
- 直接反射:当光线直接照射到物体表面时,如果物体表面非常光滑或有反光材料,光线会被直接反射,形成高光。
- 强光照射:当物体处于强烈的光照下,尤其是当光源非常接近物体时,物体表面的一部分区域会因为光线过于集中而形成高光。
- 镜面反射:当物体表面非常光滑,且光线从特定角度照射时,光线会形成镜面反射,形成一个明亮的高光点。
高光区域在图像中可能会导致图像质量下降,因为它们通常缺乏细节信息,而且可能与其他亮度较低的区域形成对比,导致视觉上的不适。为了改善图像质量,恢复被高光掩盖的细节信息,在图像处理中通常会处理高光区域。在本文中介绍一种基于连通域分析与图像修复的opencv图像高光去除方法:
二,方案简述:
首先通过图像二值化定位过亮区域,这一步骤将图像转换为黑白二值图像,其中高光区域通常表现为白色。接着,使用连通域分析确定这些高光区域,这一分析方法将图像中的像素分为不同的连通区域,从而识别出高光区域。最后,进行图像修复,以恢复被高光区域遮挡的细节信息,提高图像的整体质量。
三,算法实现步骤:
3.1 定位高光区域并生成蒙版
在进行图像处理时,首先将彩色图像转换为灰度图像以简化处理。然后,应用高斯模糊滤波器平滑图像并减少噪声。接着,通过阈值处理将图像转换为二值图像,其中高于阈值的像素被设为白色。为了进一步去除噪声和细化边缘,对二值图像进行腐蚀操作,随后通过膨胀操作扩大高亮区域。连通组件分析用于识别图像中的不同区域,并创建一个与处理后图像大小相同的掩码,初始化为0。遍历分析得到的标签图像,构建包含每个标签的掩码,并计算非零像素数量。如果连通组件的像素数量大于300,则将其添加到最终掩码中。最终,返回的掩码只包含图像中较大的连通组件,可用于进一步的图像分析或处理。连通域分析的函数为cv2.connectedComponentsWithStats()
函数介绍:
cv2.connectedComponentsWithStats 是 OpenCV 中的一个函数,用于对二值图像进行连通组件分析,并返回每个连通组件的标签、位置、大小等信息。该函数广泛应用于图像分割、目标检测、形状分析等任务。
输入:
● binary_image: 一个二值图像,通常是通过阈值处理得到的,其中非零像素表示前景,零像素表示背景。
● connectivity: 邻域连接性,可以是 4 或 8。4 表示仅考虑水平和垂直方向上的相邻像素,8 表示考虑水平和垂直方向以及四个对角线方向上的相邻像素。
输出:
● num_labels: 图像中连通组件的数量。
● labels: 每个像素的标签,表示该像素属于哪个连通组件。
● stats: 每个连通组件的统计信息,包括面积、边界框的位置和大小等。
● centroids: 每个连通组件的中心坐标
代码案例:
def create_mask(image):
# 定义一个函数 create_mask,接受一个名为 image 的参数,该参数是一个 OpenCV 图像对象。
# 将输入的彩色图像转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 对灰度图像应用高斯模糊滤波器
blurred = cv2.GaussianBlur(gray, (9,9), 0)
# 对模糊后的图像应用阈值处理,将其转换为二值图像
_, thresh_img = cv2.threshold(blurred, 230, 255, cv2.THRESH_BINARY)
kernel = np.ones((3, 3), dtype=np.uint8)
# 对二值图像应用腐蚀操作,去除噪声
thresh_img = cv2.erode(thresh_img,kernel, iterations=2)
# 对腐蚀后的图像应用膨胀操作,扩大高亮区域
thresh_img = cv2.dilate(thresh_img, kernel,iterations=4)
# 对阈值处理后的图像进行连通组件分析
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh_img, connectivity=8)
# 创建一个与阈值处理后的图像大小相同的掩码,所有像素初始化为0
mask = np.zeros(thresh_img.shape, dtype="uint8")
# 遍历连通组件分析得到的标签图像中的所有唯一标签
for label in np.unique(labels):
# 如果标签是背景标签(通常为0),则忽略它
if label == 0:
continue
# 否则,构建包含当前标签的掩码,并计算掩码中非零像素的数量
labelMask = np.zeros(thresh_img.shape, dtype="uint8")
labelMask[labels == label] = 255
# 显示当前标签的掩码
numPixels = cv2.countNonZero(labelMask) # 计算掩码中非零像素的数量
# 如果连通组件中的像素数量足够大,则将其添加到我们的掩码中
if numPixels > 300:
cv2.imshow("mask", labelMask)
mask = cv2.add(mask, labelMask) # 将当前标签的掩码与之前创建的掩码相加
return mask # 返回最终的掩码
3.2 图像高光区域修复
在获取到图像的高光区域后,下一步就是对图像的高光区域进行修复,opencv提供了一个图像修复的函数cv2.inpaint。函数介绍:
cv2.inpaint 是 OpenCV 中的一个函数,用于在图像中填充遮挡区域。这个函数可以用于修复图像中的污点、划痕或其他类型的遮挡,从而恢复被遮挡部分的图像内容。
输入
● src: 输入的图像,这是您想要修复的图像。
● inpaintMask: 输入的掩码,该掩码标记了需要修复的区域。如果掩码中的像素值为255,则对应的图像像素将被修复;如果掩码中的像素值为0,则对应的图像像素将被保留不变。
● inpaintRadius: 修复的半径,这个参数定义了修复区域的大小。较大的半径可以更好地修复遮挡区域,但可能会影响周围像素。
● flags: 用于指定修复算法。cv2.INPAINT_TELEA 和 cv2.INPAINT_NS 是两种常见的修复算法。cv2.INPAINT_TELEA 是基于偏微分方程的算法,适用于较小的修复区域;cv2.INPAINT_NS 是基于非结构化稀疏样本的算法,适用于较大的修复区域。
输出
● inpainted_image: 返回一个修复后的图像,该图像包含遮挡区域的修复内容。
函数使用:
inpainted_image = cv2.inpaint(img, mask, 10, cv2.INPAINT_TELEA)
四,整体代码实现
代码如下(示例):
import cv2
import numpy as np
def create_mask(image):
# 定义一个函数 create_mask,接受一个名为 image 的参数,该参数是一个 OpenCV 图像对象。
# 将输入的彩色图像转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 对灰度图像应用高斯模糊滤波器
blurred = cv2.GaussianBlur(gray, (9,9), 0)
# 对模糊后的图像应用阈值处理,将其转换为二值图像
_, thresh_img = cv2.threshold(blurred, 230, 255, cv2.THRESH_BINARY)
kernel = np.ones((3, 3), dtype=np.uint8)
# 对二值图像应用腐蚀操作,去除噪声
thresh_img = cv2.erode(thresh_img,kernel, iterations=2)
# 对腐蚀后的图像应用膨胀操作,扩大高亮区域
thresh_img = cv2.dilate(thresh_img, kernel,iterations=4)
# 对阈值处理后的图像进行连通组件分析
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh_img, connectivity=8)
# 创建一个与阈值处理后的图像大小相同的掩码,所有像素初始化为0
mask = np.zeros(thresh_img.shape, dtype="uint8")
# 遍历连通组件分析得到的标签图像中的所有唯一标签
for label in np.unique(labels):
# 如果标签是背景标签(通常为0),则忽略它
if label == 0:
continue
# 否则,构建包含当前标签的掩码,并计算掩码中非零像素的数量
labelMask = np.zeros(thresh_img.shape, dtype="uint8")
labelMask[labels == label] = 255
# 显示当前标签的掩码
numPixels = cv2.countNonZero(labelMask) # 计算掩码中非零像素的数量
# 如果连通组件中的像素数量足够大,则将其添加到我们的掩码中
if numPixels > 300:
cv2.imshow("mask", labelMask)
mask = cv2.add(mask, labelMask) # 将当前标签的掩码与之前创建的掩码相加
return mask # 返回最终的掩码
img = cv2.imread(r"F:\traditional_vison\1724045476967.png")
mask = create_mask(img)
inpainted_image = cv2.inpaint(img, mask, 10, cv2.INPAINT_TELEA)
cv2.imshow("mask2",inpainted_image)
cv2.waitKey(0)
五,效果:
高光图像:
高光区域:
修正后的图像: