如果需要处理的原图及代码,请移步小编的GitHub地址

  传送门:请点击我

  如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice

  本节学习图像金字塔,图像金字塔包括高斯金字塔和拉普拉斯金字塔。它是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。简单来说,图像金字塔就是用来进行图像缩放的

1,图像金字塔

  图像金字塔是指一组图像且不同分辨率的子图集合,它是图像多尺度表达的一种,以多分辨率来解释图像的结构,主要用于图像的分割或压缩。一幅图像的金字塔是一系列以金字塔性质排列的分辨率逐步降低,且来源于同一张原始图的图像集合,如下图所示,它包括了五层图像,将这一层一层的图像比喻成金字塔。图像金字塔可以通过梯次向下采样获得,直到达到某个终止条件才停止采样,在向下采样中,层次越高,分辨率越低。

  生成图像金字塔主要包括两种方式——向下取样,向上取样,在上图中,将level0级别的图像转换为 level1,level2,level3,level4,图像分辨率不断降低的过程称为向下取样;将level4级别的图像转换为 level3,level2,level1,leve0,图像分辨率不断增大的过程称为向上取样

1.1  高斯金字塔

  高斯金字塔用于下采样。高斯金字塔是最基本的图像塔。原理:首先将原图像作为最底层图像 level0(高斯金字塔的第0层),利用高斯核(5*5)对其进行卷积,然后对卷积后的图像进行下采样(去除偶数行和列)得到上一层图像G1,将此图像作为输入,重复卷积和下采样操作得到更上一层的图像,反复迭代多次,形成一个金字塔形的图像数据结构,即高斯金字塔。

  高斯金字塔是通过高斯平滑和亚采样获取一些列下采样图像,也就是说第K层高斯金字塔通过平滑,亚采样就可以获得K+1 层高斯图像,高斯金字塔包含了一系列低通滤波器,其截止频率从上一层到下一层是以因子 2 逐渐增加,所以高斯金字塔可以跨越很大的频率范围。

1.2 拉普拉斯金字塔

  拉普拉斯金字塔用于重建图形,也就是预测残差,对图像进行最大程度的还原。比如一幅小图像重建为一幅大图。原理:用高斯金字塔的每一层图像减去其上一层图像上采样并高斯卷积之后的预测图像,得到一系列的差值图像,即为Laplacian分解图像。

  拉普拉斯图像的形成过程大致为对原图像进行低通滤波和降采样得到一个粗尺度的近似图像,即分解得到的低通近似图像,把这个近似图像经过插值,滤波,再计算它和原图像的插值,就得到分解的带通分量。下一级分解是在得到的低通近似图像上进行,迭代完成多尺度分解。可以看出拉普拉斯金字塔的分解过程包括四个步骤:

  • 1,低通滤波
  • 2,降采样(缩小尺寸)
  • 3,内插(放大尺寸)
  • 4,带通滤波(图像相减)

  拉普拉斯图像突出图像中的高频分量,注意的是拉普拉斯的最后一层是低通滤波图像,不是带通滤波图像。

  我们对图像进行缩放可以用图像金字塔,也可以使用resize函数进行缩放,后者效果更好(我们后面补充resize图像缩放)。这里只是对图像金字塔做一些简单了解

  下面分别学习图像向下取样和向上取样(下采样就是图片缩小,上采样就是图片放大)。

2,图像向下取样

2.1 高斯金字塔——向下采样(缩小)

  在图像向下取样中,使用最多的是高斯金字塔。它将堆图像Gi进行高斯核卷积,并删除原图中所有的偶数行和列,最终缩小图像。其中,高斯核卷积运算就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值(券种不同)经过加权平均后得到。常见的 3*3 和 5*5 高斯核如下:

  高斯核卷积让临近中心的像素点具有更高的重要度,对周围像素计算加权平均值,如下图所示,其中心位置权重最高为 0.4。

  显而易见,原始图像 Gi 具有 M*N 个像素,进行向下采样之后,所得到的图像 Gi+1 具有 M/2 * N/2 个像素,只有原图的四分之一。通过对输入的原始图像不停迭代以上步骤就会得到整个金字塔。注意,由于每次向下取样会删除偶数行和列,所以它会不停地丢失图像的信息。

  在OpenCV中,向下取样使用的函数为 pyrDown() ,其函数原型如下:

dst = pyrDown(src[, dst[, dstsize[, borderType]]])

  cv2.pyrDown 使用Gaussian金字塔分解对输入图像向下采样。首先它对输入图像用指定滤波器进行卷积,然后通过拒绝偶数的行和列来下采样图像。

  其参数意思如下:

  • src表示输入图像,
  • dst表示输出图像,和输入图像具有一样的尺寸和类型
  • dstsize表示输出图像的大小,默认值为Size(5*5)
  • borderType表示像素外推方法,详见cv::bordertypes

  实现代码如下:

