目录
一、什么是图像直方图?图像直方图有什么用处?
图像直方图是用来表现图像中亮度分布的直方图,给出的是图像中某个亮度或者某个范围亮度下共有几个像素,即统计一幅图某个亮度像素数量。
图像直方图由于其计算代价较小,且具有图像平移、旋转、缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类。
二、计算图像直方图
1、OpenCV版
函数:cv2.calcHist(images, channels, mask, histSize, ranges, hist=None, accumulate=None)
作用:计算每个像素块在图像中的数量。(之所以是像素块,因为下面可以传入Bin改变一块中像素值个数)
参数:
- images:待计算图像,需要用方括号 [img];
- channels:通道索引,灰度图像可填入[0],彩色图像(BGR)[0]、[1]、[2]代表三个颜色通道;(也要用方括号)
- mask:掩膜,计算整个图像,传入None就行,如果要对局部图像做处理,可以定义个mask传入;
- histSize:Bin(直方图的柱子)数量,全尺寸用 [256] 就行;
- ranges:像素范围,一般设为 [0, 256]
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
def hist_demo(img):
cv2.imshow("img", img)
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
plt.plot(hist)
plt.show()
hist_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
如果我们想把BGR三通道都输出在同一张图片上:
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
def hist_demo1(img):
cv2.imshow("img", img)
colors = ('blue', 'green', 'red')
for i, color in enumerate(colors):
hist = cv2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.xlim([0, 256])
plt.show()
hist_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
不同histSize值的输出:
2、PLT版
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
def plot_demo(img):
plt.hist(img.ravel(), 256, [0, 256]) # ravel函数功能是将多维数组降为一维数组
plt.show()
plot_demo(img)
3、numpy版
(这个效率比较低,不常用)
import cv2
import numpy as np
img = cv2.imread('test.jpg')
hist, bins = np.histogram(img.ravel(), 256, [0, 256])
print("hist", hist)
print("bins", bins)
4、HSV图像,H-S直方图
色调(Hue),饱和度(Saturation)
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
def plot_2d_demo(img):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0,180, 0, 256])
plt.imshow(hist, interpolation='nearest') #临近点插值方式
plt.show()
plot_2d_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
三、直方图均衡
1、全局均衡
这种方法通常用来增加许多图像的全局对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。
就是对图像直方图作如下变化:(直方图得到了拉伸)
函数:cv2.equalizeHist(gray)
参数:传入的是一张灰度图像
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
def plot_demo(img):
plt.hist(img.ravel(), 256, [0, 256])
plt.show()
def equalHist_demo(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plot_demo(gray)
cv2.imshow("gray", gray)
dst = cv2.equalizeHist(gray)
plot_demo(dst)
cv2.imshow("dst", dst)
equalHist_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图:
图像直方图变化前后展示:
2、自定义均衡程度(clahe)
全局均衡在很多时候并不能达到我们所预期的结果,就想上面所显示的图片,明显偏暗,物体也变得难以辨识。
函数:cv2.createCLAHE(, clipLimit=None, tileGridSize=None)
参数:
- clipLimit:颜色对比度的阈值;
- titleGridSize:进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作。
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
def plot_demo(img):
plt.hist(img.ravel(), 256, [0, 256])
plt.show()
def clahe_demo(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plot_demo(gray)
cv2.imshow("gray", gray)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
dst = clahe.apply(gray)
plot_demo(dst)
cv2.imshow("dst", dst)
clahe_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
四、直方图之间的比较
函数:cv2.compareHist(H1, H2, method)
参数:
- H1,H2:分别为要比较图像的直方图;
- method:比较方式,有如下几种:
其中:
- 相关性比较 (method=cv.HISTCMP_CORREL) 值越大,相关度越高,最大值为1,最小值为0;
- 卡方比较(method=cv.HISTCMP_CHISQR 值越小,相关度越高,最大值无上界,最小值0;
- 巴氏距离比较(method=cv.HISTCMP_BHATTACHARYYA) 值越小,相关度越高,最大值为1,最小值为0。
import cv2
from matplotlib import pyplot as plt
img = cv2.imread("test.jpg")
img2 = cv2.imread("test2.jpg")
def create_rgb_hist_demo(img):
h, w, c = img.shape
rgbHist = np.zeros([16*16*16, 1], np.float32)
bsize = 256 / 16
for row in range(h):
for col in range(w):
b = img[row, col, 0]
g = img[row, col, 1]
r = img[row, col, 2]
index = np.int(b/bsize)*16*16 + np.int(g/bsize)*16 + np.int(r/bsize)
rgbHist[np.int(index), 0] += 1
return rgbHist
def compare_demo(img1, img2):
hist1 = create_rgb_hist_demo(img1)
hist2 = create_rgb_hist_demo(img2)
match1 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_BHATTACHARYYA) #巴氏距离
match2 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL) #相关性比较
match3 = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CHISQR) #卡方分布
print(match1, match2, match3)
compare_demo(img, img2)
输出结果:
0.9317744192224513 -0.0006074474067220849 1519155206.545716
五、直方图反射投影
反向投影概述
它会输出与输入图象同样大小的图像,其中的每个像素值代表了输入图象上对应点属于目标的概率。更简单来说输出图像的像素值越高的点就越可能代表我们要搜索的目标。
如果一幅图像的区域中显示的是一种结构纹理或者一个独特的物体,那么这个区域的直方图可以看做是一个概率函数,其表现形式是某个像素属于该纹理或物体的概率。而反向投影就是一种记录给定图像中的像素点如何适应直方图模型像素分布方式的一种方法。
简单的讲,所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法。例如,有一个颜色直方图,可以利用反向投影在图像中找到该区域。
反向投影的作用
反向投影用于在输入图像(通常较大)中查找与特定图像(通常较小或者仅1个像素,称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
特殊情况
如果输入图像和模板图像一样大,那么反向投影相当于直方图对比;如果输入图像比模板图像还小,直接罢工。
函数:cv2.calcBackProject(images, channels, hist, ranges, scale, dst=None)
参数:
- images:输入图像,注意加中括号。
- channels:通道。
- hist:图像的直方图。
- ranges:直方图的变化范围。
- scale:输出反投影的可选比例因子。
import cv2
from matplotlib import pyplot as plt
def back_projection_demo():
sample = cv2.imread("sample.jpg")
target = cv2.imread("target.jpg")
sample_hsv = cv2.cvtColor(sample, cv2.COLOR_BGR2HSV)
target_hsv = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
cv2.imshow("sample", sample)
cv2.imshow("target", target)
sample_hist = cv2.calcHist([sample_hsv], [0, 1], None, [32, 64], [0, 180, 0, 256])
cv2.normalize(sample_hist, sample_hist, 0, 255, cv2.NORM_MINMAX)
dst = cv2.calcBackProject([target_hsv], [0, 1], sample_hist, [0, 180, 0, 256], 1)
cv2.imshow("BackProject", dst)
back_projection_demo()
cv2.waitKey(0)
cv2.destroyAllWindows()