Opencv3.0-python的那些事儿:(八)、Opencv的直方图均衡化

# coding: utf-8
import numpy as np
import cv2
from matplotlib import pyplot as plt
'''
第22章: 直方图
直方图含义:可以对图像灰度分布有整体了解,x轴是灰度值(0到255),y轴是图片中具有同一个
灰度值点的数目,直方图是根据灰度图像绘制的、
BINS:如果需要知道两个像素值之间的数目,只需16个值来绘制直方图
需要把原来的256个值等分成16个小组,取每组的总和。每组就成为BIN。
OpenCV中用hitSize表示BINS。

DIMS:表示收集数据的参数数目,只考虑灰度值,因此参数为1
RANGE:要统计的灰度值范围,一般为[0,256]
cv2.calcHist可以统计图像的直方图
cv2.calcHist(images,channels,masks,histSize,ranges[,hist[,accumulate]])
images:原图像集合,是数组,因此用[],channels:通道,需要用[]括起来,
若图像为灰度图像,值为[0];彩色图像是[0],[1],[2]分别表示对应的通道是B,G,R
mask:掩膜图像,统计整幅图像就设置为None,统计一部分,需要使用它
histSize:BIN的数目,也要[]括起来,range:像素值范围
'''

def myHist():
    img = cv2.imread("0_snap.png" , 0)
    img = cv2.imread("home.jpg" , 0)
    hist = cv2.calcHist([img],[0],None , [256],[0,256])
    print(hist)
    #plt.imshow(hist , cmap="gray")
    #plt.show(hist)
    '''
   pyplot.hist(x , bins=10,range=None):
    作用:绘制直方图,x表示类似的一维数组(也可以是图像)

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

    '''
    cv2.imshow("histogram",hist)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    '''
    '''
    numpy.histogram(a,bins=10,range=None)
    a:类似数组的输入数据,bins:用于知道两个像素值之间的数目
    range:统计的像素范围
    返回的hist:数组,bin_edges:length(hist)+1
    hist就是一个含有256个元素的数组,数组中的每一个元素表示数组
    对应下标下的像素点个数
    np.bincount(x,weights=Nne,minlengthNone):
    x:一维数组,返回out:输出的包含
    '''
    hist,bins = np.histogram( img.ravel() , 256 , [0 ,256] )
    print("hist:%d" % len(hist) )
    print(hist)
    print("bins:%d" % len(bins))
    print(bins)

'''
使用掩膜,只需要统计局部区域的直方图,将要统计的部分设置成白色,其余部分为黑色,
就构成一副掩模图像,然后把掩模图像传给函数
这里的白色实际上是全1: 即11111111,黑色时0,因为将掩膜图像和原图像进行与运算后,
只有掩膜的部分还保留成原图像的像素值,黑色部分因为全0相与后就消失后变成黑色
'''

def mask_histogram():
    img = cv2.imread("home.jpg" , 0)
    mask = np.zeros(img.shape[ : 2 ] , np.uint8)
    mask[100:300 , 100:400] = 255
    masked_img = cv2.bitwise_and(img , img , mask = mask)
    hist_full = cv2.calcHist([img] , [0] , None , [256] , [0,256])
    hist_mask = cv2.calcHist([img] , [0] , mask , [256] , [0,256])
    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.show()

'''
直方图均衡化
一副图像中大多数店都集中在一个像素值范围内会怎样,
如果一副图片很亮,那么像素值都很高,直方图均衡化会把直方图
做横向拉伸。
直方图均衡化是把直方图映射到广泛分布的直方图中
应用:使所有的图片具有相同的亮度条件
'''
def numpy_historgamEqualization():
    #img = cv2.imread("wiki.jpg" , 0)
    img = cv2.imread("scenery.jpg" , 0)
    '''
    numpy.ndarray.flatten(order='C'):扁平化,复制一个一维的array出来
    C表示按照行的顺序,F表示按照列的顺序
    '''
    hist , bins = np.histogram(img.flatten() , 256 , [0,256])
    '''
    numpy.cumsum(a,axis=None,dtype=None ,out=None):
    a:输入数组
    作用:计算每一行或每一列的累积和,相当于分布求和函数,落在<=a的数量
    '''
    #计算累积分布图(不是标准化的)
    cdf = hist.cumsum()
    '''
    max():最大值,用分布累积值乘以,直方图最大值/分布累加最大值 ?
    标准化的值=cdf/cdf.max( < 1) * hist.max() < 1
    '''
    cdf_normalized = cdf * hist.max() / cdf.max()
    plt.plot(cdf_normalized , color = 'b')
    plt.hist(img.flatten() ,256 , [0 , 256] , color = 'r' )
    '''
    pyplot.xlime( ( xmin,xmax ) ):设置x轴的限制范围
    '''
    plt.xlim([0,256])
    '''
    pyplot.legend():为线段设置图例(其实就是解释说明)
    '''
    plt.legend(("cdf" , "histogram") , loc = "upper left")
    plt.show()

    '''
    找到直方图中的最小值(除了0),并把它用于wiki中的直方图均衡化公式,使用Numpy
    的掩膜数组,对于掩膜数组的所有操作都只对non-masked元素有效
    构建Numpy掩膜数组,cdf为原数组,当数组元素为0时,掩盖(计算时被忽略)
    numpy.ma.masked_equal(x,value,copy=True):
    掩膜一个数组当之等于给定值时
    '''
    cdf_m = np.ma.masked_equal(cdf , 0)
    #真正的归一化
    cdf_m = ( cdf_m - cdf_m.min() ) * 255  / (cdf_m.max() - cdf_m.min() )
    '''
    numpy.ma.filled
    '''
    cdf = np.ma.filled(cdf_m , 0).astype("uint8")

def mask_filled():
    img = cv2.imread("scenery.jpg" , 0)
    #img = cv2.imread("wiki.jpg" , 0)
    #img = cv2.imread("0_snap.png" , 0)
    '''
    numpy.ndarray.flatten(order='C'):扁平化,复制一个一维的array出来
    C表示按照行的顺序,F表示按照列的顺序
    '''
    hist , bins = np.histogram(img.flatten() , 256 , [0,256])
    '''
    numpy.cumsum(a,axis=None,dtype=None ,out=None):
    a:输入数组
    作用:计算每一行或每一列的累积和,相当于分布求和函数,落在<=a的数量
    '''
    #计算累积分布图(不是标准化的)
    cdf = hist.cumsum()
    '''
    找到直方图中的最小值(除了0),并把它用于wiki中的直方图均衡化公式,使用Numpy
    的掩膜数组,对于掩膜数组的所有操作都只对non-masked元素有效
    构建Numpy掩膜数组,cdf为原数组,当数组元素为0时,掩盖(计算时被忽略)
    numpy.ma.masked_equal(x,value,copy=True):
    掩膜一个数组当之等于给定值时
    '''
    cdf_m = np.ma.masked_equal(cdf , 0)
    #真正的归一化
    cdf_m = ( cdf_m - cdf_m.min() ) * 255  / (cdf_m.max() - cdf_m.min() )
    '''
    numpy.ma.filled
    '''
    #将变换应用到图片上
    cdf = np.ma.filled(cdf_m , 0).astype("uint8")
    img2 = cdf[img]
    plt.subplot(121) , plt.imshow(img , "gray") , plt.title("original image")
    plt.subplot(122) , plt.imshow(img , "gray") , plt.title("historgam equalization")
    plt.xlim([0,256])
    plt.show()

'''
opencv中直方图均衡化
cv2.euqalizeHist(src[,dst])->dst
作用:将输入图像的直方图进行均衡化
返回经过直方图处理的图像
处理过程:先计算原图像的直方图,然后对直方图进行标准化
然后计算每个灰度值的直方图: Hi'=在0<=j>> a = np.ones((2,2))
>>> b = np.eye(2)
>>> print np.vstack((a,b))
[[ 1.  1.]
 [ 1.  1.]
 [ 1.  0.]
 [ 0.  1.]]
