目录
传送门:
详解直方图均衡(一)《图像增强、灰度变换和直方图均衡化关系》
OpenCV中直方图相关函数使用:
直方图计算:
OpenCV中获取直方图的函数calcHist() 和其参数解释:
numpy中提供的两种计算直方图方法histogram()和bincount()
OpenCV中的calcHist()和numpy中的histogram()、bincount()使用方法和计算速度对比:
使用Matplotlib绘制直方图:
第一种方式,
第二种方式,
效果:
直方图均衡化的三种情况,分别是:
灰度图像直方图均衡化
彩色图像直方图均衡化
YUV 直方图均衡化
自适应直方图均衡化:
原理:
和普通直方图效果对比:
2D直方图:
直方图反投影
什么是反投影
算法实现的方法
反向投影的作用
反向投影查找原理:
查找流程:
反向投影的结果
模板和图像大小的影响:
OpenCV中的相关函数cv.calcBackProject()
演示
opencv-python 详解直方图均衡(一)《图像增强、灰度变换和直方图均衡化关系》_RayChiu757374816的博客-CSDN博客
calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
使用类似这样:
hist = CV2.calcHist([img],[0],None,[256],[0,256])
import cv2
import numpy as np
img = cv2.imread('hist.jpg', 0)
# 1.直方图计算
# 使用OpenCV函数计算
hist = cv2.calcHist([img], [0], None, [256], [0, 256]) # 性能:0.022158 s
# 使用numpy函数计算
hist, bins = np.histogram(img.ravel(), 256, [0, 256]) # 性能:0.020628 s
# 使用numpy函数计算
hist = np.bincount(img.ravel(), minlength=256) # 性能:0.003163 s
可以看出来最快的还是OpenCV提供的函数,所以直接用 calcHist() 即可。
不用借助OpenCV的calHist()函数先获取直方图,可以直接绘图出来直方图:
plt.hist(img.ravel(), 256, [0, 256])
直接用Matplotlib绘图功能:
color = ('b', 'g', 'r')
for i, col in enumerate(color):
histr = CV2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(histr, color=col)
plt.xlim([0, 256])
plt.show()
相关函数为 equalizeHist(src[, dst]) ,使用方法如下:
dst = cv2.equalizeHist(gray) # 应用全局直方图均衡化
彩色图像的直方图均衡化和灰度图像略有不同,需要将彩色图像先用split()方法,将三个通道拆分,然后分别进行均衡化.最后使用merge()方法将均衡化之后的三个通道进行合并.操作如下:
(b, g, r) = cv2.split(img)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
# 合并每一个通道
result = cv2.merge((bH, gH, rH))
cv2.imshow("img",img)
cv2.imshow("dst", result)
cv2.waitKey(0)
使用方式如下:
imgYUV = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
channelsYUV = cv2.split(imgYUV)
channelsYUV[0] = cv2.equalizeHist(channelsYUV[0])
channels = cv2.merge(channelsYUV)
result = cv2.cvtColor(channels, cv2.COLOR_YCrCb2BGR)
cv2.imshow("dst", result)
cv2.waitKey(0)
在这个方法中,图像会被划分为称为“tiles”的小块 (在OpenCV中,tileSize默认为8x8)。然后像先前一样对每个块进行直方图均衡,图像更加的清晰,事实上,我们称之为——图像锐化
import cv2
import numpy as np
img = cv2.imread('tsukuba.jpg', 0)
equ = cv2.equalizeHist(img) # 应用全局直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) # 自适应均衡化,参数可选
cl1 = clahe.apply(img)
cv2.imshow('equalization', np.hstack((img, equ, cl1))) # 并排显示
cv2.waitKey(0)
结果:
对比图(从左向右为原图、普通直方图均衡、自适应直方图均衡)
一维的直方图只考虑了像素的灰度强度值,我们通常输入灰度图像。
但是在二维直方图中,我们要考虑两个特征。通常,它用于查找颜色直方图,其中两个特征是每个像素的色相和饱和度值。
使用相同的函数 cv.calcHist ()进行计算。 对于彩色直方图,我们需要将图像从BGR转换为HSV。(请记住,对于一维直方图,我们从BGR转换为灰度)。对于二维直方图,其参数将进行如下修改:
上边说了彩色图像的直方图均值化,但是并未进行详述,其本质属于二维直方图,但同样的,它也可以进行均值化,伪代码如下:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
cv2.imshow("img",img)
cv2.imshow("res",hist)
效果:
同样numpy也可以绘制二维直方图,不在这里说明了。
反向投影可以用来做图像分割,用直方图寻找感兴趣区域,类似于我们前面讲过的ROI区域分割。它会输出与输入图像大小相同的图像,每一个像素值代表了输入图像上对应点属于目标对象的概率,简言之,输出图像中像素值越高的点越可能代表想要查找的目标。直方图投影经常与camshift(追踪算法)算法一起使用。
更通俗一点,反向投影可以通过颜色直方图来理解,我们检测图像中某个像素点的颜色是否位于直方图中,如果位于则将颜色加亮,通过对图像的检测,得出结果图像,结果图像一定和直方图像匹配。那么对于图像颜色的取样点越多,越能更好的找出目标图形。这里直方图的作用在于提供一个比较标准(也就是模版),即对于要检测的图像来说,需要给它提供一个模版,用于识别出和模版相应的特征。
首先要为包含我们感兴趣区域的图像建立直方图。被查找的对象最好是占据整个图像。最好使用颜色直方图,物体的颜色信息比灰度图像更容易被分割和识别。再将颜色直方图投影到输入图像查找目标,也就是找到输入图像中每一个像素点的像素值在直方图中对应的概率,这样就得到一个概率图像,最后设置适当的阈值对概率图像进行二值化。
经过上面的分析,下面给出反向投影的作用:反向投影用于在输入图像(通常较大)中查找特定图像(通常较小或者仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
查找的方式就是不断的在输入图像中切割跟模板图像大小一致的图像块,并用直方图对比的方式与模板图像进行比较。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)生成临时图像的直方图;
(3)用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
(6)重复(1)~(5)步直到输入图像的右下角。
反向投影的结果包含了:以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵,或者单通道的浮点型图像。
可以这样理解:对于calcBackProjectPatch,也就是是基于块的反向投影形式,利用直方图做匹配,类似于模板匹配,只不过这些模板转换为直方图,而原图中以某点为基准,抠出来作对比的部分也转换为直方图,两个直方图作匹配,匹配的结果作为此点的值,结果会是一张灰度图。
如果输入图像和模板图像一样大,那么反向投影相当于直方图对比。如果输入图像比模板图像还小,那么则无法进行反向投影。
OpenCV提供了一个内置函数cv.calcBackProject()。 它的参数与cv.calcHist()函数几乎相同。 此外,在传递给Backproject函数之前,应该对象直方图进行标准化。它返回概率图像,然后我们将图像与内核卷积并应用阈值。
接下来我们进行演示,模板图片还是可爱的lena:
模板:
测试代码:
import cv2
import numpy as np
# roi图片,就想要找的的图片
roi = cv2.imread('2.jpg')
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# 目标搜索图片
target = cv2.imread('1.jpg')
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
# 计算目标直方图
roihist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 归一化,参数为原图像和输出图像,归一化后值全部在2到255范围
cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt], [0, 1], roihist, [0, 180, 0, 256], 1)
# 卷积连接分散的点
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
dst = cv2.filter2D(dst, -1, disc)
ret, thresh = cv2.threshold(dst, 50, 255, 0)
# 使用merge变成通道图像
thresh = cv2.merge((thresh, thresh, thresh))
# 蒙板
res = cv2.bitwise_and(target, thresh)
# 矩阵按列合并,就是把target,thresh和res三个图片横着拼在一起
res = np.hstack((target, thresh, res))
cv2.imwrite('res.jpg', res)
# 显示图像
cv2.imshow('1', res)
cv2.waitKey(0)
效果: