注意:(不要被金字塔的图像误导)
- 向上采样指:调用函数pyrUp(),放大图像;
- 向下采样指:调用函数pyrDown(),缩放图像。
>>>原始图像
目录
(1)图像金字塔原理
(2)向上采样和向下采样生成金字塔的过程
(3)高斯金字塔(pyrDown and pyrUp)
(4)拉普拉斯金字塔
(5)全部代码
图像金字塔是由一幅图像的多个不同分辨率的子图所构成的图像集合(如下图所示)。该组图像是由单个图像通过不断地降采样所产生的,最小的图像可能仅仅有一个像素点。
通常情况下,图像金字塔的底部是待处理的高分辨率图像(原始图像),而顶部则为其低分辨率的近似图像。向金字塔的顶部移动时,图像的尺寸和分辨率都不断地降低。通常情况下, 每向上移动一级,图像的宽和高都降低为原来的二分之一。
*******************************************向下采样过程*******************************************
首先原始图像滤波,得到原始图像的近似图像,然后将近似图像的偶数行和偶数列删除以获取向下采样的结果。有多种滤波器可以选择。例如:
- 邻域滤波器:采用邻域平均技术求原始图像的近似图像。该滤波器能够产生平均金字塔。
- 高斯滤波器:采用高斯滤波器对原始图像进行滤波,得到高斯金字塔。这是 OpenCV 函 数 cv2.pyrDown()所采用的方式。
*******************************************向上采样过程*******************************************
首先对像素点以补零的方式完成插值。通常是在每列像素点的右侧插入值为零的列,在每行像素点的下方插入值为零的行。如下图所示:左侧是要进行向上采样的 4 个像素点,右侧是向上采样时进行补零后的处理结果。
接下来,使用向下采样时所用的高斯滤波器(高斯核)对补零后的图像进行滤波处理,以获取向上采样的结果图像。但是需要注意,此时图像中四分之三像素点的值都是零。所以,要 将高斯滤波器系数乘以 4,以保证得到的像素值范围在其原有像素值范围内。
OpenCV 提供了函数 cv2.pyrDown()和函数 cv2.pyrUp(),分别用于实现图像高斯金字塔操作中的向下采样和向上采样,其语法形式为:
dst = cv2.pyrDown( src[, dstsize[, borderType]] )
dst = cv2.pyrUp( src[, dstsize[, borderType]] )
注意:如果先对原始图像进行向上采样,再进行向下采样,不会得到原始图像,即不可逆!
因为在此操作的过程中,经过删除列和行,会有信息的丢失。
>>>向下采样运行结果图,如下:
>>>向上采样运行结果图,如下所示,明显可以发现图像已模糊
前面我们已经介绍过,一幅图像在经过向下采样后,再对其进行向上采样,是无法恢复为原始状态的。为了在向上采样时能够恢复具有较高分辨率的原始图像,就要获取在采样过程中所丢失的信息,这些丢失的信息就构成了拉普拉斯金字塔。
拉普拉斯金字塔的定义形式为:
Li = Gi - pyrUp(Gi + 1)
拉普拉斯金字塔中的第 i 层,等于“高斯金字塔中的第 i 层”与“高斯金字塔中的第 i+1 层的向上采样结果”之差。如下图所示,展示了高斯金字塔和拉普拉斯金字塔的对应关系。
>>>运行结果图,如下:
拉普拉斯金字塔的作用在于,能够恢复高分辨率的图像。下图演示了如何通过拉普拉斯金字塔恢复高分辨率图像。其中,右图是对左图的简化。
上图中各个标记的含义如下:
拉普拉斯金字塔恢复高分辨率图像的步骤:
1. 向下采样(高斯金字塔的构成)
G1=cv2.pyrDown(G0)
G2=cv2.pyrDown(G1)
G3=cv2.pyrDown(G2)
2. 拉普拉斯金字塔
L0=G0-cv2.pyrUp(G1)
L1=G1-cv2.pyrUp(G2)
L2=G2-cv2.pyrUp(G3)
3. 向上采样恢复高分辨率图像
G0=L0+cv2.pyrUp(G1)
G1=L1+cv2.pyrUp(G2)
G2=L2+cv2.pyrUp(G3)
虽然是简单的相加减关系,但是可以此过程的中间操作图像,进行创新
>>>如下图所示,已经成功恢复原始图像
import cv2
src = cv2.imread("pyramid.jpg")
# 向下采样
down0 = cv2.pyrDown(src)
down1 = cv2.pyrDown(down0)
down2 = cv2.pyrDown(down1)
print("逐个向下采样后的图像尺寸:", "\n", src.shape, "\n", down0.shape, "\n", down1.shape, "\n", down2.shape)
# 向上采样
up2 = cv2.pyrUp(down2)
up1 = cv2.pyrUp(up2)
up0 = cv2.pyrUp(up1)
print("逐个向上采样后的图像尺寸:", "\n", up2.shape, "\n", up1.shape, "\n", up0.shape)
# 拉普拉斯变换(原理)
L0 = down0 - cv2.pyrUp(down1)
L1 = down1 - cv2.pyrUp(down2)
print("拉普拉斯变换后的图像尺寸:", "\n", L0.shape, "\n", L1.shape)
# 拉普拉斯变换(恢复原始图像)
src_L0 = L0 + cv2.pyrUp(down1)
src_L1 = L1 + cv2.pyrUp(down2)
print("拉普拉斯变换恢复的图像尺寸:", "\n", src_L0.shape, "\n", src_L1.shape)
cv2.imshow("src", src)
cv2.imshow("down", down0)
cv2.imshow("down1", down1)
cv2.imshow("down2", down2)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imshow("up2", up2)
cv2.imshow("up1", up1)
cv2.imshow("up", up0)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imshow("L0", L0)
cv2.imshow("L1", L1)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imshow("src_L0", src_L0)
cv2.imshow("src_L1", src_L1)
cv2.waitKey(0)
cv2.destroyAllWindows()
>>>如有疑问,欢迎评论区一起探讨