OpenCV8-图像金字塔

OpenCV8-图像金字塔


1.图像金字塔

图像"金字塔"是通过多个分辨率表示图像的一种有效且简单的结构。一个图像"金字塔"是一系列以金字塔形状排列、分辨率逐步降低的图像集合。图像"金字塔"的底部是待处理图像的高分辨率表示,顶部是低分辨率表示。本文中将介绍图像"金字塔"中比较著名的两种:高斯"金字塔"和拉普拉斯"金字塔"。

2.高斯金字塔

高斯"金字塔"是指通过下采样不断地将图像的尺寸缩小,进而在图像"金字塔"中包含多个尺寸的图像。一般情况下,高斯"金字塔"的底层为图像的原图,每往上一层就会通过下采样缩小一次图像的尺寸,通常情况下,尺寸会缩小为原来的一半,但是如果有特俗需求,缩小的尺寸也可以根据实际情况进行调整。由于每次图像的尺寸都缩小为原来的一半,图像尺寸缩小的速度非常快,因此常见的高斯"金字塔"的层数为3~6层。

OpenCV中提供了pyrDown函数专门用于图像的下采样计算,以便构建图像的高斯"金字塔":

cpp 复制代码
void pyrDown(
    InputArray src,  // 输入待下采样的图像
    OutputArray dst, // 输出下采样后的图像
    const Size& dstsize = Size(),  // 输出图像尺寸,可以默认
    int borderType = BORDER_DEFAULT // 像素边界外推方法的标志,图像几何变换一文中-仿射变换有说明
);

该函数用于实现图像模糊并对其进行下采样,默认标志下,函数输出图像的尺寸为输入图像尺寸的一半,但是也可以通过dstsize参数来设置输出图像的大小,需要注意的是,无论输出尺寸为多少,应该满足下面公式的条件:
{ ∣ 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 l s ∣ ≤ 2 \left\{ \begin{matrix} | dstsize.width2 - src.cols | \leq 2 \\ | dstsize.height2 - src.rols | \leq 2 \\ \end{matrix} \right. {∣dstsize.width2−src.cols∣≤2∣dstsize.height2−src.rols∣≤2

该函数首先将原始图像与内核矩阵进行卷积,之后通过不适用偶数行和列的方式对图像进行下采样,最终实现尺寸缩小的下采样,内核矩阵如下:
k = 1 256 1 4 6 4 1 4 6 24 6 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 & 6 & 24 & 6 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \\ \end{bmatrix} k=2561 14641462416462436246462416414641

该函数的功能与resize函数将图像尺寸缩小一样,但是使用的内部算法不同。

3.拉普拉斯金字塔

拉普拉斯"金字塔"是通过上层小尺寸的图像构建下层大尺寸的图像。拉普拉斯"金字塔"具有预测残差的作用,需要与高斯"金字塔"一起使用。

假设我们有了一个高斯图像"金字塔",对于其中的第i层图像(高斯"金字塔"最下面为第0层),首先通过下采样得到一个尺寸缩小一半图像,即高斯"金字塔"中的第i+1层或者不在高斯"金字塔"中,之后对这福图像进行上采样,将图像尺寸恢复到第i层图像的大小,最后求取高斯"金字塔"第i层图像与经过上采样后的图像的残差图像,这个残差图像就是拉普拉斯"金字塔"的第i层图像。

对于上采样操作OpenCV提供了pyrUp函数:

cpp 复制代码
void pyrUp(
    InputArray src, 
    OutputArray dst,
    const Size& dstsize = Size(), 
    int borderType = BORDER_DEFAULT 
);
// 函数参数同pyrDown

4.Demo

cpp 复制代码
#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
	cout << "OpenCV Version: " << CV_VERSION << endl;
	utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);

	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	vector<Mat> Gauss, Lap;  //高斯金字塔和拉普拉斯金字塔
	int level = 3;  //高斯金字塔下采样次数
	Gauss.push_back(img);  //将原图作为高斯金字塔的第0层
	//构建高斯金字塔
	for (int i = 0; i < level; i++)
	{
		Mat gauss;
		pyrDown(Gauss[i], gauss);  //下采样
		Gauss.push_back(gauss);
	}
	//构建拉普拉斯金字塔
	for (int i = Gauss.size() - 1; i > 0; i--)
	{
		Mat lap, upGauss;
		if (i == Gauss.size() - 1)  //如果是高斯金字塔中的最上面一层图像
		{
			Mat down;
			pyrDown(Gauss[i], down);  //上采样
			pyrUp(down, upGauss);
			lap = Gauss[i] - upGauss;
			Lap.push_back(lap);
		}
		pyrUp(Gauss[i], upGauss);
		lap = Gauss[i - 1] - upGauss;
		Lap.push_back(lap);
	}
	//查看两个金字塔中的图像
	for (int i = 0; i < Gauss.size(); i++)
	{
		string name = to_string(i);
		imshow("G" + name, Gauss[i]);
		imshow("L" + name, Lap[i]);
	}

	waitKey(0);
	return 0;
}
相关推荐
学术 学术 Fun34 分钟前
612 次图表重建实验告诉我们的:O612 次图表重建实验告诉我们的:OCR、图形与连接线CR、图形与连接线
机器学习·计算机视觉·ocr·图表
喜欢吃燃面35 分钟前
深入 C++ STL:从 unordered_set与unordered_map到底层哈希表的原理与实现
数据结构·c++·散列表
FlightYe1 小时前
音视频修炼之基础理论(五):AAC格式与解析
android·linux·c++·音视频·aac
ShineWinsu2 小时前
对于MySQL:数据库的操作的解析
linux·数据库·c++·mysql·面试·笔试·库的操作
云小逸2 小时前
C++ 第一阶段:对象、内存与生命周期
开发语言·c++
夜航海图2 小时前
S-57 数据解剖:把一个 ENC 文件拆给你看
c++
(Charon)2 小时前
【C++】网络缓冲区设计(三):Chain Buffer链式缓冲区、动态扩容与跨节点读写
服务器·c++
大熊背3 小时前
去马赛克混叠现象分析
计算机视觉·去马赛克·颜色插值
软行4 小时前
LeetCode 每日一题 3876. 构造奇偶一致的数组 II
c++·算法·leetcode
繁星蓝雨4 小时前
C++设计原理———重载(extern “C“的由来、顺序依赖、语义依赖、overload、名称修饰符、对象操作、运算符重载、新增运算符、枚举和布尔类型)
c语言·c++·extern c·overload·重载·语义依赖·顺序依赖