# _*_coding:utf-8 _*_
import cv2
import numpy as np
import matplotlib.pyplot as plt # 读取原始图片
img = cv2.imread('kd2.jpg') # 图像向下取样
r = cv2.pyrDown(img) # # 显示图形
# cv2.imshow('origin image', img)
# cv2.imshow('processing image', r)
# cv2.waitKey(0)
# cv2.destroyAllWindows() # 为了方便将两张图对比,我们使用matplotlib
titles = ['origin', 'pyrDown']
images = [img, r]
for i in np.arange(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()

  我们可以先看OpenCV画的图,然后看两张图放一样大的效果图。

  我们从上图可以看出,向下采样将原始图像压缩成原图的四分之一。

  很明显比起第一张图,第二张图有点模糊了。

  多次向下取样的代码:

# _*_coding:utf-8 _*_
import cv2
import numpy as np
import matplotlib.pyplot as plt # 读取原始图片
img = cv2.imread('kd2.jpg') # 图像向下取样
r1 = cv2.pyrDown(img)
r2 = cv2.pyrDown(r1)
r3 = cv2.pyrDown(r2) # 为了方便将两张图对比,我们使用matplotlib
titles = ['origin', 'pyrDown1', 'pyrDown2', 'pyrDown3']
images = [img, r1, r2, r3]
for i in np.arange(4):
plt.subplot(2, 2, i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()

  结果如图所示:

  虽然我将图像展示的一样大小,但是我们可以很清楚的看到图像向下采样越多,图像越模糊。

3,图像向上取样

3.1  高斯金字塔——向上采样(放大)

  在图像向上取样是由小图像不断放图像的过程,它将图像在每个方向上扩大为原图像的2倍,新增的行和列均使用0来填充,并使用于“向下取样”相同的卷积核乘以4,再与放大后的图像进行卷积运算,以获得“新增像素”的新值,如下所示,它在原始像素45, 123, 89, 149之间各新增了一行和一列值为0的像素。

  在OpenCV中,向上取样使用的函数为 pyrUp(),其原型如下所示:

dst = pyrUp(src[, dst[, dstsize[, borderType]]])

  cv2.PyrUp() 是使用Gaussian金字塔分解对输入图像向上采样。首先通过在图像中插入 0 偶数行和偶数列,然后对得到的图像用指定的滤波器进行高斯卷积。其中滤波器乘以4做插值。所以输出图像是输入图像的2倍大小。

  • src表示输入图像,
  • dst表示输出图像,和输入图像具有一样的尺寸和类型
  • dstsize表示输出图像的大小,默认值为Size()
  • borderType表示像素外推方法,详见cv::bordertypes

  实现代码如下:

# _*_coding:utf-8 _*_
import cv2
import numpy as np
import matplotlib.pyplot as plt # 读取原始图片
img = cv2.imread('kd2.jpg') # 图像向下取样
r1 = cv2.pyrUp(img) # 显示图形
cv2.imshow('origin image', img)
cv2.imshow('processing image1', r1)
cv2.waitKey(0)
cv2.destroyAllWindows()

  由于放大了四倍,图太大,我就这样放了:

  多次向上取样的代码如下:

# _*_coding:utf-8 _*_
import cv2
import numpy as np
import matplotlib.pyplot as plt # 读取原始图片
img = cv2.imread('kd2.jpg') # 图像向下取样
r1 = cv2.pyrUp(img)
r2 = cv2.pyrUp(r1)
r3 = cv2.pyrUp(r2) # 为了方便将两张图对比,我们使用matplotlib
titles = ['origin', 'pyrUp1', 'pyrUp2', 'pyrUp3']
images = [img, r1, r2, r3]
for i in np.arange(4):
plt.subplot(2, 2, i+1), plt.imshow(images[i])
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()

  结果如下:

  每次向上取样均为上次图像的四倍,但图像的清晰度会降低。

4,拉普拉斯金字塔

  图像的拉普拉斯金字塔可以由图像的高斯金字塔得到,没有单独的函数。拉普拉斯金字塔图像是边缘图片,大部分元素是零,它被用在图像压缩上,拉普拉斯金字塔的一级是由那一级的高斯金字塔和它的更高一级高斯金字塔的图像差别来生成的。

  转换的公式为:

  拉普拉斯金字塔的代码实现:

import cv2
import numpy as np img = cv2.imread('kd2.jpg')
down = cv2.pyrDown(img)
down_up = cv2.pyrUp(down) l_1 = img - down_up
cv2.imshow('laplacian', l_1)
cv2.waitKey(0)
cv2.destroyAllWindows()

  效果图如下:

  拉普拉斯金字塔的图像看起来就像是边界图。经常被用在图像压缩中。

5,总结上采样和下采样

  上面对两种采样做了代码实现,下面再赘述一次。

  上采样:就是图片放大,使用PryUp函数。上采样的步骤:先将图像在每个方向放大为原来的两倍,新增的行和列用0填充,再使用先前同样的内核与放大后的图像卷积,获得新增像素的近似值。

  下采样:就是图片缩小,使用PyrDown函数。下采样步骤:先将图片进行高斯内核卷积,再将所有偶数列去除。

  注意PryUP() 和 PyrDown() 不是互逆的,即上采样和下采样的不是互为逆操作

  总之,上,下采样都存在一个严重的问题,那就是图像变模糊了,因为缩放的过程中发生了信息丢失的问题。要解决这个问题,就得用拉普拉斯金字塔。

  当然也可以直接使用 cv2里面的resize()函数,resize()函数的效果更好,下面我们学习一下使用resize()函数进行图像缩放。

6, 图像缩放——resize()函数

  cv2.resize()函数是opencv中专门来调整图片的大小,改变图片尺寸。

  注意:CV2是BGR,而我们读取的图片是RGB,所以要注意一下,变换的时候注意对应。

  其函数原型如下:

def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)

  对应的各个参数意思:

  src:输入,原图像,即待改变大小的图像;

  dsize:输出图像的大小。如果这个参数不为0,那么就代表将原图像缩放到这个Size(width,height)指定的大小;如果这个参数为0,那么原图像缩放之后的大小就要通过下面的公式来计算:

              dsize = Size(round(fx*src.cols), round(fy*src.rows))

其中,fx和fy就是下面要说的两个参数,是图像width方向和height方向的缩放比例。

  fx:width方向的缩放比例,如果它是0,那么它就会按照(double)dsize.width/src.cols来计算;

  fy:height方向的缩放比例,如果它是0,那么它就会按照(double)dsize.height/src.rows来计算;

  interpolation:这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:

  • INTER_NEAREST                 - 最邻近插值
  • INTER_LINEAR                     - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
  • INTER_AREA                        -  区域插值(使用像素区域关系进行重采样)    resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
  • INTER_CUBIC                      - 三次样条插值 (超过4x4像素邻域内的双立方插值)
  • INTER_LANCZOS4              -  Lanczos插值(超过8x8像素邻域内的Lanczos插值)

  对于插值方法,正常情况下使用默认的双线性插值法就够了。不过这里还是有建议的:若要缩小图像,一般情形下最好用 CV_INTER_AREA 来插值,而若要放大图像,一般情况下最好用  CV_INTER_CUBIC (效率不高,慢,不推荐使用)或 CV_INTER_LINEAR (效率较高,速度较快,推荐使用)

几种常用方法的效率为:

  最邻近插值>双线性插值>双立方插值>Lanczos插值

  但是效率和效果是反比的,所以根据自己的情况酌情使用。

  注意:输出的尺寸格式为(宽,高)

  示例:

# _*_coding:utf-8_*_
import cv2
import numpy as np image = cv2.imread('cat.jpg')
# 对图片进行灰度化,注意这里变换!!
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) crop_img = cv2.resize(gray, (224, 224), interpolation=cv2.INTER_LANCZOS4)
print(image.shape, gray.shape, crop_img.shape)
# (414, 500, 3) (414, 500) (224, 224) cv2.imshow('result', crop_img)
cv2.waitKey()
cv2.detrosyAllWindows()

  效果如下:

  对图像缩放,做一个完整的示例:

