直方图及其操作

一、直方图理论

灰度级范围[0,L-1]的数字图像的直方图是离散函数
在这里插入图片描述
其中r的k是第k级灰度值,n的k是图像中灰度为r的像素个数。

二、普通直方图

def plot_demo(image):
    """
    :param image: hist(
        x, bins=None, range=None, density=False, weights=None,
        cumulative=False, bottom=None, histtype='bar', align='mid',
        orientation='vertical', rwidth=None, log=False, color=None,
        label=None, stacked=False, *, data=None, **kwargs)
    :return:
    hist(X,bins);bins是一个事先给定的区间划分,统计X在bins这个区间划分下的个数
    ravel:将多维数组降为一维,按需生成副本,返回的数组和输入数组拥有相同数据类型。
    """
    plt.hist(image.ravel(), 256, [0, 256])
    plt.show()

在这里插入图片描述

三、RGB直方图

# 直方图分为r,g,b显示
def image_hist(image):
    color = ('blue', 'green', 'red')
    for i, color in enumerate(color):
        """
        calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
            images: 原图像图像格式为 uint8 或 float32。当传入函数时应用中括号 [] 括起来,如[img]
            channels: 如果输入的图像是灰度图像,值为[0];如果是彩色图像,传入的参数可以是[0][1][2],它们分别对应着 BGR。
            mask: 掩模图像。统计整幅图像的直方图,把它设为None。若想统计图像某一分的直方图就制作一个掩模图像并使用它。
            histSize:BIN 的数目,用中括号括来。上面的直方图显示了每个像素值的像素数从0到255,需要256个值才能显示上述直方图。若需要找到介于0到15之间的像素数,然后是16到31、...、240 到 255,只需要16个值来表示直方图。
                即将整个直方图拆分为 16 个子部分,每个子部分的值就是其中所有像素计数的总和。这每个子部分都称为"BIN"。在第一种情况下,条柱数为256(每个像素一个),而在第二种情况下,它只有16。
            ranges: 像素值范围常为 [0 256]
        """
        hist = cv.calcHist([image], [i], None, [256], [0, 256])
        # plot(hist,color)——创建color中数据对hist中对应值的二维线图
        plt.plot(hist, color=color)
        # xlim(*args, **kwargs):设置x, y轴的数值显示范围
        plt.xlim([0, 256])
    plt.show()

在这里插入图片描述

四、直方图均衡

  • 原理:直方图均衡能自动确定变换函数,通过直方图均衡变换函数产生有均匀直方图的输出图像,补偿图像在视觉上难以区分灰度级的差别。
  • 直方图均衡化基于灰色,均衡意味着将一个分布(给定直方图)映射到另一个分布(强度值的更宽和更均匀的分布),因此强度值在整个范围内扩展。
# 全局
def equalHist_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # equalizeHist(src, dst=None)
    dst = cv.equalizeHist(gray)
    cv.imshow('equalHist_demo', dst)

在这里插入图片描述

局部变换原理:定义一个邻域,把该区域的中心从一个像素移至另一个像素。在每个位置,计算邻域中的点的直方图,得到的不是直方图均衡化,就是规定化变换函数,且这个函数用于映射邻域中心像素的灰度。在邻域的中心被移至一个相邻相邻位置时,可以新数据更新前一位置得到的直方图,而不必区域每移动一个像素位置就计算邻域中所有像素的直方图。

# 局部:由于全局变换没有必要保证期望的局部增强,一些像素的计算可能被忽略。
def clahe_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    """
    createCLAHE(clipLimit=None, tileGridSize=None)
        clipLimit:对比度限制阈值
        tileGridSize直方图均衡化网格的大小。输入图像将被分割成大小相等的矩形块。tileGridSize定义行和列中的tiles数量。
    """
    clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    dst = clahe.apply(gray)
    cv.imshow('clahe_demo', dst)

在这里插入图片描述

五、图片比较

# 创建图像
def create_rgb_hist(image):
    h, w, c = image.shape
    # 16 * 16 * 16, 1:每一列为16
    rgbHist = np.zeros([16 * 16 * 16, 1], np.float32)
    bsize = 256 / 16
    for row in range(h):
        for col in range(w):
            b = image[row, col, 0]
            g = image[row, col, 1]
            r = image[row, col, 2]
            index = np.int(b / bsize) * 16 * 16 + np.int(g / bsize) * 16 + np.int(r / bsize)  #降为16*16
            rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1
        return rgbHist


#  compareHist获取一个数值参数,表示两个直方图相互匹配的程度
def hist_compare(image1, image2):
    hist1 = create_rgb_hist(image1)
    hist2 = create_rgb_hist(image2)
    # HISTCMP_BHATTACHARYYA:巴氏距离,越小越相似
    match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA)
    # HISTCMP_CORREL:相关性,越大越相似
    match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)
    # HISTCMP_CHISQR:卡方,越大越不相似
    match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)
    print('巴氏距离:%s,相关性:%s,卡方:%s' % (match1, match2, match3))

