opencv 图像直方图绘制

目标
• 使用 OpenCV 或 Numpy 函数计算直方图
• 使用 Opencv 或者 Matplotlib 函数绘制直方图
• 将要学习的函数有: cv2.calcHist(), np.histogram()
原理
  什么是直方图呢?通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值(0 到 255), y 轴是图片中具有同一个灰度值的点的数目。
  直方图其实就是对图像的另一种解释。一下图为例,通过直方图我们可以对图像的对比度,亮度,灰度分布等有一个直观的认识。几乎所有的图像处理软件都提供了直方图分析功能。下图来自Cambridge in Color website,强烈推荐你到这个网站了解更多知识
    这里写图片描述
  让我们来一起看看这幅图片和它的直方图吧。 (要记住,直方图是根据灰度图像绘制的,而不是彩色图像)。直方图的左边区域像是了暗一点的像素数量,右侧显示了亮一点的像素的数量。从这幅图上你可以看到灰暗的区域比两的区域要大,而处于中间部分的像素点很少。

1、 统计直方图

  现在我们知道什么是直方图了,那怎样获得一副图像的直方图呢?OpenCV 和 Numpy 都有内置函数做这件事。在使用这些函数之前我们有必要想了解一下直方图相关的术语。
BINS: 上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0到 255,就需要 256 个数来显示上面的直方图。但是,如果不需要知道每一个像素值的像素点数目的,而只希望知道两个像素值之间的像素点数目怎么办呢?举例来说,我们想知道像素值在 0 到 15 之间的像素点的数目,接着是 16 到 31,…., 240 到 255。我们只需要 16 个值来绘制直方图。 OpenCV Tutorials on histograms中例子所演示的内容。那到底怎么做呢?你只需要把原来的 256 个值等分成 16 小组,取每组的总和。而这里的每一个小组就被成为 BIN。第一个例子中有 256 个 BIN,第二个例子中有 16 个 BIN。在 OpenCV 的文档中用 histSize 表示 BINS。
DIMS:表示我们收集数据的参数数目。在本例中,我们对收集到的数据
只考虑一件事:灰度值。所以这里就是 1。
RANGE:就是要统计的灰度值范围,一般来说为 [0, 256],也就是说所
有的灰度值
使用 OpenCV 统计直方图 函数 cv2.calcHist 可以帮助我们统计一幅图像的直方图。我们一起来熟悉一下这个函数和它的参数:
cv2:calcHist(images; channels; mask; histSize; ranges[; hist[; accumulate]])
images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如: [img]。
channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0], [1], [2] 它们分别对应着通道 B, G, R。
mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子)
histSize:BIN 的数目。也应该用中括号括起来,例如: [256]。
ranges: 像素值范围,通常为 [0, 256]
让我们从一副简单图像开始吧。以灰度格式加载一幅图像并统计图像的直图。

img = cv2.imread('home.jpg',0)
hist = cv2.calcHist([img],[0],None,[256],[0,256])

hist 是一个 256x1 的数组,每一个值代表了与次灰度值对应的像素点数目。
使用 Numpy 统计直方图 Numpy 中的函数 np.histogram() 也可以帮
我们统计直方图。你也可以尝试一下下面的代码:

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

hist 与上面计算的一样。但是这里的 bins 是 257,因为 Numpy 计算bins 的方式为: 0-0.99,1-1.99,2-2.99 等。所以最后一个范围是 255-255.99。为了表示它,所以在 bins 的结尾加上了 256。但是我们不需要 256,到 255就够了。
其 他: Numpy 还 有 一 个 函 数 np.bincount(), 它 的 运 行 速 度 是np.histgram 的 十 倍。 所 以 对 于 一 维 直 方 图, 我 们 最 好 使 用 这 个函 数。 使 用 np.bincount 时 别 忘 了 设 置 minlength=256。 例 如,hist=np.bincount(img.ravel(), minlength=256)
注意: OpenCV 的函数要比 np.histgram() 快 40 倍。所以坚持使用OpenCV 函数。

2、绘制直方图

有两种方法来绘制直方图:
1. Short Way(简单方法):使用 Matplotlib 中的绘图函数。
2. Long Way(复杂方法):使用 OpenCV 绘图函数
使用 Matplotlib Matplotlib 中有直方图绘制函数:matplotlib.pyplot.hist()它可以直接统计并绘制直方图。你应该使用函数 calcHist() 或 np.histogram()统计直方图。代码如下:

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

img = cv2.imread('image/lufei.jpeg',0)
plt.hist(img.ravel(),255,[0,256]);
plt.title("Matplotlib Method")
plt.show()

这里写图片描述这里写图片描述
或者你可以只使用 matplotlib 的绘图功能, 这在同时绘制多通道(BGR)
的直方图,很有用。但是你首先要告诉绘图函数你的直方图数据在哪里。运行
一下下面的代码:

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

img = cv2.imread('image/lufei.jpeg')
color = ('b','g','r')
for i,col in enumerate(color):
    histr = cv2.calcHist([img], [i], None, [256], [0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])
plt.title("Matplotlib color Method")
plt.show()

结果图:
这里写图片描述
使用 OpenCV 使用 OpenCV 自带函数绘制直方图比较麻烦,这里不作介
绍,有兴趣可以自己研究。可以参考 OpenCV-Python2 的官方示例。

3、使用掩模

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

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

img = cv2.imread('image/lufei.jpeg',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.xlim([0,256])
plt.show()

结果图:
这里写图片描述
蓝线是整幅图像的直方图,绿线是进行掩模之后的直方图。

参考:OpenCV官方教程中文版(For Python)

  • 10
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值