OpenCV计算机视觉学习(7)——图像金字塔(高斯金字塔,拉普拉斯金字塔)
如果需要处理的原图及代码,请移步小编的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)——图像金字塔(高斯金字塔,拉普拉斯金字塔)的更多相关文章
- OpenCV计算机视觉学习(13)——图像特征点检测(Harris角点检测,sift算法)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 前言 ...
- OpenCV计算机视觉学习(4)——图像平滑处理(均值滤波,高斯滤波,中值滤波,双边滤波)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice &q ...
- OpenCV计算机视觉学习(12)——图像量化处理&图像采样处理(K-Means聚类量化,局部马赛克处理)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 准备 ...
- OpenCV计算机视觉学习(11)——图像空间几何变换(图像缩放,图像旋转,图像翻转,图像平移,仿射变换,镜像变换)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 图像 ...
- OpenCV计算机视觉学习(5)——形态学处理(腐蚀膨胀,开闭运算,礼帽黑帽,边缘检测)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 形态 ...
- OpenCV计算机视觉学习(10)——图像变换(傅里叶变换,高通滤波,低通滤波)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 在数 ...
- OpenCV计算机视觉学习(1)——图像基本操作(图像视频读取,ROI区域截取,常用cv函数解释)
1,计算机眼中的图像 我们打开经典的 Lena图片,看看计算机是如何看待图片的: 我们点击图中的一个小格子,发现计算机会将其分为R,G,B三种通道.每个通道分别由一堆0~256之间的数字组成,那Ope ...
- OpenCV计算机视觉学习(2)——图像算术运算 & 掩膜mask操作(数值计算,图像融合,边界填充)
在OpenCV中我们经常会遇到一个名字:Mask(掩膜).很多函数都使用到它,那么这个Mask到底是什么呢,下面我们从图像基本运算开始,一步一步学习掩膜. 1,图像算术运算 图像的算术运算有很多种,比 ...
- OpenCV计算机视觉学习(3)——图像灰度线性变换与非线性变换(对数变换,伽马变换)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 下面 ...
随机推荐
- 透过 Cucumber 学习 BDD
在需求的开发过程中,最令人困惑的地方就在于需求模糊.需求是解决业务的问题,那么验收的方式应该是由业务方提出,但是往往业务方(可能是产品经理,也可能是直接是客户)只能给出比较模糊的一个验收标准,而程序却 ...
- 安装Linux的CentOS操作系统 - 初学者系列 - 学习者系列文章
Linux系统对于一些熟悉Windows操作系统的用户来说可能比较陌生,但是它也是一种多用户.多任务的操作系统,现在也发展成为了多种版本的操作系统了.如果想对该系统进行学习,请下载这个学习文档:htt ...
- hystrix熔断器之线程池
隔离 Hystrix有两种隔离方式:信号量和线程池. 线程池隔离:对每个command创建一个自己的线程池,执行调用.通过线程池隔离来保证不同调用不会相互干扰和每一个调用的并发限制. 信号量隔热:对每 ...
- Orchard Core创建CMS/Blog站点
安装.NET Core SDK 下载并安装当前最新版本.NET Core SDK 3.1: https://dotnet.microsoft.com/download 安装visual studio ...
- 深入了解Redis(5)-内存回收
了解redis内存回收之前,需要先了解过期键删除策略. 过期键删除策略 1.定时删除 在设置键的过期时间的同时,创建一个timer,在定时器在键的过期时间到达时,立即执行对键的删除操作.内存友好型策略 ...
- dubbo学习(五)注册中心zookeeper
初识zookeeper 下载地址:https://archive.apache.org/dist/zookeeper/ 详细的ZooKeeper教程戳这里~ PS: 建议目前选择3.4的稳定版本进行使 ...
- 搜索引擎学习(二)Lucene创建索引
PS:需要用到的jar包: 代码实现 1.工程结构 2.设置工程依赖的jar包 3.代码实现 /** * Lucene入门 * 创建索引 */ public class CreateIndex { / ...
- makefile实验三 理解make工作的基本原则
代码简单,但测试花样多,若能回答对本博客的每个步骤的预期结果,可以说对makefile的基础掌握是扎实的. 一,当前的makefile代码 root@ubuntu:~/Makefile_Test# r ...
- 开源 C#工作流管理平台
{ font-family: 宋体; panose-1: 2 1 6 0 3 1 1 1 1 1 } @font-face { font-family: "Cambria Math" ...
- Python基本数据类型详细介绍
Python提供的基本数据类型主要有:布尔类型.整型.浮点型.字符串.列表.元组.集合.字典等等 1.空(None)表示该值是一个空对象,空值是Python里一个特殊的值,用None表示.None不能 ...