OpenCV(十九)直方图(直方图计算、掩膜、均衡化、自适应均衡化)

本文详细介绍了图像处理中的直方图计算及其应用,包括灰度和彩色图像的直方图、直方图掩膜、直方图均衡化以及自适应直方图均衡化。直方图能反映图像亮度分布,通过均衡化可以提升图像对比度,自适应均衡化则能更好地保留图像细节。代码示例展示了如何使用OpenCV进行直方图处理。
摘要由CSDN通过智能技术生成

目录

一、基础理论

1、原理及作用

2、专业术语

二、直方图计算

函数介绍:

1、灰度图

代码:

 效果:

2、彩色图

代码:

 三、直方图掩膜的应用(mask)

1、基础理论

2、代码

3、效果

 四、直方图均衡化

1、基础理论

2、代码

3、效果 

五、自适应的直方图均衡化

1、基础理论

2、代码

3、效果

总代码

参考资料


一、基础理论

1、原理及作用

作用:

获取图像的强度(灰度)分布

        直方图是数据统计的一种方法,并且将统计值组织到一系列实现定义好的 bin当中。其中, bin为直方图中经常用到的一个概念,可以译为“直条”或“组距”,其数值是从数据中计算出的特征统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征
        图像直方图(Image Histogram)是用以表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素个数。这种直方图中,横坐标的左侧较暗的区域,而右侧较亮的区域。因此—张较暗图片的直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。 (如图,左侧较暗,右侧较亮

         灰度直方图是一幅图像中个像素灰度值出现次数或频数的统计结果,它只反映该图像中灰度值出现的频率,而未反映某一灰度值像素所在的位置。

直方图统计的是每一个灰度值所具有的像素个数。(不同图像直方图可能相同)

 

  

注意:直方图是根据灰度图进行绘制的,而不是彩色图像。 

2、专业术语

BINS:上面的直方图显示每个像素值的像素数,即从0到255。(只需要16个值即可表示直方图,例如:找到介于0到15之间的像素数,然后找到16到31之间,…,240到255之间的像素数。)(因此,您要做的就是将整个直方图分成16个子部分)

DIMS:这是我们为其收集数据的参数的数量。在这种情况下,我们仅收集关于强度值的一件事的数据,所以这里是1。

RANGE:这是您要测量的强度值的范围。通常,它是[0,256],即所有强度值。

二、直方图计算

函数介绍:

注:这部分实现的是python代码

cv.calcHist(images,channels,mask,histSize,ranges [,hist [,accumulate]])
  1. images:它是uint8或float32类型的源图像。它应该放在方括号中,即“ [img]”。
  2. channels:也以方括号给出。它是我们计算直方图的通道的索引。例如,如果输入为灰度图像,则其值为[0]。对于彩色图像,您可以传递[0],[1]或[2]分别计算蓝色,绿色或红色通道的直方图。
  3. mask:图像掩码。为了找到完整图像的直方图,将其指定为“无”。但是,如果要查找图像特定区域的直方图,则必须为此创建一个掩码图像并将其作为掩码。(我将在后面显示一个示例。)
  4. histSize:这表示我们的BIN计数。需要放在方括号中。对于全尺寸,我们通过[256]。
  5. ranges:这是我们的RANGE。通常为[0,256]。
hist = cv2.calcHist([img], [0],   None,         [256], [0, 256])
#                   图像   通道索引 掩码(完整/局部) bin计数 范围

1、灰度图

代码:

#计算直方图(灰度)
def Calculate_Hist():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)  # 0即灰度图,1彩图
    cv2.imshow("img", img)

    # 2、获取并绘制直方图
    hist = cv2.calcHist([img], [0],   None,         [256],  [0, 256])   #获取
    #                   图像   通道索引 掩码(完整/局部) bin计数  范围
    plt.plot(hist)      # 绘图(基于一点或多点)

    # 3、直方图展示
    plt.show()          # 显示

 效果:

打印直方图获取的像素(hist)结果:

