OpenCV学习笔记(6)_由例程学习高斯图像金字塔和拉普拉斯金字塔

news2024/11/26 19:47:41

在这里插入图片描述

1 图像金字塔

图像金字塔是图像多尺度表达的一种。

尺度,顾名思义,可以理解为图像的尺寸和分辨率。处理图像时,经常对源图像的尺寸进行缩放变换,进而变换为适合我们后续处理的大小的目标图像。这个对尺寸进行放大缩小的变换过程,称之为尺度调整。

图像金字塔则是图像多尺度调整表达的一种重要的方式,图像金字塔方法的原理是:将参加整合的每幅图像分解为拥有多个尺度的金字塔图像序列,越低分辨率的图像,位于金字塔的越上层,反之,越高分辨率的图像,则位于金字塔的越下层。金字塔的层数,则由下而上分别为0, 1, 2, …, N.

每一层的图像的大小都为上一层的1/4。

把这些不同尺度的金字塔图像按照上述规则组合起来,则得到一个形如金字塔的结构,即称为图像金字塔。

在这里插入图片描述

图像金字塔最初用于机器视觉和图像压缩,主要用于图像的分割和融合。

2 高斯金字塔和拉普拉斯金字塔

有两种类型的金字塔经常出现在文献和应用当中,它们分别是:

  • 高斯金字塔(Gaussian Pyramid):主要是用来向下采样(缩小);
  • 拉普拉斯金字塔(Laplacian Pyramid):用来从金字塔低层图像重建上层未采样的图像,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。

2.1 高斯金字塔

在图像向下取样中,一般分两步:
(1) 对图像 G i G_i Gi进行高斯卷积核(高斯滤波);
(2) 删除所有的偶数行和列。

在第一步中,使用的高斯卷积核为:
1 16 [ 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 ] \frac{1}{16}\left[ \begin{array}{c} 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{array}\right] 161 1464141624164624362464162416414641
卷积完成后,将偶数行和偶数列抽走删除,即得到下一层图像。

若是向上取样,一般也分两步:
(1) 对图像 G i + 1 G_{i+1} Gi+1 增加偶数行和偶数列,都用0填充;
(2) 对图像进行高斯卷积,插值时滤波器乘以系数4。

2.2 拉普拉斯金字塔

在高斯金字塔下采样的过程中,可以看出图像信息出现了损失。这意味着如果下采样之后再上采样,图像并不能还原。图像将丢失掉部分高频信息。

此时如果想要保留图像的高频信息,则需要引入拉普拉斯金字塔:
L i = G i − P y r U p ( P y r D o w n ( G i ) ) L_i = G_i - PyrUp(PyrDown(G_i)) Li=GiPyrUp(PyrDown(Gi))
即第i层的拉普拉斯金字塔图像,先计算高斯金字塔下采样再上采样的图像 P y r U p ( P y r D o w n ( G i ) ) PyrUp(PyrDown(G_i)) PyrUp(PyrDown(Gi)),然后用第i层的原图 G i G_i Gi减去它。

3 OpenCV中的图像金字塔例程

3.1 pyrUp和pyrDown函数

OpenCV中的pyrUp函数原型为:

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

pyrDown函数原型为:

void cv::pyrDown(InputArray src,
				OutputArray dst,
				const Size & dstSize = Size(),
				int borderType = BORDER_DEFAULT)

其中,src为原始图像,dst为上采样/下采样的目标图像, dstSize为目标图像的尺寸, borderType为边界类型,这里默认为BORDER_DEFAULT.

3.2 Pyramids.cpp例程

原理部分讲述结束,下面进入OpenCV的例程:

OpenCV的Sample文件夹下有关于图像金字塔的例程:
samples/cpp/tutorial_code/ImgProc/Pyramids/Pyramids.cpp

#include "iostream"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
const char* window_name = "Pyramids Demo";
int main(int argc, char** argv)
{
	cout << "\n Zoom In-Out demo \n "
		"------------------  \n"
		" * [i] -> Zoom in   \n"
		" * [o] -> Zoom out  \n"
		" * [ESC] -> Close program \n" << endl;
	const char* filename = argc >= 2 ? argv[1] : "../data/chicky_512.png";
	// Loads an image
	Mat src = imread(samples::findFile(filename));
	// Check if image is loaded fine
	if (src.empty()) {
		printf(" Error opening image\n");
		printf(" Program Arguments: [image_name -- default chicky_512.png] \n");
		return EXIT_FAILURE;
	}
	for (;;)
	{
		imshow(window_name, src);
		char c = (char)waitKey(0);
		if (c == 27)
		{
			break;
		}
		else if (c == 'i')
		{
			pyrUp(src, src, Size(src.cols * 2, src.rows * 2));
			printf("** Zoom In: Image x 2 \n");
		}
		else if (c == 'o')
		{
			pyrDown(src, src, Size(src.cols / 2, src.rows / 2));
			printf("** Zoom Out: Image / 2 \n");
		}
	}
	return EXIT_SUCCESS;
}

