OpenCV-Python——第18.3章:2D直方图

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yukinoai/article/details/88071816

目录

1 OpenCV中的2D直方图         2 Numpy中2D直方图        3 绘制2D直方图


在前面的部分我们介绍了如何绘制一维直方图,之所以称为一维,是因为我们只考虑了图像的一个特征:灰度值。但是在 2D 直方图中我们就要考虑 两个图像特征。对于彩色图像的直方图通常情况下我们需要考虑每个的颜色(Hue)和饱和度(Saturation)。根据这两个特征绘制 2D 直方图。

1 OpenCV中的2D直方图

使用函数 cv2.calcHist() 来计算直方图既简单又方便。

cv2.calcHist(images, channels, mask, histSize, ranges, hist, accumulate)

  • images:原图像(图像格式为 uint8 或 float32)。当传入函数时应该 用中括号 [] 括起来,例如:[img]。
  • channels:同样需要用中括号括起来,它会告诉函数我们要统计那幅图 像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是BGR彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
  • mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如 果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子)
  • histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。 5. ranges: 像素值范围,通常为 [0,256]
  • hist:是一个 256x1 的数组作为返回值,每一个值代表了与次灰度值对应的像素点数目。
  • accumulate:是一个布尔值,用来表示直方图是否叠加。

如果要绘制颜色直方图的话,我们首先需要将图像的颜色空间从 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。

例如:

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])

2 Numpy中2D直方图

Numpy 同样提供了绘制 2D 直方图的函数:np.histogram2d()。(绘制 1D 直方图时使用的是 np.histogram())。

Numpy函数就不展开讲了,第一个参数是 H 通道,第二个参数是 S 通道,第三个参数是 bins 的数 目,第四个参数是数值范围。

例如:

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]])

3 绘制2D直方图

下面用3中方法来绘制2D直方图

方法 1:使用 cv2.imshow()

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

方法2:使用matplotlib()

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

例如:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('test2.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.axis('off'),
plt.title('Original')

plt.subplot(122), plt.imshow(hist, interpolation='nearest'),
plt.title('2D Histogram')

plt.show()

结果如下:

 方法 3:OpenCV 风格

这种方法的2D直方图显示了对应的颜色。

首先创建了一个 HSV 格式的颜色地图,然后把它转换成 BGR 格式。再将得到的直方图与颜色直方图相乘。

程序如下:

import cv2
import numpy as np


# 定义回调函数
def set_scale(val):
    global hist_scale
    hist_scale = val


# 构建HSV颜色地图
hsv_map = np.zeros((180, 256, 3), np.uint8)
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

cv2.createTrackbar('scale', 'hist', hist_scale, 32, set_scale)

while(True):
    frame = cv2.imread('test1.jpg')
    cv2.imshow('camera', frame)
    # 通过图像金字塔降低分辨率,但不会对直方图有太大影响。
    # 但这种低分辨率,可以很好抑制噪声,从而去除孤立的小点对直方图的影响
    small = cv2.pyrDown(frame)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # 取 v 通道 (亮度) 的值。
    dark = hsv[:, :, 2] < 32
    hsv[dark] = 0
    h = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
    h = np.clip(h*0.005*hist_scale, 0, 1)
    vis = hsv_map*h[:, :, np.newaxis] / 255.0
    cv2.imshow('hist', vis)

    ch = 0xFF & cv2.waitKey(1)
    if ch == 27:
        break
cv2.destroyAllWindows()

结果如下:

                                           

猜你喜欢

转载自blog.csdn.net/yukinoai/article/details/88071816