Python 图像处理 OpenCV (14):图像金字塔
前文传送门:
「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」
「Python 图像处理 OpenCV (3):图像属性、图像感兴趣 ROI 区域及通道处理」
「Python 图像处理 OpenCV (4):图像算数运算以及修改颜色空间」
「Python 图像处理 OpenCV (5):图像的几何变换」
「Python 图像处理 OpenCV (6):图像的阈值处理」
「Python 图像处理 OpenCV (7):图像平滑(滤波)处理」
「Python 图像处理 OpenCV (8):图像腐蚀与图像膨胀」
「Python 图像处理 OpenCV (9):图像处理形态学开运算、闭运算以及梯度运算」
「Python 图像处理 OpenCV (10):图像处理形态学之顶帽运算与黑帽运算」
「Python 图像处理 OpenCV (11):Canny 算子边缘检测技术」
「Python 图像处理 OpenCV (12): Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子边缘检测技术」
「Python 图像处理 OpenCV (13): Scharr 算子和 LOG 算子边缘检测技术」
引言
前面的文章中,我们有用过图像方法或者缩小的函数 resize()
,这个函数既可以放大图像,也可以缩小图像,其中:
- 缩小图像:一版使用
CV_INETR_AREA
(区域插值)来插值。 - 放大图像,一般使用
CV_INTER_LINEAR
(线性插值)来插值。
图像缩放除了可以使用函数 resize()
,还有另外的一种方式 —— 「图像金字塔」。
图像金字塔是什么?
在说清楚什么事图像金字塔之前,要先介绍另一个概念:「尺度」。
尺度:先从字面意思来看说的就是尺寸和分辨率。
我们在进行图像处理的时候,会经常对源图像的尺寸进行放大或者缩小的变换,进而转换为我们需要的尺寸的目标图像。
对图像进行放大和缩小的变换的这个过程,称为尺度调整。
而图像金字塔则是图像多尺度调整表达的一种重要的方式。
图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。
图像金字塔方法的总体思想主要是是:将参加融合的的每幅图像分解为多尺度的金字塔图像序列,将低分辨率的图像在上层,高分辨率的图像在下层,上层图像的大小为前一层图像大小的 1/4 。层数为 0 , 1 , 2 …… N 。将所有图像的金字塔在相应层上以一定的规则融合,就可得到合成金字塔,再将该合成金字塔按照金字塔生成的逆过程进行重构,得到融合金字塔。
实现方式
通常而言,我们一般讨论两种图像金字塔:「高斯金字塔( Gaussian pyramid )」 和 「拉普拉斯金字塔( Laplacian pyramid )」 。
高斯金字塔( Gaussian pyramid )
高斯金字塔是由底部的最大分辨率图像逐次向下采样得到的一系列图像。最下面的图像分辨率最高,越往上图像分辨率越低。
高斯金字塔向下采样:
这个过程实际上就是一个重复高斯平滑并重新对图像采样的过程。
- 对于原始图像先进行一次高斯平滑处理,使用高斯核(
5 * 5
)进行一次卷积处理。下面是5 * 5
的高斯核。
\left[
\begin{matrix}
1 & 4 & 6 & 4 & 1\\
4 & 16 & 24 & 16 & 4\\
6 & 24 & 36 & 24 & 6\\
4 & 16 & 24 & 16 & 4\\
1 & 4 & 6 & 4 & 1\\
\end{matrix}
\right]
\]
- 接下来是对图像进行采样,这一步会去除图像中的偶数行和奇数列,从而得到一张图像。
- 再然后是重复上面两步,直到得到最终的目标图像为止。
从上面的步骤可以看出,再每次循环中,得到的结果图像只有原图像的 1/4 大小(横纵向均做隔行采样)。
注意:向下采样会逐渐丢失图像信息,属于非线性的处理,此过程不可逆,属于有损处理。
高斯金字塔向上采样:
- 将图像在每个方向扩大为原来的两倍,新增的行和列以 0 填充。
- 使用高斯核(
5 * 5
)对得到的图像进行一次高斯平滑处理,获得 「新增像素」的近似值。
注意:此过程与向下采样的过程一样,属于非线性处理,无法逆转,属于有损处理。
此过程得到的图像为放大后的图像,与原图相比会比较模糊,因为在缩放的过程中丢失了一些图像信息,如果想在缩小和放大整个过程中减少信息的丢失。
如果在缩放过程中想要减少图像信息的丢失,这就引出了第二个图像金字塔 —— 「拉普拉斯金字塔」 。
拉普拉斯金字塔( Laplacian pyramid )
拉普拉斯金字塔可以认为是残差金字塔,用来存储下采样后图片与原始图片的差异。
上面我们介绍了基于高斯金字塔,一个原始图像 Gi
,先进行向下采样得到 G(i-1)
,再对 G(i-1)
进行向上采样得到 Up(Down(Gi))
,最终得到的 Up(Down(Gi))
与原始的 Gi
是存在差异的。
这是因为向下采样丢失的信息并不能由向上采样来进行恢复,高斯金字塔是一种有损的采样方式。
如果我们想要完全恢复原始图像,那么我们在进行采样的时候就需要保留差异信息。
这就是拉普拉斯金字塔的核心思想,每次向下采样后,将再次向上采样,得到向上采样的 Up(Down(Gi))
后,记录 Up(Down(Gi))
与 Gi
的差异信息。
下面这个公式是差异的记录过程:
\]
OpenCV 函数
OpenCV 为向上采样和向下采样提供了两个函数: pyrDown()
和 pyrUp()
。
pyrDown()
的原函数如下:
def pyrDown(src, dst=None, dstsize=None, borderType=None)
- src: 表示输入图像。
- dst: 表示输出图像,它与src类型、大小相同。
- dstsize: 表示降采样之后的目标图像的大小。
- borderType: 表示表示图像边界的处理方式。
注意:dstsize 参数是有默认值的,调用函数的时候不指定第三个参数,那么这个值是按照 Size((src.cols+1)/2, (src.rows+1)/2) 计算的。而且不管如何指定这个参数,一定必须保证满足以下关系式:|dstsize.width * 2 - src.cols| ≤ 2; |dstsize.height * 2 - src.rows| ≤ 2。也就是说降采样的意思其实是把图像的尺寸缩减一半,行和列同时缩减一半。
pyrUp()
的原函数如下:
def pyrUp(src, dst=None, dstsize=None, borderType=None)
- src: 表示输入图像。
- dst: 表示输出图像,它与src类型、大小相同。
- dstsize: 表示降采样之后的目标图像的大小。
- borderType: 表示表示图像边界的处理方式。
参数释义和上面的 pyrDown()
保持一致。
下面是高斯金字塔和拉普拉斯金字塔的代码示例:
import cv2 as cv
#高斯金字塔
def gaussian_pyramid(image):
level = 3 #设置金字塔的层数为3
temp = image.copy() #拷贝图像
gaussian_images = [] #建立一个空列表
for i in range(level):
dst = cv.pyrDown(temp) #先对图像进行高斯平滑,然后再进行降采样(将图像尺寸行和列方向缩减一半)
gaussian_images.append(dst) #在列表末尾添加新的对象
cv.imshow("gaussian"+str(i), dst)
temp = dst.copy()
return gaussian_images
#拉普拉斯金字塔
def laplacian_pyramid(image):
gaussian_images = gaussian_pyramid(image) #做拉普拉斯金字塔必须用到高斯金字塔的结果
level = len(gaussian_images)
for i in range(level-1, -1, -1):
if (i-1) < 0:
expand = cv.pyrUp(gaussian_images[i], dstsize = image.shape[:2])
laplacian = cv.subtract(image, expand)
# 展示差值图像
cv.imshow("laplacian_down_"+str(i), laplacian)
else:
expand = cv.pyrUp(gaussian_images[i], dstsize = gaussian_images[i-1].shape[:2])
laplacian = cv.subtract(gaussian_images[i-1], expand)
# 展示差值图像
cv.imshow("laplacian_down_"+str(i), laplacian)
src = cv.imread('maliao.jpg')
print(src.shape)
# 先将图像转化成正方形,否则会报错
input_image = cv.resize(src, (560, 560))
# 设置为 WINDOW_NORMAL 可以任意缩放
cv.namedWindow('input_image', cv.WINDOW_AUTOSIZE)
cv.imshow('input_image', src)
laplacian_pyramid(src)
cv.waitKey(0)
cv.destroyAllWindows()
上面这段程序有一点需要注意,我当前使用 opencv-python
的版本是 4.3.0.36
,理论上在向上采样的过程中,目标大小只需要满足关系 |dstsize.width - src.cols * 2| ≤ (dstsize.width mod 2)
即可。
实际上经过测试,输入图像是必须使用正方形,长方形的图像会直接爆出如下错误:
error: (-215:Assertion failed) std::abs(dsize.width - ssize.width*2) == dsize.width % 2 && std::abs(dsize.height - ssize.height*2) == dsize.height % 2 in function 'cv::pyrUp_'
具体原因并没有想通,希望哪位知道的大佬可以解释下。
参考
https://blog.csdn.net/zhu_hongji/article/details/81536820
https://zhuanlan.zhihu.com/p/80362140
Python 图像处理 OpenCV (14):图像金字塔的更多相关文章
- 跟我学Python图像处理丨关于图像金字塔的图像向下取样和向上取样
摘要:本文讲述图像金字塔知识,了解专门用于图像向上采样和向下采样的pyrUp()和pyrDown()函数. 本文分享自华为云社区<[Python图像处理] 二十一.图像金字塔之图像向下取样和向上 ...
- Python 图像处理 OpenCV (15):图像轮廓
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- Python 图像处理 OpenCV (16):图像直方图
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- Python 图像处理 OpenCV (3):图像属性、图像感兴趣 ROI 区域及通道处理
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 图像属性 图像 ...
- Python 图像处理 OpenCV (4):图像算数运算以及修改颜色空间
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- Python 图像处理 OpenCV (5):图像的几何变换
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- Python 图像处理 OpenCV (6):图像的阈值处理
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像
前文传送门: 「Python 图像处理 OpenCV (1):入门」 普通操作 1. 读取像素 读取像素可以通过行坐标和列坐标来进行访问,灰度图像直接返回灰度值,彩色图像则返回B.G.R三个分量. 需 ...
- Python 图像处理 OpenCV (7):图像平滑(滤波)处理
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
随机推荐
- 使用ssh连接数据库时出现Permission denied, please try again.解决方案
安装ssh(如果已经安装则会覆盖)sudo apt-get install openssh-server找到/etc/ssh/sshd_config这个文件 将permitrootlogin的值设置为 ...
- Windows 10 WSL 2.0安装并运行Docker
在Windows 10 2004版本,微软更新WSL到了2.0,WSL 2.0已经拥有了完整的Linux内核!今天来测试一下,是否可以安装docker! 一.开启WSL 以管理员运行Powershe ...
- SLS编写规范
SLS编写规范 规范要点说明 首先,状态的执行不可回滚,执行完了就是执行完了,并不会中断回滚,其次,状态的执行,可以反复执行,也就是说一个状态文件,可以多次来进行调用. 在编写状态文件过程中,有以下几 ...
- js Date format(日期格式化:yyyy-MM-dd HH:mm:ss.S)
今天在做日期显示的时候,那个显示格式困扰了很久,各种组件都尝试了,总是不如意,最后自己网上找了一个,然后稍微修改一下,感觉这个Util挺常用的,这里mark一下 Date.prototype.form ...
- 搜索引擎ElasticSearch入门
前言 最近项目上需要用到搜索引擎,由于之前自己没有了解过,所以整理了一下搜索引擎的相关概念知识. 正文 想查数据就免不了搜索,搜索就离不开搜索引擎,百度.谷歌都是一个非常庞大复杂的搜索引擎,他们几乎索 ...
- php artisan migrate数据迁移报错
laravel 5.4 改变了默认的数据库字符集,现在utf8mb4包括存储emojis支持.如果你运行MySQL v5.7.7或者更高版本,则不需要做任何事情. 当你试着在一些MariaDB或者一些 ...
- 2020/6/11 JavaScript高级程序设计 DOM
DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序接口).他描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分. 10.1 节点层次 DOM将任何HTML和XML ...
- dart快速入门教程 (1)
1.环境搭建 1.1.dart简介 Dart 是一种 易于学习. 易于扩展.并且可以部署到 任何地方 的 应用 编程 语言.Google 使用 Dart 来开发 大型应用.flutter使用dart语 ...
- mfc 中unicode 字符和字符串的使用
在MFC或SDK程序中,不需要进行任何关于unicode的设置,记住下面两个宏,保你程序一路畅通: 用TCHAR/TCHAR*代替char/char* 及wchar/wchar*用TEXT(" ...
- 关于 charset 的几种编码方式
经常遇到charset=gb2312.charset=iso-8859-1.charset=utf-8这几种编码方式,它们有什么不同,看下面的图 编码方式 含义 charset=iso-8859-1 ...