注意以上源码是被小白修改了的,因为小白的工程里面用于放缩的图片的位置是在data文件夹下

const char* filename = argc >= 2 ? argv[1] : "../data/chicky_512.png";

这个程序打开后会显示一幅小狗的图像,并一直等待键盘输入。
在这里插入图片描述

如果你输入一个"i",则图像将被放大,即Zoom In;
如果你输入一个"o",则图像将被缩小,即Zoom Out;
直到你输入一个"ESC",程序退出。

但是这个程序只使用了高斯金字塔,反复测试几次你就会发现:如果先缩小了很多倍,再重新放大,那么由于下采样时总是在丢失图像信息,多操作几次之后,小狗的面目就变得非常模糊。
下图就是缩小了3次之后再放大到原始尺寸时所看到的小狗:
在这里插入图片描述

那么有没有办法把这个例程改造成可以带有拉普拉斯金字塔,可以在放缩后仍然还原原始分辨率细节的小狗图呢?当然有。

3.3 改造后的图像金字塔例程

使用STL中的stack来保存拉普拉斯金字塔图像,则可以简单地实现分辨率还原的功能:

#include "iostream"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <stack>
using namespace std;
using namespace cv;
const char* window_name = "Pyramids Demo";
int main(int argc, char** argv)
{
	cout << "\n Zoom In-Out demo \n "
		"------------------  \n"
		" * [i] -> Zoom in   \n"
		" * [o] -> Zoom out  \n"
		" * [ESC] -> Close program \n" << endl;
	const char* filename = argc >= 2 ? argv[1] : "../data/chicky_512.png";
	// 加载一幅图像
	Mat src = imread(samples::findFile(filename));
	int picMaxWidth = src.cols;
	int picMaxHeight = src.rows;
	// 检查是否加载成功
	if (src.empty()) {
		printf(" Error opening image\n");
		printf(" Program Arguments: [image_name -- default chicky_512.png] \n");
		return EXIT_FAILURE;
	}

	// 用于存储拉普拉斯金字塔的栈结构
	stack<Mat> stackMat;

	for (;;)
	{
		imshow(window_name, src);
		char c = (char)waitKey(0);
		if (c == 27)												// ESC Key 则退出
		{
			break;
		}
		// 放大图像但不允许超过原图大小
		else if (c == 'i')
		{
			if (src.cols >= picMaxWidth)
			{
				printf("** cannot Zoom In: Image reaches max size!\n");
				continue;
			}
			pyrUp(src, src, Size(src.cols * 2, src.rows * 2));
			if (!stackMat.empty())
			{
				Mat temp;
				temp = stackMat.top();
				src.convertTo(src, CV_16SC3);						// 对图像格式进行转换,目的是进行负差值的正确计算
				src += temp;										// 取栈顶的拉普拉斯金字塔图像进行原图还原
				src.convertTo(src, CV_8UC3);						// 将图像还原成8位3通道,便于显示
				stackMat.pop();
			}
			printf("** Zoom In: Image x 2 \n");
		}
		// 缩小图像
		else if (c == 'o')
		{
			Mat temp1, temp2;
			src.copyTo(temp1);
			pyrDown(src, src, Size(src.cols / 2, src.rows / 2));
			pyrUp(src, temp2, Size(src.cols * 2, src.rows * 2));
			// 对图像进行格式转换, 目的是得到差值图像的正确负值
			temp1.convertTo(temp1, CV_16SC3);
			temp2.convertTo(temp2, CV_16SC3);
			temp1 -= temp2;											// 计算拉普拉斯金字塔差值图像
			stackMat.push(temp1);									// 将拉普拉斯金字塔压进栈中
			printf("** Zoom Out: Image / 2 \n");
		}
	}
	return EXIT_SUCCESS;
}

这段代码中:

  • 通过一个stackMat来记录缩小时造成的图像信息损失;
  • 通过压栈和出栈的方式保证每一层下采样时的拉普拉斯金字塔都能得以保存;
  • 通过图像类型反复转换来保证在计算差值时能够正确地保留像素差的负值;
  • 通过限制放大的倍率,防止在放大到超过原始图像分辨率,再重新下采样时造成不可逆的图像信息损失。

