python实现直方图均衡化、自适应直方图均衡化、连接组件标记算法
- 1.直方图均衡化算法详解
- 算法步骤
- 公式
- Python 实现
- 详细解释
- 优缺点
- 2.自适应直方图均衡化算法详解
- 算法步骤
- 公式
- Python 实现
- 详细解释
- 优缺点
- 3.连接组件标记算法详解
- 算法步骤
- 8连通与4连通
- 公式
- Python 实现
- 详细解释
- 优缺点
1.直方图均衡化算法详解
直方图均衡化(Histogram Equalization)是一种用于增强图像对比度的技术。它通过调整图像的灰度值分布,使图像的灰度值更加均匀,从而提升图像的整体对比度。
算法步骤
- 计算原始图像的灰度直方图:统计图像中每个灰度值出现的次数。
- 计算累积分布函数(CDF):累积直方图。
- 应用均衡化公式:将原始图像中的每个灰度值映射到新的灰度值。
- 生成均衡化后的图像。
公式
Python 实现
以下是直方图均衡化算法的Python实现代码:
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
def histogram_equalization(image):
# 将图像转换为灰度图像
grayscale_image = image.convert("L")
image_array = np.array(grayscale_image)
# 计算灰度直方图
hist, bins = np.histogram(image_array.flatten(), bins=256, range=[0, 256])
# 计算累积分布函数(CDF)
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max() / cdf.max() # 归一化
# 使用累积分布函数(CDF)进行均衡化
cdf_min = cdf.min()
cdf_m = np.ma.masked_equal(cdf, 0)
cdf_m = (cdf_m - cdf_min) * 255 / (cdf.max() - cdf_min)
cdf = np.ma.filled(cdf_m, 0).astype('uint8')
# 将均衡化后的灰度值映射到原始图像
equalized_image_array = cdf[image_array]
equalized_image = Image.fromarray(equalized_image_array)
return equalized_image
# 示例用法
if __name__ == "__main__":
image = Image.open('example.jpg') # 打开原始图像
equalized_image = histogram_equalization(image) # 调用直方图均衡化函数
equalized_image.show() # 显示均衡化后的图像
equalized_image.save('equalized_example.jpg') # 保存均衡化后的图像
# 绘制原始图像和均衡化后的直方图
plt.figure()
plt.subplot(121)
plt.title('Original Image Histogram')
plt.hist(np.array(image.convert("L")).flatten(), bins=256, range=[0, 256], color='black')
plt.subplot(122)
plt.title('Equalized Image Histogram')
plt.hist(np.array(equalized_image).flatten(), bins=256, range=[0, 256], color='black')
plt.show()
详细解释
-
读取图像和转换为灰度图像:
image = Image.open('example.jpg') grayscale_image = image.convert("L")
-
计算灰度直方图:
image_array = np.array(grayscale_image) hist, bins = np.histogram(image_array.flatten(), bins=256, range=[0, 256])
-
计算累积分布函数(CDF):
cdf = hist.cumsum() cdf_normalized = cdf * hist.max() / cdf.max()
-
使用CDF进行均衡化:
cdf_min = cdf.min() cdf_m = np.ma.masked_equal(cdf, 0) cdf_m = (cdf_m - cdf_min) * 255 / (cdf.max() - cdf_min) cdf = np.ma.filled(cdf_m, 0).astype('uint8')
-
映射原始灰度值到新的灰度值:
equalized_image_array = cdf[image_array] equalized_image = Image.fromarray(equalized_image_array)
-
显示和保存均衡化后的图像:
equalized_image.show() equalized_image.save('equalized_example.jpg')
-
绘制直方图:
plt.subplot(121) plt.title('Original Image Histogram') plt.hist(np.array(image.convert("L")).flatten(), bins=256, range=[0, 256], color='black') plt.subplot(122) plt.title('Equalized Image Histogram') plt.hist(np.array(equalized_image).flatten(), bins=256, range=[0, 256], color='black') plt.show()
优缺点
优点:
- 增强对比度:提高图像的整体对比度,使细节更加清晰。
- 实现简单:算法简单,易于实现。
缺点:
- 可能引入噪声:在一些情况下,可能会引入不必要的噪声。
- 不适用于所有图像:对于已经具有良好对比度的图像,效果可能不明显。
直方图均衡化是一种简单且有效的图像增强技术,适用于提升图像对比度的应用场景。
2.自适应直方图均衡化算法详解
自适应直方图均衡化(Adaptive Histogram Equalization, AHE)是一种改进的直方图均衡化方法,它在局部区域内(即图像的子块)进行直方图均衡化,而不是对整个图像进行全局均衡化。这种方法可以更好地增强图像的局部对比度,但也可能会引入噪声。
对比度受限的自适应直方图均衡化(Contrast Limited Adaptive Histogram Equalization, CLAHE)是AHE的一种改进版本。CLAHE通过对每个子块中的直方图进行剪裁,限制对比度增强的程度,从而减少噪声的引入。
算法步骤
- 将图像划分为多个子块:将图像分成多个不重叠的子块。
- 对每个子块进行直方图均衡化:计算每个子块的直方图和累积分布函数(CDF),并应用均衡化公式。
- 对每个子块进行对比度限制(CLAHE):对直方图进行剪裁,限制增强的对比度。
- 插值重构图像:对每个子块的均衡化结果进行双线性插值,重构整个图像。
公式
Python 实现
以下是自适应直方图均衡化(CLAHE)的Python实现代码:
import cv2
import numpy as np
from PIL import Image
def adaptive_histogram_equalization(image, clip_limit=2.0, grid_size=(8, 8)):
"""
自适应直方图均衡化 (CLAHE) 算法实现
参数:
image (PIL.Image): 输入图像
clip_limit (float): 对比度限制
grid_size (tuple): 网格大小
返回:
PIL.Image: 均衡化后的图像
"""
# 将图像转换为灰度图像
grayscale_image = image.convert("L")
image_array = np.array(grayscale_image)
# 创建CLAHE对象
clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=grid_size)
# 应用CLAHE算法
equalized_image_array = clahe.apply(image_array)
# 将处理后的数组转换为图像
equalized_image = Image.fromarray(equalized_image_array)
return equalized_image
# 示例用法
if __name__ == "__main__":
image = Image.open('example.jpg') # 打开原始图像
equalized_image = adaptive_histogram_equalization(image) # 调用自适应直方图均衡化函数
equalized_image.show() # 显示均衡化后的图像
equalized_image.save('equalized_example.jpg') # 保存均衡化后的图像
详细解释
-
读取图像和转换为灰度图像:
image = Image.open('example.jpg') grayscale_image = image.convert("L")
-
将灰度图像转换为NumPy数组:
image_array = np.array(grayscale_image)
-
创建CLAHE对象:
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
-
应用CLAHE算法:
equalized_image_array = clahe.apply(image_array)
-
将处理后的数组转换为图像:
equalized_image = Image.fromarray(equalized_image_array)
-
显示和保存均衡化后的图像:
equalized_image.show() equalized_image.save('equalized_example.jpg')
优缺点
优点:
- 增强局部对比度:能够有效增强图像的局部对比度,适用于对局部细节要求较高的图像。
- 减少噪声引入:相比传统的AHE,CLAHE通过对比度限制减少了噪声的引入。
缺点:
- 计算复杂度高:由于需要对每个子块进行处理,计算复杂度较高。
- 实现复杂:相比全局直方图均衡化,实现过程更复杂。
自适应直方图均衡化特别适用于那些需要增强局部对比度的应用场景,如医学影像、卫星图像等。CLAHE进一步改善了AHE的不足,使其在实际应用中更加实用。
3.连接组件标记算法详解
连接组件标记算法(Connected Component Labeling, CCL)是一种用于在二值图像中标识和分类不同连接组件的算法。连接组件是指图像中所有像素值相同且彼此相邻的像素组成的区域。CCL算法用于图像分割、物体检测和图像理解等任务中。
算法步骤
- 初始化标签:为每个像素初始化一个唯一的标签。
- 遍历图像:扫描图像的每个像素,根据邻域像素的标签更新当前像素的标签。
- 合并标签:在遍历过程中记录不同标签的合并关系,形成等价类。
- 第二次遍历:根据标签的合并关系,更新图像中的标签。
8连通与4连通
- 4连通:每个像素与上下左右四个像素相邻。
- 8连通:每个像素与周围八个像素相邻。
公式
Python 实现
以下是连接组件标记算法的Python实现代码:
import numpy as np
import cv2
from matplotlib import pyplot as plt
def connected_component_labeling(image):
"""
连接组件标记算法实现
参数:
image (numpy.ndarray): 二值图像
返回:
numpy.ndarray: 标记后的图像
"""
# 将图像转换为二值图像
binary_image = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)[1]
# 获取图像的行和列
rows, cols = binary_image.shape
# 初始化标签数组
labels = np.zeros((rows, cols), dtype=int)
label = 1 # 初始化标签
# 记录等价类
label_equivalence = {}
# 遍历图像
for i in range(rows):
for j in range(cols):
if binary_image[i, j] == 255: # 如果当前像素为前景像素
# 获取邻域像素的标签
neighbors = []
if i > 0 and labels[i-1, j] > 0:
neighbors.append(labels[i-1, j])
if j > 0 and labels[i, j-1] > 0:
neighbors.append(labels[i, j-1])
if neighbors:
min_label = min(neighbors)
labels[i, j] = min_label
for neighbor in neighbors:
if neighbor != min_label:
if neighbor in label_equivalence:
label_equivalence[neighbor].add(min_label)
else:
label_equivalence[neighbor] = {min_label}
if min_label in label_equivalence:
label_equivalence[min_label].add(neighbor)
else:
label_equivalence[min_label] = {neighbor}
else:
labels[i, j] = label
label += 1
# 合并等价标签
for i in range(rows):
for j in range(cols):
if labels[i, j] in label_equivalence:
min_equivalent_label = min(label_equivalence[labels[i, j]])
labels[i, j] = min_equivalent_label
return labels
# 示例用法
if __name__ == "__main__":
# 创建一个简单的二值图像
binary_image = np.array([
[0, 0, 0, 255, 255, 0, 0, 0],
[0, 255, 255, 255, 255, 255, 0, 0],
[0, 255, 255, 255, 255, 255, 255, 0],
[0, 0, 0, 255, 255, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 255, 255, 0, 0, 0, 0],
[0, 255, 255, 255, 255, 0, 0, 0],
[0, 0, 0, 255, 0, 0, 0, 0]
], dtype=np.uint8)
labeled_image = connected_component_labeling(binary_image)
# 显示结果
plt.imshow(labeled_image, cmap='jet')
plt.title('Connected Component Labeling')
plt.colorbar()
plt.show()
详细解释
-
读取图像并转换为二值图像:
binary_image = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)[1]
-
初始化标签数组:
labels = np.zeros((rows, cols), dtype=int) label = 1 # 初始化标签
-
遍历图像并更新标签:
for i in range(rows): for j in range(cols): if binary_image[i, j] == 255: # 如果当前像素为前景像素 neighbors = [] if i > 0 and labels[i-1, j] > 0: neighbors.append(labels[i-1, j]) if j > 0 and labels[i, j-1] > 0: neighbors.append(labels[i, j-1]) if neighbors: min_label = min(neighbors) labels[i, j] = min_label for neighbor in neighbors: if neighbor != min_label: if neighbor in label_equivalence: label_equivalence[neighbor].add(min_label) else: label_equivalence[neighbor] = {min_label} if min_label in label_equivalence: label_equivalence[min_label].add(neighbor) else: label_equivalence[min_label] = {neighbor} else: labels[i, j] = label label += 1
-
合并等价标签:
for i in range(rows): for j in range(cols): if labels[i, j] in label_equivalence: min_equivalent_label = min(label_equivalence[labels[i, j]]) labels[i, j] = min_equivalent_label
-
显示结果:
plt.imshow(labeled_image, cmap='jet') plt.title('Connected Component Labeling') plt.colorbar() plt.show()
优缺点
优点:
- 简单易实现:基础的CCL算法实现简单,适合初学者学习。
- 有效分割前景和背景:能够有效分割图像中的不同连接组件。
缺点:
- 计算复杂度高:特别是在处理大图像时,计算复杂度较高。
- 内存消耗大:需要额外的内存来存储标签和等价类信息。
连接组件标记算法在图像分割和物体检测中具有广泛的应用,特别适用于需要识别和分类图像中不同区域的任务。通过对等价标签的合并,可以有效地解决图像中的连通区域标记问题。