python-opencv自学,图像金字塔与图像融合

本篇文章讲解基于python-opencv图像金字塔API及浅析原理


一. 图像金字塔

1. 图像金字塔是什么?为什么要叫它图像金字塔?

图像金字塔是对出现处理发展至今的一种手段。它是图像多尺度表达的一种,它的本质就是一张图片的集合,我们可以用列表存,可以用字典存,只要是可变的结构就可以存储。该集合中每一个元素就是一个原图的子图集。他之所以称之为金字塔,是因为,图像金字塔的构建是采用一次次梯度向下取样获得,最后组成的层次性的结果像一个金字塔一样,取名为图像金字塔。
在这里插入图片描述

2. 图像金字塔构建原理

图像金字塔的构建,得从两个金字塔来说

①. 高斯金字塔

高斯金字塔是最基本的图像金字塔。
其构建过程为对一张大图采用,将原图像的连续行和列去除利用一个总长为5的高斯核进行模糊的操作。
一般的过程为,先对图像进行高斯内核卷积,完成模糊操作,之后去除掉偶数行和列,这样原图就会变为以前的四分之一(因为行列都变为以前的二分之一),高斯核从官档来看应该是1*5若是有问题可以指出,这里我没有太关注,之后重复以上过程,直至达到终止条件或者报错。

②. 拉普拉斯金字塔

拉普拉斯金字塔,是基于高斯金字塔获取的图像金字塔。一般情况下先计算高斯金字塔。其计算公式如下
在这里插入图片描述
这里的L就是拉普拉斯金字塔。G就是高斯金字塔,i为下标,pyrup方法是对图片的扩大,这里注意它并不是图像降采样的逆方法,它的扩大过程为填充新的偶数行和列为0,并利用先前的卷积核进行卷积,近似的估计元素,它并不能获取原图,只能获取一个预测图。公式表明,每一层的拉普拉斯金字塔,就高斯金字塔该层图的减去下一层的放大图。求出高斯金字塔列表后,用代码也很容易构建。拉普拉斯金字图大多是如下:
在这里插入图片描述

像这样一个边界图,其实,拉普拉斯金字塔更多时用于图片压缩的。

二. 代码方面

1. 构建高斯金字塔

#利用图像金字塔对图像进行融合
import cv2 as cv
import numpy as np

def load_image():
    src_1=cv.imread('same_1.jpg')
    src_1=cv.resize(src_1,(2048,2048))
    #src_2=cv.imread('same_2.jpg')
    #src_2=cv.resize(src_2,(512,512))
    return src_1#,src_2

#做高斯金字塔
def pyramid(image):
    src=image.copy()
    level=5
    pyramid_reduce=[]
    for i in range(level):
        dst=cv.pyrDown(src)
        cv.imshow('input'+str(i),dst)
        pyramid_reduce.append(dst)
        src=dst.copy()
    cv.waitKey(0)
    cv.destroyAllWindows()
    return pyramid_reduce

pyramid(load_image())
  • 注意传入的图像一定要是正方图,如果不是正方图要记得用numpy的reshape或者cv2的resize将图转化为正方图。

np.reshape():

import numpy as np

a=np.random.rand(1,9)
a=np.reshape(a,(3,3))
print(a)

在这里插入图片描述

cv2.resize():转化图片的尺寸

import cv2 as cv

a=cv.imread('noise.jpg')
print(a.shape)
a=cv.resize(a,(256,256))
print(a.shape)

在这里插入图片描述

  • 在构建金字塔那里需要不断的迭代和保存
  • cv2.copy()方法可以获取一张copy后的图片,并且不对原图片产生影响。

2. 拉普拉斯金字塔

#利用图像金字塔对图像进行融合
import cv2 as cv
import numpy as np

def load_image():
    src_1=cv.imread('con_1.jpg')
    src_1=cv.resize(src_1,(1024,1024))
    #src_2=cv.imread('same_2.jpg')
    #src_2=cv.resize(src_2,(512,512))
    return src_1#,src_2
#做高斯金字塔
def pyramid(image):
    src=image.copy()
    level=4
    pyramid_reduce=[]
    for i in range(level):
        dst=cv.pyrDown(src)
        pyramid_reduce.append(dst)
        src=dst.copy()
    return pyramid_reduce
def lapalian(image):
    #设置拉普拉斯金字塔返回值列表
    lap=[]
    #获取高斯金字塔
    gaussian=pyramid(image)
    #获取长度 用于遍历
    level=len(gaussian)
    #从最低层开始
    for i in range(level-1,-1,-1):
        #升维后 利用公式计算拉普拉斯 利用pyrup
        #为0直接计算原图
        if i == 0:
            extend=cv.pyrUp(gaussian[i],dstsize=image.shape[:2])
            lpls=cv.subtract(image,extend)
            lap.append(lpls)
            cv.imshow('lap'+str(i),lpls)
        else:
            extend=cv.pyrUp(gaussian[i],dstsize=gaussian[i-1].shape[:2])
            lpls=cv.subtract(gaussian[i-1],extend)
            lap.append(lpls)
            cv.imshow('lap'+str(i),lpls)
    #返回列表
    cv.waitKey(0)
    cv.destroyAllWindows()
    return lap


