直方图均衡化和自适应直方图均衡化

前言: Hello大家好,我是Dream。 均衡化是数字图像处理中常用的一种技术,用于增强图像的视觉效果和对比度。,今天我们将实现对同一张图像的直方图均衡化自适应直方图均衡化处理,学习一下两者的的基本原理和实现过程,一起来看看吧~

一、直方图均衡化

直方图均衡化(Histogram Equalization)是一种图像处理技术,通过重新分配图像灰度级别来增强图像的对比度和视觉效果。它基于整个图像的灰度直方图来调整像素的灰度值分布。通过增加较暗区域的亮度和减少较亮区域的亮度,直方图均衡化可以使图像的灰度级别分布更均匀,从而增强图像的细节和对比度。

1.得到灰度图

通过三同道的彩色图生成单通道的灰度图
首先,我们使用PIL库中的Image.open()函数读取彩色图像,并将其转换为数组。然后,我们获取图像的高度和宽度,并创建一个与原始图像大小相同、数据类型为uint8的全黑数组gray_img,用于保存灰度图像。

接着,我们遍历每个像素,将三个通道的值求平均,并将结果保存到灰度图像中。由于RGB图像的三个通道具有相同的权重,因此将三个通道的值求平均可以得到一个比较准确的灰度值。

然后,我们将灰度图像转换为PIL图像对象,并使用Matplotlib库中的plt.imshow()函数显示彩色图像和灰度图像。最后,我们使用PIL库中的Image.save()函数将灰度图像保存为文件。

import numpy as np
import cv2
from PIL import Image
import matplotlib.pyplot as plt

# 读取彩色图像
img = Image.open('image.jpg')

# 将图像转换为数组
img_arr = np.array(img)

# 获取图像的高度和宽度
h, w, _ = img_arr.shape

# 创建一个新的数组,用于保存灰度图像
gray_img = np.zeros((h, w), dtype=np.uint8)

# 遍历每个像素,将三个通道的值求平均,并保存到灰度图像中
for i in range(h):
    for j in range(w):
        gray_img[i, j] = int(np.mean(img_arr[i, j]))

# 将灰度图像转换为PIL图像对象
gray_pil_img = Image.fromarray(gray_img)
plt.imshow(img)
plt.title('imge')
plt.axis('off')
plt.show()
plt.imshow(gray_pil_img, cmap='gray')
plt.title('gray_pil_imge')
plt.axis('off')
plt.show()
# 保存灰度图像
gray_pil_img.save('gray_image.jpg')

在这里插入图片描述
在这里插入图片描述

2. 直方图统计

使用PIL库中的Image.open()函数读取灰度图像,并使用convert('L')方法将图像转换为灰度模式。然后,我们获取图像的宽度和高度,并创建一个长度为256的全0列表hist,用于保存直方图统计结果。

接着,遍历每个像素,获取其灰度值,并将对应的直方图计数器加1。最后,我们输出直方图统计结果,即每个灰度值出现的像素数。

# 读取灰度图像
gray_img = Image.open('gray_image.jpg').convert('L')
width, height = gray_img.size

# 统计直方图
hist = [0] * 256
for y in range(height):
    for x in range(width):
        pixel = gray_img.getpixel((x, y))
        hist[pixel] += 1
print(hist)
# 输出直方图统计结果
for i in range(len(hist)):
    print("灰度值 %d: %d 个像素" % (i, hist[i]))

在这里插入图片描述

3. 绘制直方图

# 绘制直方图
plt.bar(range(256), hist)
plt.show()

在这里插入图片描述

4. 直方图均衡化

使图片有更好的视觉效果,有更高的对比度,即像素的灰度分布更平均
首先,我们使用PIL库中的histogram()函数对灰度图像进行直方图统计,得到一个长度为256的列表equ_img,其中每个元素表示对应灰度级别的像素数量。

接着,我们创建一个空列表lut,用于保存灰度级别的映射表。然后,通过遍历equ_img列表,将每个灰度级别的像素数量除以255得到一个步长step,表示每个灰度级别在均衡化后的直方图中所占的比例。接下来,我们定义一个变量n,初始化为0,用于记录当前累积的像素数量。

在内层循环中,我们遍历256个灰度级别,并将当前累积的像素数量除以步长step得到一个映射值n / step。这个映射值表示当前灰度级别在均衡化后的直方图中所对应的灰度级别。

最后,我们使用PIL库中的point()方法,根据映射表lut将灰度图像进行映射,得到均衡化后的图像equ_img。在这里,lut列表中的值被用作灰度级别的映射,'L'参数表示输出图像的模式为灰度模式。

这样,经过直方图均衡化处理后,图像的灰度分布将更加均匀,增强了图像的对比度和细节。