前者较亮(直方图偏右)后者较暗(直方图偏左)

 纯黑白:

2、彩色图

代码:

#计算直方图(彩图)
def Calculate_Hist_RGB():
    # 1、读取图片
    img = cv2.imread("Resource/test11.jpg")       #彩图
    cv2.imshow("img", img)

    # 设置颜色通道
    color = ["b", "g", "r"]

    # 2、获取直方图
    for i, c in enumerate(color):           #i是索引,c是内容
        hist = cv2.calcHist([img], [i], None, [256], [0, 256])
        plt.plot(hist, color=c)

    # 3、直方图展示
    plt.legend(["B Channel", "G Channel", "R Channel"])     #批注
    plt.show()

 三、直方图掩膜的应用(mask)

1、基础理论

1、作用
(1)提取感兴趣区域:用预先制作的感兴趣区掩模与待处理图像进行"与“操作,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
(2)屏蔽∶用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
(3)结构特征提取∶用相似性变量或方图像匹配法检测和提取图像中与掩模相似的结构特征。·特殊形状图像制作。

掩膜在遥感影像处理中使用较多,当提取道路或者河流,或者房屋时,通过一个掩膜矩阵来对图像进行像素过滤,然后将我们需要的地物或者标志突出显示出来。(提取感兴趣区域

2、原理

在数字图像处理中,通常使用二维矩阵数组进行掩膜。掩膜是由0和1组成一个二进制图像,利用该掩膜图像要处理的图像进行掩膜,其中1值的区域被处理0值区域被屏蔽,不会处理。
 

2、代码

#掩膜
def Mask():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)
    cv2.imshow("img", img)

    # 2、创建mask
    mask = np.zeros(img.shape, np.uint8)
    mask[100:400, 20:200] = 255                          #白色掩膜
    #   横坐标范围  纵坐标范围
    cv2.imshow("mask", mask)

    # 3、获取mask后的图像
    masked_img = cv2.bitwise_and(img, img, mask=mask)    #把掩膜用于图像
    cv2.imshow("masked_img", masked_img)

    # 4、获取并绘制直方图
    hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])     #全部直方图
    plt.plot(hist_full)
    hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])     #掩膜直方图
    plt.plot(hist_mask)

    # 5、显示直方图
    plt.show()

3、效果

 四、直方图均衡化

1、基础理论

作用:通常用于提高图像的对比度。(强化细节

        想象一下,如果一副图像中的大多数像素点的像素值都集中在某一个小的灰度值值范围之内会怎样呢?如果一幅图像整体亮,那所有的像素值的取值个数应该都会很高。所以应该把它的直方图做一个横向拉伸(如下图),就可以扩大图像像素值的分布范围,提高图像的对比度,这就是直方图均衡化要做的事情。

图像均衡化:“直方图均衡化"是把原始图像的灰度直方图从比较集中的某个灰度区间变成在更广泛灰度范围内的分布。直方图均衡化就是对图像进行非线性拉伸重新分配图像像素值使一定灰度范围内的像素数量大致相同直方图被拉伸(均衡化)之后,细节自然能够强化

函数: 

cv2.equalizeHist(img)           #直方图均衡化

2、代码

#直方图均衡化
def Equalize_Hist():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)  #灰度图

    # 2、直方图均衡化
    img_equal = cv2.equalizeHist(img)           #直方图均衡化

    # 3、显示直方图
    f, ax = plt.subplots(2, 2, figsize=(16, 16))
    #显示图像
    ax[0, 0].imshow(img, "gray")
    ax[0, 1].imshow(img_equal, "gray")          #注:"gray"是有效名,不能乱写
    #显示直方图
    ax[1, 0].hist(img.ravel(), 256)             #ravel():多维数组转一维数组
    ax[1, 1].hist(img_equal.ravel(), 256)
    #显示plt画板
    plt.show()

3、效果 

直方图均衡化的缺陷由于太暗,损失了许多信息。 所以引入:自适应的直方图均衡化

五、自适应的直方图均衡化

1、基础理论