import cv2
import os
import numpy as np
import matplotlib.pyplot as plt img = cv2.imread("cat.jpg")
# resize的插值方法:正常情况下使用默认的双线性插值法
res_img = cv2.resize(img, (200, 100))
res_fx = cv2.resize(img, (0, 0), fx=0.5, fy=1)
res_fy = cv2.resize(img, (0, 0), fx=1, fy=0.5)
print('origin image shape is ',img.shape)
print('resize 200*100 image shape is ',res_img.shape)
print('resize 0.5:1 shape is ',res_fx.shape)
print('resize 1:0.5 image shape is ',res_fy.shape)
'''
origin image shape is (414, 500, 3)
resize 200*100 image shape is (100, 200, 3)
resize 0.5:1 shape is (414, 250, 3)
resize 1:0.5 image shape is (207, 500, 3)
''' # 标题
title = ['Origin Image', 'resize200*100', 'resize_fx/2', 'resize_fy/2']
# 对应的图像
image = [img, res_img, res_fx, res_fy] for i in range(len(image)):
plt.subplot(2, 2, i+1), plt.imshow(image[i])
plt.title(title[i])
plt.xticks([]), plt.yticks([])
plt.show()

  效果图如下:

  

参考文献:https://blog.csdn.net/Eastmount/article/details/89341077

