图像处理
三通道的RGB 和 BGR 的图像数据在 NumPy 数组中的形状都是 [H, W, 3],它们的核心区别在于 通道顺序
示例:一个像素值为 [255, 0, 0] 的数组:
- 在 RGB 中表示红色(Red=255, Green=0, Blue=0)
- 在 BGR 中表示蓝色(Blue=255, Green=0, Red=0)
在图像处理中直方图用来表示图像中像素值的分布情况
像素值定义:
像素是数字图像的最小单位,每个像素包含颜色或灰度信息。
- 表现形式:
- 灰度图像:每个像素用一个数值(整数)表示亮度(如0=纯黑,255=纯白)。
- 彩色图像:每个像素由多个通道的值组成(如RGB图像的红、绿、蓝三通道)。
-
直方图的横轴代表像素值,纵轴代表该像素值出现的频率(即有多少个像素具有该值)。 根据图像类型不同,直方图分为:
(1) 灰度图像直方图
ht = np.histogram(data, bins) '''功能:使用NumPy计算输入图像数据(data)的直方图。 参数: data:输入图像(通常为灰度图像,像素值范围0~255)。 bins:直方图的区间数(例如256个灰度级)。 返回值: ht 是一个元组,包含两个数组: ht[0]:每个bin的频数(即有多少像素落在该区间)。 例如,ht表示灰度值在[0, 1)范围内的像素数量,实际也就是落在0上的数量。 ht[1]:每个bin的边界值(长度为bins + 1)。 例如,ht = [0, 1, 2, ..., 255](若bins=255)。''' - 横轴:灰度级(通常0~255,0为黑,255为白)。
- 纵轴:对应灰度级的像素数量。
- 示例:
- 若直方图左侧(低灰度值)峰值高,说明图像偏暗。
- 右侧(高灰度值)峰值高,说明图像偏亮。
-
(2) 彩色图像直方图
- 通常分别绘制 R、G、B三个通道的直方图,表示各颜色分量的分布。
- 也可能包含亮度直方图(将RGB转换为灰度后的分布)。
-
对比度衡量的是图像中最亮部分(高光)与最暗部分(阴影)之间的亮度差异。差异越大,对比度越高;
- 高对比度:亮部非常亮,暗部非常暗,界限分明(如黑白分明的剪影)。
- 低对比度:亮部和暗部接近,整体显得灰蒙蒙(如雾天拍摄的照片)。
-
1.半径计算权重参数矩阵
-
半径计算权重参数矩阵指的是:在图像处理中,根据一个给定的半径(Radius)值,来计算一个核(Kernel),这个核本身就是一个包含了所有权重参数的矩阵,用于后续的滤波操作。
2. 什么是“半径”(Radius)?
·在图像处理中,半径定义了核的大小以及模糊的程度。
•物理意义:它决定了在模糊一个像素时,需要参考其周围多大范围内的像素。
•数学关系:核的尺寸,通常与半径 r的关系是:size = 2 * r + 1。
•例如:半径 r = 2,则核的大小是 5x5。
•半径越大,参与的像素范围越广,模糊效果越强烈。
3. 什么是“权重参数矩阵”?
这就是核本身。它是一个矩阵,矩阵中的每一个值代表一个权重。这个权重决定了对应位置的像素对中心像素最终值的“贡献”有多大。权重越高,该像素的影响就越大。
1
1
0
1
1
# 根据半径计算权重参数矩阵 g_para = {}#定义了一个全局字典 g_para用于缓存已经计算过的权重矩阵,避免重复计算。 def getPara(radius=5): global g_para m = g_para.get(radius, None) if m is not None: #如果该半径的矩阵已经计算过(在g_para中),则直接返回。 return m size = radius * 2 + 1 m = np.zeros((size, size)) #创建一个大小为 (2radius+1) x (2radius+1) 的矩阵m,并初始化为0。 for h in range(-radius, radius + 1):#然后遍历这个矩阵的每一个位置(相对于中心点的偏移h和w),计算每个位置的权重值(计算时将矩阵的中心点位置当作(0,0)。 for w in range(-radius, radius + 1): if h == 0 and w == 0: continue m[radius + h, radius + w] = 1.0 / math.sqrt(h ** 2 + w ** 2) #sqrt(h² + w²) 计算当前点 (h,w) 到中心点 (0,0) 的几何距离。 #物理意义:距离越近的像素对中心点影响越大,符合图像局部相关性原理,权重值等于几何距离的倒数 m /= m.sum() #然后对矩阵进行归一化(除以所有元素之和),目的:卷积操作后图像整体亮度不变。 g_para[radius] = m return m #存储计算结果到全局缓存,返回生成的权重矩阵 -
三、zmIce
1、ACE自适应对比度增强
是一种用于提升图像视觉质量的局部图像处理技术,它特别擅长增强低对比度图像中的细节
•局部自适应:不同于全局拉伸或直方图均衡化,ACE能根据图像不同区域的特性进行自适应增强,效果通常更自然。
•细节突出:能有效增强低对比度图像中的细节信息,提高图像的视觉清晰度。
-
# 常规的ACE实现 '''还有一些其他场景1. 手机摄影增强 ○ 参数:ratio=4, radius=7, clip=30 ○ 效果:提升暗部细节同时抑制高光过曝 2.医学影像处理 ○ 参数:ratio=1.8, radius=3, clip=15 ○效果:增强微血管对比度而不放大噪声 3. 工业检测 ○ 参数:ratio=5.0, radius=2, clip=50 ○效果:突出产品表面划痕缺陷''' def zmIce(I, ratio=4, radius=300,clip=1): #函数的目标是实现一种自适应的图像对比度增强, para = getPara(radius) #这里调用之前定义的getPara函数,根据给定的半径radius生成一个(2radius+1) x (2radius+1)的权重矩阵。 height, width = I.shape zh = [] zw = [] #创建两个列表zh和zw,分别用于行和列的索引扩展。 n = 0 ''' while n < radius: zh.append(0) #在zh列表的前面添加radius个0(即镜像了第0行radius次) zw.append(0) #在zw列表的前面添加radius个0(即镜像了第0列radius次) n += 1 for n in range(height): zh.append(n) #然后,将原始图像的高度索引(0到height - 1)添加到zh中 for n in range(width): zw.append(n) #将原始图像的宽度索引(0到width - 1)添加到zw中 n = 0 while n < radius: zh.append(height - 1) #最后,在zh列表的后面添加radius个height - 1(即镜像了最后一行radius次) zw.append(width - 1) #在zw列表的后面添加radius个width - 1(即镜像了最后一列radius次) n += 1 Z = I[np.ix_(zh, zw)] #使用扩展后的行列索引创建新的扩展图像Z:尺寸为(height+2*radius, width+2*radius)实例见图一''' res = np.zeros(I.shape) for h in range(radius * 2 + 1): for w in range(radius * 2 + 1): if para[h][w] == 0: continue '''为什么处理之后就能达到去雾的效果?利用大半经radius=300生成的Z当背景(若为雾图像则此时Z的亮度亮度主要由雾决定) ,然后通过原始图片减去背景(雾的亮度)得到原始图片比雾亮/暗多少,ratio 增强多少倍效果,np.clip(..., -1, 1) 是防止调整过度,说明见图二''' res += (para[h][w] * np.clip((I - Z[h:h + height, w:w + width]) * ratio, -clip, clip)) return res #res的物理意义① 对比度增强量:正值:表示该像素需要变亮 负值:表示该像素需要变暗 绝对值大小:表示增强强度 '''# 单通道ACE快速增强实现,代码逻辑见图三''' def zmIceFast(I, ratio, radius): #输入参数:图像 I,增强系数 ratio,邻域半径 radius。 height, width = I.shape[:2] if min(height, width) <= 2: return np.zeros(I.shape) + 0.5 #如果图像的最小边长小于等于2,直接返回一个0.5的常数矩阵(避免递归到太小图像) Rs = cv2.resize(I, (int((width + 1) / 2), int((height + 1) / 2))) #下采样:将图像缩小到大约一半的大小 Rf = zmIceFast(Rs, ratio, radius) # 递归调用,对缩小后的图像递归调用快速ACE算法。 Rf = cv2.resize(Rf, (width, height)) Rs = cv2.resize(Rs, (width, height)) #将递归结果Rf和之前下采样的图像Rs都上采样到原始尺寸。 return Rf + zmIce(I, ratio, radius) - zmIce(Rs, ratio, radius)
-
图一
-
tu

