直方图及其应用

直方图定义

直方图是一种描述数据的分布

通过将连续变量划分成一系列区间,统计区间频率,并用来表示,以表征其统计特征

在图像处理中,直方图可以用来表示图像中像素值的分布状况,描述不同灰度级的像素在图像中的占比

直方图应用

1. 图像增强。通过调整像素值,让图像的像素复合某种统计特性,达到增强图像的目的

2. 图像分割。利用直方图来将图像划分为多个区域,从而进行目标分割

3. 像素的统计特性,可以作为图像的一种特征,用于对图像内容进行分类、检索、压缩

https://blog.csdn.net/yishuihanq/article/details/120220374

OpenCV画直方图

  1. cv2.calcHist(images,channels,mask,histSize,ranges)

关于`cv2.calcHist`函数的说明

hist = cv2.calcHist(images, channels, mask, histSize, ranges, accumulate)

- images: 源图像

- channels:参与计算直方图的通道

- mask:一个可选的掩膜,它与源图像具有相同的尺寸,用于指定计算直方图的区域。例如,可以通过指定一个矩形来计算图像的某个区域的直方图。

- histSize:表示要计算的直方图的大小以方括号形式传入。如果输入图像是灰度图像,则为灰度级别数;如果是彩色图像,则可以对每个通道指定不同的大小,例如 [256, 256, 256] 表示每个通道的直方图大小为 256。

- ranges:表示像素值的范围,以方括号形式传入。如果输入图像是灰度图像,则范围应该是 [0, 256];如果是彩色图像,则可以为每个通道指定不同的范围,例如 [0, 256, 0, 256, 0, 256] 表示每个通道的范围分别为 [0, 256]。

- accmulate:一个可选的参数,用于指定是否要累加直方图。如果指定为 True,则计算整幅图像的直方图;如果指定为 False,则只计算当前区域的直方图。

2. (numpy)np.histagram

关于np.histagram的用法:

hist, bins = np.histogram(a, bins=10, range=None, normed=False, weights=None, density=None)

- a: 输入的一维数组。

- bins: 直方图的bin数量,也可以指定每个bin的边界,如[0, 10, 20, 30, 40]。

- range: 直方图统计的范围。

- normed和density:两个参数效果相同,设置是否对结果进行归一化。

对比度增强

对比度:最暗的像素和最大的像素值的对比

一个经典的对比度增强的方法:对比度拉伸,局限:仅适用于低动态图像

https://blog.csdn.net/xinjay1992/article/details/108672007

直方图均衡化

直方图最广泛的应用之一,就是直方图均衡化。

直方图均衡化,是一种对**图像增强**的方法:通过重新分配像素值的灰度级,来增强图像的对比度

对于矩阵的意义:让像素在整个像素范围更加均匀

基本思想

将直方图变换为一个均匀分布的直方图,使得像素值更加均匀,从而达到增强图像的目的。

通常,直方图中呈现尖峰的位置,说明处于该值的像素较为接近

而直方图均衡化后,可以令这些像素取值更加分散,因此视觉上可以将不明显的物体与周围物体区分开来

计算过程

https://blog.csdn.net/weixin_45930877/article/details/119581282

直方图性质等详解:https://zhuanlan.zhihu.com/p/411042641

底层代码

np.interp 是 NumPy 中的一个函数,用于进行线性插值。具体来说,

np.interp(x, xp, fp, left=None, right=None, period=None) 函数用于计算一个新的数组 x 对应的线性插值结果。其中,x 表示需要进行插值的位置,xp 表示已知数据的位置,fp 表示已知数据的取值。

具体地说,np.interp 的计算方式为:对于 x 中的每一个位置,找到其在 xp 中的相邻位置 xp_i 和 xp_{i+1},然后在这两个位置的 fp 取值中进行线性插值,得到 x 对应位置的插值结果。

如果 x 中的某个位置超出了 xp 的取值范围,那么根据参数 left 和 right 的取值,有不同的处理方式。如果 left 和 right 都未指定,那么超出取值范围的位置将返回 np.nan;如果 left 和 right 中的一个指定了值,那么超出取值范围的位置将使用该值进行插值;如果两者都指定了值,那么会根据超出位置的方向分别使用两个值进行插值。