>>> print np.hstack((a,b))
[[ 1.  1.  1.  0.]
 [ 1.  1.  0.  1.]]

    '''
    #相当于在原图像上叠加均衡化的直方图,从而使得图片亮度基本保持一致,这个是将两个图像放在一起
    res = np.hstack((img , equ))
    cv2.imwrite("res.png" , res)
    plt.subplot(121) , plt.imshow(img , "gray") , plt.title("original")
    plt.subplot(122) , plt.imshow(equ , "gray") , plt.title("opencv historgam equalization")
    plt.show()

'''
CLAHE:优先对比适应性直方图均衡化
直方图均衡化的缺点:会改变整个图像的对比度,会丢失信息。
原因:图像的直方图并不是集中在某一个区域
解决方法:使用自适应的直方图均衡化,将图像分成很多小块(tiles,默认8*8)
再对每个小块分别进行直方图均衡化,在每一个区域中,直方图会集中在某一个小的区域
中。如果有噪声,噪声会被放大。
为了避免上述情况要使用对比度限制,对每个小块来说,如果直方图中的bin超过对比度
上限,就把其中的像素点均匀分散到其他的bins中,然后进行直方图均衡化。
最后:为了去除每个小块之间人造边界,使用双线性插值,对小块进行缝合。
'''
def CLAHE_test():
    img = cv2.imread("tsukuba_l.png" , 0)
    '''
    cv2.createCLAHE([,clipLimit[,tileGridSize]])->retval
    '''
    clahe = cv2.createCLAHE(clipLimit=2.0 , tileGridSize=(8,8))
    cl1 = clahe.apply(img)
    plt.subplot(121) , plt.imshow(img , "gray") , plt.title("original")
    plt.subplot(122) , plt.imshow(cl1 , "gray") , plt.title("clahe equalization")
    plt.show()







if __name__ == "__main__":
    #myHist()
    #mask_histogram()
    #numpy_historgamEqualization()
    #mask_filled()
    #opencv_histogramEqualization()
    CLAHE_test()

你可能感兴趣的:(Opencv3.0-python的那些事儿:(八)、Opencv的直方图均衡化)