直方图是对图像像素的统计分布,它统计了每个像素(0到L-1)的数量。
注意:
pycharm从2017.3版之后,将matplotlib的绘图的结果默认显示在SciView窗口中,而不是弹出独立的窗口。
修改方式见链接:
新版Pycharm中Matplotlib图像不在弹出独立的显示窗口
将多维数组降为一维
可以传入索引:‘C’, ‘F’, ‘A’, ‘K’
参考链接:
numpy 辨异 (五)—— numpy.ravel() vs numpy.flatten()
枚举
参考链接:
绘制直方图,一般用来绘制灰度直方图
def hist(
x, bins=None, range=None, density=False, weights=None,
cumulative=False, bottom=None, histtype='bar', align='mid',
orientation='vertical', rwidth=None, log=False, color=None,
label=None, stacked=False, *, data=None, **kwargs):
return gca().hist(
x, bins=bins, range=range, density=density, weights=weights,
cumulative=cumulative, bottom=bottom, histtype=histtype,
align=align, orientation=orientation, rwidth=rwidth, log=log,
color=color, label=label, stacked=stacked,
**({"data": data} if data is not None else {}), **kwargs)
注意: 此处还没有将图像转换为灰度图
from matplotlib import pyplot as plt
def plot(image):
"""画出image的直方图"""
# image.ravel()将图像展开为一维数组,256为bins数量,[0, 256]为数值范围(不包括256)
plt.hist(image.ravel(), 256, [0, 256])
plt.show() # 显示直方图
结果:
计算图像直方图
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) ->hist
注意:
绘制image的直方图(BGR三个通道)
def image_hist(image):
"""绘制image的直方图(三个通道)"""
color = ('blue', 'green', 'red')
for i, color in enumerate(color): # # enumerate 枚举,返回元素以及对应的索引
# 计算出直方图,calcHist(images, channels, mask, histSize(有多少个bin), ranges[, hist[, accumulate]]) -> hist
# hist 是一个 256x1 的数组,每一个值代表了与该灰度值对应的像素点数目。
hist = cv.calcHist(image, [i], None, [256], [0, 256])
# print(hist.shape)
plt.plot(hist, color=color) # 绘制函数曲线
plt.xlim([0, 256]) # 设置坐标轴刻度取值范围
plt.show()
结果:
参考链接:
问题一:
在按照https://blog.csdn.net/u010472607/article/details/82290159点击查看的操作,让图表单独显示后,产生了图框出现而内容不出现的问题,如下图所示:
原因:未知,个人猜测是交互模式和阻碍模式的问题(可能性高),或是线程阻碍产生的结果
解决方案:
第一种:
# cv.imshow("example", src1)
plot(src1)
第二种:
plt.show(False)
第三种(推荐):
第四种(推荐):
参考链接:
问题二:
在出现问题一并解决后,想要同时显示两张图表,却发现两张图只显示前一张
原因: 显示第一张的时候就用了plt.show
解决方案:
第一种:
第二种:
直方图均衡化就是将原始的直方图拉伸,使之均匀分布在全部灰度范围内,从而增强图像的对比度。
直方图均衡化的中心思想是把原始图像的的灰度直方图从比较集中的某个区域变成在全部灰度范围内的均匀分布。
如果一幅图像的灰度直方图几乎覆盖了整个灰度的取值范围,并且除了个别灰度值的个数较为突出,整个灰度值分布近似于均匀分布,那么这幅图像就具有较大的灰度动态范围和较高的对比度,同时图像的细节更为丰富。
均衡化步骤:
参考链接:
注意:
OpenCV里的直方图均衡化都是基于灰度图
直方图均衡化
equalizeHist(src[, dst]) -> dst
直方图均衡化
def equal_hist(image):
"""全局直方图均衡化,用于增强图像对比度,即黑的更黑,白的更白"""
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
dst = cv.equalizeHist(gray)
cv.imshow("equalHist", dst)
结果:
直方图均衡化可以可能到是一种全局意义上的均衡化,但是有的时候这种操作并不是很好,会把某些不该调整的部分给调整了。OpenCV中还有一种直方图均衡化,它是一种局部局部来的均衡化,也就是是说把整个图像分成许多小块(比如按10*10作为一个小块),那么对每个小块进行均衡化。这种方法主要对于图像直方图不是那么单一的(比如存在多峰情况)图像比较实用。
自适应均衡化图像
createCLAHE([, clipLimit[, tileGridSize]]) -> retval
注意:
局部直方图均衡化
def local_equal_hist(image):
"""局部直方图均衡化"""
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# clipLimit颜色对比度的阈值,titleGridSize进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作
local_hist = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) # 实例化均衡直方图函数
local_hist_dst = local_hist.apply(gray)
cv.imshow("local_equal_hist", local_hist_dst)
结果:
参考链接:
参考链接:
如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。
直方图比较
compareHist(H1, H2, method) -> retval
比较方式有:
==注意: ==
用巴氏距离和相关性比较好
参考链接:
利用直方图比较图像相似性
def create_rgbhist(image):
"""创建直方图"""
h, w, c = image.shape
rgbHist = np.zeros([16 * 16 * 16, 1], np.float32) # 每个通道的灰度值(0~255共256个值)分为16个刻度
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]
# 单一通道的灰度值依据刻度的宽度归到16个刻度内得到对应的值
# 像素点的BGR三通道分别依据得到的值,按权重取得索引(就是三通道的值排到一起了)
# index = np.int(b / bsize) * 16 * 16 + np.int(g / bsize) * 16 + np.int(r / bsize)
# rgbHist[np.int(index), 0] = rgbHist[np.int(index), 0] + 1 # 对应索引处的值(频数)+1
index = int(b / bsize) * 16 * 16 + int(g / bsize) * 16 + int(r / bsize)
rgbHist[int(index), 0] = rgbHist[int(index), 0] + 1 # 对应索引处的值(频数)+1
return rgbHist
def hist_compare(image1, image2):
"""利用直方图比较相似性"""
hist1 = create_rgb_demo(image1)
hist2 = create_rgb_demo(image2)
match1 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_BHATTACHARYYA)
match2 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_CORREL)
match3 = cv.compareHist(hist1, hist2, method=cv.HISTCMP_CHISQR)
print("巴式距离:%s, 相关性:%s, 卡方:%s" % (match1, match2, match3))
结果:
SRC1
SRC2
计算结果:
注意:
上述比较的代码只能用于两张大小一样的图片,如果需要比较两张不一样
大小的图片,需要进行归一化操作
把RGB颜色空间,想象成一个三维立体的坐标系,rgb对应xyz轴,每个颜色8 bins,对应xyz三个轴上,8个等分刻度,这样就得到一个8x8x8=512个小立方体构成的大立方体,要的直方图就是每个小立方体在大立方体中出现的概率分布。
参考链接:
按照教程调用hist_compare函数的时候显示:
`np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
原因:Python不推荐使用np.int
解决方案:将np.int修改为int
一维直方图,需要从BGR转换为灰度,二维直方图,需要将图像从BGR转换为HSV。
def hist2d(image):
"""绘制图像的二维直方图"""
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [180, 360], [0, 180, 0, 256]) # 计算H和S通道的2D直方图
print(hist.shape)
# cv.imshow("hist2d", hist)
plt.imshow(hist, interpolation="nearest") # 直方图显示,插值方法为最近领域内插法
plt.title("2D Histogram")
plt.ioff()
plt.show()
结果:
注意:
interpolation='nearest’如果显示分辨率与图像分辨率不同(通常是这种情况),则只显示图像而不尝试在像素之间进行插值。它将生成一个像素显示为多个像素的正方形的图像。
参考链接:
归一化(矩阵的值通过某种方式变到某一个区间内)
normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]) -> dst
src-输入数组。
dst-与SRC大小相同的输出数组。
α-范数值在范围归一化的情况下归一化到较低的范围边界。
β-上限范围在范围归一化的情况下;它不用于范数归一化。
norm_type-规范化类型,见下面参考链接。
dType——当输出为负时,输出数组具有与SRC相同的类型;否则,它具有与SRC相同的信道数和深度=CVH-MatthAsHead(DyType)。
mask-可选的操作掩膜。
参考链接:
直方图反向投影
calcBackProject(images, channels, hist, ranges, scale[, dst]) -> dst
参数与cv2.calchist几乎相同
注意:
在传递给backproject函数之前,应该对对象直方图进行归一化。
def back_projection(sample, target):
"""直方图反向投影,sample是样本,target是需要寻找的输入图像"""
roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
cv.imshow("sample", sample)
cv.imshow("target", target)
roiHist = cv.calcHist([roi_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 归一化:原始图像,结果图像,映射到结果图像中的最小值,最大值,归一化类型
# cv.NORM_MINMAX对数组的所有值进行转化,使它们线性映射到最小值和最大值之间
# 归一化后的图像便于显示,归一化后到0,255之间了
cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX)
dst = cv.calcBackProject([target_hsv], [0, 1], roiHist, [0, 180, 0, 256], 1)
cv.imshow("backProjectionDemo", dst)
结果: