python中绘制数组直方图一维数组划分10组_opencv-python 绘制直方图和均衡化

直方图

什么是直方图?一个数字图像是由像素点组成的,每个像素点在计算机里都是以二进制代码存储的,通常都是8bit编码,也就是说一个像素的可能值是00H到FFH,如果是灰度图像,那么每个像素值便代表它的灰度值,如果是RGB三通道图像,每个像素值是一个数组比如[60,40,244] 它代表每个通道的灰度值。直方图用来统计每个灰度值出现的次数。也就是每个灰度值出现的频数,横坐标是像素点的值,比如8bit编码横坐标就是0-255,纵坐标就是相应出现的次数,画出一种柱形图,这个柱形图就是直方图。

下面有若干种方法来画直方图,其实也可以自己实现,用for循环统计每个像素出现的次数。

import cv2

import numpy as np

from matplotlib import pyplot as plt

def demo():

# 生成一个一维数组0-15

vec = np.arange(0,15)

print(vec)

# 把一维数组转为3 * 5的一个矩阵

mat = vec.reshape(3,5)

print(mat)

# 把这个3*5的矩阵再转换为一维数组,在python做直方图的时候需要用到

arr = mat.flatten()

print(arr)

def zhifangtu():

# 灰度图像的直方图

path = "e:/images/1.JPEG"

img = cv2.imread(path,0)

plt.figure("灰度直方图")

arr=img.flatten()

''' hist的参数非常多,但常用的就这五个,只有第一个是必须的,后面四个可选 arr: 需要计算直方图的一维数组 bins: 直方图的柱数,可选项,默认为10 normed: 是否将得到的直方图向量归一化。0:不归一化,统计的是频数,1是归一化,统计的是频率,默认为0 facecolor: 直方图颜色 alpha: 透明度 返回值 : n: 直方图向量,是否归一化由参数设定 bins: 横坐标下标 patches: 返回每个bin里面包含的数据,是一个list '''

n, bins, patches = plt.hist(arr, bins=256, normed=1, facecolor='green', alpha=0.75)

print(patches[0])

plt.show()

def zhifangtu1():

# 彩色图像的直方图

path = "e:/images/1.JPEG"

img = cv2.imread(path)

plt.figure("彩色直方图")

b = img[:,:,0]

g = img[:,:,1]

r = img[:,:,2]

ar = np.array(r).flatten()

plt.hist(ar, bins=256, normed=1, facecolor='r', edgecolor='r')

ag = np.array(g).flatten()

plt.hist(ag, bins=256, normed=1, facecolor='g', edgecolor='g')

ab = np.array(b).flatten()

plt.hist(ab, bins=256, normed=1, facecolor='b', edgecolor='b')

plt.show()

def drawHist():

# 绘制直方图的官方方法

''' def calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None): images: 原图像(图像格式为uint8或float32)。当传入函数时应该用中括号[]括起来,例如:[img]。 channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是[0];如果是彩色图像的话,传入的参数可以是[0],[1],[2]它们分别对应着通道B,G,R。 mask: 掩模图像。要统计整幅图像的直方图就把它设为None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子) histSize: BIN的数目。也应该用中括号括起来,例如:[256]。 ranges: 像素值范围,通常为[0,256] :return: '''

path = "e:/images/1.JPEG"

img = cv2.imread(path,0)

hist = cv2.calcHist([img], [0], None, [256], [0, 256])

# img.ravel() 将图像转成一维数组,这里没有中括号。

# matplotlib展示

plt.hist(img.ravel(), 256, [0, 256]);

plt.show()

img = cv2.imread(path)

color = ('b', 'g', 'r')

# 对一个列表或数组既要遍历索引又要遍历元素时

# enumerate 会将数组或列表组成一个索引序列。

# 使我们再获取索引和索引内容的时候更加方便

for i, col in enumerate(color):

histr = cv2.calcHist([img], [i], None, [256], [0, 256])

plt.plot(histr, color=col)

plt.xlim([0, 256])

plt.show()

def main():

drawHist()

if __name__ == '__main__':

main()

直方图的均衡化

直方图为什么要均衡化,首先举一个例子,如果一个灰度图像,它的像素点都集中在100到130之间,其它的像素点比较少,那么这意味着什么呢?我们知道像素点为0代表纯黑,255代表纯白,在中间的时候是黑到白之间的颜色,换句话说像素点为0代表的黑色和像素点1代表的黑色是非常接近的,人眼基本看不出来。那么回到刚才那个例子中,像素点都集中在100到130之间,那么这个图像的颜色都比较接近,对比度很小,视觉效果不好,如果能够把各个像素点的分布分开的话,那么对比度不就大了嘛,人眼也就能看出差别了。

下面用程序说话

def drawHist():

path = "e:/images/11.png"

img = cv2.imread(path,0)

cv2.imshow("image",img)

cv2.waitKey(0)

cv2.calcHist([img],[0],None,[256],[0,256])

plt.hist(img.ravel(), 256, [0, 256]);

plt.show()

先看一下什么效果:

可以看出,它的像素点基本都在15-90之间,下面把这幅图片的直方图均衡化。

import cv2

import numpy as np

from matplotlib import pyplot as plt

def drawHist():

path = "e:/images/11.png"

img = cv2.imread(path,0)

cv2.imshow("image",img)

cv2.waitKey(0)

cv2.calcHist([img],[0],None,[256],[0,256])

plt.hist(img.ravel(), 256, [0, 256]);

plt.show()

# cv2.equalizeHist() 均衡化函数,返回新图像的二维数组

res = cv2.equalizeHist(img)

plt.hist(res.ravel(),256,[0,256])

plt.show()

cv2.imshow("after",res)

cv2.waitKey(0)

# 保存图片

cv2.imwrite('res.png', res)

def main():

drawHist()

if __name__ == '__main__':

main()

后来的直方图和后来的图片:

这就是所谓的直方图均衡化,增强对比度的效果,但是有人就要问了,直方图均衡化的原理是什么?可以参考

[直方图均衡化的数学原理]

你可能感兴趣的:(python中绘制数组直方图一维数组划分10组_opencv-python 绘制直方图和均衡化)