# 直方图均衡化
equ_img = gray_img.histogram()
lut = []
for b in range(0, len(equ_img), 256):
    step = sum(equ_img[b:b+256]) / 255
    n = 0
    for i in range(256):
        lut.append(n / step)
        n += equ_img[b+i]
equ_img = gray_img.point(lut, 'L')

# 显示原始图像和均衡化后的图像
plt.imshow(gray_img, cmap='gray')
plt.title('Original Image')
plt.axis('off')
plt.show()

plt.imshow(equ_img, cmap='gray')
plt.title('Equalized Image')
plt.axis('off')
plt.show()

# 保存原始图像和均衡化后的图像
gray_img.save('Original.jpg')
equ_img.save('Equalized.jpg')

# 统计均衡化后的直方图
hist_equ = equ_img.histogram()

# 绘制均衡化前后的直方图
plt.hist(gray_img.histogram(), 256, [0, 256])
plt.title('Original Image')
plt.xlim([0, 256])
plt.show()

plt.hist(hist_equ, 256, [0, 256])
plt.title('Equalized Image')
plt.xlim([0, 256])
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、自适应直方图均衡化

自适应直方图均衡化(Adaptive Histogram Equalization)是直方图均衡化的一种变体,它考虑到图像中不同区域的局部差异。与直方图均衡化不同,自适应直方图均衡化将图像分成多个小块,并在每个小块内独立地应用直方图均衡化。通过这种方式,自适应直方图均衡化可以更好地保留图像的细节,并避免过度增强噪声。自适应直方图均衡化可以根据图像的局部特征自动调整每个小块的灰度级别,以实现更精细的图像增强。

1.自适应直方图均衡化(AHE)

AHE是一种局部直方图均衡化方法,它将图像分成若干个小区域,对每个小区域进行直方图均衡化处理,从而增强图像的对比度。该算法的核心思想是在每个小区域内计算直方图,并将其变换为累积分布函数(CDF),然后将CDF拉伸以增加对比度。因此,AHE可以有效地增强图像中的局部细节信息。
在此处,我们的输入参数包括原始图像img和窗口大小window_size。首先,函数遍历每个像素,获取以该像素为中心的大小为window_size的窗口。如果窗口越界,则跳过该像素。然后,计算窗口的直方图,并计算其累积分布函数。接着,将CDF归一化并拉伸,以增加窗口内像素的对比度。最后,将均衡化后的像素值放回原图中,得到均衡化后的结果。

# 自适应直方图均衡化(AHE)
def adaptive_histogram_equalization(img, window_size):
    # 获取图像大小
    height, width = img.shape[:2]
    # 创建一个全黑的图像
    result = np.zeros((height, width), dtype=np.uint8)
    # 遍历每个像素
    for i in range(height):
        for j in range(width):
            # 获取窗口中心点
            center_x, center_y = i + window_size // 2, j + window_size // 2
            # 如果窗口越界,则跳过
            if center_x < window_size // 2 or center_x >= height - window_size // 2 or center_y < window_size // 2 or center_y >= width - window_size // 2:
                continue
            # 获取窗口
            window = img[center_x - window_size // 2:center_x + window_size // 2 + 1, center_y - window_size // 2:center_y + window_size // 2 + 1]
            # 计算窗口的直方图
            hist, _ = np.histogram(window.ravel(), 256, [0, 256])
            # 计算累积分布函数
            cdf = hist.cumsum()
            # 归一化
            cdf_normalized = cdf * 255 / cdf[-1]
            # 将均衡化后的像素值放回原图中
            result[i][j] = cdf_normalized[img[i][j]]
    return result

2.限制对比度自适应直方图均衡化(CRHE)

CRHE是在AHE的基础上增加了对比度限制。它通过在AHE之后对像素值进行限制,以避免过度增加对比度而导致噪声的出现。该算法的核心思想是先使用AHE增强图像的对比度,然后使用限制对比度的方法对像素值进行截断,从而控制对比度的增加。
在代码中,输入参数包括原始图像img、窗口大小window_size和对比度限制因子clip_limit。首先,调用自己实现的自适应直方图均衡化函数adaptive_histogram_equalization对原始图像进行直方图均衡化处理,得到均衡化后的结果。接着,使用OpenCV库中的cv2.createCLAHE函数创建一个限制对比度的CLAHE对象,并将均衡化后的图像作为输入进行处理。

# 限制对比度自适应直方图均衡化(CRHE)
def contrast_limited_adaptive_histogram_equalization(img, window_size, clip_limit):
    # 使用自己实现的自适应直方图均衡化
    ahe_img = adaptive_histogram_equalization(img, window_size)
    # 使用OpenCV库实现限制对比度自适应直方图均衡化
    clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(window_size, window_size))
    result = clahe.apply(ahe_img)
    return result

3.读取图片

# 读取图片
img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)

4.自适应直方图均衡化

