在Opencv中直方图的绘制

直方图

什么是直方图呢?

直方图是对数据集合统计,并将统计结果分布于一系列定义的bins中。这里的数据不仅仅是灰度值,统计数据可能是任何能够有效描述图像的特征,例如颜色、梯度/边缘、形状、纹理、局部特征点、视觉词汇等。

灰度直方图

通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值(0 到 255),y 轴是图片中具有同一个灰度值的点的数目。
灰度直方图其实就是对图像的另一种解释。通过直方图我们可以对图像的对比度,亮度,灰度分布等有一个直观的认识。几乎所有的图像处理软件都提供了直方图分析功能。在这里,直方图是根据灰度图像绘制的,而不是彩色图像。直方图的左边区域像是了暗一点的像素数量,右侧显示了亮一点的像素的数量。

灰度直方图.png

使用OpenCV 统计直方图函数 cv2.calcHist 可以帮助我们统计一幅图像的直方图。

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

参数意义如下:

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

  • channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。

  • mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子)

  • histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。

  • ranges: 像素值范围,通常为 [0,256]

例子:以灰度格式加载一幅图像并统计图像的直方图

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

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(img.shape) == 3:
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    #plt.xticks([])
    #plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("cute-dog.jpg",0)
    #别忘了中括号[img1],[0],None,[256],[0,256],只有mask没有中括号
    hist = cv2.calcHist([img1],[0],None,[256],[0,256])
      
    plt.figure(figsize=(12,8),dpi=80)
    plt.subplot(121)
    img_show('原图',img1)
    plt.subplot(122)
    plt.plot(hist)
    plt.xlim([0,256])
    plt.ylim([0,800000])
    plt.xlabel('直方图',fontproperties='FangSong',fontsize=12)
直方图1.png

使用 Matplotlib Matplotlib 中有直方图绘制函数:matplotlib.pyplot.hist()它可以直接统计并绘制直方图。

img1 = cv2.imread("cute-dog.jpg",0)

plt.figure(figsize=(12,8),dpi=80)
plt.subplot(121)
img_show('原图',img1)
plt.subplot(122)
plt.hist(img1.ravel(),256,[0,256])
plt.xlim([0,256])
plt.xlabel('直方图',fontproperties='FangSong',fontsize=12)
直方图2.png

例子:绘制BGR通道直方图

img1 = cv2.imread("cute-dog.jpg")
color = ('b','g','r')
# 对一个列表或数组既要遍历索引又要遍历元素时
# 使用内置enumerrate函数会有更加直接,优美的做法
# enumerate会将数组或列表组成一个索引序列。
# 使我们再获取索引和索引内容的时候更加方便
for i,col in enumerate(color):
    print(i)
    print(col)
    hist = cv2.calcHist([img1],[i],None,[256],[0,256])
    plt.plot(hist,color=col)
    plt.xlim([0,256])
    plt.ylim([0,800000])
plt.show()
直方图3.png
img1 = cv2.imread("cute-dog.jpg")
color = ('b','g','r')

for i,col in enumerate(color):
    
    plt.hist(img1[:,:,i].ravel(),256,[0,256],color=col,alpha=1)
    plt.xlim([0,256])
    plt.ylim([0,800000])
plt.show()
直方图4.png

使用掩模
要统计图像某个局部区域的直方图只需要构建一副掩模图像。将要统计的部分设置成白色,其余部分为黑色,就构成了一副掩模图像。然后把这个掩模图像传给函数就可以了。

例子:统计图像某个局部区域的直方图

img1 = cv2.imread("cute-dog.jpg")
img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)

# 创建掩膜
mask = np.zeros(img.shape[:2],np.uint8)
mask[1000:4000,100:3200] = 255
img_mask = cv2.bitwise_and(img,img,mask =mask)

# 创建一个掩膜和一个无掩膜的直方图
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img_mask],[0],mask,[256],[0,256])

plt.figure(figsize=(10,8),dpi=80)
plt.subplot(221)
plt.imshow(img,'gray')
plt.subplot(222)
plt.imshow(mask,'gray')
plt.subplot(223)
plt.imshow(img_mask,'gray')
plt.subplot(224)
plt.plot(hist_full,label='original')
plt.plot(hist_mask,label='img_mask')
plt.legend()
plt.xlim([0,256])
plt.ylim([0,800000])
局部直方图.png

例子

img1 = cv2.imread("empire.jpg")
chans = cv2.split(img1)
colors = ('b','g','r')

plt.figure(figsize=(15,5),dpi=150)
plt.subplot(121)
img_show('原图',img1)
plt.subplot(122)
for (chan,color) in zip (chans,colors):
    hist = cv2.calcHist([chan],[0],None,[256],[0,256])
    plt.plot(hist,color=color)
    plt.xlim([0,256])
plt.xlabel('彩色直方图',fontproperties='FangSong',fontsize=12)
彩色直方图.png
img1 = cv2.imread("empire.jpg")
chans = cv2.split(img1)
colors = ('b','g','r')

plt.figure(figsize=(18,5),dpi=80)
plt.subplot(131)
hist =cv2.calcHist([chans[1],chans[0]],[0,1],None,[32,32],[0,256,0,256])

plt.title('G和B的二维彩色直方图',fontproperties='FangSong',fontsize=12)
plt.colorbar(plt.imshow(hist,interpolation= 'nearest'))

plt.subplot(132)
hist =cv2.calcHist([chans[1],chans[2]],[0,1],None,[32,32],[0,256,0,256])
plt.title('G和R的二维彩色直方图',fontproperties='FangSong',fontsize=12)
plt.colorbar(plt.imshow(hist,interpolation= 'nearest'))

plt.subplot(133)
hist =cv2.calcHist([chans[0],chans[2]],[0,1],None,[32,32],[0,256,0,256])
plt.title('B和R的二维彩色直方图',fontproperties='FangSong',fontsize=12)
plt.colorbar(plt.imshow(hist,interpolation= 'nearest'))

print('二维直方图形状:%s,和%s'%(hist.shape,hist.flatten().shape[0]))

二维彩色直方图.png

第一个是绿色和蓝色通道的二维颜色直方图,第二个是绿色和红色,第三个是蓝色和红色。
蓝色阴影表示低像素计数,而黄色阴影表示高像素计数(即2D直方图中的峰值)。

参考资料:
网址:Matplotlib基础教程
书籍:《数字图像处理》《OpenCV-Python-Toturial-中文版》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容