此外,如果 xp 中的值不是单调递增的,那么可以使用参数 period 指定数据的周期,从而进行周期性插值。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 先把图像变暗
img = cv2.imread('E:/notebook/lena.png', 0)
plt.imshow(img, cmap='gray')
plt.show()
dark = (0.5 * img).astype('uint8')
# cv2.imwrite("E:/notebook/dark_lena.jpg", dark)
image = cv2.imread("E:/notebook./dark_lena.jpg")
plt.imshow(image, cmap='gray')
plt.show()
# 计算直方图
hist, bins = np.histogram(img.flatten(), 256, [0,256])
plt.hist(hist, bins=bins)
plt.show()
print(hist[100:105])
# [1950 1950 1881 1862 1683]
# 直方图归一化
hist_norm = hist.astype(np.float32) / hist.sum()
print(hist_norm[100:105])
# [0.00743866 0.00743866 0.00717545 0.00710297 0.00642014]
# 计算累积直方图
cum_hist = hist_norm.copy()
for i in range(1, len(cum_hist)):
    cum_hist[i] = cum_hist[i-1] + cum_hist[i]
print(cum_hist[100:105])
# [0.32024384 0.3276825  0.33485794 0.34196091 0.34838104]
# 均衡化
img_equalized = np.interp(img.flatten(), bins[:-1], cum_hist).reshape(img.shape)
# print(bins)
plt.imshow(img_equalized, cmap='gray')
plt.show()

缺点

直方图整体均衡化用于增强图像质量。通过将图像映射到小区间,并进行归一化,使得其像素范围能够充斥整个空间。从而达到增强图像对比度,或者将亮度调整到适宜空间内的效果。

然而,对图像总体进行直方图均衡化,也会造成一些负面效果。

* 图像中某部分很亮,其他部分很暗,直方图均衡化会导致亮部过曝

* 图像分层

* 噪声问题

自适应直方图均衡(AHE, adaptive histogram equalization)

将图像分成若干的各区域对每个小区域做直方图均衡化