首先创建一个与原始图像img相同大小的全黑图像ahe_result,用于保存处理后的结果。然后,使用一个循环遍历多个窗口尺寸,依次调用自适应直方图均衡化函数adaptive_histogram_equalization对原始图像进行处理,并将处理后的结果加到ahe_result中。最后得到多个尺寸的均衡化结果的平均值,作为最终的均衡化结果。

我们使用了不同尺寸的窗口,分别为50、100、150和200。最后将这四个结果取平均值作为最终结果,这种方法可以提高均衡化的效果,因为不同尺寸的窗口可以捕捉到图像中不同尺度的局部细节信息,从而增强图像的对比度和细节信息,避免过大或过小的窗口对结果产生较大影响。

# 自适应直方图均衡化
# 创建一个和原始图像大小相同的全零数组ahe_result,用于存储最终的自适应直方图均衡化结果

ahe_result = np.zeros_like(img)

# 遍历不同的窗口大小,从50到200,步长为50
for window_size in range(50, 201, 50):
    # 对原始图像img进行自适应直方图均衡化操作,使用当前窗口大小window_size
    ahe_img = adaptive_histogram_equalization(img, window_size)
    # 将每次处理后的图像ahe_img累加到ahe_result中
    ahe_result += ahe_img

# 将ahe_result除以4取整,得到最终的自适应直方图均衡化结果
ahe_result //= 4

5.限制对比度自适应直方图均衡化

首先创建一个与原始图像img相同大小的全黑图像crhe_result,用于保存处理后的结果。然后,使用一个循环遍历多个窗口尺寸,依次调用限制对比度自适应直方图均衡化函数对原始图像进行处理,并将处理后的结果加到crhe_result中。在本例中,设置对比度限制因子clip_limit为2.0。
我们使用了不同尺寸的窗口,分别为50、100、150和200。最后将这四个结果取平均值作为最终结果,避免过大或过小的窗口对结果产生较大影响。

# 限制对比度自适应直方图均衡化
# 创建一个和原始图像大小相同的全零数组crhe_result,用于存储最终的限制对比度自适应直方图均衡化结果

crhe_result = np.zeros_like(img)

# 遍历不同的窗口大小,从50到200,步长为50
for window_size in range(50, 201, 50):
    # 对原始图像img进行限制对比度自适应直方图均衡化操作,使用当前窗口大小window_size和对比度限制参数2.0
    crhe_img = contrast_limited_adaptive_histogram_equalization(img, window_size, 2.0)
    # 将每次处理后的图像crhe_img累加到crhe_result中
    crhe_result += crhe_img

# 将crhe_result除以4取整,得到最终的限制对比度自适应直方图均衡化结果
crhe_result //= 4

6.可视化显示结果

# 显示结果
fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(12, 8))
ax[0].imshow(img, cmap='gray')
ax[0].set_title('Original1 Image')
ax[1].imshow(ahe_result, cmap='gray')
ax[1].set_title('AHE1 Image')
ax[2].imshow(crhe_result, cmap='gray')
ax[2].set_title('CRHE1 Image')
plt.show()

在这里插入图片描述

三、对比总结

直方图均衡化(Histogram Equalization)和自适应直方图均衡化(Adaptive Histogram Equalization)都是用于图像增强的技术,目的是改善图像的对比度和视觉效果。它们的主要区别在于处理图像的方式和局部性

直方图均衡化是一种全局的方法,它基于整个图像的灰度直方图来调整像素的灰度值分布。通过使灰度级别在图像中更均匀地分布,直方图均衡化可以增强图像的对比度和细节。它使用累积分布函数将原始图像中的灰度级别映射到一个新的灰度范围,从而实现图像的均衡化。

然而,直方图均衡化是一种全局的方法,它没有考虑到图像中不同区域的局部差异。这可能会导致图像的某些区域过度增强或细节丢失的问题。为了解决这个问题,自适应直方图均衡化应运而生。

自适应直方图均衡化是一种局部的方法,在处理图像时会考虑到不同区域的灰度分布情况。它将图像分成许多小区域,对每个区域独立地应用直方图均衡化。通过这种方式,自适应直方图均衡化可以更好地保留图像细节,并避免过度放大噪声。

自适应直方图均衡化的一种常见变体是自适应直方图均衡化(CLAHE),它在每个小区域中使用对比度限制来防止过度放大噪声。CLAHE的核心思想是将图像分成许多小块,然后对每个小块进行局部直方图均衡化,并对像素值进行裁剪以限制对比度的增强程度。通过这种方式,CLAHE在增强图像细节的同时有效控制了噪声的增强。

总而言之,直方图均衡化是一种全局的方法,通过整个图像的灰度直方图来增强图像对比度。自适应直方图均衡化是一种局部的方法,通过对图像的小块进行独立的直方图均衡化来增强图像,并通过对比度限制来控制噪声的放大

猜你喜欢

转载自blog.csdn.net/weixin_51390582/article/details/132372072
今日推荐