图像金字塔
一般情况下,我们要处理是一副具有固定分辨率的图像。但是有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况下,我们需要创建创建一组图像,这些图像是具有不同分辨率的原始图像。我们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集合)如果我们把最大的图像放在底部,最小的放在顶部,看起来像一座金字塔,故而得名图像金字塔。
有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。
高斯金字塔
高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中5个像素的高斯加权平均值。这样操作一次一个MxN的图像就变成了一个M/2xN/2的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数cv2.pyrDown()
和cv2.pyrUp()
构建图像金字塔。
函数 cv2.pyrDown()
从一个高分辨率大尺寸的图像向上构建一个金子塔尺寸变小,分辨率降低。
例:下采样
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("lena.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
lower_reso = cv2.pyrDown(img)
plt.figure(figsize=(10,10),dpi= 80)
plt.subplot(221)
plt.imshow(img)
plt.xlabel("原图",fontproperties='SimHei')
plt.subplot(222)
plt.imshow(lower_reso)
plt.xlabel("下采样",fontproperties='SimHei')
plt.tight_layout()
plt.show()
函数cv2.pyrUp()
从一个低分辨率小尺寸的图像向下构建一个金子塔(尺寸变大,但分辨率不会增加)
higher_reso = cv2.pyrUp(lower reso)
你要记住的是是 higher_reso和 img是不同的。因为一旦使用cv2.pyrDown()
,图像的分辨率就会降低,信息就会被丢失。下图就是从cv2.pyrDown()
产生的图像金字塔的(由下到上)第三层图像使用函数cv2.pyrUp()
得到的图像,与原图像相比分辨率差了很多。
例:上采样
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("lena.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
lower_reso = cv2.pyrDown(img)
higer_reso = cv2.pyrUp(lower_reso)
plt.figure(figsize=(10,10),dpi= 80)
plt.subplot(221)
plt.imshow(img)
plt.xlabel("原图",fontproperties='SimHei')
plt.subplot(222)
plt.imshow(higer_reso)
plt.xlabel("上采样",fontproperties='SimHei')
plt.tight_layout()
plt.show()
拉普拉斯金字塔
拉普拉斯金字塔可以有高斯金字塔计算得来,公式如下:
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0。他们经常被用在图像压缩中。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("lena.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
lower_reso = cv2.pyrDown(img)
higer_reso = cv2.pyrUp(lower_reso)
lp_img = cv2.subtract(img, higer_reso)
plt.figure(figsize=(10,10),dpi= 80)
plt.subplot(221)
plt.imshow(img)
plt.xlabel("原图",fontproperties='SimHei')
plt.subplot(222)
plt.imshow(lp_img)
plt.xlabel("拉普拉斯金字塔",fontproperties='SimHei')
plt.tight_layout()
plt.show()
使用金字塔进行图像融合
图像金字塔的一个应用是图像融合。例如,在图像缝合中,你需要将两幅图叠在一起,但是由于连接区域图像像素的不连续性,整幅图的效果看起来会很差。这时图像金字塔就可以排上用场了,他可以帮你实现无缝连接。这里的个经典案例就是将两个水果融合成一个,看看下图也许你就明白我在讲什么。
主要步骤如下:
- 读入两幅图像,苹果和橘子
- 构建苹果和橘子的高斯金字塔(6 层)
- 根据高斯金字塔计算拉普拉斯金字塔
- 在拉普拉斯的每一层进行图像融合(苹果的左边与橘子的右边融合)
- 根据融合后的图像金字塔重建原始图像。
# -*- coding: utf-8 -*-
"""
Created on Thu Feb 20 14:22:42 2020
@author: 陨星落云
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
A = cv2.imread("apple.jpg")
B = cv2.imread("orange.jpg")
# 生成苹果高斯金字塔
G = A.copy()
gpA = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpA.append(G)
# 生成橘子高斯金字塔
G = B.copy()
gpB = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpB.append(G)
# 生成苹果的拉普拉斯金字塔
lpA = [gpA[5]]
for i in range(5,0,-1):
GE = cv2.pyrUp(gpA[i])
L = cv2.subtract(gpA[i-1], GE)
lpA.append(L)
# 生成橘子的拉普拉斯金字塔
lpB = [gpB [5]]
for i in range(5,0,-1):
GE = cv2.pyrUp(gpB [i])
L = cv2.subtract(gpB [i-1], GE)
lpB.append(L)
# 现在将左边的苹果与右边的橘子进行拼接
LS = []
for la,lb in zip(lpA,lpB):
rows,cols,c = la.shape
ls = np.hstack((la[:,0:cols//2],lb[:,cols//2:]))
LS.append(ls)
# 重建图像
ls_ = LS[0]
for i in range(1,6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_,LS[i])
# 直接拼接的图像
real = np.hstack((A[:,:cols//2],B[:,cols//2:]))
# 使用mayplotlib需要将BGR颜色空间转换RGB
A = cv2.cvtColor(A, cv2.COLOR_BGR2RGB)
B = cv2.cvtColor(B, cv2.COLOR_BGR2RGB)
ls_ = cv2.cvtColor(ls_, cv2.COLOR_BGR2RGB)
real = cv2.cvtColor(real, cv2.COLOR_BGR2RGB)
# 显示图像
plt.figure(figsize=(10,10),dpi= 80)
plt.subplot(221)
plt.imshow(A)
plt.xlabel("苹果",fontproperties='SimHei')
plt.subplot(222)
plt.imshow(B)
plt.xlabel("橘子",fontproperties='SimHei')
plt.subplot(223)
plt.imshow(ls_)
plt.xlabel("金字塔图像融合结果",fontproperties='SimHei')
plt.subplot(224)
plt.imshow(real)
plt.xlabel("直接拼接结果",fontproperties='SimHei')
plt.tight_layout()
plt.show()
参考资料:《OpenCV-Python 中文教程》