在Opencv中直方图的绘制

作者: 陨星落云 | 来源:发表于2019-07-15 11:14 被阅读0次

    直方图

    什么是直方图呢?

    直方图是对数据集合统计,并将统计结果分布于一系列定义的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

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

    相关文章

      网友评论

        本文标题:在Opencv中直方图的绘制

        本文链接:https://www.haomeiwen.com/subject/izwgkctx.html