https://www.cnblogs.com/FHC1994/p/9128005.html

https://www.cnblogs.com/zsb517/archive/2012/06/10/2543739.html

OpenCV计算机视觉学习(7)——图像金字塔(高斯金字塔,拉普拉斯金字塔)的更多相关文章

  1. OpenCV计算机视觉学习(13)——图像特征点检测(Harris角点检测,sift算法)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 前言 ...

  2. OpenCV计算机视觉学习(4)——图像平滑处理(均值滤波,高斯滤波,中值滤波,双边滤波)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice &q ...

  3. OpenCV计算机视觉学习(12)——图像量化处理&图像采样处理(K-Means聚类量化,局部马赛克处理)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 准备 ...

  4. OpenCV计算机视觉学习(11)——图像空间几何变换(图像缩放,图像旋转,图像翻转,图像平移,仿射变换,镜像变换)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 图像 ...

  5. OpenCV计算机视觉学习(5)——形态学处理(腐蚀膨胀,开闭运算,礼帽黑帽,边缘检测)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 形态 ...

  6. OpenCV计算机视觉学习(10)——图像变换(傅里叶变换,高通滤波,低通滤波)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 在数 ...

  7. OpenCV计算机视觉学习(1)——图像基本操作(图像视频读取,ROI区域截取,常用cv函数解释)

    1,计算机眼中的图像 我们打开经典的 Lena图片,看看计算机是如何看待图片的: 我们点击图中的一个小格子,发现计算机会将其分为R,G,B三种通道.每个通道分别由一堆0~256之间的数字组成,那Ope ...

  8. OpenCV计算机视觉学习(2)——图像算术运算 & 掩膜mask操作(数值计算,图像融合,边界填充)

    在OpenCV中我们经常会遇到一个名字:Mask(掩膜).很多函数都使用到它,那么这个Mask到底是什么呢,下面我们从图像基本运算开始,一步一步学习掩膜. 1,图像算术运算 图像的算术运算有很多种,比 ...

  9. OpenCV计算机视觉学习(3)——图像灰度线性变换与非线性变换(对数变换,伽马变换)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 下面 ...

随机推荐

  1. Linux实战(13):Ubuntu被远程

    此方法采用的xrdp原生方案,优点兼容性比较好. 安装xrdp sudo apt install xrdp #最高权限安装xrdp 修改配置 nano /etc/xrdp/startwm.sh #使用 ...

  2. spring boot之AOP

    首先,aop是面向对象切面,嗯,就是说不面向静态方法,我做测试demo的时候controller方法有个加了static,尴尬的是就用了那个方法测,检查了几遍配置... 参看这篇文章https://m ...

  3. RXJAVA之变换操作

    RXJAVA提供了以下变换操作,对Observable的消息进行变换操作: 1.window 定期将来自Observable的数据分拆成一些Observable窗口,然后发射这些窗口,而不是每次发射一 ...

  4. 如何设置一个生产级别的高可用etcd集群

    在之前的文章中,我们详细介绍了K3s的架构以及部署场景,给尚未了解K3s的朋友提供了一个很好的入门方向.那么,在本文中我们将探索如何配置一个3节点的etcd集群,它将会被用于高可用.多节点的K3s集群 ...

  5. Burp Suite的安装

    安装均在虚拟机环境下进行. 1.首先在浏览器找到java进行最新版本的安装. 2.然后找到burp suite 的安装包下载 不知道这一次 怎么直接跳过安装打开了.

  6. 浅谈 Java线程状态转换及控制

    线程的状态(系统层面) 一个线程被创建后就进入了线程的生命周期.在线程的生命周期中,共包括新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead)这五 ...

  7. Spring AOP系列(三) — 动态代理之JDK动态代理

    JDK动态代理 JDK动态代理核心是两个类:InvocationHandler和Proxy 举个栗子 为便于理解,首先看一个例子: 希望实现这样一个功能:使用UserService时,只需关注自己的核 ...

  8. log4net 纯代码配置

    当需要输出的日志很多的时候,每次修改config都很麻烦,于是想可不可以动态生成. 网上找的案例都是获取单个appender/logger的,此处例子是任意logger,appender相同 log4 ...

  9. 点、像素、分辨率、PPI、DPI等

    屏幕尺寸 屏幕尺寸是屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米. pixel 像素,它是组成图片的最小单元,代表红绿蓝等各种颜色. dot 点,它是屏幕发光.cmos感光的最小物理单元,水平 ...

  10. spring-boot-route(八)整合mybatis操作数据库

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML ...