画直方图要用到matplotlib库
图像直方图是反映一个图像像素分布的统计表,其横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。图像是由像素构成,因为反映像素分布的直方图往往可以作为图像一个很重要的特征。直方图的显示方式是左暗又亮,左边用于描述图像的暗度,右边用于描述图像的亮度。
matplotlib.pyplot.hist函数绘制直方图
plt.hist(x, bins=None, range=None, density=None, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, normed=None, hold=None, data=None, **kwargs)
cv2.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
import cv2 as cv
import matplotlib.pyplot as plt
def plot_hist(image):
# ravel函数将多维数组降为一维数组
plt.hist(image.ravel(), 256, [0, 256])
image_hist(src)
plt.show()
def image_hist(image):
colors = ['blue', 'green', 'red']
for i, color in enumerate(colors):
# 三个通道
hist = cv.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.show()
src = cv.imread(r'./test/004.jpg')
cv.imshow('src', src)
plot_hist(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下:
直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法,是图像增强的一个手段。
直方图均衡化:如果一副图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度和多变的灰度色调。直方图均衡化就是一种能仅靠输入图像直方图信息自动达到这种效果的变换函数。它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像元取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。
cv2.equalizeHist(src, dst=None)
函数equalizeHist的作用:直方图均衡化,提高图像质量。
import cv2 as cv
# 全局直方图均衡化可能得到是一种全局意义上的均衡化,但是有的时候这种操作并不是很好,会把某些不该调整的部分给调整了
def equal_hist(image):
# 全局直方图均衡化 基于灰度图像 单通道
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
dst = cv.equalizeHist(gray)
cv.imshow('equal_image', dst) # 增强图像对比度
src = cv.imread(r'./test/013.png')
src = cv.resize(src, None, fx=0.5, fy=0.5)
cv.imshow('src', src)
equal_hist(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下:
cv2.createCLAHE(clipLimit=None, tileGridSize=None)
import cv2 as cv
# 局部直方图均衡化,也就是是说把整个图像分成许多小块(比如按10*10作为一个小块),那么对每个小块进行均衡化
def clache_demo(image):
# 局部直方图均衡化 基于灰度图像 局部增强对比度
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(10, 10))
dst = clahe.apply(gray) # 将clahe这种局部直方图均衡化应用到灰度图gray
cv.imshow('clahe_image', dst)
src = cv.imread(r'./test/013.png')
src = cv.resize(src, None, fx=0.5, fy=0.5)
cv.imshow('src', src)
clache_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下:
cv2.compareHist(H1, H2, method)
比较方法(method)
import cv2 as cv
import numpy as np
def create_rgb_hist(image):
h, w, c = image.shape
# 创建一个(16*16*16,1)的初始矩阵,作为直方图矩阵
# 16 ** 3 的意思为三通道每通道有16个bins
rgb_hist = np.zeros([16 ** 3, 1], np.float32)
bsize = 256 / 16
for row in range(h):
for col in range(w):
b = image[row, col, 0]
g = image[row, col, 1]
r = image[row, col, 2]
# 构建直方图矩阵的索引,该索引是通过每一个像素点的三通道值进行构建
index = np.int(b / bsize)*16*16 + np.int(g / bsize)*16 + np.int(r / bsize)
# 该处形成的矩阵即为直方图矩阵
rgb_hist[np.int(index), 0] += 1
return rgb_hist
def hist_compare(image1, image2):
# 第一幅图的rgb三通道直方图(直方图矩阵)
hist1 = create_rgb_hist(image1)
# 第二幅图的rgb三通道直方图(直方图矩阵)
hist2 = create_rgb_hist(image2)
# 三种方法比较
match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA)
match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)
match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)
print(f'巴氏距离:{match1} 相关性:{match2} 卡方:{match3}')
src1 = cv.imread(r'./test/014.png')
src2 = cv.imread(r'./test/006.png')
cv.imshow('src1', src1)
cv.imshow('src2', src2)
hist_compare(src1, src2)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下:
巴氏距离:0.07197755337904468 相关性:0.994234165782534 卡方:15669.370232792859
import cv2 as cv
import matplotlib.pyplot as plt
def hist2D_demo(image):
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [32, 48], [0, 180, 0, 256])
# cv.imshow('hist2D', hist)
plt.imshow(hist, interpolation='nearest') # 插值方式 邻进点插值
plt.title('2D hist') # 2D直方图空间
plt.show()
src = cv.imread(r'./test/004.jpg')
cv.imshow('src', src)
hist2D_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下:
直方图反向投影用于图像分割或查找图像中感兴趣的对象,简单来说,它会创建一个与输入图像大小相同(单个通道)的图像,其中每个像素对应于属于我们对象该像素的概率,输出图像将使我们感兴趣的对象比其余部分更明显。
首先,我们创建一个包含我们感兴趣对象的图像的直方图,对象应尽可能填充图像以获得更好的结果,颜色直方图比灰度直方图更受青睐,因为对象的颜色比灰度强度更能定义对象,然后我们将这个直方图反投影到我们需要找到对象的测试图像上。
cv2.normalize(src, dst, alpha=None, beta=None, norm_type=None, dtype=None, mask=None)
归一化类型
cv2.calcBackProject(images, channels, hist, ranges, scale, dst=None)
import cv2 as cv
# 直方图反向投影
def back_projection():
sample = cv.imread(r'./test/020.png')
target = cv.imread(r'./test/017.jpg')
# 转到HSV色彩空间
roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
# show image
cv.imshow('sample', sample)
cv.imshow('target', target)
# 调bins个数 少 效果更好 2D直方图
roi_hist = cv.calcHist(images=[roi_hsv], channels=[0, 1], mask=None, histSize=[16, 16], ranges=[0, 180, 0, 256])
# 归一化到 0-255之间
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)
# 反向投影
dst = cv.calcBackProject([target_hsv], [0, 1], roi_hist, [0, 180, 0, 256], 1)
cv.imshow('back_projection', dst)
back_projection()
cv.waitKey(0)
cv.destroyAllWindows()
运行效果如下: