一、图像直方图
画直方图要用到 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)
- x参数表示是一个数组或一个序列,是指定每个bin分布的数据。
- bins参数表示指定bin的个数
- range参数表示横坐标显示的范围,范围之外的将被舍弃。
cv2.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
- images:输入图像
- channels:传入图像的通道,如果是灰度图像,只有一个通道,值为0;如果是彩色图像(有3个通道),那么值为0、1、2中选择一个,对应着BGR各个通道,这个值也得用 [ ] 传入。
- mask:表示掩膜图像,如果统计整幅图,那么为None;而如果要统计部分图的直方图,就得构造相应的掩膜来计算。
- histSize:灰度级的个数,需要中括号,比如[256]。
- ranges:像素值的范围,通常[0,256]。此外,假如channels为[0,1],ranges为[0,256,0,180],则代表0通道范围是0-256,1通道范围0-180。
importcv2ascvimportmatplotlib.pyplotaspltdefplot_hist(image): # ravel函数将多维数组降为一维数组plt.hist(image.ravel(), 256, [0, 256]) image_hist(src) plt.show() defimage_hist(image): colors= ['blue', 'green', 'red'] fori, colorinenumerate(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()
运行效果如下:
二、直方图应用
1. 直方图均衡化
直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法,是图像增强的一个手段。
直方图均衡化:如果一副图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度和多变的灰度色调。直方图均衡化就是一种能仅靠输入图像直方图信息自动达到这种效果的变换函数。它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像元取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。
cv2.equalizeHist(src, dst=None) # 函数equalizeHist的作用:直方图均衡化,提高图像质量。
importcv2ascv# 全局直方图均衡化可能得到是一种全局意义上的均衡化,但是有的时候这种操作并不是很好,会把某些不该调整的部分给调整了defequal_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)
- clipLimit:对比度的大小
- tileGridSize:每次处理块的大小
importcv2ascv# 局部直方图均衡化,也就是是说把整个图像分成许多小块(比如按10*10作为一个小块),那么对每个小块进行均衡化defclache_demo(image): # 局部直方图均衡化 基于灰度图像 局部增强对比度gray=cv.cvtColor(image, cv.COLOR_BGR2GRAY) clahe=cv.createCLAHE(clipLimit=2.0, tileGridSize=(10, 10)) dst=clahe.apply(gray) # 将clahe这种局部直方图均衡化应用到灰度图graycv.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()
运行效果如下:
2. 直方图比较
cv2.compareHist(H1, H2, method)
- H1,H2:要比较的两张直方图
- method:比较方法
比较方法(method)
- 相关性比较 (method=cv2.HISTCMP_CORREL) 值越大,相关度越高,最大值为1,最小值为0。
- 卡方比较(method=cv.HISTCMP_CHISQR 值越小,相关度越高,最大值无上界,最小值0。
- 巴氏距离比较(method=cv.HISTCMP_BHATTACHARYYA) 值越小,相关度越高,最大值为1,最小值为0。
importcv2ascvimportnumpyasnpdefcreate_rgb_hist(image): h, w, c=image.shape# 创建一个(16*16*16,1)的初始矩阵,作为直方图矩阵 # 16 ** 3 的意思为三通道每通道有16个binsrgb_hist=np.zeros([16**3, 1], np.float32) bsize=256/16forrowinrange(h): forcolinrange(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] +=1returnrgb_histdefhist_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
三、直方图反向投影
1. HSV和RGB色彩空间
importcv2ascvimportmatplotlib.pyplotaspltdefhist2D_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()
运行效果如下:
2. 反向投影
直方图反向投影用于图像分割或查找图像中感兴趣的对象,简单来说,它会创建一个与输入图像大小相同(单个通道)的图像,其中每个像素对应于属于我们对象该像素的概率,输出图像将使我们感兴趣的对象比其余部分更明显。
首先,我们创建一个包含我们感兴趣对象的图像的直方图,对象应尽可能填充图像以获得更好的结果,颜色直方图比灰度直方图更受青睐,因为对象的颜色比灰度强度更能定义对象,然后我们将这个直方图反投影到我们需要找到对象的测试图像上。
cv2.normalize(src, dst, alpha=None, beta=None, norm_type=None, dtype=None, mask=None)
- src:输入数组
- dst:输出与src相同大小的数组,支持原地运算。
- alpha:range normalization模式的最小值
- beta:range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
- norm_type:归一化的类型
归一化类型
- NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
- NORM_INF:归一化数组的C-范数(绝对值的最大值)
- NORM_L1:归一化数组的L1-范数(绝对值的和)
- NORM_L2:归一化数组的(欧几里德)L2-范数
cv2.calcBackProject(images, channels, hist, ranges, scale, dst=None)
- images:输入图像(是HSV图像),传入时应该用中括号[ ]括起来。
- channels:计算反向投影的通道列表,通道数必须与直方图维度相匹配。
- hist:输入的模板图像直方图
- ranges:直方图中每个维度bin的取值范围(即每个维度有多少个bin)
- scale:可选输出反向投影的比例因子,一般取1。
importcv2ascv# 直方图反向投影defback_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 imagecv.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()
运行效果如下: