直方图

直方图简述:

Opencv提供了将图像转换成直方图的一些操作。

如下图,是一张小猫的图像:

在这里插入图片描述
转化成灰度图:

在这里插入图片描述
这张灰度图对应的直方图如下图所示:

在这里插入图片描述
代码:

import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline 

# 定义显示图像的函数
def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

img = cv2.imread('C:/Users/www12/Desktop/cat.jpg',0) #0表示灰度图
cv_show(img, 'img')
# calcHist就算将图像转换成直方图的函数
hist = cv2.calcHist([img],[0],None,[256],[0,256])
print(hist.shape)
plt.plot(hist)

# # 用matplotlib将直方图显示出来
# plt.hist(img.ravel(),256); 
# plt.show()

(256, 1)

plt.plot(hist)显示如下:
在这里插入图片描述

plt.hist(img.ravel(),256); 
plt.show()

显示如下:

在这里插入图片描述
原理如下:

假设给定一个灰度图,这个灰度图对应的像素如下图:

在这里插入图片描述
所有像素值的个数统计起来,统计成直方图

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

images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]

注意: 一定要将图像用[]括起来!!!

channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果图像是灰度图它的值就是[0], 如果彩色图像的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
mask: 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并使用它。
histSize:BIN 的数目。也应用中括号括来,一般都是用[256],表示分成256个区间来统计,也可以分成0-10,11-20…这样来统计.
ranges: 像素值范围常为 [0, 256]

下面传入一个有色图,分别看其BGR三种颜色通道的直方图:

img = cv2.imread('C:/Users/www12/Desktop/cat.jpg') 
color = ('b','g','r')
for i,col in enumerate(color): 
    histr = cv2.calcHist([img],[i],None,[256],[0,256]) 
    plt.plot(histr,color = col) 
    plt.xlim([0,256]) 

在这里插入图片描述

有时候我们不想进行全图统计,只想截取一张的图的一部分画出,这时候就可以用到mask掩膜

首先创建一个mask,我们用如下代码创建一个200*300的掩膜,也就是创建一张和待分析图像大小相同空图像(像素值均为0),字符类型为uint8类型

在这里插入图片描述
然后将灰度图读取进来:

img = cv2.imread('C:/Users/www12/Desktop/cat.jpg', 0)
cv_show(img,'img')

在这里插入图片描述

然后进行与操作,将创建的掩膜加到需要处理的图像上,并覆盖到原图像上:

masked_img = cv2.bitwise_and(img, img, mask=mask)#与操作
cv_show(masked_img,'masked_img')

在这里插入图片描述
再来看看将掩膜添加到直方图函数上的效果:

hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])

plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()

将添加掩膜前后的直方图进行对比图如下所示:

在这里插入图片描述

直方图均衡化:

在这里插入图片描述
直方图均衡化就是对图像的直方图进行"长胖"处理,比如上图的一只小狗,可以观察到其直方图分布还是很不均衡的.
在这里插入图片描述
均衡化的意思就是将图像分布相对均衡一些,均衡化处理后的结果就算图像相对于原来变得更亮了一些
在这里插入图片描述
上图就是直方图均衡化的原理,先统计每一个灰度值的像素个数,得出其概率,往下逐渐累加依次得到累计概率,然后就根据函数映射后的灰度值取整
这样可以明显地看到灰度值为50的像素个数由4变成了64,灰度值为128的像素个数由3变成了112…这样就实现了均衡化

现在来看看均衡化之后的效果

原图

img = cv2.imread('C:/Users/www12/Desktop/clahe.jpg',0) #0表示灰度图 #clahe
plt.hist(img.ravel(),256); 
plt.show()

在这里插入图片描述
均衡化:

equ = cv2.equalizeHist(img) 
plt.hist(equ.ravel(),256)
plt.show()

在这里插入图片描述
将这两个直方图一起画出来:

res = np.hstack((img,equ))
cv_show(res,'res')

在这里插入图片描述
可以明显地看到均衡化处理之后地图像变亮了, 但是也可以看到一点弊端, 比如人头那一块儿均衡化之后很多细节部分都没有原来清晰了,这是因为将整个图均衡化,图中会有些地方被图中其他地方也均衡了,这就是将整个图均衡化地弊端,解决这种情况可以将图像分成几块来均衡化,但是这样会导致图像的分界线明显,opencv为我们提供了自适应直方图均衡化方法.

自适应均衡化:

clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) 

createCLAHE函数中的tileGridSize设定为(8,8)意思就是将图像分成多个8*8的小块儿进行均衡化来处理.

res_clahe = clahe.apply(img)
res = np.hstack((img,equ,res_clahe))
cv_show(res,'res')

将clahe应用到img上, 然后返回的直方图对应的数组保存到变量res_clahe中, 将三张图像(原图, 均衡化, 自适应均衡化)一起显示出来, 然后对比结果差异.


可以看到自适应均衡化之后图像变亮了,但是细节也保存下来了.

使用均衡化还是自适应均衡化根据实际情况而定.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值