【OpenCV学习笔记21】- 图像金字塔

发布时间:2024年01月24日

这是对于 OpenCV 官方文档中 图像处理 的学习笔记。学习笔记中会记录官方给出的例子,也会给出自己根据官方的例子完成的更改代码,同样彩蛋的实现也会结合多个知识点一起实现一些小功能,来帮助我们对学会的知识点进行结合应用。
如果有喜欢我笔记的请麻烦帮我关注、点赞、评论。谢谢诸位。

学习笔记:
学习笔记目录里面会收录我关于OpenCV系列学习笔记博文,大家如果有什么不懂的可以通过阅读我的学习笔记进行学习。
【OpenCV学习笔记】- 学习笔记目录

内容

  • 我们将了解图像金字塔。
  • 我们将使用图像金字塔创建一个新的水果,“Orapple”
  • 我们将看到这些功能: cv2.pyrUp() , cv2.pyrDown()

理论

通常,我们通常使用固定大小的图像。但在某些情况下,我们需要以不同的分辨率处理(相同的)图像。例如,在搜索图像中的某些内容(例如面部)时,我们不确定该对象将在所述图像中出现的大小。在这种情况下,我们需要创建一组具有不同分辨率的相同图像,并在所有图像中搜索对象。这些具有不同分辨率的图像集称为图像金字塔(因为当它们保存在堆栈中时,最高分辨率的图像在底部,最低分辨率的图像在顶部,它看起来像金字塔)。

有两种图像金字塔。

  1. 高斯金字塔
  2. 拉普拉斯金字塔

高斯金字塔中的较高级别(低分辨率)是通过删除较低级别(较高分辨率)图像中的连续行和列而形成的。然后,较高层的每个像素由具有高斯权重的底层 5 个像素的贡献组成。通过这样做,一个M× N图像变成(M/ 2)×(N/2)图像。这样面积就减少到原来面积的四分之一。它被称为八度。当我们进入金字塔的上部时,相同的模式继续存在(即分辨率降低)。同样,扩张时,每层面积变为4倍。我们可以使用 cv2.pyrDown()cv2.pyrUp() 函数找到高斯金字塔。

示例代码:

# 图像金字塔
import cv2

higher_reso = cv2.imread('../image/3.8.1.png')
cv2.imshow('higher_reso', higher_reso)
cv2.waitKey(0)
lower_reso = cv2.pyrDown(higher_reso)
cv2.imshow('lower_reso', lower_reso)
cv2.waitKey(0)
lower_reso2 = cv2.pyrDown(lower_reso)
cv2.imshow('lower_reso2', lower_reso2)
cv2.waitKey(0)
lower_reso3 = cv2.pyrDown(lower_reso2)
cv2.imshow('lower_reso3', lower_reso3)
cv2.waitKey(0)
cv2.destroyAllWindows()

以下是图像金字塔中的 4 个级别。
效果图:
在这里插入图片描述
现在你可以用 cv2.pyrUp() 函数处理图像金字塔。

请记住,higher_reso2不等于higher_reso,因为一旦降低了分辨率,就会丢失信息。下图为将上述金字塔中最高级别图像下降三个级别后的结果(即重构三次)。将其与原始图像进行比较,可以发现分辨率相同,但丢失了许多信息:

示例代码:

# 图像金字塔
import cv2

higher_reso = cv2.imread('../image/3.8.1.png')
cv2.imshow('higher_reso', higher_reso)
cv2.waitKey(0)
lower_reso = cv2.pyrDown(higher_reso)
lower_reso2 = cv2.pyrDown(lower_reso)
lower_reso3 = cv2.pyrDown(lower_reso2)
higher_reso2 = cv2.pyrUp(lower_reso3)
higher_reso3 = cv2.pyrUp(higher_reso2)
higher_reso4 = cv2.pyrUp(higher_reso3)
cv2.imshow('higher_reso4', higher_reso4)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果图:
在这里插入图片描述
拉普拉斯金字塔由高斯金字塔转化而来,没有专属功能。拉普拉斯金字塔图像与边缘图像相似,它的大部分元素都是零,可以用于图像压缩。拉普拉斯金字塔中的某一层次即高斯金字塔中的该层次与高斯金字塔中的上层的扩展版本之间的差异。拉普拉斯级别的三个级别如下所示(效果为调整对比度以凸显内容):

效果图:
在这里插入图片描述
调整对比度进行边缘检测:

示例代码:

# 图像金字塔
import cv2

