【OpenCV C++20 学习笔记】图像缩放-高斯金字塔
创始人
2024-11-04 00:03:39

图像缩放-高斯金字塔

  • 原理
    • 高斯金字塔
  • 代码实现
    • 放大
    • 缩小
    • 形成金字塔

原理

在图像处理中,经常需要将图像转化成不同的尺寸,即放大或缩小。
除了直接用resize()函数重新设置图片尺寸,另一种常用的方法就是“图像金字塔”。
图像金字塔是从底层的原始图像开始,通过层层放大叠加而成的金字塔形状的图像集合。
主要有两种图像金字塔:

  • 高斯金字塔:常用来生成图片的缩小版本
  • 拉普拉斯金字塔:常用来将图片的缩小版本放大

高斯金字塔

用图片来表示高斯金字塔会更形象:
高斯金字塔
图层越高,图像越小。
图像的编号又下往上依次增大。从下往上数第 i + 1 i+1 i+1个图层,记为 G i G_{i} Gi​;则第 i + 2 i+2 i+2个图层 G i + 1 G_{i+1} Gi+1​比 G i G_i Gi​小。
要生成 G i + 1 G_{i+1} Gi+1​就要对 G i G_i Gi​进行如下操作:

  1. 用高斯卷积核 K K K对 G i G_i Gi​进行卷积运算;
    K = 1 256 [ 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 ] K=\frac{1}{256} \begin{bmatrix} 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{bmatrix} K=2561​​14641​41624164​62436246​41624164​14641​
  2. 移除所有的偶数行和偶数列
    很显然,最后的结果会变成原来图片的1/4。将这个操作迭代地运用在原图 G 0 G_0 G0​上,就会形成上图所示的金字塔。
    其实高斯金字塔方法也可以用来放大图片。只要进行以下操作:
  3. 将行和列都扩大到原来的2倍;
  4. 将上面的卷积核 K K K乘以4之后近似地模拟出填充值来填充扩大出来的行和列

注意:缩小图片实际上丢失了一部分原图的信息。

代码实现

这里使用的图片是OpenCV安装文件中自带的示例图,其路径为:"...\opencv\sources\samples\data\chicky_512.png"
chick_512.png

放大

在OpenCV中可以pyrUp()函数来进行高斯金字塔中的放大操作。其函数原型如下:

void cv::pyrUp(InputArray	src, 			OutputArray		dst, 			const Size& 	dstsize = size(), 			int				borderType = BORDER_DEFAULT) 