def AHE(im, wsz=100):
    h, w = im.shape
    out = np.zeros(im.shape) # Declare output variable
    for x in range(wsz//2, h + wsz//2):
        for y in range(wsz//2, w + wsz//2):
            blk = im[x-wsz//2:x+wsz//2, y-wsz//2:y+wsz//2]
            tmp = cv2.equalizeHist(blk)
            out[x-wsz//2:x+wsz//2, y-wsz//2:y+wsz//2] = tmp
    return out
img = cv2.imread("E:/notebook/person.png", 0)
plt.imshow(img, cmap="gray")
plt.show()
img = AHE(cv2.imread("E:/notebook/person.png", 0), wsz=50)
plt.imshow(img, cmap="gray")
plt.show()

CLAHE (contrast limited adaptive histogram equalization)

**核心思想** 将图像划分为若干个小块,并在小块内进行限制性直方图均衡化,经双线性最后的均衡化后的图像。

**步骤**

1. 将图像划分成若干个大小相等的块

2. 对每个子图进行“限制性”均衡化

3. 插值,得到均衡化后的像素值

“限制性”均衡化

**参数解释**

`clipLimit`: 控制了直方图均衡化中对比度增强的程度。该参数的数值越大,对比度增强的程度也越大,但是同时也会增加图像出现伪影的概率。

clip_limit = clip_limit_factor * (M / N)

其中,clip_limit_factor是一个用户定义的参数,通常取值在0.01到0.1之间;M是图像像素数量,N是直方图中的最高峰的数量。通常情况下,N的取值在50到200之间。

import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
clip_limit = 5
arr_clipped = np.clip(arr, a_min=None, a_max=clip_limit)
print(arr_clipped)
# [1 2 3 4 5 5 5 5 5]

平滑伪影

`tileGridSize` 表示将图像分割成的小块的大小。它对均衡化结果的影响主要体现在以下两个方面:

* 计算直方图时的像素点数量:由于 CLAHE 算法是在每个小块上进行直方图均衡化,因此 tileGridSize 的大小会直接影响每个小块中包含的像素点数量。如果 tileGridSize 太小,每个小块中的像素点数量就会很少,可能会导致直方图统计不准确,从而影响均衡化结果。而如果 tileGridSize 太大,每个小块中的像素点数量就会很多,可能会导致直方图过于集中,也会影响均衡化结果。因此,要根据具体的图像特征和处理需求,选择适当的 tileGridSize 大小。

* 均衡化效果的细节保留:tileGridSize 的大小还会影响均衡化结果中细节的保留程度。如果 tileGridSize 太小,每个小块中的像素点数量较少,可能会导致细节的损失。而如果 tileGridSize 太大,每个小块中的像素点数量较多,可能会导致一些小细节被平滑掉,从而导致细节不够清晰。因此,要根据具体的需求和图像特征,选择适当的 tileGridSize 大小,以达到最优的均衡化效果和细节保留程度。

cl = cv2.createCLAHE(clipLimit=3, tileGridSize=(8, 8))
im = cl.apply(cv2.imread("E:/notebook/person.png", 0))
plt.imshow(im, cmap='gray')
plt.show()

直方图应用---图像分割

直方图的波动曲线,表示了不同像素等级的统计信息

对于一个语义上关联较为紧密的物体,其像素的关联可能也较为紧密

因此,在对某个高频像素进行处理的时候,往往也是对于语义关联较为紧密的物体进行处理

最优阈值怎么选?

img = cv2.imread('E:/notebook/greenscreen.png')
plt.imshow(img)
plt.show()
hist, bins = np.histogram(img.flatten(), 256, [0, 256])
print(hist)
plt.bar(range(256), hist.ravel())
plt.show()
max_peak = np.argmax(hist)
print(max_peak) # 最多的43阈值1
second_peak = np.argmin(hist[100: 150]) + 100
print(second_peak) # 第二多的119阈值2
# 区间1 [0: max]
img_bin = np.zeros_like(img)
img_bin = np.where((img >= max_peak), 255, img_bin)[:, :, 0]
plt.imshow(img_bin, cmap='gray')
plt.show()
img_bin_2 = np.ones_like(img) * 0
img_bin_2 = np.where((img <= second_peak), 255, img_bin_2)[:, :, 0]
plt.imshow(img_bin_2, cmap='gray')
plt.show()
mask = img_bin * img_bin_2
plt.imshow(mask, cmap='gray')
plt.show()

[ 4453 8 45 52 136 241 268 419 321 185

125 146 146 151 149 168 178 251 253 323

375 475 584 1422 6139 48787 56813 54050 46046 43175

44371 46881 50671 58219 67125 74001 79400 86139 94594 101315

106251 109673 111434 112107 108057 98107 82611 64185 45954 32076

21640 15553 11695 9372 7469 6331 5179 4293 4001 4069

4792 6236 7699 8896 9643 10292 10823 11433 11818 11658

11690 11837 11720 10725 9846 8624 8447 8868 9864 11090

12556 13322 14375 14455 14782 15375 16505 18185 20749 23972

27871 32725 37063 40653 43648 46654 50872 55540 60205 64409

68385 71674 73997 71533 64290 54777 45432 38829 34013 27982

19619 11758 5682 2464 1106 706 514 488 441 417

438 421 431 444 427 437 465 474 555 690

1209 2081 3344 4898 6402 7349 7833 7570 7398 7632

7893 8051 8164 8724 10058 10658 10922 10622 9631 8468

7228 6841 7235 7717 8257 8614 8938 9540 10613 11682

12396 12713 13697 14371 14911 16181 17299 19732 21809 24816

27204 29519 32065 37209 41996 45069 46880 49048 51798 53681

54753 57345 63271 69282 69754 65532 56153 46119 39935 33199

23103 10697 3033 681 246 182 183 124 108 104

86 100 81 95 73 84 79 86 81 73

81 106 119 131 119 125 113 124 128 132

142 126 157 133 129 142 181 169 183 140

100 82 100 93 107 150 169 182 145 195

250 318 440 511 573 544 426 427 376 354

276 230 161 115 110 95]

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值