用于相似图片搜索引擎的Python OpenCV图像直方图
图像直方图
那么,图像直方图到底是什么?
图片
图像的构成是由像素点构成的,每个像素点的值代表着该点的颜色(灰度图或者彩色图)。所谓直方图就是对图像的中的这些像素点的值进行统计,得到一个统一的整体的灰度概念。直方图表示图像中颜色的分布。可以将其可视化为图表(或曲线图),以直观地了解强度(像素值)分布。直方图的好处就在于可以清晰了解图像的整体灰度分布,这对于计算机视觉处理图片有关重要。
一般情况下直方图都是灰度图像,直方图x轴是灰度值(一般0~255),y轴就是图像中每一个灰度级对应的像素点的个数。
灰度空间图片直方图
如何获取图片直方图
图片直方图的获取,opencv已经帮我们集成了函数,当然numpy也同样可以 获取
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
#numpy方法读取-np.histogram()
#hist_np,bins = np.histogram(img.ravel(),256,[0,256])
#numpy的另一种方法读取-np.bincount()
#hist_np1 = np.bincount(img.ravel(),minlength=256)
cv2.imshow("gray", img)
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(hist)
plt.show()
代码截图
cv2.calcHist(),该函数传递5个参数:
- image输入图像,此参数是一个list 对象
- channels::传入图像的通道,如果是灰度图像,只有一个通道,值为0,如果是彩色图像(B G R),那么值为0,1,2,中选择一个,对应着BGR各个通道。同样为list 对象。
- mask:掩膜图像。如果统计整幅图,那么为none。主要是如果要统计部分图的直方图,就得构造相应的掩膜图像来计算。
- histSize:灰度级的个数,比如[256],或者三个通道的[32,32,32]
- ranges:像素值的范围,通常[0,256],通常,这是[0, 256]针对每个通道的,但是如果您使用的颜色空间不是RGB(例如HSV),则范围可能会有所不同。
以上展示了图片在灰度值中的颜色直方图,当然,我们的图片是R G B的三色图片,我们也可以分别展示图片在R G B 空间内的图片直方图。
彩色空间图片直方图
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
cv2.imshow("image", image)
chans = cv2.split(image)
colors = ("b", "g", "r")
plt.figure()
plt.title("'Flattened' Color Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
features = []
for (chan, color) in zip(chans, colors):
hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
features.extend(hist)
plt.plot(hist, color = color)
plt.xlim([0, 256])
plt.show()
代码截图
chans = cv2.split(image)函数把图片分别分割成 R G B 三色空间
分别把三色空间的 R G B 空间传入cv2.calcHist([chan], [0], None, [256], [0, 256])函数来生成不同空间内的颜色图片直方图,最后把图片显示出来
图片mask参数
cv2.calcHist函数可以接受mask 来进行图片直方图的显示,默认计算图片的所有区域,但是有时候我们不需要图片的所有区域,我们可以使用mask来扣自己需要的图片区域,进而可以进行自己想要图片区域的直方图
mask 图片直方图
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
mask = np.zeros(img.shape[:2],np.uint8)
mask[100:500,100:500] = 255
mask_img = cv2.bitwise_and(img,img,mask=mask)
hist = cv2.calcHist([img], [0], mask, [256], [0, 256])
cv2.imshow("mask", mask_img)
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(hist)
plt.show()
代码截图
首先我们获取图片的尺寸img.shape[:2],有了图片的尺寸
我们可以标注自己需要的图片区域mask[100:500,100:500] = 255
使用cv2.bitwise_and 函数把原来图片中的需要的局部区域提取出来,我们可以show一下,看看是否是自己需要的区域
有了mask的区域,使用cv2.calcHist([img], [0], mask, [256], [0, 256])函数,传递mask 参数,进而可以实现mask图片的直方图显示。
图片直方图均衡化
这种方法通常用来增加许多图像的全局对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。
这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景噪声的对比度并且降低有用信号的对比度。
图片直方图均衡化
有两个问题比较难懂,一是为什么要选用累积分布函数,二是为什么使用累积分布函数处理后像素值会均匀分布。
直方图均衡化包括三个步骤:
- 统计直方图中每个灰度级出现的次数;
- 计算累计归一化直方图;
- 重新计算像素点的像素值;
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
res = cv2.equalizeHist(img)
cv2.imshow('img',img)
cv2.imshow('res',res)
cv2.waitKey(0)
代码截图
opencv 使用此函数res = cv2.equalizeHist(img),对图片进行均衡化进行处理,此函数是opencv全局化操作,这个操作在我们需要局部调整时不太适用,同理mask参数,opencv存在一种局部化处理的函数cv2.createCLAHE(),此函数接受一个局部尺寸参数数据
局部化处理
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#res = cv2.equalizeHist(img)
cla = cv2.createCLAHE(clipLimit=2,tileGridSize=(10,10))
res = cla.apply(img)
cv2.imshow('img',img)
cv2.imshow('res',res)
cv2.waitKey(0)
代码截图
总结
图片直方图在相识图片搜索引擎中起到了至关重要的作用,如何使用图片直方图来进行相识图片的搜索,我们下期分享,帮你打造一款属于自己的相识图片搜索引擎。