OpenCV常用基本处理函数(7)图像金字塔和直方图

高斯金字塔

高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。

这样操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。

可以得到一个分辨率不断下降的图像金字塔。我们可以使用函数cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。

图像的轮廓:

轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同、的颜色或者灰度;

在一个二值图像中查找轮廓:
  函数 cv2.findContours() 有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。

直方图

直方图是根据灰度图像绘制的,而不是彩色图

使用 OpenCV  统计一幅图像的直方图

参数:
cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])
  1. images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如:[img]。
  2. channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
  3. mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子)
  4. histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。
  5. ranges: 像素值范围,通常为 [0,256]

也可以这样,Matplotlib Matplotlib 中有直方图绘制函数:matplotlib.pyplot.hist()
它可以直接统计并绘制直方图

可以只使用 matplotlib 的绘图功能,这在同时绘制多通道(BGR)的直方图

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg')
color = ('b','g','r')
# 对一个列表或数组既要遍历索引又要遍历元素,使用enumerate
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()

直方图均衡化

一维直方图

直接得到的直方图可能某些像素值聚集在一个地方,一副高质量的图像的像素值分布应该很广泛。

所以你应该把它的直方图变成均衡分布,这就是直方图均衡化。通常情况下这种操作会改善图像的对比度

这里直接介绍自适应的直方图均衡化的函数,可以有效的保留图像的某些细节部分;

这种情况下,整幅图像会被分成很多小块,这些小块被称为“tiles”(也就是函数的第二个参数默认是 8x8),然后再对每一个小块分别进行直方图均衡化

import numpy as np
import cv2
img = cv2.imread('tsukuba_l.png',0)
#创建一个clahe对象
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) cl1 = clahe.apply(img) cv2.imwrite('clahe_2.jpg',cl1)

2D直方图

一维直方图只考虑灰度值这一因素,2d直方图要考虑颜色和饱和度两个因素;(hsv空间的前两个就是颜色和饱和度)


用cv2.calcHist()计算 2D 直方图,参数要修改:
  • channels=[0 ,1] 同时处理 H 和 S 两个通道。
  • bins=[180 ,256]H 通道为 180,S 通道为 256。
  • range=[0 ,180 ,0 ,256]H 的取值范围在 0 到 180,S 的取值范围在 0 到 256。
最后一行是使用plt的画图函数画出彩色直方图,插值函数用nearest.
img = cv2.imread('home.jpg')
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')

直方图反向投影

目的是在图像中找寻我们感兴趣的部分或者其他作用;

投影后会输出与输入图像(待搜索)同样大小的图像,其中的每一个像素值代表了输入图像上对应点属于目标对象的概率。、

用更简单的话来解释,输出图像中像素值越高(越白)的点就越可能代表我们要搜索的目标(在输入图像所在的位置)。

OpenCV 里使用函数 cv2.calcBackProject() 做直方图反向投影。它的参数与函数 cv2.calcHist 的参数基本相同。其中的一个参数是我们要查找目标的直方图。第三个参数是锁定目标的直方图

同样再使用目标的直方图做反向投影之前我们应该先对其做归一化处理。返回的结果是一个概率图像,我们再使用一个圆盘形卷积核对其做卷操作,最后使用阈值进行二值化

import cv2
import numpy as np
roi = cv2.imread('tar.jpg')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target = cv2.imread('roi.jpg')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
# calculating object histogram
roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
# normalize histogram and apply backprojection
# 归一化:原始图像,结果图像,映射到结果图像中的最小值,最大值,归一化类型
#cv2.NORM_MINMAX 对数组的所有值进行转化,使它们线性映射到最小值和最大值之间
# 归一化之后的直方图便于显示,归一化之后就成了 0255 之间的数了。
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
# Now convolute with circular disc
# 此处卷积可以把分散的点连在一起
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
dst=cv2.filter2D(dst,-1,disc)
# threshold and binary AND
ret,thresh = cv2.threshold(dst,50,255,0)
# 别忘了是三通道图像,因此这里使用 merge 变成 3 通道
thresh = cv2.merge((thresh,thresh,thresh))
# 按位操作
res = cv2.bitwise_and(target,thresh)
res = np.hstack((target,thresh,res))
cv2.imwrite('res.jpg',res)
# 显示图像
cv2.imshow('1',res)
cv2.waitKey(0)

结果如图所示:

 参考自:https://www.cnblogs.com/Undo-self-blog/p/8439149.html

原文地址:https://www.cnblogs.com/ywheunji/p/10990311.html