• OpenCV-Python : 直方图


    啥叫直方图

    直方图简单来说就是图像中每个像素值的个数统计,比如一副灰度图中像素值为0的有多少个,1的有多少个...

    在计算直方图之前,先了解几个术语:

    • dims:要计算的通道数,对于灰度图dims=1,普通彩色图dims=3
    • range:要计算的像素值范围,一般为[0,255]
    • bins:子区段数目,如果我们统计0~255每个像素值,bins=256;如果划分区间,比如0~15,16~31...240~255这样16个区间,bins=16

    计算直方图

    OpenCV和Numpy中提供了计算直方图的函数,我们对比一下他们的性能

    OpenCV中直方图计算

    在OpenCV中使用 cv2.calcHist(images,channels,mask,histSize,ranges) 计算,其中:

    • 参数1:要计算的原图,以方括号的传入,如:[img]
    • 参数2:类似前面提到的dims,灰度图写[0]就行,彩色图B、G、R分别传入[0]、[1]、[2]
    • 参数3:要计算的区域,计算整幅图的话,写None
    • 参数4:前面提到的bins
    • 参数5:前面提到的range
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    start = cv2.getTickCount()
    
    img = cv2.imread('hist.jpg', 0)
    hist = cv2.calcHist([img], [0], None, [256], [0, 256])
    
    end = cv2.getTickCount()
    
    print((end - start) / cv2.getTickFrequency())

    这里我使用到了评估代码运行时间,且并没有给出最初最后print()函数输出的结果,其实这个结果一直在变化。这里简单的介绍一下获取代码运行时间的两种方式

    第一种:

    import cv2
    start = cv2.getTickCount()
    # 这里写测试代码...
    end = cv2.getTickCount()
    print((end - start) / cv2.getTickFrequency())

    这段代码就是用来测量程序运行时间(单位:s),其中cv2.getTickCount()函数得到电脑启动以来的时钟周期数,cv2.getTickFrequency()返回你电脑的主频,前后相减再除以主频就是你代码的运行时间。我这里就是使用的第一种

    第二种:使用Python中的time模块计时:

    import time
    start = time.clock()
    # 这里写测试代码...
    end = time.clock()
    print(end - start)

    Numpy中直方图计算

    也可用Numpy的函数计算,使用 ravel() 函数 将二维矩阵展平变成一维数组,

    hist, bins = np.histogram(img.ravel(), 256, [0, 256])

    还有一种更高效的的方式:

    hist = np.bincount(img.ravel(), minlength=256)

    绘制直方图

    其实Matplotlib自带了一个计算并绘制直方图的功能,不需要用到上面的函数

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

         

    从直方图上可以看出图片的像素点集中子150附近,图片偏灰白,效果不好。接下来我们来看看如何来改善它。

    当然,我们也可以用前面计算出来的结果绘制:

    plt.plot(hist)
    plt.show()

    直方图的均衡化

    一幅效果好的图像通常在直方图上的分布比较均匀,直方图均衡化就是用来改善图像的全局亮度和对比度的。

    OpenCV中用cv2.equalizeHist()实现均衡化,我们把两张图片并排显示一下,对比一下:

    equ = cv2.equalizeHist(img)
    cv2.imshow('equalization', np.hstack((img, equ)))  # 并排显示
    cv2.waitKey(0)

    均衡后的直方图:

    plt.hist(equ.ravel(), 256, [0, 256])
    plt.show()

    可以看出均衡后的直方图明显好于原图。均衡后的图片的亮度和对比度效果明显好于原图

    自适应均衡化

    直方图均衡化是应用于整幅图片的,那是不是所有图片都适合?会不会出现什么问题?看下图:

    很明显,因为全局调整亮度和对比度的原因,脸部太亮,大部分细节都丢失了。

    自适应均衡化就是解决这一问题的:它在每一个小区域内(默认8x8)进行直方图均衡化。当然,如果有噪点的话,噪点会被放大,需要对小区域的对比度进行了限制,所以这个算法全称叫:对比度受限的自适应直方图均衡化 CLAHEContrast Limited Adaptive Histogram Equalization

    # 自适应均衡化,参数可选
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    cl1 = clahe.apply(img)
    cv2.imshow('equalization', np.hstack((equ, cl1)))  # 并排显示
    cv2.waitKey(0)

    效果比均衡化效果要好,至少脸部的细节保留了

    使用掩膜

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

    img = cv2.imread('home.jpg', 0)
    
    # 创建一个掩膜
    mask = np.zeros(img.shape[:2], np.uint8) # 取彩色通道的长宽
    mask[0 : 200, 0 : 200] = 255
    masked_img = cv2.bitwise_and(img, img, mask = mask)
    
    Original_Hist = cv2.calcHist([img], [0], None, [256], [0, 256])
    masked_img_Hist = cv2.calcHist([img], [0], mask, [256], [0, 256])
    
    plt.subplot(231), plt.imshow(img, 'gray')
    plt.subplot(232), plt.imshow(mask, 'gray')
    plt.subplot(233), plt.imshow(masked_img, 'gray')
    plt.subplot(234), plt.plot(Original_Hist)
    plt.subplot(235), plt.plot(masked_img_Hist)
    plt.subplot(236), plt.plot(Original_Hist), plt.plot(masked_img_Hist)
    plt.show()

    其中在混合的那副直方图中,蓝色为原图的直方图,橙色为进行掩膜之后的直方图。

  • 相关阅读:
    接口XMPPConnection
    Smack 4.3.4 API
    Tigase XMPP Server
    Openfire Meetings插件是一个包含各种Jitsi项目(如VideoBridge和Meet)的实现
    华为方舟编译器 下载 和 LiteOS Studio Setup 2019-04-16.exe SDK下载
    华为 鸿蒙系统(HarmonyOS)
    C#.NET常见问题(FAQ)-如何使用2D绘图控件ZedGraph绘制坐标轴和坐标曲线
    C#.NET常见问题(FAQ)-如何声明list的多维数组
    C#.NET常见问题(FAQ)-如何设置控件水平对齐,垂直对齐
    C#.NET常见问题(FAQ)-如何修改Form不能修改窗体大小
  • 原文地址:https://www.cnblogs.com/gezhuangzhuang/p/10716047.html
Copyright © 2020-2023  润新知