自己是一个菜鸡,希望通过写博客的方式提升自己,最近正好接触到了opencv,想把学习路程以博客的形式记录下来,也算是学习opencv的一种动力吧,好吧,话不多说,干就完了!
一、基础知识
直方图
1. 直方图代表了一幅图像上各个(或范围)灰度值的数目。
API:cv2.calcHist(images, channels, mask, histSize, ranges)
images:一个列表,里面是计算直方图所用的图像,一定要用list修饰一下!我也不知道为什么不修饰图就不对了。
channels:一个列表,代表了channels的索引,所以灰度值只能是[0],而RGB图就是[0, 1, 2],当然你也可以只算绿色,蓝色,红色或者他们的组合,索引正确就好。
mask:和位运算的mask的功能是一致的,mask图像和原图大小一致,并且是黑白图像。所以只计算mask图像中白色部分的直方图,相当于ROI。没有mask的话设置为None就好。
histSize:是一个列表,代表了每个通道上bins的数目。直观理解就是如果值是[256]的话,就是不放过每一个灰度值,所以横轴的尺度比较精细。如果是100,那就统计灰度值范围在[0, 99]上的灰度分布情况。
ranges:一个列表,代表灰度值范围,一般都是[0, 256]。除非你是别的颜色区间,这个数值会发生改变。
直方图均衡化
直方图均衡化能够提高图像的对比度,对于有明显前、背景的图像,均衡化后变得更加清晰,使得像素的灰度值在[0, 255]区间内分布更加均匀,但同时灰度级间的间隔也变宽了。
image_equal = cv2.equalizeHist(image) 用法很简单
二、Demo
import cv2
import argparse
import os
import matplotlib.pyplot as plt
image_src = cv2.imread('./beach.png')
image = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY) # 转灰度图
cv2.imwrite('gray.jpg', image)
hist = cv2.calcHist([image], [0], None, [256], [0, 256]) # 计算直方图
plt.figure() # 用pyplot来画直方图并创建一个画布
plt.title('Grayscale Histogram') # 直方图标题
plt.xlabel('Bins') # 横轴标题
plt.ylabel('# of Pixels') # 纵轴标题
plt.xlim([0, 256]) # 横轴范围(让图像更好的显示)
plt.plot(hist) # 画图
plt.show() # 显示
# 下面画一个三通道的直方图
chans = cv2.split(image_src) # 一个元组,代表了每个通道的图像,顺序是BGR
colors = ('b', 'g', 'r') # 画线的颜色,也代表了相应的通道
plt.figure()
plt.title('Flattened Color Histogram')
plt.xlabel('Bins')
plt.ylabel('# of Pixels')
for chan, color in zip(chans, colors):
hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
plt.xlim([0, 256])
plt.plot(hist, color=color)
# 直方图均衡化并且画出其直方图
image_gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
image_equal = cv2.equalizeHist(image_gray)
cv2.imwrite('equal.jpg', image_equal)
hist_equal = cv2.calcHist([image_equal], [0], None, [256], [0, 256])
plt.figure()
plt.xlabel('equal_list image\'s bins')
plt.ylabel('# pixel nums')
plt.xlim([0, 256])
plt.plot(hist_equal)
plt.show()
# 利用掩膜
def plot_hist(image, mask=None): # 把前面画直方图的代码包装一下,使用起来方便
plt.figure()
plt.xlabel('bins')
plt.ylabel('# nums')
plt.title('hist_image')
plt.xlim([0, 256])
if image.shape[2] == 3:
chans = cv2.split(image)
colors = ('b', 'g', 'r')
for (chan, color) in zip(chans, colors):
hist = cv2.calcHist([chan], [0], mask, [256], [0, 256])
plt.plot(hist, color=color)
plt.show()
else:
hist = cv2.calcHist([image], [0], mask, [256], [0, 256])
plt.plot(hist)
plt.show()
mask = np.zeros(image_src.shape[:2], dtype='uint8')
cv2.rectangle(mask, (15, 15), (130, 100), 255, -1)
masked = cv2.bitwise_and(image_src, image_src, mask=mask)
cv2.imwrite('masked.jpg', masked)
plot_hist(image_src, mask)
运行结果:
![]()
![]()
![]()
![]()
![]()
![]()
三、总结
- 明白了单通道(灰度)直方图,RGB图像三通道直方图的同时显示,直方图均衡化,利用掩膜操作的直方图显示。
- 本文并没有涉及到双通道直方图的同时显示(类似于热力图那种),如果以后用到了就再编辑吧,感觉用到的不多就没写。
- 排版乱。