higher_reso = cv2.imread('../image/3.8.1.png')
lower_reso = cv2.pyrDown(higher_reso)
lower_reso2 = cv2.pyrDown(lower_reso)
lower_reso3 = cv2.pyrDown(lower_reso2)
higher_reso2 = cv2.pyrUp(lower_reso3)
edges2 = cv2.convertScaleAbs(higher_reso2, alpha=2.0, beta=0)
edges2 = cv2.Canny(edges2, 0, 40)
cv2.imshow('higher_reso2', edges2)
cv2.waitKey(0)
higher_reso3 = cv2.pyrUp(higher_reso2)
edges3 = cv2.convertScaleAbs(higher_reso3, alpha=2.0, beta=0)
edges3 = cv2.Canny(edges3, 0, 40)
cv2.imshow('higher_reso3', edges3)
cv2.waitKey(0)
higher_reso4 = cv2.pyrUp(higher_reso3)
edges4 = cv2.convertScaleAbs(higher_reso4, alpha=2.0, beta=0)
edges4 = cv2.Canny(edges4, 0, 40)
cv2.imshow('higher_reso4', edges4)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果图:
在这里插入图片描述

使用金字塔的图像混合

金字塔的一个应用是图像混合。例如,在图像拼接中,您需要将两个图像堆叠在一起,但由于图像之间的不连续性,它可能看起来不太好。在这种情况下,使用金字塔进行图像混合可以实现无缝混合,而不会在图像中留下多余数据。典型的例子是混合橙子和苹果图像。在查看下面的效果图就明白什么含义。

请在其他资源中查看第一个参考资料,它有关于图像混合,拉普拉斯金字塔等的完整图表细节。简单的表述如下:

  1. 加载苹果和橙色的两个图像
  2. 找到苹果和橙色的高斯金字塔(在这个例子中,级别数是 6)
  3. 从高斯金字塔,找到他们的拉普拉斯金字塔
  4. 现在加入左半部分的苹果和右半部分的拉普拉斯金字塔
  5. 最后,从这个联合图像金字塔,重建原始图像。

这里的代码把官方的例子简单的优化了一下。在图像数据相互处理的时候,进行了尺寸归一处理。

示例代码:

# 图像金字塔
# 使用金字塔的图像混合
import cv2
import numpy as np

# apple
A = cv2.imread('../image/3.8.2.png')
# orange
B = cv2.imread('../image/3.8.3.png')
# 让A的尺寸和B的尺寸保持一致
height, width = B.shape[:2]
A = cv2.resize(A, (width, height))
# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
# generate Gaussian pyramid for B
G2 = B.copy()
gpB = [G2]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)
    G2 = cv2.pyrDown(G2)
    gpB.append(G2)

# generate Laplacian Pyramid for A
lpA = [gpA[5]]
# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in range(5, 0, -1):
    GE_A = cv2.pyrUp(gpA[i])
    # 保证 GE_A 和 gpA[i - 1] 尺寸一致
    height_A, width_A = gpA[i - 1].shape[:2]
    GE_A = GE_A[:height_A, :width_A]
    L_A = cv2.subtract(gpA[i - 1], GE_A)
    lpA.append(L_A)

    GE_B = cv2.pyrUp(gpB[i])
    # 保证 GE_B 和 gpB[i - 1] 尺寸一致
    height_B, width_B = gpB[i - 1].shape[:2]
    GE_B = GE_B[:height_B, :width_B]
    L_B = cv2.subtract(gpB[i - 1], GE_B)
    lpB.append(L_B)

# Now add left and right halves of images in each level
LS = []
for la, lb in zip(lpA, lpB):
    rows, cols, dpt = la.shape
    # 确保 cols / 2 是整数
    ls = np.hstack((la[:, 0: int(cols / 2)], lb[:, int(cols / 2):]))
    LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
    ls_ = cv2.pyrUp(ls_)
    # 保证 ls_ 和 LS[i] 尺寸一致
    height, width = LS[i].shape[:2]
    ls_ = ls_[:height, :width]
    # 这里如果 ls_ 和 LS[i] 尺寸不一致,没办法相加
    ls_ = cv2.add(ls_, LS[i])

# image with direct connecting each half
real = np.hstack((A[:, :int(cols / 2)], B[:, int(cols / 2):]))
# cv2.imwrite('Pyramid_blending2.jpg', ls_)
# cv2.imwrite('Direct_blending.jpg', real)

cv2.imshow('Apple', A)
cv2.waitKey(0)
cv2.imshow('Orange', B)
cv2.waitKey(0)
cv2.imshow('Direct Connection', real)
cv2.waitKey(0)
cv2.imshow('Pyramid Blending2', ls_)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果图:
在这里插入图片描述

其他资源

  1. 图像混合
文章来源:https://blog.csdn.net/q664243624/article/details/135821937
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。