直方图

何为直方图?没那么高大上,其实就是二维统计图。每个照片都是有像素点所组成,当然也是[0,255],直方图就是统计每个值所对应的像素点有几个。
直方图横坐标表示0-255这些像素点值;纵坐标表示对应像素点值的个数有多少个,例如:像素为55的像素点有多少个
cv2.calcHist(images,channels,mask,histSize,ranges)cv2.calcHist([img],[0],None,[256],[0,256])

参数一:images:原图像格式为uint8或float32;当传入函数时应该用中括号括住,通常情况下都是输入的是灰度图
参数二:同样用中括号括起来,它会告诉函数我们图像的直方图;如果输入图像时灰度图它的值就是[0];如果时彩色图像传入的参数可以是[0][1][2],分别对应BGR
参数三:掩模图像,说白了就是取部分图像而已;统计整个图像的直方图时就把它设置为None;当然也可以通过掩模来统计图像的某部分的直方图
参数四:BIN的数目,也就是横坐标的总量程而已,一般都是256,也就是0-255这256个像素点值,也需要用中括号括起来
参数五:像素值的范围,一般设置为[0,256]
import cv2
import numpy as np
from matplotlib import pyplot as plt

def show_photo(name,picture):#图像显示函数
    cv2.imshow(name,picture)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
img = cv2.imread('E:\Jupyter_workspace\study\data/cat.png',0)#这里的参数0表示以灰度图进行读取
hist = cv2.calcHist([img],[0],None,[256],[0,256])#当然由于是灰度图通道数也只有一个即参数二[0];参数三None表示没有使用掩模直接输出整体图像的直方图;参数四[256]直方图的横坐标量程;参数五[0,256]像素值的范围
hist.shape#结果为:(256, 1) 其中256表示这个图像中有0-255这256个取值,1表示得到的直方图是二维的,即每个像素出现多少个

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


img = cv2.imread('E:\Jupyter_workspace\study\data/cat.png')#第二个参数不填表示原图输入,这个图像为彩色图也就是彩色图输入
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])
plt.show()

原图:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_像素点


原图对应的灰度图的直方图:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_均衡化_02


原图的BGR直方图:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_均衡化_03

掩模mask

np.zeros(img.shape[:2],np.uint8)上面的函数中有掩模的操作,接下来介绍一下掩模mask的定义的操作

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

def show_photo(name,picture):#图像显示函数
    cv2.imshow(name,picture)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
#创建mast,掩模是由黑白两部分组成的,然后与原图重叠,掩模白色区域对应原图区域不变,黑色区域对应原图区域变黑
mask = np.zeros(img.shape[:2],np.uint8)#这里面的掩码实际上就是边缘黑中间白,此时的mask就和原图片大小相同,uint8表示无符号八位整数0-255之间
print(mask.shape)#结果为:(321, 287)
mask[50:200,50:200] = 255#要保存的东西是白色的,白色区域为要保存的地方,所以将选取地方置为255
show_photo('mask',mask)

img = cv2.imread('E:\Jupyter_workspace\study\data/cat.png',0)#灰度图读取照片
print(img.shape)#结果为:(321, 287)
show_photo('img',img)

masked_img = cv2.bitwise_and(img,img,mask=mask)#与操作,也就是有0则0,黑色为0所以说掩码黑色地区都为黑;参数一表示原图像,参数三表示掩模图像
show_photo('masked_img',masked_img)

hist_full = cv2.calcHist([img],[0],None,[256],[0,256])#不带掩模的图像进行统计直方图
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])#带掩模mask的时候统计图像的部分掩模区域的直方图

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()

掩模图像:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_直方图_04


原图:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_直方图_05


掩模操作后的图像:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_均衡化_06


上一:原图

上二:自定义的掩模

下一:掩模对应的原图部分

下二:蓝线对应原图的直方图,橙线对应掩模处理的部分原图的直方图

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_python_07

直方图均衡化

假设某图片部分像素值为:

255

128

200

50

50

200

255

50

255

200

128

128

200

200

255

50

下面表格中的函数映射中(255-0)表示设置的横轴的量程这里设置的是0-255

灰度值

像素个数

概率

累积概率

根据函数映射后灰度值

取整

50

4

4/16 = 0.25

0.25

0.25*(255-0)=63.75

64

128

3

3/16 = 0.1875

0.25+0.1875=0.4375

0.4375*(255-0)=111.5625

112

200

5

5/16 = 0.3125

0.25+0.1875+0.3125=0.75

0.75*(255-0)=191.25

191

255

4

4/16 = 0.25

0.25+0.1875+0.3125+0.25=1

1*(255-0)=255

255

均衡化后的像素值为:

255

112

191

64

64

191

255

64

255

191

112

112

192

191

255

255

均衡化之后发现了这16个数相差的并不是特别大了

cv2.equalizeHist(img) 传入图像对象名称即可进行整体均衡化

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

def show_photo(name,picture):#图像显示函数
    cv2.imshow(name,picture)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
img = cv2.imread('E:\Jupyter_workspace\study\data/people.jpg',0)
plt.hist(img.ravel(),256)#原图像的直方图
plt.show()

equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)#均衡化后的直方图
plt.show()

res = np.hstack((img,equ))
show_photo('img_equ',res)#显示原图和均衡化后的图片

原图直方图:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_python_08


均衡化后的直方图:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_python_09


原图和均衡化后的图片对比:

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_python_10

均衡化后的图像脸上的细节变得更加模糊了,尴尬不???
这时候就需要自定义均衡化

自定义均衡化

直方图的均衡化也就是整体的均衡化,其他像素点值大的地方给平均给其他地方了导致一下细节会丢失
若将原图分成块进行均衡化,每块进行自己块的均衡化效果会比全局整体均衡化更好些
当然,若图像里面噪音太大,局部反而没有整体均衡化好,需要自己事先去衡量一下
cv2.createCLAHE(clipLimit = 2.0,tileGridSize = (8,8)) (8,8)表示分块均衡化中块的大小

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

def show_photo(name,picture):#图像显示函数
    cv2.imshow(name,picture)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
img = cv2.imread('E:\Jupyter_workspace\study\data/people.jpg',0)
plt.hist(img.ravel(),256)#原图像的直方图

equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)#均衡化后的直方图

clahe = cv2.createCLAHE(clipLimit = 2.0,tileGridSize = (8,8))#自定义均衡化,每8*8分成块,按块进行均衡化
res_clahe = clahe.apply(img)

res = np.hstack((img,equ,res_clahe))
show_photo('img_equ_clahe',res)

原图-整体均衡化-自定义均衡化

grafana 用直方图 横坐标显示时间 纵坐标展示数字 直方图的横纵坐标_均衡化_11