lapalian(load_image())

结果如下图
在这里插入图片描述

  • 注意pyrUp的参数,dstsize一般这个尺寸大小是按照 Size(src.cols* 2, src.rows*2) 来计算的。
  • cv.subtract:之前讲过,对图像做减法。
  • 高斯金字塔构建完毕之后,最小的图像在最高层,但是在列表的最后,因此需要从最后一张图片开始遍历。始终记住公式和关系,代码就很容易构建。

三. 使用实例

1. 必要掌握的知识基础

讲到图像融合,这里需要说明两个方法,在numpy中比较重要。

np.vstack():矩阵在竖直方向进行堆叠
np.hstack():在横向方向进行平铺

import numpy as np
import cv2 as cv

array_1=np.array([[1,2,3],[4,5,6],[7,8,9]])
array_2=np.array([[10,11,12],[13,14,15],[16,17,18]])

print(array_1)
print(array_2)

array_3=np.vstack((array_1,array_2))
print(array_3)

array_4=np.hstack((array_1,array_2))
print(array_4)

结果如下:
在这里插入图片描述

不难想到可以利用这俩个方法对图像进行操作,将图像以某种方式合并。

import numpy as np
import cv2 as cv

img_1=cv.imread('con_1.jpg')
img_1=cv.resize(img_1,(540,540))
img_2=cv.imread('con_2.jpg')
img_2=cv.resize(img_2,(540,540))

img_3=np.vstack((img_1[:img_1.shape[0]//2,:,:],img_2[:img_2.shape[0]//2,:,:]))
img_4=np.hstack((img_1[:,:img_1.shape[1]//2,:],img_2[:,:img_2.shape[1]//2,:]))
cv.imshow('fuse_1',img_3)
cv.imshow('fuse_2',img_4)
cv.waitKey(0)
cv.destroyAllWindows()

结果如下:
在这里插入图片描述

这里我们明显可以看到图像合并之间有一条接线,而利用金字塔进行合并便是牺牲一定信息的情况下,抹除掉这条界限。

2. 使用图像金字塔合并图像

#利用图像金字塔对图像进行融合
import cv2 as cv
import numpy as np

def load_image():
    src_1=cv.imread('same_1.jpg')
    src_1=cv.resize(src_1,(512,512))
    src_2=cv.imread('same_2.jpg')
    src_2=cv.resize(src_2,(512,512))
    return src_1,src_2
#做高斯金字塔
def pyramid(image):
    src=image.copy()
    level=6
    pyramid_reduce=[]
    for i in range(level):
        dst=cv.pyrDown(src)
        pyramid_reduce.append(dst)
        src=dst.copy()
    return pyramid_reduce
def lapalian(image):
    #设置拉普拉斯金字塔返回值列表
    lap=[]
    #获取高斯金字塔
    gaussian=pyramid(image)
    #获取长度 用于遍历
    level=len(gaussian)
    #从最低层开始
    for i in range(level-1,-1,-1):
        #升维后 利用公式计算拉普拉斯 利用pyrup
        #为0直接计算原图
        if i == 0:
            extend=cv.pyrUp(gaussian[i],dstsize=image.shape[:2])
            lpls=cv.subtract(image,extend)
            lap.append(lpls)
        else:
            extend=cv.pyrUp(gaussian[i],dstsize=gaussian[i-1].shape[:2])
            lpls=cv.subtract(gaussian[i-1],extend)
            lap.append(lpls)
    #返回列表
    return lap
def fuse_app(image_1,image_2):
    #构建拉普拉斯金字塔
    lap_1=lapalian(image_1)
    lap_2=lapalian(image_2)
    #存储合并图片的列表
    l_s=[]
    for l_1,l_2 in zip(lap_1,lap_2):
        row,col=l_1.shape[:2]
        l_add=np.hstack((l_1[:,:col//2],l_2[:,:col//2]))
        l_s.append(l_add)
        
    l_t=l_s[0]
    for i in range(1,6):
        l_t=cv.pyrUp(l_t)
        l_t=cv.add(l_t,l_s[i])
    cv.imshow('fuse',l_t)
    cv.waitKey(0)
    cv.destroyAllWindows()
fuse_app(*load_image())

结果如下:
在这里插入图片描述

三. 对之前知识的补充

1. 读取视频文件,做加速或者缓速

import numpy as np
import cv2 as cv

capture=cv.VideoCapture('test.mp4')
while True :
    #利用read方法获取帧数以及布尔值
    ret,frame=capture.read()
    cv.imshow('input',frame)
    c=cv.waitKey(30)
    #27为esc的asc
    if c==27:
        break
cv.destroyAllWindows()
  • 一般情况下25~30为比较舒服的速度,如果将waitKey的参数调制1那么速度就会很快,如果太大就会造成延迟播放的情况。

这里主要是一个同学这块,想起之前没有细说。

猜你喜欢

转载自blog.csdn.net/qq_45804132/article/details/113830565