直方图均衡化的缺陷由于太暗,损失了许多信息。 所以引入:自适应的直方图均衡化

作用:

在直方图均衡化的基础上,尽可能保留细节信息。(把直方图分成多个小块,防止细节信息由于过暗而损失掉

为了解决这个问题,需要使用自适应的直方图均衡化。此时,整幅图像会被分成很多小块,这些小块被称为"tiles”(在OpenCV中tiles的大小默认是8x8),然后再对每一个小块分别进行直方图均衡化。所以在每一个的区域中,直方图会集中在某一个小的区域中)。如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的bin 超过对比度的上限的话,就把其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。

如下图,把直方图像素点分散:

为了去除每一个小块之间的边界,再使用双线性差值,对每个小块进行拼接。

函数:

cv.createCLAHE(clipLimit, titleGridSize)

参数1 clipLimit:        对比度限值(默认40)。(阈值

参数2 titleGridSize: 分块的大小(默认8*8)。(分成几块

2、代码

#自适应直方图均衡化
def Clahe_Hist():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)  #灰度图

    # 2、自适应直方图均衡化
    cl = cv2.createCLAHE(2.0,       (8,8))
    #                   对比度限制   分块大小
    clahe = cl.apply(img)                   #自适应直方图均衡化

    # 3、显示直方图
    f, ax = plt.subplots(2, 2, figsize=(16, 16))
    #显示图像
    ax[0, 0].set_title("origin")
    ax[0, 0].imshow(img, "gray")
    ax[0, 1].set_title("Equalized")
    ax[0, 1].imshow(clahe, "gray")          #注:"gray"是有效名,不能乱写
    #显示直方图
    ax[1, 0].hist(img.ravel(), 256)         #ravel():多维数组转一维数组
    ax[1, 1].hist(clahe.ravel(), 256)
    #显示plt画板
    plt.show()

3、效果

尤其是最后一张,可以明显感觉到普通均衡化和自适应均衡化的差距。

总代码

#直方图计算、掩膜及均衡化
import cv2
import numpy as np
from matplotlib import pyplot as plt
#plt:本库函数主要是一些plt常见的画图操作,如设置图的颜色,线条,字体,坐标轴,标题,legend,在画好的图上写文字等。


#计算直方图(灰度)
def Calculate_Hist():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)  # 0即灰度图,1彩图
    cv2.imshow("img", img)

    # 2、获取并绘制直方图
    hist = cv2.calcHist([img], [0],   None,         [256],  [0, 256])   #获取
    #                   图像   通道索引 掩码(完整/局部) bin计数  范围
    plt.plot(hist)      # 绘图(基于一点或多点)

    # 3、直方图展示
    plt.show()          # 显示


#计算直方图(彩图)
def Calculate_Hist_RGB():
    # 1、读取图片
    img = cv2.imread("Resource/test11.jpg")       #彩图
    cv2.imshow("img", img)

    # 设置颜色通道
    color = ["b", "g", "r"]

    # 2、获取直方图
    for i, c in enumerate(color):           #i是索引,c是内容
        hist = cv2.calcHist([img], [i], None, [256], [0, 256])
        plt.plot(hist, color=c)

    # 3、直方图展示
    plt.legend(["B Channel", "G Channel", "R Channel"])     #批注
    plt.show()


#掩膜
def Mask():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)
    cv2.imshow("img", img)

    # 2、创建mask
    mask = np.zeros(img.shape, np.uint8)
    mask[100:400, 20:200] = 255                          #白色掩膜
    #       高       宽
    cv2.imshow("mask", mask)

    # 3、获取mask后的图像
    masked_img = cv2.bitwise_and(img, img, mask=mask)    #把掩膜用于图像
    cv2.imshow("masked_img", masked_img)

    # 4、获取并绘制直方图
    hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])     #全部直方图
    plt.plot(hist_full)
    hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])     #掩膜直方图
    plt.plot(hist_mask)

    # 5、显示直方图
    plt.show()


