前文传送门:

「Python 图像处理 OpenCV (1):入门」

「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 )

高斯金字塔是由底部的最大分辨率图像逐次向下采样得到的一系列图像。最下面的图像分辨率最高,越往上图像分辨率越低。

高斯金字塔向下采样:

这个过程实际上就是一个重复高斯平滑并重新对图像采样的过程。

  1. 对于原始图像先进行一次高斯平滑处理,使用高斯核(5 * 5)进行一次卷积处理。下面是 5 * 5 的高斯核。

\[K = \frac{1}{125}
\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. 接下来是对图像进行采样,这一步会去除图像中的偶数行和奇数列,从而得到一张图像。
  2. 再然后是重复上面两步,直到得到最终的目标图像为止。

从上面的步骤可以看出,再每次循环中,得到的结果图像只有原图像的 1/4 大小(横纵向均做隔行采样)。

注意:向下采样会逐渐丢失图像信息,属于非线性的处理,此过程不可逆,属于有损处理。

高斯金字塔向上采样:

  1. 将图像在每个方向扩大为原来的两倍,新增的行和列以 0 填充。
  2. 使用高斯核(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 的差异信息。

下面这个公式是差异的记录过程:

\[L_i = G_i - Up(Down(G_i))
\]

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):图像金字塔的更多相关文章

  1. 跟我学Python图像处理丨关于图像金字塔的图像向下取样和向上取样

    摘要:本文讲述图像金字塔知识,了解专门用于图像向上采样和向下采样的pyrUp()和pyrDown()函数. 本文分享自华为云社区<[Python图像处理] 二十一.图像金字塔之图像向下取样和向上 ...

  2. Python 图像处理 OpenCV (15):图像轮廓

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  3. Python 图像处理 OpenCV (16):图像直方图

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  4. Python 图像处理 OpenCV (3):图像属性、图像感兴趣 ROI 区域及通道处理

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 图像属性 图像 ...

  5. Python 图像处理 OpenCV (4):图像算数运算以及修改颜色空间

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  6. Python 图像处理 OpenCV (5):图像的几何变换

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  7. Python 图像处理 OpenCV (6):图像的阈值处理

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  8. Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 普通操作 1. 读取像素 读取像素可以通过行坐标和列坐标来进行访问,灰度图像直接返回灰度值,彩色图像则返回B.G.R三个分量. 需 ...

  9. Python 图像处理 OpenCV (7):图像平滑(滤波)处理

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

随机推荐

  1. Shell总结01-shell解释器

    常见Shell解释器种类 就像不同地区有不同方言一样,不同的Linux/Unix系统使用着不同类型的shell,其中sh是UNIX上的最基本的shell,遵循POSIX接口规范 操作系统 默认shel ...

  2. Python中的字段分割

    很多时候我们要完成分词的任务,这篇文章讲的非常非常好.生动形象,原文是https://www.cnblogs.com/douzi2/p/5579651.html,作者是宋桓公.

  3. 跨云厂商部署 k3s 集群

    原文链接:https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/ 最近一两年各大云服务商都出了各种福利活动,很多小伙伴薅了一波又 ...

  4. 【解读】TCP粘包拆包

    一.TCP粘包.拆包图解 假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到字节数是不确定的,故可能存在以下四种情况: 1)服务端分两次读取到了两个独立的数据包,分别是D1和D2, ...

  5. linux shell编程子bash变量

    参考视频:https://www.imooc.com/u/279399/courses?sort=publish https://www.imooc.com/video/6516 慕课网 用户的自定义 ...

  6. python3 闭包函数 装饰器

    闭包函数 1.闭:定义在函数内部的函数 2.包:内部函数引用了外部函数作用域的名字 在函数编程中经常用到闭包.闭包是什么,它是怎么产生的及用来解决什么问题呢.给出字面的定义先:闭包是由函数及其相关的引 ...

  7. Python 简明教程 --- 15,Python 函数

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 测试只能证明程序有错误,而不能证明程序没有错误. -- Edsger Dijkstra 目录 本节我 ...

  8. keras训练实例-python实现

    用keras训练模型并实时显示loss/acc曲线,(重要的事情说三遍:实时!实时!实时!)实时导出loss/acc数值(导出的方法就是实时把loss/acc等写到一个文本文件中,其他模块如前端调用时 ...

  9. return ,continue,break的用法与区别总结

    1.return 语句的作用 (1) return 从当前的方法中退出,返回到该调用的方法的语句处,继续执行.       (2) return 返回一个值给调用该方法的语句,返回值的数据类型必须与方 ...

  10. LeetCode59. 螺旋矩阵 II

    这题和第54题类似,都是套一个搜索的模板. 用dx和dy表示方向,方向的顺序是先向右,再向下,再向左,再向上,再向右... 如果"撞墙"了就需要改变到下一个方向."撞墙& ...