OpenCV3图片缩放

版权声明:本文为博主原创文章,欢迎转载,转载时请以超链接形式标明文章原始出处。 https://blog.csdn.net/lilongsy/article/details/84554026

图片缩放方式

如果放大或者缩小图片的尺寸,可以使用OpenCV为我们提供的如下两种方式:
(1)resize函数。这是最直接的方式,
(2)pyrUp()pyrDown()函数。即图像金字塔相关的两个函数,对图像进行向上采样,向下采样的操作。
pyrUp、pyrDown其实和专门用作放大缩小图像尺寸的resize在功能上差不多,披着图像金字塔的皮,说白了还是在对图像进行放大和缩小操作。另外需要指出的是,pyrUp、pyrDown在OpenCV的imgproc模块中的Image Filtering子模块里。而resize在imgproc 模块的Geometric Image Transformations子模块里。

图像金字塔

图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。
金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。
我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

一般情况下有两种类型的图像金字塔常常出现在文献和以及实际运用中。他们分别是:
高斯金字塔(Gaussianpyramid): 用来向下采样,主要的图像金字塔
拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。
两者的简要区别:高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。
要从金字塔第i层生成第i+1层(我们表示第i+1层为G_i+1),我们先要用高斯核对G_1进行卷积,然后删除所有偶数行和偶数列。当然的是,新得到图像面积会变为源图像的四分之一。按上述过程对输入图像G_0执行操作就可产生出整个金字塔。
当图像向金字塔的上层移动时,尺寸和分辨率就降低。OpenCV中,从金字塔中上一级图像生成下一级图像的可以用PryDown。而通过PryUp将现有的图像在每个维度都放大两遍。
图像金字塔中的向上和向下采样分别通过OpenCV函数 pyrUp 和 pyrDown 实现。
对图像向上采样:pyrUp函数
对图像向下采样:pyrDown函数
但需要注意的是,PryUp和PryDown不是互逆的,即PryUp不是降采样的逆操作。这种情况下,图像首先在每个维度上扩大为原来的两倍,新增的行(偶数行)以0填充。然后给指定的滤波器进行卷积(实际上是一个在每个维度都扩大为原来两倍的过滤器)去估计“丢失”像素的近似值。

PryDown( )是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,我们要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。

示例

//-----------------------------------【头文件包含部分】---------------------------------------
//		描述:包含程序所依赖的头文件
//---------------------------------------------------------------------------------------------- 
#include "pch.h"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//-----------------------------------【宏定义部分】--------------------------------------------
//	描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME "【程序窗口】"		//为窗口标题定义的宏


//-----------------------------------【命名空间声明部分】--------------------------------------
//		描述:包含程序所使用的命名空间
//----------------------------------------------------------------------------------------------- 
using namespace std;
using namespace cv;


//-----------------------------------【全局变量声明部分】--------------------------------------
//		描述:全局变量声明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_dstImage, g_tmpImage;


//-----------------------------------【全局函数声明部分】--------------------------------------
//		描述:全局函数声明
//-----------------------------------------------------------------------------------------------
static void ShowHelpText();


//-----------------------------------【ShowHelpText( )函数】----------------------------------
//		描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
	//输出一些帮助信息
	printf("\n\n\n\t欢迎来到OpenCV图像金字塔和resize示例程序~\n\n");
	printf("\n\n\t按键操作说明: \n\n"
		"\t\t键盘按键【ESC】或者【Q】- 退出程序\n"
		"\t\t键盘按键【1】或者【W】- 进行基于【resize】函数的图片放大\n"
		"\t\t键盘按键【2】或者【S】- 进行基于【resize】函数的图片缩小\n"
		"\t\t键盘按键【3】或者【A】- 进行基于【pyrUp】函数的图片放大\n"
		"\t\t键盘按键【4】或者【D】- 进行基于【pyrDown】函数的图片缩小\n"
	);
}

//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main()
{
	//显示帮助文字
	ShowHelpText();

	//载入原图
	g_srcImage = imread("jinan.jpg");//工程目录下需要有一张名为jinan.jpg的测试图像,且其尺寸需被2的N次方整除,N为可以缩放的次数
	if (!g_srcImage.data) { printf("读取srcImage错误~! \n"); return false; }

	// 创建显示窗口
	namedWindow(WINDOW_NAME, CV_WINDOW_AUTOSIZE);
	imshow(WINDOW_NAME, g_srcImage);

	//参数赋值
	g_tmpImage = g_srcImage;
	g_dstImage = g_tmpImage;

	int key = 0;

	//轮询获取按键信息
	while (1)
	{
		key = waitKey(9);//读取键值到key变量中

		//根据key变量的值,进行不同的操作
		switch (key)
		{
			//======================【程序退出相关键值处理】=======================  
		case 27://按键ESC
			return 0;
			break;

		case 'q'://按键Q
			return 0;
			break;

			//======================【图片放大相关键值处理】=======================  
		case 'a'://按键A按下,调用pyrUp函数
			pyrUp(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
			printf(">检测到按键【A】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸×2 \n");
			break;

		case 'w'://按键W按下,调用resize函数
			resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
			printf(">检测到按键【W】被按下,开始进行基于【resize】函数的图片放大:图片尺寸×2 \n");
			break;

		case '1'://按键1按下,调用resize函数
			resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
			printf(">检测到按键【1】被按下,开始进行基于【resize】函数的图片放大:图片尺寸×2 \n");
			break;

		case '3': //按键3按下,调用pyrUp函数
			pyrUp(g_tmpImage, g_dstImage, Size(g_tmpImage.cols * 2, g_tmpImage.rows * 2));
			printf(">检测到按键【3】被按下,开始进行基于【pyrUp】函数的图片放大:图片尺寸×2 \n");
			break;
			//======================【图片缩小相关键值处理】=======================  
		case 'd': //按键D按下,调用pyrDown函数
			pyrDown(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
			printf(">检测到按键【D】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2\n");
			break;

		case  's': //按键S按下,调用resize函数
			resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
			printf(">检测到按键【S】被按下,开始进行基于【resize】函数的图片缩小:图片尺寸/2\n");
			break;

		case '2'://按键2按下,调用resize函数
			resize(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2), (0, 0), (0, 0), 2);
			printf(">检测到按键【2】被按下,开始进行基于【resize】函数的图片缩小:图片尺寸/2\n");
			break;

		case '4': //按键4按下,调用pyrDown函数
			pyrDown(g_tmpImage, g_dstImage, Size(g_tmpImage.cols / 2, g_tmpImage.rows / 2));
			printf(">检测到按键【4】被按下,开始进行基于【pyrDown】函数的图片缩小:图片尺寸/2\n");
			break;
		}

		//经过操作后,显示变化后的图
		imshow(WINDOW_NAME, g_dstImage);

		//将g_dstImage赋给g_tmpImage,方便下一次循环
		g_tmpImage = g_dstImage;
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/lilongsy/article/details/84554026