• 2D 直方图


    2D 直方图

    目标
      本节我们会学习如何绘制 2D 直方图,我们会在下一节中使用到它。

    介绍
      在前面的部分我们介绍了如何绘制一维直方图,之所以称为一维,是因为我们只考虑了图像的一个特征:灰度值。但是在 2D 直方图中我们就要考虑两个图像特征。对于彩色图像的直方图通常情况下我们需要考虑每个的颜色(Hue)和饱和度(Saturation)。根据这两个特征绘制 2D 直方图。
      OpenCV 的官方文档中包含一个创建彩色直方图的例子。本节就是要和大家一起来学习如何绘制颜色直方图,这会对我们下一节学习直方图投影有所帮助。
      
    OpenCV 中的 2D 直方图
      使用函数 cv2.calcHist() 来计算直方图既简单又方便。如果要绘制颜色直方图的话,我们首先需要将图像的颜色空间从 BGR 转换到 HSV。(记住,计算一维直方图,要从 BGR 转换到 HSV)。计算 2D 直方图,函数的参数要做如下修改:
      • channels=[0,1] 因为我们需要同时处理 H 和 S 两个通道。
      • bins=[180,256]H 通道为 180,S 通道为 256。
      • range=[0,180,0,256]H 的取值范围在 0 到 180,S 的取值范围在 0 到 256。
    代码如下:

    # -*- coding: utf-8 -*-
    """
    Created on Thu Jan 16 19:37:21 2014
    @author: duan
    """
    import cv2
    import numpy as np
    img = cv2.imread('home.jpg')
    hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Numpy 中 2D 直方图
       Numpy 同样提供了绘制 2D 直方图的函数:np.histogram2d()。(还记得吗,绘制 1D 直方图时我们使用的是 np.histogram())。

    # -*- coding: utf-8 -*-
    """
    Created on Thu Jan 16 19:37:21 2014
    @author: duan
    """
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    img = cv2.imread('home.jpg')
    hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    第一个参数是 H 通道,第二个参数是 S 通道,第三个参数是 bins 的数目,第四个参数是数值范围。
    现在我们要看看如何绘制颜色直方图。

    绘制 2D 直方图
    方法 1:使用 cv2.imshow() 我们得到结果是一个 180x256 的两维数组。所以我们可以使用函数 cv2.imshow() 来显示它。但是这是一个灰度图,除非我们知道不同颜色 H 通道的值,否则我们根本就不知道那到底代表什么颜色。

    方法 2:使用 Matplotlib() 我们还可以使用函数 matplotlib.pyplot.imshow()来绘制 2D 直方图,再搭配上不同的颜色图(color_map)。这样我们会对每个点所代表的数值大小有一个更直观的认识。但是跟前面的问题一样,你还是不知道那个数代表的颜色到底是什么。虽然如此,我还是更喜欢这个方法,它既简单又好用。注意:在使用这个函数时,要记住设置插值参数为 nearest

    注意:在使用这个函数时,要记住设置插值参数为 nearest。

    代码如下:

    # -*- coding: utf-8 -*-
    """
    Created on Thu Jan 16 19:37:21 2014
    @author: duan
    """
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    img = cv2.imread('home.jpg')
    hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
    plt.imshow(hist,interpolation = 'nearest')
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    下面是输入图像和颜色直方图。X 轴显示 S 值,Y 轴显示 H 值。
    在这里插入图片描述
    在直方图中,你可以看到在 H=100,S=100 附近有比较高的值。这部分与天的蓝色相对应。同样另一个峰值在 H=25 和 S=100 附近。这一宫殿的黄色相对应。你可用通过使用图像编辑软件(GIMP)修改图像,然后在绘制直方图看看我说的对不对。

    方法 3:OpenCV 风格 在官方文档中有一个关于颜色直方图的例子。运行一下这个代码,你看到的颜色直方图也显示了对应的颜色。简单来说就是:输出结果是一副由颜色编码的直方图。效果非常好(虽然要添加很多代码)。

    在那个代码中,作者首先创建了一个 HSV 格式的颜色地图,然后把它转换成 BGR 格式。再将得到的直方图与颜色直方图相乘。作者还用了几步来去除小的孤立的的点,从而得到了一个好的直方图。

    我把对代码的分析留给你们了,自己去玩一下把。下边是对上边的图运行这段代码之后得到的结果:
    在这里插入图片描述
      从直方图中我们可以很清楚的看出它们代表的颜色,蓝色,换色,还有棋盘带来的白色,漂亮!!!
      练习

    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
    import numpy as np
    import cv2
    from time import clock
    import sys
    import video
    #video 模块也是 opencv 官方文档中自带的
    if __name__ == '__main__': # 构建 HSV 颜色地图
    hsv_map = np.zeros((180, 256, 3), np.uint8)
    # np.indices 可以返回由数组索引构建的新数组。
    # 例如:np.indices((3,2));其中(3,2)为原来数组的维度:行和列。
    # 返回值首先看输入的参数有几维:(3,2)有 2 维,所以从输出的结果应该是
    # [[a],[b]], 其中包含两个 3 行,2 列数组。
    # 第二看每一维的大小,第一维为 3, 所以 a 中的值就 0 到 2(最大索引数),
    # a 中的每一个值就是它的行索引;同样的方法得到 b(列索引)
    # 结果就是
    # array([[[0, 0],
    # [1, 1],
    # [2, 2]],
    ## [[0, 1],
    # [0, 1],
    # [0, 1]]])
    h, s = np.indices(hsv_map.shape[:2])
    hsv_map[:,:,0] = h
    hsv_map[:,:,1] = s
    hsv_map[:,:,2] = 255
    hsv_map = cv2.cvtColor(hsv_map, cv2.COLOR_HSV2BGR)
    cv2.imshow('hsv_map', hsv_map)
    cv2.namedWindow('hist', 0)
    hist_scale = 10
    def set_scale(val):
    global hist_scale
    hist_scale = val
    cv2.createTrackbar('scale', 'hist', hist_scale, 32, set_scale)
    try: fn = sys.argv[1]
    except: fn = 0
    cam = video.create_capture(fn, fallback='synth:bg=../cpp/baboon.jpg:class=chess:noise=0.05')
    
    
    while True:
    flag, frame = cam.read()
    cv2.imshow('camera', frame)
    # 图像金字塔
    # 通过图像金字塔降低分辨率,但不会对直方图有太大影响。
    # 但这种低分辨率,可以很好抑制噪声,从而去除孤立的小点对直方图的影响。
    small = cv2.pyrDown(frame)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # 取 v 通道 (亮度) 的值。
    # 没有用过这种写法,还是改用最常见的用法。
    #dark = hsv[...,2] < 32
    # 此步操作得到的是一个布尔矩阵,小于 32 的为真,大于 32 的为假。
    dark = hsv[:,:,2] < 32
    hsv[dark] = 0 h = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
    #numpy.clip(a, a_min, a_max, out=None)[source]
    #Given an interval, values outside the interval are clipped to the interval edges.
    #For example, if an interval of [0, 1] is specified, values smaller
    #than 0 become 0, and values larger than 1 become 1.
    #>>> a = np.arange(10)
    #>>> np.clip(a, 1, 8)
    #array([1, 1, 2, 3, 4, 5, 6, 7, 8, 8])
    h = np.clip(h*0.005*hist_scale, 0, 1)
    #In numpy one can use the 'newaxis' object in the slicing syntax to create an
    #axis of length one. one can also use None instead of newaxis,
    #the effect is exactly the same
    #h 从一维变成 3 维
    vis = hsv_map*h[:,:,np.newaxis] / 255.0
    cv2.imshow('hist', vis)
    ch = 0xFF & cv2.waitKey(1)
    if ch == 27:
    break
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
  • 相关阅读:
    基于ssm+jsp框架实现的学生选课信息管理系统【源码+数据库】
    暴力破解-破解 Apache BASIC 认证
    LeetCode 之 移除元素
    web系统接口设计总结
    指纹浏览器是什么?可以用来解决流量套利的什么问题?
    Vue(三)——过滤器,内置指令,自定义指令,组件
    ddddocr基本使用和介绍
    Self Attention(自注意力机制)原理讲解
    交换机聚合配置 (H3C)
    C/C++算法入门 | 简单模拟
  • 原文地址:https://blog.csdn.net/yyyyyya_/article/details/125546803