#直方图均衡化
def Equalize_Hist():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/test11.jpg", 0)  #灰度图

    # 2、直方图均衡化
    img_equal = cv2.equalizeHist(img)           #直方图均衡化

    # 3、显示直方图
    f, ax = plt.subplots(2, 2, figsize=(16, 16))
    #显示图像
    ax[0, 0].set_title("origin")
    ax[0, 0].imshow(img, "gray")
    ax[0, 1].set_title("Equalized")
    ax[0, 1].imshow(img_equal, "gray")          #注:"gray"是有效名,不能乱写
    #显示直方图
    ax[1, 0].hist(img.ravel(), 256)             #ravel():多维数组转一维数组
    ax[1, 1].hist(img_equal.ravel(), 256)
    #显示plt画板
    plt.show()


#自适应直方图均衡化
def Clahe_Hist():
    # 1、读取图片, 并转换成灰度图
    img = cv2.imread("Resource/vague1.jpg", 0)  #灰度图

    # 2、自适应直方图均衡化
    cl = cv2.createCLAHE(2.0,       (8,8))
    #                   对比度限制   分块大小
    clahe = cl.apply(img)                   #自适应直方图均衡化

    # 3、显示直方图
    f, ax = plt.subplots(2, 2, figsize=(16, 16))
    #显示图像
    ax[0, 0].set_title("origin")
    ax[0, 0].imshow(img, "gray")
    ax[0, 1].set_title("Equalized")
    ax[0, 1].imshow(clahe, "gray")          #注:"gray"是有效名,不能乱写
    #显示直方图
    ax[1, 0].hist(img.ravel(), 256)         #ravel():多维数组转一维数组
    ax[1, 1].hist(clahe.ravel(), 256)
    #显示plt画板
    plt.show()


if __name__ == '__main__':
    plt.style.use("fivethirtyeight")    #直方图样式设计
    plt.figure(figsize=(6, 4))          #直方图大小

    Calculate_Hist()         #计算直方图(灰度)
    Calculate_Hist_RGB()     #计算直方图(彩图)
    Mask()                   #掩膜直方图
    Equalize_Hist()          #直方图均衡化
    Clahe_Hist()             #自适应直方图均衡化

参考资料

https://www.bilibili.com/video/BV1Fo4y1d7JL?p=29

https://iamarookie.blog.csdn.net/article/details/119092739

http://woshicver.com/FifthSection/4_10_2_%E7%9B%B4%E6%96%B9%E5%9B%BE-2%EF%BC%9A%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1/

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
对于图像处理中的直方图均衡化操作,传统的方法是对整幅图像进行全局的直方图均衡化,但是该方法存在一些缺陷,例如处理后的图像可能会出现过度增强的现象,同时在一些区域中会出现过度降低的现象。为了解决这些问题,可以使用自适应直方图均衡化(AHE)来处理图像。 AHE算法的基本思想是将整幅图像分成若干个小区域,然后对每个小区域进行直方图均衡化。这样做的主要好处是可以避免全局的过度增强和降低现象,同时能够更好地保留图像的细节和纹理信息。 下面是使用OpenCV实现自适应直方图均衡化的代码: ```python import cv2 # 读取图像 img = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE) # 定义区域大小和对比度 tile_size = 32 clip_limit = 3.0 # 创建CLAHE对象 clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(tile_size, tile_size)) # 对图像进行自适应直方图均衡化 img_clahe = clahe.apply(img) # 显示原始图像和处理后的图像 cv2.imshow('Original Image', img) cv2.imshow('CLAHE Image', img_clahe) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上述代码中,首先读取了需要处理的图像,然后定义了区域大小和对比度参数。接着使用`cv2.createCLAHE()`函数创建CLAHE对象,并传入上述参数。最后调用`clahe.apply()`函数对图像进行自适应直方图均衡化,得到处理后的图像。最后使用`cv2.imshow()`函数显示原始图像和处理后的图像。 需要注意的是,自适应直方图均衡化的效果取决于区域大小和对比度参数的选择,需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_(*^▽^*)_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值