细节其实挺多,针对第三点和第四点简单铺开讲一下:

  • 如果不进行图像类型的转换(大家可以试试把那几句图像类型转换的代码注释掉),那么在计算拉普拉斯金字塔时,图像差值将无法保留负值,这将会导致在反复缩放过程中,图像的部分信息发生丢失,小狗图中的高频细节会越来越亮,像下图中一样;
    在这里插入图片描述

  • 如果不限制图像的放缩倍率,那么当图像先放大到原始图像尺寸的2倍,再重新缩小到原始尺寸时,图像先经历了一次上采样,放大时的插值部分属于无中生有,再重新下采样时,就引入了信息失真,因此对原例程进行了修改,使其无法将图像放大到超过原始尺寸,这样就保证了在图像回到原始尺寸大小时,其图像细节能与原始图像保持一致。下图是如果不限制放大倍率,在放大超过原始尺寸后再重新回到原始尺寸时,图像的效果:(如果你将它和原始图像比较一下,会发现有细微的差别)
    在这里插入图片描述

至此,小白和大家一起学习了这个例程,并对高斯图像金字塔和拉普拉斯图像金字塔有了更深层次的理解。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1005076.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python的get请求报错Error: Unexpected status code 400

一句话导读&#xff1a; 最近在做研发效能提升的事情&#xff0c;其中有一块就是要对项目管理相关数据做统计&#xff0c;我们使用的是ones做的项目管理&#xff0c;ones本身带的那些报表满足不了我们的需求&#xff0c;就想着看这些数据是不是能自己拿出来做统计&#xff0c;有…

代码随想录--数组--长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s &#xff0c;找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组&#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0。 示例&#xff1a; 输入&#xff1a;s 7, nums [2,3,1,2,4,3]输出&#xff1a;2…

华为3面已过,面议薪资要价10K,面试官说我不尊重华为?

在不知道一个公司的普遍薪资水平的时候&#xff0c;很多面试者不敢盲目的开价&#xff0c;但就因为这样可能使得面试官怀疑你的能力。一位网友就在网上诉说了自己的经历&#xff0c;男子是一位测试员&#xff0c;已经有九年的工作经历了&#xff0c;能力自己觉得还不错。 因为…

2002-2020年地级市各类制造业企业进入数量数据

2002-2020年地级市各类制造业企业进入数量数据 1、时间&#xff1a;2002-2020年 2、指标&#xff1a;地区、年份、城市代码、所属省份、省份代码、高技术行业企业数量、中高技术行业企业数量、中低技术行业企业数量、低技术行业企业数量 3、样本量&#xff1a;1万多条 4、来…

mac使用squidMan设置代理服务器

1&#xff0c;下载squidMan http://squidman.net/squidman/ 2, 配置SquidMan->Preference 3, mac命令窗口配置 export http_proxy export https_porxy 4&#xff0c;客户端配置&#xff08;centos虚拟机&#xff09; export http_proxyhttp://服务器ip:8080 export https…

肖sir__mysql之单表__004

mysql之单表 一、建表语句 1、show databases 查看所有的数据库 2、create databaes 数据库名 创建数据库 3、use 数据库名 指定使用数据库 4、show tables &#xff1b; 5、创建表 格式&#xff1a;create table 表名 (字段名1 数据类型1(字符长度),字段名2 数据类型2(字…

【鸿蒙(HarmonyOS)】UI开发的两种范式:ArkTS、JS(以登录界面开发为例进行对比)

文章目录 一、引言1、开发环境2、整体架构图 二、认识ArkUI1、基本概念2、开发范式&#xff08;附&#xff1a;案例&#xff09;&#xff08;1&#xff09;ArkTS&#xff08;2&#xff09;JS 三、附件 一、引言 1、开发环境 之后关于HarmonyOS技术的分享&#xff0c;将会持续使…

学习记忆——宫殿篇——记忆宫殿——数字编码——记忆数字知识点

面对错综复杂的数字信息&#xff0c;我们想要记住可以通过以下三点&#xff1a; 1、首先找到关键词 2、数字编码牢记 3、关键词跟编码链接 案例&#xff1a;会计考试-时间期限为 3、7、10 日、1 年的知识点 3 天 (1)托收承付的承付期验单付款为 3 天。 (2)失票人应当在通…

