图像直方图是反映一个图像像素分布的统计表,其横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。
图像是由像素构成,那么反映像素分布的直方图往往可以作为图像一个很重要的特征。直方图的显示方式是左暗又亮,左边用于描述图像的暗度,像素值比较小;右边用于描述图像的亮度,像素值比较大。
按照维数去分类可以分为一维直方图和二维直方图。
一维直方图
python中绘制图像像素一维直方图(也成为单通道像素直方图)有两种方式,一种是opencv中的cv2.calcHist()
函数;另一种是matplotlib.pyplot中的plt.hist()
函数。
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) ->hist
参数说明:
1、images
(输入图像)参数必须用方括号括起来。
2、channels
计算直方图的通道。
3、Mask
(掩膜),一般用None
,表示处理整幅图像。
4、histSize
,表示这个直方图分成多少份(即多少个直方柱)。
5、range
,直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
6、最后两个是可选参数,由于直方图作为函数结果返回,所以第六个hist
就没有意义了(待确定) 最后一个accumulate
是一个布尔值,用来表示直方图是否叠加。plt.hist(x,bins=None,range=None, density=None, bottom=None, histtype='bar', align='mid', log=False, color=None, label=None, stacked=False, normed=None)
参数说明:
1、x
: 数据集,最终的直方图将对数据集进行统计
2、bins
: 统计的区间分布
3、range
:tuple
, 显示的区间,range
在没有给出bins
时生效
4、density
:bool
,默认为false
,显示的是频数统计结果,为True
则显示频率统计结果,这里需要注意,频率统计结果=区间数目/(总数*区间宽度),和normed
效果一致,官方推荐使用density
5、histtype
: 可选{'bar', 'barstacked', 'step', 'stepfilled'}
之一,默认为bar
,推荐使用默认配置,step
使用的是梯状,stepfilled
则会对梯状内部进行填充,效果与bar
类似
6、align
: 可选{'left', 'mid', 'right'}
之一,默认为'mid',控制柱状图的水平分布,left或者right,会有部分空白区域,推荐使用默认
7、log
:bool
,默认False
,即y坐标轴是否选择指数刻度
8、stacked
:bool
,默认为False
,是否为堆积状图
代码实现:
# -*-coding:utf-8-*-
"""
File Name: image_histogram_operation.py
Program IDE: PyCharm
Date: 19:58
Create File By Author: Hong
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def image_hist(image_path: str):
"""
图像直方图是反映一个图像像素分布的统计表,其横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。
纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。
图像是由像素构成,那么反映像素分布的直方图往往可以作为图像一个很重要的特征。
直方图的显示方式是左暗又亮,左边用于描述图像的暗度,右边用于描述图像的亮度。
:param image_path: 传入查找像素的图像文件
:return: 无返回值
"""
# 一维直方图(单通道直方图)
img = cv.imread(image_path, cv.IMREAD_COLOR)
cv.imshow('input', img)
color = ('blue', 'green', 'red')
# 使用plt内置函数直接绘制
plt.hist(img.ravel(), 20, [0, 256])
plt.show()
# 一维像素直方图,也即是单通道直方图
for i, color in enumerate(color):
hist = cv.calcHist([img], [i], None, [256], [0, 256])
print(hist)
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == '__main__':
path = 'images/daiyutong.png'
image_hist(path)
效果展示:
二维直方图
它非常简单,并且使用相同的函数cv2.calcHist()
进行计算。 对于颜色直方图,我们需要将图像从BGR转换为HSV。(请记住,对于一维直方图,我们从BGR转换为灰度)。对于二维直方图,其参数将进行如下修改:
-
channel = [0,1]
,因为我们需要同时处理H和S平面。 -
bins = [180,256]
对于H平面为180,对于S平面为256。 -
range = [0,180,0,256]
色相值介于0和180之间,饱和度介于0和256之间。
可以使用opencv中的imshow()
和matplotlib中的show()
两种方式显示。
# -*-coding:utf-8-*-
"""
File Name: image_histogram_operation.py
Program IDE: PyCharm
Date: 19:58
Create File By Author: Hong
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def image_hist2d(image_path: str):
# 二维直方图
img = cv.imread(image_path, cv.IMREAD_COLOR)
cv.imshow('img', img)
# 图像转HSV颜色空间
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [48, 48], [0, 180, 0, 256])
dst = cv.resize(hist, (400, 400))
# 像素归一化
cv.normalize(dst, dst, 0, 255, cv.NORM_MINMAX)
# 色彩填充
dst = cv.applyColorMap(np.uint8(dst), cv.COLORMAP_JET)
cv.imshow('hist', dst)
plt.imshow(hist, interpolation='nearest')
plt.title('2D Histogram')
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == '__main__':
path = 'images/daiyutong.png'
image_hist2d(path)
结果展示:
直方图均衡化
直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法。
如何做到?
均衡化指的是把一个分布 (给定的直方图) 映射 到另一个分布 (一个更宽更统一的强度值分布), 所以强度值分布会在整个范围内展开。
以上图为例实现直方图均衡化:
# -*-coding:utf-8-*-
"""
File Name: image_histogram_operation.py
Program IDE: PyCharm
Date: 19:58
Create File By Author: Hong
"""
import cv2 as cv
def hist_equalization(image_path: str):
# 直方图均衡化
img = cv.imread(image_path, cv.IMREAD_GRAYSCALE)
cv.imshow('input', img)
result = cv.equalizeHist(img)
cv.imshow('result', result)
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == '__main__':
path = 'images/daiyutong.png'
hist_equalization(path)
结果展示:
获取更多计算机视觉内容,请关注微信公众号 ”AI与计算机视觉“