【OpenCV 学习笔记】第十一章: 图像金字塔

article/2025/10/22 4:52:43

第十一章: 图像金字塔

一、什么是图像金字塔¶

同一张图片不同分辨率的子图的集合。

 

图像金字塔底部是待处理的高分辨率图像,也就是原始图像,顶部是低分辨率的近似图像。一般情况下,都是每向上移动一级,图像的宽和高都降低为原来的1/2 。

二、为什么要生成图像金字塔,图像金字塔能干啥?

  • 1、我们可以提取更'有用'的特征。如果一张图片是1024x1024大小的,那么它就有100万多个像素点,如果我们把图片的原始数据喂入神经网络模型,光输入的神经元数量都要100多万个,计算资源会迅速崩掉。图像金字塔是对图像尺寸进行的处理,这样有利于我们提取最'有用'的特征,或者说进行降维操作。
  • 2、可以避免模型过拟合。在某些图像处理的算法中,图像金字塔这种的多分辨率运算可以避免陷入局部点,增强模型鲁棒性。
  • 3、图像金字塔底层是清晰的原始图像,越往上图像越模糊,因此我们可以通俗的理解:在底层可以看清楚更多的图像细节,在高层只可以看到轮廓。所以,在目标检测领域,图像中的物体通常很可能是远近不一,大小不一的,此时我们就可以利用金字塔来检测不同尺度下的物体。这种方法要比使用不同大小的sliding window在原图上做检测节省太多的算力!并且效果也要好很多!
  • 4、对一张图像构建不同的尺度空间,这种操作在目标检测中非常有用,比如最简单的Viola的人脸检测器就是用的这个技术。
  • 5、图像金字塔从另外一个角度理解就是:它将原图像分别分解到不同的空间频带上,所以可以用在多分辨率融合算法中,融合过程是在各空间频率层上分别进行的,这样就可以针对不同分解层的不同频带上的特征与细节,采用不同的融合算子以达到突出特定频带上特征与细节的目的。也就是有可能将来自不同图像的特征与细节融合在一起。
  • 6、图像金字塔用的最多的就是用在SIFT算法中,在SIFT提取的时候,因为template上的局部特征跟目标图像上的实际特征可能存在尺度上的差异,使用尺度空间是为了达到尺度不变性
  • 7、在ORB的改进算法中也可以运用图像金字塔解决尺度不变换特性。
  • 8、SURF算法中也用到了图像金字塔的思想。

    小结:要找原因,原因很多,也说明图像金字塔应用很广泛,是一个基础理论和技术。其实在计算机视觉里,很多看似直观且简单的东西往往有层出不穷用法,除了本章的金字塔,还有比如直方图,比如二值化,比如卷积,比如积分图,比如距离变换……等等。虽然都不是什么高级的难以理解的东西,但一旦用到巧处,就非常耐人寻味!

三、理论基础:下采样、上采样、滤波器

  • 下采样:自下而上生成一个图像金字塔,最下面一般就是原图,依次往上的图片尺寸减半。
  • 上采样:自上而下生成一个图像金字塔,最上面一般是一个尺寸较小的特征图,依次往下的图片尺寸变为原来的二倍。

如果我们通过下采样生成一个金字塔,最简单的做法就是:不断地删除图像的偶数行和偶数列,重复这个过程,就得到一个金字塔。
如果我们通过上采样生成一个金字塔,最简单的就是:在每列像素点的右边插入值为0的列,在每行像素点下面插入值为0的行,不断重复,就生成一个金字塔了。
小结:
1、下采样是图像不断变小的过程,上采样是图像不断变大的过程。
2、一个图像下采样一次,在执行一次上采样,虽然尺寸恢复到原图像的尺寸,但像素值已经改变!!!也就是这两种操作是不可逆的。

  • 滤波器
    为什么要用滤波器?
    我们下采样生成金字塔图像时,是直接删除偶数行偶数列的操作,但这种操作意味着直接丢弃图像中的信息!为了减轻图像信息的丢失,我们在下采样操作之前先用滤波器对原始图像滤波操作一遍,这样滤波后的图像就是原始图像的近似图像,此时我们在删偶数行偶数列,就没有直接的信息损失了。而对原始图像进行滤波操作有很多方法,比如我们可以用邻域滤波器进行操作,这样生成的图像就是平均金字塔。如果我们用高斯滤波器处理,我们就生成的是高斯金字塔 。
    同理,当我们上采样生成图像金字塔时,我们直接右插入列下插入行操作,这种操作会生成大量的0值像素点,这些0值像素点毫无意义,我们就需要对0值像素点进行赋值。而赋值就是插值处理。插值处理也有很多方法,比如用区域均值补充,那生成的就是平均金字塔,如果用高斯核填充就是高斯金字塔