image1 = cv.imread('D:/OpenCV/opencv-python/lancet.png')
image2 = cv.imread('D:/OpenCV/opencv-python/qianxie.png')
# cv.imshow('image1', image1)
# cv.imshow('image2', image2)
hist_compare(image1, image2)

巴氏距离:1.0,相关性:-0.0030097475217914548,卡方:512.0

六、反向投影

# 反向投影;后投影是一种记录给定图像的像素适合直方图模型中像素分布的方式。
def back_project_demo():
    # 读入图像
    sample = cv.imread('D:/OpenCV/opencv-python/xiexie.png')
    target = cv.imread('D:/OpenCV/opencv-python/yiyi.jpg')
    # 转入hsv色彩空间
    roi_hsv = cv.cvtColor(sample, cv.COLOR_RGB2HSV)
    target_hsv = cv.cvtColor(target, cv.COLOR_RGB2HSV)
    """
    calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None):统计直方图信息
        images: 原图像图像格式为 uint8 或 float32。当传入函数时应用中括号 [] 括起来,如[img]
        channels: 如果输入的图像是灰度图像,值为[0];如果是彩色图像,传入的参数可以是[0][1][2],它们分别对应着 BGR。
        mask: 掩模图像。统计整幅图像的直方图,把它设为None。若想统计图像某一分的直方图就制作一个掩模图像并使用它。
        histSize:BIN 的数目,用中括号括来。上面的直方图显示了每个像素值的像素数从0到255,需要256个值才能显示上述直方图。若需要找到介于0到15之间的像素数,然后是16到31、...、240 到 255,只需要16个值来表示直方图。
                即将整个直方图拆分为 16 个子部分,每个子部分的值就是其中所有像素计数的总和。这每个子部分都称为"BIN"。在第一种情况下,条柱数为256(每个像素一个),而在第二种情况下,它只有16。
        ranges: 像素值范围常为 [0 256]
    """
    roi_hist = cv.calcHist([roi_hsv], [0, 1], None, [32, 64], [0, 180, 0, 256])
    # normalize对数组进行归一化为0到255之间
    """
    normalize(src, dst, alpha=None, beta=None, norm_type=None, dtype=None, mask=None)
        alpha:距离归一化模式的最小值
        beta:距离归一化模式的最大值
        norm_type:归一化的类型
            NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
            NORM_INF:可能是归一化数组的C-范数(绝对值的最大值)
            NORM_L1 :归一化数组的L1-范数(绝对值的和)
            NORM_L2: 归一化数组的(欧几里德)L2-范数
        dtype:为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
        mask:操作掩膜,用于指示函数是否仅仅对指定的元素进行操作
    """
    cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)
    # 产生反向投影;calcBackProject获取相同图像的Backprojection
    """
    calcBackProject(images, channels, hist, ranges, scale, dst=None)
        images:输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
        channels:用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,第二个数组通道从图像image[0].channels()到image[0].channels()+image[1].channels()-1计数
        hist:输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
        ranges:直方图中每个维度bin的取值范围
        scale=1:可选输出反向投影的比例因子
        dst:backProject:目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
    """
    dst = cv.calcBackProject([target_hsv], [0, 1], roi_hist, [0, 180, 0, 256], 1)
    cv.imshow('back_project_demo', dst)

反向投影

七、原始图像与掩模图像直方图比较

def mask_demo(image):
    # 把彩色图像转换为灰色图像有两种方法,一种IMREAD_GRAYSCALE,一种cvtColor的COLOR_RGB2GRAY
    # src = cv.imread('D:/OpenCV/opencv-python/qianxie.png', cv.IMREAD_GRAYSCALE)
    src = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
    mask = np.zeros(src.shape, np.uint8)  # 必须是mask.rows == size.height+2 && mask.cols == size.width+2
    mask[200:400, 200:400] = 255
    # 掩膜结果图像显示出来
    cv.imshow('image', src)
    # 计算直方图信息
    hist_target = cv.calcHist([src], [0], None, [256], [0, 256])
    target_hist = cv.calcHist([src], [0], mask, [256], [0, 256])
    # 原始图像的直方图
    plt.plot(hist_target)
    # 掩膜结果图像的直方图
    plt.plot(target_hist)
    plt.show()  # 需要这个直方图图像才显示出来

掩模图像

  • 橙色为掩膜直方图信息,蓝色为原始图像信息

八、calcHist统计直方图信息

# 二进制直方图计算与显示
def hist2d_demo(image):
    hsv = cv.cvtColor(image, cv.COLOR_RGB2HSV)
    # 计算;calcHist来计算图像数组的直方图
    hist = cv.calcHist([hsv], [0, 1], None, [16, 16], [0, 180, 0, 256])
    # 显示
    plt.imshow(hist, interpolation='nearest')
    plt.title('2D Histogram')
    plt.show()

方块图

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值