考研英语笔记:经济学人特别一篇,看到此,流口水

文 / 谷雨 考研是一件非常痛苦的事情。 你可能在一个漫长时间当中&#xff0c;看不到任何回报。但是成功和失败之间就在于你是否能够坚持走完这段路。 无数备考的朋友&#xff0c;无不走过这段路。 很多人可能复习了好几个月&#xff0c;上考场之后还是发现没有一点进步&#x…

嘉泰实业:真实低门槛,安全有保障

在互联网金融大行其道的当下&#xff0c;无论用户是多么的青睐、喜爱这种便捷的理财方式&#xff0c;也一定得把资金安全放在心上。要投就投那些实力背景雄厚&#xff0c;诚信经营的平台&#xff0c;可以选择投资用户基数庞大的理财老品牌&#xff0c;也可以选择发展势头迅猛的…

学习记忆——宫殿篇——记忆宫殿——数字编码——三十六计

案例&#xff1a;中国古代兵书《三十六计》 第1计 瞒天过海 第2计 围魏救赵 第3计 借刀杀人 第4计 以逸待劳 第5计 趁火打劫 第6计 声东击西 第7计 无中生有 第8计 暗渡陈仓 第9计 隔岸观火 第10计 笑里藏刀 我们可以这样记忆&#xff1a; 一、先熟悉1-10的编码&#xff1a;…

解决方案 | 法大大电子签为物流行业发展提速提效

近年来&#xff0c;受益于物流行业的快速发展&#xff0c;人们的生活便利度得到了极大提升。与此同时&#xff0c;传统的物流行业也在面临着新时代的挑战&#xff0c;长期面临回程空驶、装载率低、仓库资源闲置、堆存利用率低等痛点&#xff0c;尤其在公路货运市场&#xff0c;…

[GWCTF 2019]我有一个数据库

过来毛都没有 直接dirsearch 扫一下 发现存在 phpadmin 我们直接访问一下 啥都没有 但是给我们了 phpadmin的版本 我们去搜搜看是否存在漏洞 phpMyAdmin 4.8.1后台文件包含漏洞&#xff08;CVE-2018-12613&#xff09;_phpmyadmin cve-2018-12613漏洞获取webshell_zhang三的…

Facebook 惊现网络钓鱼浪潮,每周攻击 10 万个账户

Bleeping Computer 网站披露&#xff0c;某黑客组织通过一个伪造和受损的 Facebook 账户网络&#xff0c;发送数百万条 Messenger 钓鱼信息&#xff0c;利用密码窃取恶意软件攻击 Facebook 企业账户。 据悉&#xff0c;网络攻击者通过诱骗目标用户下载一个 RAR/ZIP 压缩包&…

Shell编程之定时任务

什么是定时任务 顾名思义&#xff0c;定时任务指的就是在指定/特定的时间进行工作&#xff0c;例如备份/归档数据、清理临时文件等。 在 Linux 中&#xff0c;可以使用 cron 定时器来定期执行任务。cron 是一个在后台运行的守护进程&#xff0c;用于根据指定的时间表自动执行任…

驱动开发,udev机制创建设备节点的过程分析

1.创建设备文件的机制种类 mknod命令&#xff1a;手动创建设备节点的命令 devfs:可以用于创建设备节点&#xff0c;创建设备节点的逻辑在内核空间&#xff08;内核2.4版本之前使用&#xff09; udev:自动创建设备节点的机制&#xff0c;创建设备节点的逻辑在用户空间&#xf…

【正点原子STM32连载】 第三十章 PVD电压监控实验 摘自【正点原子】APM32F407最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html# 第三…

VUE 的eslint 代码规范检查

报错&#xff1a; You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file. 解决&#xff1a; 注释&#xff1a;...(config.dev.useEslint ? [creat…

ThreadLocal功能实现

模拟ThreadLocal功能实现 当前线程任意方法内操作连接对象 一个栈对应一个线程 , 一个方法调用另一个方法都是在一个线程内 , 只有执行了线程的start方法才会创建一个线程 定义一个Map集合 , key是当前线程(Thread.currentThread) , value是要绑定的数据(Connection对象) 以…

2023年澳大利亚标普ASX200指数研究报告

第一章 指数概况 1.1 指数基本情况 澳大利亚标普ASX200&#xff08;S&P/ASX200&#xff09;指数是由标准普尔&#xff08;S&P&#xff09;和澳大利亚证券交易所&#xff08;Australian Securities Exchange, ASX&#xff09;共同编制的主要股票市场指数&#xff0c;简…