【opencv-python】图像金字塔

参考资料:

基本原理

一般情况下,我们要处理是一副具有固定分辨率的图像。但是有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况下,我们需要创建创建一组图像,这些图像是具有不同分辨率的原始图像。我们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集合)。如果我们把最大的图像放在底部,最小的放在顶部,看起来像一座金字塔,故而得名图像金字塔。图像金字塔有两类:高斯金字塔拉普拉斯金字塔

高斯金字塔

高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值(高斯模糊)。这样操作一次一个 MxN 的图像就变成了一个 (M+1)/2x(N+1)/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数cv2.pyrDown()和 cv2.pyrUp()构建图像金字塔。函数 cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金子塔,尺寸变小,本质是直接讲偶数行列消除,函数说明如下图所示:
在这里插入图片描述我们可以通过如下测试代码对图像进行测试:

import cv2
import numpy as np

def show_img(self, img, title):
	'''
	@brief:把图像显示三句函数整合为一个函数
	'''
	cv2.imshow(title, img)
	cv2.waitKey(0)
	cv2.destroyAllWindows()

img = cv2.imread('特斯拉.jpg')
for i in range(4):
    self.show_img(img, 'pydown')
    img = cv2.pyrDown(img)

运行效果为:
在这里插入图片描述在这里插入图片描述在这里插入图片描述 在这里插入图片描述图中终端的尺寸是一定的,图片的size一直在通过下采样缩小,分辨率也一直在降低,比如下采样四级之后,图像显著变小,我们将其放大查看,效果如下:

在这里插入图片描述
可见图像变得非常模糊,分辨率降低。同理,我们可以通过cv2.pyrUp()函数实现上采样,函数解释如下图所示:
在这里插入图片描述
代码只需要把相应函数直接替换即可,效果如下图所示(因为是增采样,我们选一行初始尺寸比较小的图片进行演示):
在这里插入图片描述源图像尺寸是(371,580)。

在这里插入图片描述
一次上采样之后尺寸变为(742,1160)。
在这里插入图片描述
再一次变为(1484,2320),扩大一倍。我怀疑是mac系统对大图有自动显示缩小的功能,让图片无论多大都能在一个屏幕内显示清楚,但是在windows系统里面却不是这样的,好像图片无论多大都可以以真实尺寸显示,结果效果就是一个屏显示不下。我们详细分析一下pyrUP()函数的运行机制,定义一个小size数组,代码如下图所示:

#测试上采样效果
img_test = np.uint8([[1, 2, 3, 4, 5],
                     [6, 7, 8, 9, 10],
                     [11, 12, 13, 14, 15],
                     [16, 17, 18, 19, 20],
                     [21, 22, 23, 24, 25]])
print('src:', img_test)
img_test = cv2.pyrUp(img_test)
print('dst:', img_test)

结果如下图所示:
在这里插入图片描述
可见src经过pyrUp()之后变成了dst的样子。

拉普拉斯金字塔

拉普拉斯金字塔是友高斯金字塔所形成的,opencv中没有独立的函数实现这个功能。拉普拉斯金字塔的效果类似边缘图像,图像中大部分像素值为0,主要用于图像压缩。拉普拉斯金字塔中的一个级别是由高斯金字塔中的该级别和高斯金字塔中其上一级别的扩展版本之间的差异形成的,这句话可以用以下公式清晰解释:
D i = S i − U p ( D o w n ( S i ) ) D_i=S_i-Up(Down(S_i)) Di=SiUp(Down(Si))
上述公式中, S i S_i Si代表源图像(src), D o w n ( ) Down() Down()算子代表对图像进行下采样, U p ( ) Up() Up()算子代表对图像进行上采样,所以如果对源图像先进行下采样再进行上采样,由于上下采样过程中都伴随着高斯滤波,因此图像经过上下采样后与源图像必不相同,其差异就是高斯金字塔处理后的结果。

图像融合

图像金字塔的一个主要应用就是图像融合。例如,在图像拼接中,我们需要讲两张图像堆积在一起,但是因为二者在边缘处不连续,两张图片很难实现无缝拼接,看起来效果不太好。在这种情况下,通过基于图像金字塔的图像融合具有一种无缝衔接的效果且在图像中不遗留很多数据。下面展示的是一个比较经典的苹果橘子融合的案例,我们可以观察融合的效果:

在这里插入图片描述实现这个功能的代码段如下所示:


def test_imgblending(self):
        '''
        @brief:测试图像融合
        '''
        A = cv2.imread('apple.jpg')
        B = cv2.imread('orange.jpg')

        # generate Gaussian pyramid for A
        G = A.copy()
        gpA = [G]
        for i in range(6):
            G = cv2.pyrDown(G)
            gpA.append(G)

        # generate Gaussian pyramid for B
        G = B.copy()
        gpB = [G]
        for i in range(6):
            G = cv2.pyrDown(G)
            gpB.append(G)

        # generate Laplacian Pyramid for A
        lpA = [gpA[5]]
        for i in range(5,0,-1):
            print('i:', i)
            GE = cv2.pyrUp(gpA[i])
            L = cv2.subtract(gpA[i-1],GE)
            lpA.append(L)

        # generate Laplacian Pyramid for B
        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)

        # Now add left and right halves of images in each level
        LS = []
        # https://www.runoob.com/python/python-func-zip.html
        for la,lb in zip(lpA,lpB):
            rows,cols,dpt = la.shape
            #print('cols/2', cols/2, type(cols/2))
            '''
            cv2.imshow('imga',la)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
            
            cv2.imshow('imgb',lb)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
            '''
            
            # https://blog.csdn.net/m0_37393514/article/details/79538748
            ls = np.hstack((la[:,0:int(cols/2)], lb[:,int(cols/2):]))
            '''
            cv2.imshow('hstackab',ls)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
            '''
            LS.append(ls)

        # now reconstruct
        ls_ = LS[0]
        for i in range(1,6):
            ls_ = cv2.pyrUp(ls_)
            ls_ = cv2.add(ls_, LS[i])

        # image with direct connecting each half
        real = np.hstack((A[:,:int(cols/2)],B[:,int(cols/2):]))


        #self.show_img('Pyramid_blending2', ls_)

        cv2.imwrite('Pyramid_blending2.jpg',ls_)
        cv2.imwrite('Direct_blending.jpg',real)

这段代码的流程图可以按照下图表示:
在这里插入图片描述
其核心思想是:先分别将苹果和橘子进行高斯金字塔处理,再进行拉普拉斯金字塔处理,再将苹果的左半边和橘子的右半边合成为一张图,再通过上采样和相应级别的拉普拉斯金字塔图像逐级相加,最后得到苹果-橘子图像融合后的结果。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hunter206206

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值