2019-8-2 opencv图像处理10-直方图1(Histograms)获取,绘制与分析,掩膜

64 篇文章 3 订阅

官网参加https://docs.opencv.org/3.4.1/d1/db7/tutorial_py_histogram_begins.html

什么是是直方图?
直方图可以理解为是一个图表,通过它可以对图像的灰度分布有一个全面的了解。
它的X轴上是像素值(一般为0-255,不总是这样),Y轴是和X轴对应像素点的数量。

直方图是对图像的另外一种理解方式。

通过图像的直方图,你可以直观的了解图像的对比度、亮度、强度分布等。现在所有的图像处理工具都提供了直方图功能。
在这里插入图片描述
上图来自 www.cambridgeincolour.com/tutorials/histograms1.htm ,强烈推荐访问该网站获取更多信息。

观察上图(注意:直方图是灰度图,不是彩色图)。左边区域显示的是图像中较暗像素的数量,而右边区域显示的图像中明亮像素的数量。从直方图中可以发现,图像中较暗区域比明亮区域要大,而中间部分的像素数量很少。

1.获得直方图

我们已经知道了什么是直方图,现在可以研究如何获得直方图。opencv和numpy都有内置函数获得直方图。在使用这些函数之前,我们先来了解一下直方图的相关术语。

BINS :上面的直方图显示了每个像素值(pixel value)对应的像素数量。例如:像素值是从0到255,你就需要255个数来显示上面的直方图。但是,如果你不需要获得所有像素值对应的像素数量,而是只想知道2个像素值之间像素数量,该怎么办呢?例如:你需要知道0-15之间像素数量,然后是16-31…最后是240-255。此时你只需要16个值来绘制直方图。这个例子就在下面链接中 https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html#histogram-calculation

所以,你只需要把直方图分成16个子部分,每个子部分的值就是其中所有像素数量之和。这里的子部分,我们就称为BINS。上面提到的第1个例子中有256个BIN,第2个例子中有16个BIN。在OpenCV 的文档中用histSize表示BINS。

DIMS : 我们收集数据的参数数目。在本例中,我们对收集到数据只考虑1件事情,灰度值。所以DIMS=1。

RANGE : 你要测量的灰度值范围。一般[0,255],也就是所有的灰度值。

1-1.opencv中的直方图计算

opencv提供cv.calcHist() 函数获得直方图。

hist = cv.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
  • images:原图像(类型为uint8 或float32)。当传入函数时应该用中括号[] 括起来,例如:[img]。
  • channels : 需要用中括号括起来。它是我们计算直方图的通道索引。如果是灰度图,值为[0];如果是彩色图,值为[0], [1] or [2],代表计算直方图的蓝色,绿色或者红色通道。
  • mask :图像遮罩。如果要或者整个图像的直方图,就设置为None。如果要获得图像中某个区域的直方图,你就必须创建1个遮罩并使用它。
  • histSize : BINS数量。要用中括号括起来。例如:全部,[256]。
  • ranges :像素值范围。通常为[0,256]

例,获得下图灰度图的直方图
在这里插入图片描述
代码

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


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

plt.plot(hist)
plt.xlim([0,256])
plt.show()

在这里插入图片描述

hist 是一个256x1的数组,每一个值代表了与次灰度值对应的像素点数目。

1-2.numpy中的直方图计算

numpy中提供np.histogram()函数获得直方图。
例,获得直方图

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


img = cv2.imread('result.jpg',0)
hist,bins = np.histogram(img.ravel(),256,[0,256])

plt.plot(hist)
plt.xlim([0,256])
plt.show()

和opencv中对比,区别就是下面这句

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

hist 与opencv计算一样。计算的一样。但是这里的bins是257,因为Numpy计算bins 的方式为:0-0.99,1-1.99,2-2.99 等。所以最后一个范围是255-255.99。为了表示它,所以在bins 的结尾加上了256。但是我们不需要256,到255就够了。

numpy还有另外一个函数np.bincount() ,它的运行速度是histogram()的10倍。如果是1维直方图,请使用np.bincount()。使用别忘记设置minlength = 256。例如

hist = np.bincount(img.ravel(),minlength=256)

注意:opencv的calcHist()要比np.histgram()快40倍。

2.绘制直方图

有2种方法可以绘制直方图
a.简便方法:使用Matplotlib的绘图函数
b.复杂方法:使用opencv中的绘图函数

2-1.使用Matplotlib

Matplotlib提供绘图函数matplotlib.pyplot.hist()。这个函数可以直接统计并绘制直方图。不再需要使用calcHist()或者np.histogram()函数。
例1,使用Matplotlib绘制直方图

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

img = cv2.imread('result.jpg',0)
plt.hist(img.ravel(),256,[0,256])
plt.show()

在这里插入图片描述
直方图如上。

你也可以使用Matplotlib的普通绘画功能,这个对于bgr图非常好。不过,首先必须找到直方图数据。
例2,使用Matplotlib的普通绘画函数绘制bgr图像的直方图

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

img = cv2.imread('result.jpg')

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.show()

在这里插入图片描述
直方图显示如上。

2-2.使用opencv

你也可以使用opencv的cv.line() 和cv.polyline()函数来画出上面的图。
OpenCV-Python2有官方的例子,samples/python/hist.py。

3.掩膜应用

我们可以使用cv.calcHist() 函数去找到整个图像的直方图。那么如何获得局部区域的直方图呢?可以创建一个掩膜图像,需要获得直方图区域设置为白色,剩余部分设置为黑色。然后把这个掩膜图像传入函数。

例,创建掩膜

# -*- coding: cp936 -*-
import cv2 
import numpy as np
from matplotlib import pyplot as plt


img = cv2.imread('result.jpg',0)

# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img,img,mask = mask)
# Calculate histogram with mask and without mask
# Check third argument for 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()

在这里插入图片描述
结果如上图。蓝色是整个图像的直方图,红色是局部区域直方图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值