直方图

1.0 基本概念

    什么是直方图呢?通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值(0 到 255),y 轴是图片中具有同一个灰度值的点的数目。

    直方图其实就是对图像的另一种解释。一下图为例,通过直方图我们可以对图像的对比度,亮度,灰度分布等有一个直观的认识。几乎所有的图像处理软件都提供了直方图分析功能。

    让我们来一起看看这幅图片和它的直方图吧。(要记住,直方图是根据灰图像绘制的,而不是彩色图像)。直方图的左边区域像是了暗一点的像素数量,右侧显示了亮一点的像素的数量。从这幅图上你可以看到灰暗的区域比两的区域要大,而处于中间部分的像素点很少。

    现在我们知道什么是直方图了,那怎样获得一副图像的直方图呢?OpenCV 和 Numpy 都有内置函数做这件事。在使用这些函数之前我们有必要想了解一下直方图相关的术语。

    BINS:上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0到 255,你就需要 256 个数来显示上面的直方图。但是,如果你不需要知道每一个像素值的像素点数目的,而只希望知道两个像素值之间的像素点数目怎么办呢?举例来说,我们想知道像素值在 0 到 15 之间的像素点的数目,接着是 16 到 31,....,240 到 255。我们只需要 16 个值来绘制直方图。OpenCV
Tutorials on histograms中例子所演示的内容。那到底怎么做呢?你只需要把原来的 256 个值等分成 16 小组,取每组的总和。而这里的每一个小组就被成为 BIN。

    DIMS:表示我们收集数据的参数数目。在本例中,我们对收集到的数据只考虑一件事:灰度值。所以这里就是 1。

    RANGE:就是要统计的灰度值范围,一般来说为 [0,256],也就是说所有的灰度值

 

1.1 matlab绘制直方图

【matlab绘制直方图】
1.hist()函数
功能:根据数据源和像素级绘制直方图
语法:plt.hist(o.ravel(),256):根据数据源和像素级绘制直方图
    |-数据源:必须是一维数组,一般灰度图像都是二维数组,o.ravel()将其转换为一维数组
    |-像素级:一般256
2.ravel()函数
功能:将原始图像(二维数组)o转换为一维数组
语法:一维数组=多维数组.ravel()
    [[1,2,3],
     [4,5,6],
     [7,8,9]]        转成一维数组       [1,2,3,4,5,6,7,8,9]
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("image\\boat.jpg",0)
print(o.shape)
cv2.imshow("original",o)
print(o)
plt.hist(o.ravel(),256)
print(o.ravel())
plt.show()
cv2.waitKey()
cv2.destroyAllWindows()

输出:

(1024, 1024)
[[127 125 124 ... 171 170 163]
 [127 126 125 ... 168 168 166]
 [128 127 126 ... 163 165 170]
 ...
 [113 113 114 ...  96  98 104]
 [113 114 115 ...  95  96 100]
 [113 114 116 ...  94  94  98]]
[127 125 124 ...  94  94  98]

【扩充】plot的使用

【plot使用】
plt.plot(x, y)
    |-x:指定x的取值
    |-y:指定y的取值
np.arange(0, 5, 0.1)
    |-0:起点
    |-5:终点
    |-0.1:步长
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 5, 0.1)        #起始:0   结束:5    步长:0.1
y = np.sin(x)
plt.plot(x, y)
plt.show()

【plot使用】
plt.plot(a,color='r')
    |-a:给出y轴[1,2,1,2]的取值序列,x轴会按照单位长度自动对应填充[0,1,2,3]
    |-color:指定线的颜色
import numpy as np
import matplotlib.pyplot as plt
a= [1,2,1,2]  #仅有4个元素的列表
#以红色曲线,显示列表的值
plt.plot(a,color='r')  
plt.show()

1.2 使用OpenCV统计直方图

使用 OpenCV 统计直方图 函数 cv2.calcHist 可以帮助我们统计一幅图像的直方图。我们一起来熟悉一下这个函数和它的参数:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
1. images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如:[img]。
2. channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
3. mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。
4. histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。
5. ranges: 像素值范围,通常为 [0,256]

【使用openCV统计直方图】
hist = cv2.calcHist([img],[0],None,[256],[0,255])
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
1. images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如:[img]。
2. channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。
   如果输入图像是灰度图,它的值就是 [0];
   如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
3. mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。
4. histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。
5. ranges: 像素值范围,通常为 [0,256]
import cv2
import numpy as np
img=cv2.imread("image\\boat.jpg",0)
hist = cv2.calcHist([img],[0],None,[256],[0,255])
print(type(hist))           #<class 'numpy.ndarray'>
print(hist.size)            #256
print(hist.shape)           #(256, 1)
print(hist)

输出:

<class 'numpy.ndarray'>
256
(256, 1)
[[6.5000e+01]
 [2.1000e+01]
......
 [6.0000e+00]
 [0.0000e+00]]

1.3 使用OpenCV绘制直方图

【绘制灰度图像直方图】
hist = cv2.calcHist(images,channels,mask,histSize,ranges,accumulate)
    |-hist:直方图,一个二维数组
    |-images:原始图像,用[]括起来
    |-channels:指定通道 灰度图:[0]     彩色图:[0][1][2]分别对应BGR
    |-mask:掩码图像 在统计整幅图时,设为None
    |-histSize:BINS的数量  一般取[256]
    |-ranges:像素值的范围 [0,255]
    |-accumulate:累计标识,一般省略
histb = cv2.calcHist([o],[0],None,[256],[0,255])        先获取统计直方图
plt.plot(histb,color='r')                               再根据统计直方图画直方图
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("image\\boatGray.bmp",0)
histb = cv2.calcHist([o],[0],None,[256],[0,255])
print(histb)
plt.plot(histb,color='r')
plt.show()

输出:

[[0.000e+00]
 [0.000e+00]

......
 [0.000e+00]
 [2.000e+00]]

【绘制彩色图像直方图】
hist = cv2.calcHist(images,channels,mask,histSize,ranges,accumulate)
    |-hist:直方图,一个二维数组
    |-images:原始图像,用[]括起来
    |-channels:指定通道 灰度图:[0]     彩色图:[0][1][2]分别对应BGR
    |-mask:掩码图像 在统计整幅图时,设为None
    |-histSize:BINS的数量  一般取[256]
    |-ranges:像素值的范围 [0,255]
    |-accumulate:累计标识,一般省略
histb = cv2.calcHist([o],[0],None,[256],[0,255])        先获取统计直方图
histg = cv2.calcHist([o],[1],None,[256],[0,255])        先获取统计直方图
histr = cv2.calcHist([o],[2],None,[256],[0,255])        先获取统计直方图
plt.plot(histb,color='b')                               再根据统计直方图画直方图
plt.plot(histg,color='g')                               再根据统计直方图画直方图
plt.plot(histr,color='r')                               再根据统计直方图画直方图
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("image\\girl.bmp")
histb = cv2.calcHist([o],[0],None,[256],[0,255])
histg = cv2.calcHist([o],[1],None,[256],[0,255])
histr = cv2.calcHist([o],[2],None,[256],[0,255])
plt.plot(histb,color='b')
plt.plot(histg,color='g')
plt.plot(histr,color='r')
plt.show()

1.4 掩模直方图

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

【掩模演示】
mask=np.zeros(image.shape,np.uint8)         生成全黑图
mask[200:400,200:400]=255                   中国区域填充白色图
mi=cv2.bitwise_and(image,mask)              利用bitwise_and函数生成掩模图
import cv2
import numpy as np
import matplotlib.pyplot as plt
image=cv2.imread("image\\boat.bmp",0)
mask=np.zeros(image.shape,np.uint8)
mask[200:400,200:400]=255
mi=cv2.bitwise_and(image,mask)
cv2.imshow('original',image)
cv2.imshow('mask',mask)
cv2.imshow('mi',mi)
cv2.waitKey()
cv2.destroyAllWindows()

【掩模直方图】
mask=np.zeros(image.shape,np.uint8)         生成全黑图
mask[200:400,200:400]=255                   中国区域填充白色图
histMI=cv2.calcHist([image],[0],mask,[256],[0,255])     利用calcHist函数绘制
import cv2
import numpy as np
import matplotlib.pyplot as plt
image=cv2.imread("image\\girl.bmp",cv2.IMREAD_GRAYSCALE)
mask=np.zeros(image.shape,np.uint8)
mask[200:400,200:400]=255
histMI=cv2.calcHist([image],[0],mask,[256],[0,255])         #掩模图
histImage=cv2.calcHist([image],[0],None,[256],[0,255])      #原图
plt.plot(histImage)
plt.plot(histMI)
plt.show()

