图像金字塔与图像多分辨率的原理和opencv实现

  • 1图像多分辨率及其实现
  • 例子
  • 2图像金字塔及其实现
  • 2.1原理
  • 2.2opencv中实现
  • 2.3代码


1图像多分辨率及其实现

图像的多分辨率表示同一图像采用不同的采样方式,也可以通过一幅图像进行缩放得到不同分辨率的图像。比如姨夫500500的像素要缩小为250250,怎么办呢?

你可能想到的办法是直接在原图像上间隔采样,但这样会丢失很多原有图像的信息。再比如你想要将500500的图像放大一倍,变成10001000像素的,那你又怎么办呢?

图像处理中常用的处理图像缩放的方法就是插值。主要包括最近邻插值、双线性插值、双三次插值等,其中双三次插值是Photoshop等商业软件的标准内插方法。

双线性插值的公式如下:

openCV 实现图像信噪比_插值


我们用四个最近邻的位置(上下左右)去估计该点的像素值,充分利用了原图像的信息,并保证了图像的平滑。为了获得更好的平滑效果,你可以采用双三次内插,公式如下,它们的原理相同,只是采用的近邻数目不同。

openCV 实现图像信噪比_图像金字塔_02


讲了图像缩放的原理,下面说一下图像缩放在opencv中的实现,函数原型如下:

cv2.resize(src, dsize, dst, fx, fy, interpolation)

参数

描述

src

【必需】原图像

dsize

【必需】输出图像大小

fx

【可选】沿水平方向的比例因子

fy

【可选】沿竖直方向的比例因子

interpolation

【可选】图像插值方式

上面讲述的三种插值方式的参数如下:

最近邻插值

cv.INTER_NEAREST

双线性插值

cv.INTER_LINEAR

双三次插值

cv.INTER_CUBIC

例子

import cv2
img1=cv2.imread('flower.png')
cv2.imshow('flower_show',img1)

scale_percent = 50       # percent of original size
width = int(img1.shape[1] * scale_percent / 100)
height = int(img1.shape[0] * scale_percent / 100)
dim = (width, height)

img2=cv2.resize(img1,dim,interpolation =cv2.INTER_AREA)
cv2.imshow('flower1_show',img2)
cv2.imwrite('flower1_show.jpg',img2)
cv2.waitKey()
cv2.destroyAllWindows()

原图像

openCV 实现图像信噪比_图像金字塔_03

缩小一半图像(三次插值)

openCV 实现图像信噪比_图像金字塔_04

直觉上看,两幅图的效果没有差别。但如果你仔细观察的话,第二幅图的细节更加模糊了。

2图像金字塔及其实现

2.1原理

图像金字塔和第一节的图像多分辨率很相似,但存在一些差别。图像金字塔主要是想从不同的维度来对原图像进行表达,从而获得不同尺度下的细节。比如一幅512512的图像,可以降采样得到256256的图像,再降采样得到128*128的图像,继续这个过程可以得到不同级的图像。

图像金字塔的原理如下图所示:

openCV 实现图像信噪比_插值_05

为了保证降采样得到的图像更加逼近原图像,会对原来的图像进行平滑滤波器滤波,不同的滤波方法得到不同的图像金字塔,比如采用高斯低通滤波得到高斯金字塔。

为了将图像金字塔还原为原图像,一般会在降采样得到图像金字塔的过程中维护一个残差金字塔,也称拉普拉斯金字塔,具体的流程如上图所示。对降采样得到的图像进行上采样(伴随着插值滤波)得到和原图像分辨率相同的图像,然后和原图像作差得到残差图像。

2.2opencv中实现

opencv中提供了两个函数pyrUppyrDown用于实现高斯金字塔和拉普拉斯金字塔。

pyrUp函数完成了高斯低通滤波和降采样两个操作,可以方便地得到高斯金字塔。

pyrDown函数完成了上采样和插值滤波两个操作,可以结合高斯金字塔得到拉普拉斯金字塔。

2.3代码

import cv2 as cv
 
#高斯金字塔
def pyramid_image(image):
    cv.imshow("timg1.jpg",image)
    level = 2#金字塔的层数
    temp = image.copy()#拷贝图像
    pyramid_images = []
    for i in range(level):
        dst = cv.pyrDown(temp)
        pyramid_images.append(dst)
        cv.imshow("pyramid"+str(i), dst)
        temp = dst.copy()
    return pyramid_images
 
#拉普拉斯金字塔
def lpls_image(image):
    pyramid_images = pyramid_image(image)
    level = len(pyramid_images)
    for i in range(level-1, -1, -1):#数组下标从0开始 i从金字塔层数-1开始减减
        if (i-1)<0:#原图
            expand = cv.pyrUp(pyramid_images[i])
            lpls = cv.subtract(image, expand)
            cv.imshow("lpls_%s" % i, lpls)
        else:
            expand = cv.pyrUp(pyramid_images[i])
            lpls = cv.subtract(pyramid_images[i-1], expand)
            cv.imshow("lpls_%s" % i, lpls)
 
 
img = cv.imread("timg.jpg")
lpls_image(img)
cv.waitKey(0)
cv.destroyAllWindows()

高斯金字塔

openCV 实现图像信噪比_插值_06


openCV 实现图像信噪比_插值_07

拉普拉斯金字塔

openCV 实现图像信噪比_高斯金字塔_08

openCV 实现图像信噪比_图像金字塔_09