[opencv自学笔记]绘制直方图和均衡化

直方图

  什么是直方图?一个数字图像是由像素点组成的,每个像素点在计算机里都是以二进制代码存储的,通常都是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()

后来的直方图和后来的图片:
这里写图片描述
这里写图片描述
这就是所谓的直方图均衡化,增强对比度的效果,但是有人就要问了,直方图均衡化的原理是什么?可以参考

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

(http://blog.csdn.net/superjunenaruto/article/details/52431941 “直方图均衡化数学原理”)

猜你喜欢

转载自blog.csdn.net/tsfx051435adsl/article/details/78569960