1.5 直方图均衡化

想象一下如果一副图像中的大多是像素点的像素值都集中在一个像素值范围之内会怎样呢?例如,如果一幅图片整体很亮,那所有的像素值应该都会很高。但是一副高质量的图像的像素值分布应该很广泛。所以你应该把它的直方图做一个横向拉伸(如下图),这就是直方图均衡化要做的事情。通常情况下这种操作会改善图像的对比度。

【直方图均衡化】
equ = cv2.equalizeHist(img)         将直方图均衡化
plt.hist(equ.ravel(),256)           hist()函数绘制均衡化直方图
plt.show()
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image\\equ.bmp',cv2.IMREAD_GRAYSCALE)
equ = cv2.equalizeHist(img)         #将直方图均衡化
plt.hist(img.ravel(),256)           #绘制原图
plt.show()
plt.figure()
plt.hist(equ.ravel(),256)           #绘制均衡化后的图
plt.show()

【直方图均衡化】
equ = cv2.equalizeHist(img)         将直方图均衡化
import cv2
import numpy as np
import matplotlib.pyplot as plt
o=cv2.imread("image\\equ.bmp",cv2.IMREAD_GRAYSCALE)
r=cv2.equalizeHist(o)               #将直方图均衡化
cv2.imshow("original",o)
cv2.imshow("result",r)
cv2.waitKey()
cv2.destroyAllWindows()

1.6 其他函数使用

1.6.1 subplot()函数

【subplot函数】
作用:在一幅图中显示多张图像
plt.subplot(121),plt.hist(img.ravel(),256)      在第一行第一列的位置放置原图的直方图
plt.subplot(122),plt.hist(equ.ravel(),256)      在第一行第二列的位置放置均衡化后图的直方图
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image\\equ.bmp',cv2.IMREAD_GRAYSCALE)
equ = cv2.equalizeHist(img)
plt.subplot(121),plt.hist(img.ravel(),256)
plt.subplot(122),plt.hist(equ.ravel(),256)
plt.show()

1.6.2 matplotlib.pyplot.imshow()函数

【matplot.pyplot.imshow函数的使用-->显示成灰度图像】
在使用matplot.pyplot.imshow进行显示时,由于通道采用RGB与opencv中BGR不一致,
所以只有这种方式能够正确显示[以灰度图读入,灰度图图输出]
    g=cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)           以灰度图读入
    plt.imshow(g,cmap=plt.cm.gray),plt.axis('off')  plt.axis('off')取消显示坐标   cmap指定颜色图谱
import cv2
import matplotlib.pyplot as plt
o = cv2.imread('image\\girl.bmp')
g=cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)       #以灰度图读入

#以BGR图读入,BGR图输出
plt.subplot(221)
plt.imshow(o),plt.axis('off')
#以BGR图读入,灰度图输出
plt.subplot(222)
plt.imshow(o,cmap=plt.cm.gray),plt.axis('off')
#以灰度图读入,BGR图输出
plt.subplot(223)
plt.imshow(g),plt.axis('off')
#以灰度图读入,灰度图图输出【正确】
plt.subplot(224)
plt.imshow(g,cmap=plt.cm.gray),plt.axis('off')
plt.show()

【matplot.pyplot.imshow函数的使用-->显示成彩色图像】
当希望可以显示成彩色图象时
    b,g,r=cv2.split(img)
    img2=cv2.merge([r,g,b])
    plt.imshow(img),plt.axis('off')
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image\\girl.bmp')
b,g,r=cv2.split(img)
img2=cv2.merge([r,g,b])
plt.subplot(121)
plt.imshow(img),plt.axis('off')            #结果错误
plt.subplot(122)
plt.imshow(img2),plt.axis('off')           #结果正确
plt.show()

1.6.3 直方图均衡化对比

import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image\\boat.bmp',cv2.IMREAD_GRAYSCALE)
equ = cv2.equalizeHist(img)
plt.subplot(221)
plt.imshow(img,cmap=plt.cm.gray),plt.axis('off')
plt.subplot(222)
plt.imshow(equ,cmap=plt.cm.gray),plt.axis('off')
plt.subplot(223)
plt.hist(img.ravel(),256)
plt.subplot(224)
plt.hist(equ.ravel(),256)
plt.show()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值