第1个和第2个参数不用介绍了,分别是输入矩阵和输出矩阵。
第3个参数为放大后的尺寸,默认为Size(src.cols*2, src.rows*2),即行和列都放大为原来的2倍。但是如果用户要自定义放大倍数的话,需要满足以下条件:
{ ∣ d s t s i z e . w i d t h − s r c . c o l s ∗ 2 ∣ ≤ ( d s t s i z e . w i d t h m o d 2 ) ∣ d s t s i z e . h e i g h t − s r c . r o w s ∗ 2 ∣ ≤ ( d s t s i z e . h e i g h t m o d 2 ) \begin{cases} |dstsize.width - src.cols*2| \leq (dstsize.width mod 2) \\ |dstsize.height - src.rows*2| \leq (dstsize.height mod 2) \end{cases} {∣dstsize.width−src.cols∗2∣≤(dstsize.widthmod2)∣dstsize.height−src.rows∗2∣≤(dstsize.heightmod2)​
乍一看有点复杂,我们来仔细分析一下:
首先看两个不等式的右边,因为图片的宽和高一般都是整数,所以无论是宽还是高,除以2的余数都只有两种情况:0或1。

  • 不等式右边为0:说明放大后的图片的宽或高是偶数,且等式左边必须小于等于0;又因为不等式左边为一个绝对值的结果,那么只有一种可能——不等式左边等于0,即 d s t s i z e . w i d t h = s r c . c o l s ∗ 2 dstsize.width = src.cols*2 dstsize.width=src.cols∗2或 d s t s i z e . h e i g h t = s r c . r o w s ∗ 2 dstsize.height = src.rows*2 dstsize.height=src.rows∗2,也就是这个参数的默认情况。
  • 不等式右边为1:说明放大的图片的宽或高是奇数,且等式左边必须小于等于1;因为奇数减偶数只能等于奇数,所以等式左边的结果只能为1,即只能是 s r c . c o l s ∗ 2 + 1 src.cols * 2 + 1 src.cols∗2+1或者 s r c . r o w s ∗ 2 + 1 src.rows*2+1 src.rows∗2+1。

综上所述,第3个参数只能有两种:

  1. 宽和高都放大为原来的2倍,即默认情况
  2. 宽和高都放大为原来的2倍加1。

为什么有这种限制?答案在最后一节。

第4个参数基本使用默认值,先不用管它。

我们看看宽和高都放大为原来的宽和高的2倍的具体实现:

pyrUp(src,							//原图 	up_dst,							//输出图 	Size(src.cols*2, src.rows*2));	//放大后的尺寸:原图的2*2 

一次放大后的效果:
放大后的效果

缩小

类似的,可以使用pryDown()函数来缩小图片。这个函数的参数与pryUp()相同,但第3个参数,即缩小后的尺寸的具体条件不一样。
pryDown()中,第3个参数dstsize默认值为Size((src.cols+1)/2, (src.rows+1)/2),即原图的宽和高加1的一半。如果用户要自定义缩小尺寸,需要满足以下条件:
{ ∣ d s t s i z e . w i d t h ∗ 2 − s r c . c o l s ∣ ≤ 2 ∣ d s t s i z e . h e i g h t ∗ 2 − s r c . r o w s ∣ ≤ 2 \begin{cases} |dstsize.width*2 - src.cols| \leq 2 \\ |dstsize.height*2 - src.rows| \leq 2 \end{cases} {∣dstsize.width∗2−src.cols∣≤2∣dstsize.height∗2−src.rows∣≤2​
这也就是说缩小之后的图片的宽和高的2倍不能与原来的宽高相差2以上,即缩小后的图片的尺寸只有这些选择:

  1. 原图的宽高的一半,此时不等式左边就是0
  2. 原图的宽高加1的一半,即默认情况,不等式左边为1
  3. 原图的宽高加2的一半,此时不等式左边为2

为什么有这种限制?答案在最后一节。

第1中情况的具体用法如下:

pryDown(src,							//原图 		down_dst,						//输出图 		Size( src.cols/2, src.rows/2));	//缩小后的尺寸:原图的(1/2)*(1/2) 

原图缩小一次的效果如下:
缩小后的图片

形成金字塔

要形成金字塔不能只进行单次缩放的操作,需要进行迭代。
正是因为要迭代,所以前面才会对pyrUp()pyrDown()函数的第3个参数有那么严格的限制。如果缩放的尺寸没有限制,那可以1次迭代就放大100或缩小100倍,那很有可能就没有进行第2次迭代的必要了。要形成有意义的金字塔,缩放的比例必须要控制在一个相对较小的范围内,而这两个函数都将比例限制在了2或1/2左右。

如果我们将迭代次数限定为5次,我们可以进行这样的缩小图片的迭代:

#include  #include  #include   using namespace cv; using namespace std;  int main() { 	Mat src{ imread("chicky_512.png") };  	//缩小迭代 	String winName{ "缩小" }; 	for (int i{ 0 }; i < 5; i++) { 		imshow(winName+to_string(i), src); 		pyrDown(src, 			src, 			Size(src.cols / 2, src.rows / 2)); 	} 	waitKey(0); } 

结果如下:
高斯金字塔

相关内容

热门资讯

裸辞做“一人公司”,我后悔了 去年这个时候,一位以色列程序员正在东南亚旅行。他顺手把一个在脑子里转了很久的想法做成了产品,一个让任...
南京建成国内首个Pre-6G试... 4月21日,2026全球6G技术与产业生态大会在南京开幕。全息互动技术展台前,一名远在北京的工作人员...
超梵求职受邀参加“2025抖音... 超梵求职受邀参加“2025抖音巨量引擎成人教育行业生态大会”,探讨分享优质内容传播,服务万千学员。 ...
摩托罗拉Razr 2026(R... IT之家 4 月 22 日消息,摩托罗拉宣布新一代 Razr 折叠手机将于 4 月 29 日在美国发...
库克卸任,特纳斯领航:苹果新纪... 苹果首席执行官蒂姆·库克将卸任,硬件工程主管约翰·特纳斯将接任,苹果公司今天宣布此事。 库克将在夏季...