-
图二
-

-
图三
-
---------------------------------------------------------------------------------------------------------------------
-
d = np.cumsum(ht[0]) / float(data.size) '''累积分布函数(CDF)其主要目的是将图像的像素值分布进行重新映射,以改善对比度或实现特定增强效果。 数学原理: 新像素值=round((L−1)×CDF(原像素值)) L 是灰度级数(如256),CDF是累积概率(范围0~1) 核心目的:直方图均衡化''' '''功能:计算直方图的累积分布函数(CDF),表示像素值的累积概率分布。 步骤分解: np.cumsum(ht[0]): 对直方图频数ht计算累积和。 例如,若ht = [10, 20, 5],则np.cumsum(ht) = [10, 30, 35]。 / float(data.size): 将累积和除以图像总像素数(data.size),归一化为概率值(范围0~1)。 例如,若总像素数为100,则d = [0.1, 0.3, 0.35]。d[i]表示灰度值 ≤ i 的像素在图像中的占比'''---------------------------------------------------------------------------------------------------------------------
-
完整的图像去雾代码

-
import cv2 import numpy as np import math # 线性拉伸处理 # 去掉最大最小0.5%的像素值 线性拉伸至[0,1] def stretchImage(data, s=0.005, bins=2000): ht = np.histogram(data, bins) #使用numpy的histogram函数计算输入图像数据的直方图。 #返回值ht是一个元组,包含两个数组: #第一个数组是每个bin的频数(即有多少个像素落在该区间) #第二个数组是bin的边界(长度为bins+1) d = np.cumsum(ht[0]) / float(data.size) #计算直方图的累积分布函数(CDF)。 #np.cumsum(ht[0])计算频数的累积和。 #除以总像素数(data.size)得到累积概率分布,即每个bin的累积概率。 lmin = 0 lmax = bins - 1 while lmin < bins: if d[lmin] >= s: break lmin += 1 while lmax >= 0: if d[lmax] <= 1 - s: break lmax -= 1 return np.clip((data - ht[1][lmin]) / (ht[1][lmax] - ht[1][lmin]), 0, 1) #对图像数据进行线性拉伸变换: #将原图像数据减去找到的最小边界值(ht[1][lmin],即第lmin个bin的左边界) #然后除以(最大边界值ht[1][lmax]减去最小边界值)的差,将像素值映射到[0,1]区间。 #np.clip函数将超出[0,1]范围的值截断到0和1之间。 # 根据半径计算权重参数矩阵 g_para = {}#定义了一个全局字典 g_para用于缓存已经计算过的权重矩阵,避免重复计算。 def getPara(radius=5): global g_para m = g_para.get(radius, None) if m is not None: #如果该半径的矩阵已经计算过(在g_para中),则直接返回。 return m size = radius * 2 + 1 m = np.zeros((size, size)) #创建一个大小为 (2radius+1) x (2radius+1) 的矩阵m,并初始化为0。 for h in range(-radius, radius + 1):#然后遍历这个矩阵的每一个位置(相对于中心点的偏移h和w),计算每个位置的权重值(计算时将矩阵的中心点位置当作(0,0)。 for w in range(-radius, radius + 1): if h == 0 and w == 0: continue m[radius + h, radius + w] = 1.0 / math.sqrt(h ** 2 + w ** 2) #sqrt(h² + w²) 计算当前点 (h,w) 到中心点 (0,0) 的几何距离。 #物理意义:距离越近的像素对中心点影响越大,符合图像局部相关性原理,权重值等于几何距离的倒数 m /= m.sum() #然后对矩阵进行归一化(除以所有元素之和),目的:卷积操作后图像整体亮度不变。 g_para[radius] = m return m #存储计算结果到全局缓存,返回生成的权重矩阵 # 常规的ACE实现 def zmIce(I, ratio=4, radius=300): #函数的目标是实现一种自适应的图像对比度增强, para = getPara(radius) #这里调用之前定义的getPara函数,根据给定的半径radius生成一个(2radius+1) x (2radius+1)的权重矩阵。 height, width = I.shape zh = [] zw = [] #创建两个列表zh和zw,分别用于行和列的索引扩展。 n = 0 ''' while n < radius: zh.append(0) #在zh列表的前面添加radius个0(即镜像了第0行radius次) zw.append(0) #在zw列表的前面添加radius个0(即镜像了第0列radius次) n += 1 for n in range(height): zh.append(n) #然后,将原始图像的高度索引(0到height - 1)添加到zh中 for n in range(width): zw.append(n) #将原始图像的宽度索引(0到width - 1)添加到zw中 n = 0 while n < radius: zh.append(height - 1) #最后,在zh列表的后面添加radius个height - 1(即镜像了最后一行radius次) zw.append(width - 1) #在zw列表的后面添加radius个width - 1(即镜像了最后一列radius次) n += 1 Z = I[np.ix_(zh, zw)] #使用扩展后的行列索引创建新的扩展图像Z:尺寸为(height+2*radius, width+2*radius)实例见图一''' res = np.zeros(I.shape) for h in range(radius * 2 + 1): for w in range(radius * 2 + 1): if para[h][w] == 0: continue '''为什么处理之后就能达到去雾的效果?利用大半经radius=300生成的Z当背景(若为雾图像则此时Z的亮度亮度主要由雾决定) ,然后通过原始图片减去背景(雾的亮度)得到原始图片比雾亮/暗多少,ratio 增强多少倍效果,np.clip(..., -1, 1) 是防止调整过度,说明见图二图三''' res += (para[h][w] * np.clip((I - Z[h:h + height, w:w + width]) * ratio, -1, 1)) return res #res的物理意义① 对比度增强量:正值:表示该像素需要变亮 负值:表示该像素需要变暗 绝对值大小:表示增强强度 '''# 单通道ACE快速增强实现,代码逻辑见图四''' def zmIceFast(I, ratio, radius): #输入参数:图像 I,增强系数 ratio,邻域半径 radius。 height, width = I.shape[:2] if min(height, width) <= 2: return np.zeros(I.shape) + 0.5 #如果图像的最小边长小于等于2,直接返回一个0.5的常数矩阵(避免递归到太小图像) Rs = cv2.resize(I, (int((width + 1) / 2), int((height + 1) / 2))) #下采样:将图像缩小到大约一半的大小 Rf = zmIceFast(Rs, ratio, radius) # 递归调用,对缩小后的图像递归调用快速ACE算法。 Rf = cv2.resize(Rf, (width, height)) Rs = cv2.resize(Rs, (width, height)) #将递归结果Rf和之前下采样的图像Rs都上采样到原始尺寸。 return Rf + zmIce(I, ratio, radius) - zmIce(Rs, ratio, radius) # rgb三通道分别增强 ratio是对比度增强因子 radius是卷积模板半径 def zmIceColor(I, ratio=4, radius=3): res = np.zeros(I.shape) # 初始形化一个与输入图像I状相同的全零数组res,用于存储增强后的图像。 for k in range(3): res[:, :, k] = stretchImage(zmIceFast(I[:, :, k], ratio, radius)) return res """ 整体流程: 1、启动与输入:程序从 main 函数开始,读取一张名为 foggy.jpg 的输入图像。 2、预处理:将图像数据从整数范围 [0, 255] 归一化到浮点数范围 [0, 1]。几乎所有图像处理算法(如CNN、Retinex、ACE)都会先将图像归一化到 [0,1] 或 [-1,1]: 1)统一输入尺度:使算法参数(如 ratio=4、radius=3)在不同分辨率/亮度的图像上效果一致 2)适配深度学习框架:若后续接入神经网络,归一化是必须的预处理步骤 3)降低数值敏感:浮点数运算对硬件(CPU/GPU)更友好,不易因整数溢出导致崩溃 3、分通道处理:将彩色图像拆分为R, G, B三个独立的通道。 4、核心增强(对每个通道): 使用快速多尺度ACE算法 (zmIceFast) 对每个通道进行处理。该算法通过递归,高效地计算了每个像素与其非常大邻域内像素的相对关系,从而显著提升了局部对比度。 5、后处理(对每个通道): 对增强后的通道数据进行线性拉伸 (stretchImage),剔除极端值,使灰度分布更饱满,覆盖整个 [0, 1] 范围。拉伸后,图像会更清晰,暗部和亮部细节更容易分辨。 类似于 直方图均衡化,但更加温和,只是做线性拉伸。 6、合并通道:将处理好的R, G, B三个通道合并回一幅彩色图像。 7、输出:将最终结果的数据范围从 [0, 1] 转换回 [0, 255],并保存为 out.jpg 文件。 """ # 主函数 if __name__ == '__main__': img = cv2.imread('foggy5.jpg') res = zmIceColor(img / 255.0) * 255 cv2.imwrite('out7.jpg', res)
更多推荐

所有评论(0)