四、上下采样API:

下采样:cv2.pyrDown(img [, dstsize, borderType])
上采样:cv2.pyrUp(img [, dstsize, borderType])
默认的尺寸都是一半一半的减小,或者一倍一倍的增加。
默认的滤波器都是高斯滤波器。

五、高斯金字塔

 

#例11.1 对lena进行下采样
import cv2
import numpy as np
import matplotlib.pyplot as pltlena0 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0)
lena1 = cv2.pyrDown(lena0)
lena2 = cv2.pyrDown(lena1)
lena3 = cv2.pyrDown(lena2)
lena4 = cv2.pyrDown(lena3)Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(33,33)
axes1=Fig.add_subplot(Grid[:17,:17]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[:9,17:25]), plt.imshow(lena1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:5,25:29]), plt.imshow(lena2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[:3,29:31]), plt.imshow(lena3, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes5=Fig.add_subplot(Grid[:1,31:32]), plt.imshow(lena4, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()

 

#例11.2 对lena进行上采样
import cv2
import numpy as np
import matplotlib.pyplot as pltlena0 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0)   #512
lena1 = cv2.pyrUp(lena0)  #1024
lena2 = cv2.pyrUp(lena1)  #2048
lena3 = cv2.pyrUp(lena2)  #4096Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(16,16)
axes1=Fig.add_subplot(Grid[0,0]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[0:3,1:3]), plt.imshow(lena1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[0:5,3:7]), plt.imshow(lena2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[0:9,7:15]), plt.imshow(lena3, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()

 

#例11.3 对lena先下采样再上采样,看结果图核原始图的差异,然后再lena先上采样再下采样,看结果图和原始图的差异
import cv2
import numpy as np
import matplotlib.pyplot as pltlena0 = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0)   #512
lena1 = cv2.pyrDown(lena0)  #216
lena2 = cv2.pyrUp(lena1)  #512
diff1 = lena2-lena0lena11 = cv2.pyrUp(lena0)  #1024
lena22 = cv2.pyrDown(lena11)  #512
diff2 = lena22-lena0Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(6,10)
axes1=Fig.add_subplot(Grid[:2,:2]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[0,2]), plt.imshow(lena1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:2,3:5]), plt.imshow(lena2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[:2,5:7]), plt.imshow(diff1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes21=Fig.add_subplot(Grid[2:4,:2]), plt.imshow(lena0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes22=Fig.add_subplot(Grid[2:6,2:6]), plt.imshow(lena11, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes23=Fig.add_subplot(Grid[2:4,6:8]), plt.imshow(lena22, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes24=Fig.add_subplot(Grid[2:4,8:10]), plt.imshow(diff2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()

 

六、拉普拉斯金字塔

拉普拉斯金字塔是在高斯金字塔的基础上生成的。
为啥要发明拉普拉斯金字塔?还是因为高斯金字塔,虽然它用高斯核过滤了一遍,但或多或少还是有信息丢失,而这些丢失的信息就是拉普拉斯金字塔 。所以拉普拉斯金字塔的作用就在于能够恢复图像的细节,就是我们从高层的尺寸小的特征图中提取特征后,我们还能通过拉普拉斯金字塔数据找回高层像素点对应的底层清晰度更高的图像,就是返回来找到更多图像的细节。
Li = Gi - PyrUp( PyrDown(Gi) )
其中,Gi:原始图像 ; Li:拉普拉斯金字塔图像

 

#例11.4 对lena图片构造拉普拉斯金字塔
import cv2
import numpy as np
import matplotlib.pyplot as pltlena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0)   #512G0 = lena
G1 = cv2.pyrDown(G0)
G2 = cv2.pyrDown(G1)
G3 = cv2.pyrDown(G2)
L0 = G0 - cv2.pyrUp(G1)
L1 = G1 - cv2.pyrUp(G2)
L2 = G2 - cv2.pyrUp(G3)Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(33,33)
axes1=Fig.add_subplot(Grid[:17,:17]), plt.imshow(G0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[:9,17:25]), plt.imshow(G1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:5,25:29]), plt.imshow(G2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes4=Fig.add_subplot(Grid[:3,29:31]), plt.imshow(G3, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])Fig=plt.figure(figsize=(16,10))
Grid=plt.GridSpec(33,33)
axes1=Fig.add_subplot(Grid[:17,:17]), plt.imshow(L0, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes2=Fig.add_subplot(Grid[:9,17:25]), plt.imshow(L1, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
axes3=Fig.add_subplot(Grid[:5,25:29]), plt.imshow(L2, cmap='gray'), plt.box(), plt.xticks([]), plt.yticks([])
plt.show()

 

#例11.5 使用拉普拉斯金字塔和高斯金字塔恢复原始图像
import cv2
import numpy as np
import matplotlib.pyplot as pltlena = cv2.imread(r'C:\Users\25584\Desktop\lena.bmp', 0)   #512
#生成高斯金字塔
G0 = lena
G1 = cv2.pyrDown(G0)
G2 = cv2.pyrDown(G1)
G3 = cv2.pyrDown(G2)
#生成拉普拉斯金字塔
L0 = G0 - cv2.pyrUp(G1)
L1 = G1 - cv2.pyrUp(G2)
L2 = G2 - cv2.pyrUp(G3)
#恢复原始图像
G0_1 = L0 + cv2.pyrUp(G1)
G1_1 = L1 + cv2.pyrUp(G2)
G2_1 = L2 + cv2.pyrUp(G3)
#确认每层是否真的复原
f0 = G0_1 - G0
f1 = G1_1 - G1
f2 = G2_1 - G2
print(np.sum(abs(f0)))
print(np.sum(abs(f1)))
print(np.sum(abs(f2)))
0
0
0

http://chatgpt.dhexx.cn/article/Kb6OEfQ7.shtml

相关文章

openCV——图像金字塔

图像金字塔 理论基础 通常情况下,图像金字塔的底部是待处理的高分辨率图像(原始图像),而顶部则为其低 分辨率的近似图像。向金字塔的顶部移动时,图像的尺寸和分辨率都不断地降低。通常情况下, 每向上移动一…

第11章:图像金字塔

第11章:图像金字塔 一、理论基础:1. 向下采样:2. 向上采样: 二、pyrDown函数使用:三、pyrUp函数及使用:四、采样可逆性研究五、拉普拉斯金字塔1. 定义:2. 应用: 什么是图像金子塔&am…

C语言for语句简单打印心形。

C语言简单for语句打印心形 #include<stdio.h> int main() {int i;int j;int k;int n;int m;printf("\n\n\n\n\n\n\n\n表白朋友圈:\n\n\n\n");for (i 1; i < 3; i){if (i 1){printf(" ");printf(&quo…

C语言暴力解法:围圈报数(解析与思考)

围圈报数 题目 解题步骤 一.整体逻辑 1.从第&#xff11;个人开始报数&#xff0c; 2.数到第&#xff4d;个人出列&#xff0c; 3.然后从出列的下一个人开始报数&#xff0c; 4.数到第&#xff4d;个人又出列&#xff0c;…&#xff0c;如此反复到所有的人全部出列为止。 二…

html 一个圆圈一个c,如何用c语言程序画一个圆?

以一个空心圆来举例。 /* 判断是是否在圆上 */ int isAtCircle(int x, int y, int r) { /* 将(x, y)转换为相当圆心(r, r)的坐标 */ int rx x - r; int ry y - r; double d sqrt(rx*rx ry*ry) - r; /*计算到圆心的距离*/ if(fabs(d) < 0.5)""> return 1; e…

在HTML 页面中如何显示带圈圈的数字

数字外面有个圈圈&#xff0c; 或者圈圈里有反底色显示&#xff0c;效果类似&#xff1a; 带圈圈的数字示例&#xff1a; ① 反色圈圈数字示例&#xff1a; ❶ 要实现上面的效果&#xff0c;使用以下技术都可以达成&#xff1a; 方式1&#xff0c;. 使用图片 <image&…

C语言打印出心形表白,初学C语言也能看懂~(3)

例2&#xff1a;C语言实现打印出心形&#xff0c;初学者的表白神器。 解题思路&#xff1a;这道例题可以分成4部分&#xff0c;前3行一部分&#xff0c;4-6行一部分&#xff0c;7-13行一部分&#xff0c;最后一行一部分&#xff0c;读者请仔细阅读注释&#xff0c;小林写的很详…

C语言-报数出圈问题(链表实现)

问题描述&#xff1a;n个人围成一圈&#xff0c;顺序编号。从第一个人开始从1到m报数&#xff0c;凡报到m的人退出圈子&#xff0c;编程求解最后留下的人的初始编号。 程序运行示例&#xff1a; 6 3&#xff08;两个输入数据之间有空格&#xff09; 1输入格式&#xff1a;scanf…

蓝桥杯 小朋友崇拜圈 C语言

标题&#xff1a;小朋友崇拜圈 班里N个小朋友&#xff0c;每个人都有自己最崇拜的一个小朋友&#xff08;也可以是自己&#xff09;。 在一个游戏中&#xff0c;需要小朋友坐一个圈&#xff0c; 每个小朋友都有自己最崇拜的小朋友在他的右手边。 求满足条件的圈最大多少人&…

java 圈复杂度_详解圈复杂度

详解圈复杂度 圈复杂度概念 圈复杂度(Cyclomatic complexity,简写CC)也称为条件复杂度,是一种代码复杂度的衡量标准。由托马斯J麦凯布(Thomas J. McCabe, Sr.)于1976年提出,用来表示程序的复杂度,其符号为VG或是M。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为…

控制台图形化打印二叉树(c/c++)

二叉树作为一种常见的数据结构,我们在学习的过程中会经常用到. 当我们做课设的时候,能把二叉树图形化的打印出来无疑是一个加分项,所以今天我们就来探讨一下如何图形化的打印出二叉树来. 目录 分析阶段 如何打印 如何将数据存入打印数组 代码实现 存储结构定义 二叉树的…

C语言:围圈报数游戏

游戏规则&#xff1a;有N个人围成一圈&#xff0c;顺序排号&#xff0c;从第一个人开始1到D报数&#xff0c;&#xff0c;凡报到D的人退出圈子&#xff08;下场&#xff09;&#xff0c;问最后留下来的是原来的第几号&#xff1f; 逻辑思想&#xff1a;用布尔数组记下每个人的…

c语言 打印共九行的菱形,用C语言打印图案的几种实现方法

循环的使用 维普资讯 http://doc.xuehai.net 科技伯. 1 1 0计算机与信息技术 0 S IN E I F R TO CE C N O MA I N 20 06年第 4期 用 C语言打印图案的几种实现方法 陈莹张青锋 (口师范学院计科系河南周口周 46 0 ) 60 0 摘要&#xff1a;经过几年来在 c语言教学中的实践&#xf…

C语言实现打印简易圣诞树

C语言实现打印简易圣诞树 引言想法的诞生一棵简易的圣诞树怎么构成梯形的代码梯形的叠加做一个长方形树干 总代码及其输出的简易圣诞树 引言 各位大佬好&#xff0c;我是一名大一的学生&#xff0c;目前只学习了C语言的语法基础&#xff0c;在CSDN这个平台上将自己所学的东西记…

HTML圈c怎么打出来,一种方便固定手表的展示C圈的制作方法

本实用新型属于展示C圈技术领域&#xff0c;具体涉及一种方便固定手表的展示C圈。 背景技术&#xff1a; 展示C圈是用来展示手表的必备器材&#xff0c;展示C圈采用耐用透明展示底座&#xff0c;方便工作人员为顾客展示手表的折光度。 原有展示C圈&#xff0c;手表固定在C圈上时…

c语言圈复杂度switch,干货|C语言switch\/case圈复杂度优化重构

点击上方“中兴开发者社区”&#xff0c;关注我们 每天读一篇一线开发者原创好文 ▍作者简介 作者陈彬是一名Linux驱动开发工程师&#xff0c;对Linux内核、软件设计和敏捷有较浓厚的兴趣和长期实践经验。自从项目建立起代码质量规范和监控工具后&#xff0c;如何重构高圈复杂度…

c语言圈复杂度switch,C语言switch/case圈复杂度优化重构

软件重构是改善代码可读性、可扩展性、可维护性等目的的常见技术手段。圈复杂度作为一项软件质量度量指标,能从一定程度上反映这些内部质量需求(当然并不是全部),所以圈复杂度往往被很多项目采用作为软件质量的度量指标之一。 C语言开发的项目中,switch/case代码块是一个很容…

Excel2016打开文件后显示空白

打开文件时显示 打开后空白 解决办法:

Excel双击文件打开后是空白,再次双击才能打开

Excel双击打开文件只弹出空白页面&#xff0c;再双击才打开所需页面。 解决方案&#xff08;仅供参考&#xff09;&#xff1a;WINR -->regedit-->修改HKEY_CLASSES_ROOT\Excel.Sheet.12\shell\Open\command项->默认值 数值数据原值后面加上 “%1” 点击确定即可 如&…

【Windows】Excel2019打开文档显示空白且工具栏灰色无法点击

如标题&#xff0c;要想打开Excel文档&#xff0c;只能通过菜单栏操作&#xff1a;文件->打开&#xff0c;然后选择要打开的文档才能正常显示。遇到这个问题很久了&#xff0c;今天着实忍不住了&#xff0c;特记录一下解决方法。 1、查看是否隐藏 点击“视图”菜单&#x…