小言_互联网的博客

在OpenCV里生成图像金字塔

556人阅读  评论(0)

今天介绍图像处理邻域中比较常用的一种方法,image pyramid, 也叫图像金字塔。就是将图像进行一层一层的下采样,图像金字塔是为了构建图像的多尺度,让模型能够更好的适应图像的尺度变化,图像金字塔可以广泛应用于图像识别,目标检测,还有光流配准,块匹配都能看到它的身影。图像金字塔主要有两种,一种是高斯金字塔,gaussian pyramid,另外一种是拉普拉斯金字塔,Laplacian Pyramids。

图像金字塔是一种以多分辨率来解释图像的结构,通过对原始图像进行多尺度像素采样的方式,生成N个不同分辨率的图像。把具有最高级别分辨率的图像放在底部,以金字塔形状排列,往上是一系列像素(尺寸)逐渐降低的图像,一直到金字塔的顶部只包含一个像素点的图像,这就构成了传统意义上的图像金字塔。

获得图像金字塔一般包括二个步骤:

1. 利用低通滤波器平滑图像

2. 对平滑图像进行抽样(采样)

有两种采样方式——上采样(分辨率逐级升高)和下采样(分辨率逐级降低)

在OpenCV定义这两个函数:

这个函数主要采用下面高斯平滑算子:

这个函数实现向下高斯平滑和采样,另外一个函数cv.pyrUp向上高斯平滑和采样。可以采用下面的例子来演示:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt

#读取图片
A = cv2.imread('dft6.jpg')

#生成高斯金字塔
G = A.copy()
gpA = [G]

for i in range(4): #生成四级
	G = cv2.pyrDown(G) #调用高斯金字塔函数pyrDown
	gpA.append(G) #保存到队列

G = np.zeros_like(A)
#第1级图像
rowX2 = gpA[1].shape[0]
colX2 = gpA[1].shape[1]
G[:rowX2, :colX2, :] = gpA[1]
#第2级图像
rowX4 = rowX2 // 2
colX4 = colX2 // 2
G[rowX2:rowX2+rowX4, colX2:colX2+colX4, :] = gpA[2]
G[:rowX4, colX2:colX2+colX4, :] = gpA[2]
#第3级图像
rowX8 = rowX4 // 2
colX8 = colX4 // 2
G[rowX2+rowX4:rowX2+rowX4+rowX8, colX2+colX4:colX2+colX4+colX8,          :] = gpA[3]
G[ :rowX8, colX2+colX4:colX2+colX4+colX8, :] = gpA[3]

cv2.imshow("Gaussian Pyramid", G)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

 

上面的例子,只是介绍了向下采样的情况,现在来学习利用图像金字塔完成两幅图像混合,具体步骤如下:

  1. 加载两幅图像
  2. 生成两幅图像的高斯金字塔
  3. 从高斯金字塔生成拉普拉斯金字塔
  4. 每一级的拉普拉斯金字塔进行一半合并
  5. 采用向上重构图像

具体例子如下:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt

#读取图片
A = cv2.imread('apple1.png')
B = cv2.imread('orange1.png')

h, w = A.shape[:2]
B = cv2.resize(B, (w,h))

#从A生成高斯金字塔
G = np.copy(A)
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

#从B生成高斯金字塔
G = np.copy(B)
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

#从A生成拉普拉斯金字塔
lpA = [gpA[5]]
for i in range(5,0,-1):
    GE = cv2.pyrUp(gpA[i])
    
    x, y =  gpA[i-1].shape[0:2]
    resizeImg = cv2.resize(GE,(y,x))
    L = cv2.subtract(gpA[i-1],resizeImg)
    lpA.append(L)

#从B生成拉普拉斯金字塔
lpB = [gpB[5]]
for i in range(5,0,-1):
    GE = cv2.pyrUp(gpB[i])
    x, y =  gpB[i-1].shape[0:2]
    resizeImg = cv2.resize(GE,(y,x))
    L = cv2.subtract(gpB[i-1],resizeImg)
    lpB.append(L)

#拉普拉斯金字塔合并,每个取半边
LS = []
for la,lb in zip(lpA,lpB):
    rows,cols,dpt = 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_)
    
    x, y =  LS[i].shape[0:2]
    resizeImg = cv2.resize(ls_,(y,x))

    ls_ = cv2.add(resizeImg, LS[i])

#从原图直接取半边的合并
cols = w//2
real = np.hstack((A[:,:cols],B[:,cols:]))


cv2.imshow('Pyramid_blending',ls_)
cv2.imshow('Direct_blending',real)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

直接合并的混合效果

采用金字塔方式混合效果

https://blog.csdn.net/caimouse/article/details/102530873


转载:https://blog.csdn.net/caimouse/article/details/102541566
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场