【OpenCV + Python】直方图

38 篇文章 0 订阅
31 篇文章 3 订阅

• 使用 OpenCV 或 Numpy 函数计算直方图
• 使用 Opencv 或者 Matplotlib 函数绘制直方图
• 将要学习的函数有: cv2.calcHist(), np.histogram()
直方图统计
BINS: 一个histogram,通常可以用一个列向量表示(例子中的a,b),列向量里面的每一个值就是一个bin(a,b),比如说列向量有个50个元素,那么就代表有50个bin。
DIMS: 表示我们收集数据的参数数目。在本例中,我们对收集到的数据
只考虑一件事:灰度值。所以这里就是 1。
RANGE: 就是要统计的灰度值范围,一般来说为 [0, 256],也就是说所有的灰度值

函数 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方法:

img = cv2.imread('13.jpg',0)
#别忘了中括号 [img],[0],None,[256],[0,256],只有 mask 没有中括号
hist = cv2.calcHist([img],[0],None,[256],[0,256])

Numpy方法:

#img.ravel() 将图像转成一维数组,这里没有中括号。
hist,bins = np.histogram(img.ravel(),256,[0,256])

在这里插入图片描述
绘制直方图:
有两种方法来绘制直方图:
Short Way(简单方法):使用 Matplotlib 中的绘图函数。
Long Way(复杂方法):使用 OpenCV 绘图函数

import cv2
from matplotlib import pyplot as plt
img = cv2.imread('1.jpg',1)
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
plt.hist(img.ravel(),256,[0,256])  #直接统计并绘制直方图
plt.show()
cv2.imshow("imgray",imgray)
cv2.waitKey()

在这里插入图片描述
只使用matplotlib绘制功能:

import cv2
from matplotlib import pyplot as plt
img = cv2.imread('1.jpg',1)
color = ('b','g','r')
# 对一个列表或数组既要遍历索引又要遍历元素时
# 使用内置enumerrate 函数会有更加直接,优美的做法
#enumerate 会将数组或列表组成一个索引序列。
# 使我们再获取索引和索引内容的时候更加方便
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()
cv2.imshow("img",img)
cv2.waitKey()

在这里插入图片描述

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('1.jpg',0)
# img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 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()
cv2.imshow("img",img)
cv2.waitKey()

在这里插入图片描述
直方图均衡化:

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

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('4.jpg',0)
#flatten() 将数组变成一维
hist,bins = np.histogram(img.flatten(),256,[0,256])
# 计算累积分布图
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'b')
plt.hist(img.flatten(),256,[0,256], color = 'r')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
plt.show()
# 构建Numpy 掩模数组,cdf 为原数组,当数组元素为0 时,掩盖(计算时被忽略)。
cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
# 对被掩盖的元素赋值,这里赋值为0
cdf = np.ma.filled(cdf_m,0).astype('uint8')
img2 = cdf[img]
cv2.imshow("img",img)
cv2.imshow("img2",img2)
cv2.waitKey()

在这里插入图片描述
在这里插入图片描述
因此,直方图均衡化经常用来使所有的图片具有相同的亮度条件的参考工具。这在很多情况下都很有用。例如,脸部识别,在训练分类器前,训练集的所有图片都要先进行直方图均衡化从而使它们达到相同的亮度条件。当直方图中的数据集中在某一个灰度值范围内时,直方图均衡化很有用。
OpenCV 中的直方图均衡化:

import cv2
import numpy as np
img = cv2.imread('4.jpg',0)
equ = cv2.equalizeHist(img)
res = np.hstack((img,equ))
cv2.imshow("img",img)
cv2.imshow("res",res)
cv2.waitKey()

在这里插入图片描述
CLAHE 有限对比适应性直方图均衡化(自适应均衡化):
我们需要使用自适应的直方图均衡化。这种情况下,整幅图像会被分成很多小块,这些小块被称为“tiles”(在OpenCV 中tiles 的大小默认是8x8),然后再对每一个小块分别进行直方图均衡化(跟前面类似)。所以在每一个的区域中,直方图会集中在某一个小的区域中(除非有噪声干扰)。如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的bin 超过对比度的上限的话,就把其中的像素点均匀分散到其他bins 中,然后在进行直方图均衡化。最后,为了去除每一个小块之间“人造的”(由于算法造成)边界,再使用双线性差值,对小块进行缝合。
例子(直方图均衡化):

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('5.jpg',0)
equ = cv2.equalizeHist(img)
res = np.hstack((img,equ))
cv2.imshow("res",res)
plt.hist(img.ravel(),256,[0,256]);
plt.show()
cv2.waitKey()

有信息损失:
在这里插入图片描述
自适应均衡化:

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('5.jpg',0)
# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
res = np.hstack((img,cl1))
cv2.imshow("res",res)
plt.hist(img.ravel(),256,[0,256]);
plt.show()
cv2.waitKey()

在这里插入图片描述
图像对比:

match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA)
match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR)

巴氏距离、相关性、卡方:第一个越小越好,第二个越大越好(接近1),第三个越小越好。下面是相似的两张图:
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖子工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值