opencv 图像的缩放(放大,缩小),翻转,旋转

2023-09-20 16:39:54

opencv 图像的缩放(放大,缩小),翻转,旋转

opencv 最常用的图像缩放方法是使用 cv2::resize() 函数,它需要指定输出图像的大小,和插值算法;

opencv 最常用的图像翻转方法是使用 cv::flip() 函数,它需要指定图像翻转方式;

opencv 最常用的图像旋转方法是使用 cv::warpAffine() 函数,它需要指定输出图像的大小,和插值算法;

1、图像的缩放,旋转过程中为什么需要插值:

通过使用适当的插值方法,可以确保图像在变换过程中保持合理的视觉品质和准确性;

(1)非整数坐标位置: 在进行缩放、翻转、旋转等变换时,新位置的坐标通常是浮点数,不一定是整数。例如,对于一个2倍放大的操作,像素的坐标会变成原来的两倍,如1.5、3.7等。但图像只能在整数坐标位置获取像素值;

(2)保持图像连续性: 插值算法可以保持图像在变换过程中的连续性和平滑性,避免出现锯齿状的边缘或形变;

2、常见的插值算法包括:
  • 最近邻插值(cv2::INTER_NEAREST): 选择距离变换位置最近的一个像素的值作为新位置的像素值;
  • 双线性插值(cv2::INTER_LINEAR): 使用相邻四个像素的加权平均值来估计新位置的像素值;
  • 双三次插值(cv2::INTER_CUBIC): 使用相邻16个像素的加权平均值来估计新位置的像素值;
3、图像的缩放,翻转,旋转:
(1)图像的缩放 cv2::resize(),用于改变图像大小的函数,它可以用于图像的放大、缩小操作:
函数原型:
void cv::resize(
    InputArray src,
    OutputArray dst,
    Size dsize,
    double fx = 0, 
    double fy = 0,
    int interpolation = INTER_LINEAR
);

参数解释:
src:输入图像;
dst:输出图像;
dsize:输出图像的大小,通常使用cv::Size()来指定; 
fx:沿水平轴的缩放因子,如果设置为0,则通过 fy 来确定缩放比例; 
fy:沿垂直轴的缩放因子,如果设置为0,则通过 fx 来确定缩放比例; 
interpolation:插值算法(
	INTER_NEAREST
	INTER_LINEAR	默认
        INTER_CUBIC	适合放大操作
); 

示例:将一个图像缩小为原来的一半
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
	//读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy4.jpg");
	if (src.empty()) {
		printf("could not load image..../n");
		return -1;
	}

	imshow("src", src);

	// 通过指定缩放因子,将图像缩小为原来的一半
	cv::Mat amplify1, amplify2, reduce1, reduce2;
	cv::resize(src, amplify1, cv::Size(), 0.5, 0.5, cv::INTER_LINEAR);
	cv::imshow("amplify1", amplify1);

	// 通过指定输出图像的尺寸,将图像缩小为原来的一半
	int w = src.cols;
	int h = src.rows;
	cv::resize(src, amplify2, cv::Size(w/2, h/2), 0, 0, cv::INTER_LINEAR);
	cv::imshow("amplify2", amplify2);

	// 通过指定缩放因子,将图像放大为原来的1.5倍
	cv::resize(src, reduce1, cv::Size(), 1.5, 1.5, cv::INTER_LINEAR);
	cv::imshow("reduce1", reduce1);

	// 通过指定输出图像的尺寸,将图像放大为原来的1.5倍
	cv::resize(src, reduce2, cv::Size(w*1.5, h*1.5), 0, 0, cv::INTER_LINEAR);
	cv::imshow("reduce2", reduce2);

	waitKey();
	destroyAllWindows();
	return 0;
}

(2)图像的翻转 cv2::flip(),用于实现图像翻转(镜像)操作的函数,它可以在水平方向、垂直方向或者同时在两个方向上进行翻转:
函数原型:
void cv::flip(
    InputArray src,   
    OutputArray dst,  
    int flipCode   
);

参数解释:
src:输入图像;
dst:输出图像;
flipCode:翻转方式(
	0	-> 沿x轴翻转(垂直翻转)(上下翻转)
	1	-> 沿y轴翻转(水平翻转)(左右翻转)
	-1	-> 同时沿x和y轴翻转(对角线翻转)
); 

示例:将一个图像沿水平方向进行翻转
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
	//读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
		printf("could not load image..../n");
		return -1;
	}

	imshow("src", src);

	cv::Mat flipped_image;
	cv::flip(src, flipped_image, 1);    // 沿y轴翻转

	cv::imshow("Flipped Image", flipped_image);

	waitKey();
	destroyAllWindows();
	return 0;
}

(3)图像的旋转 cv2::warpAffine(),用于实现图像仿射变换的函数(图像仿射变换是指对图像进行平移、旋转、缩放、翻转等几何变换的操作)
函数原型:
void cv::warpAffine(
    InputArray src, 
    OutputArray dst, 
    InputArray M, 
    Size dsize, 
    int flags = INTER_LINEAR,
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar()
);

1、参数解释:
src:输入图像;
dst:输出图像;
M:仿射变换矩阵,用于定义变换关系,这里定义的是旋转矩阵,需要借助cv2.getRotationMatrix2D()函数定义图像旋转参数,函数返回一个cv::Mat类型的矩阵,其中包含了进行旋转变换的矩阵信息;
dsize:输出图像的大小,通常使用cv::Size()来指定;  
flags :插值算法(
	INTER_NEAREST
	INTER_LINEAR	默认
        INTER_CUBIC	适合放大操作
); 
borderMode:边界模式,默认为BORDER_CONSTANT常数边界模式;
borderValue:borderValue默认值等于Scalar(),表示创建一个所有通道值为0的常量颜色,

2、定义旋转矩阵:
cv::Mat cv::getRotationMatrix2D(
	cv::Point2f center, 	// 旋转的中心坐标 (x, y),类型为cv::Point2f,使用的是浮点数作为坐标
	double angle, 		// 旋转角度,以度为单位(正值表示逆时针旋转,负值表示顺时针旋转)
	double scale		// 缩放比例,可选参数,默认为1.0
);

3、注意:
const Scalar& borderValue = Scalar()表达式的含义如下:
Scalar 是OpenCV库中用于表示多通道颜色值的数据类型,可以包括1到4个通道;
borderValue 是函数的参数名,它表示用于边界填充的颜色值;
=Scalar() 表示给定参数的默认值,在这里Scalar()创建了一个所有通道值为0的标量(黑色),用于作为默认的边界填充颜色;
const修饰符,表示borderValue是一个常量引用,即在函数中不能对其进行修改;

示例:将一个图像按照指定角度进行旋转
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
	//读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
		printf("could not load image..../n");
		return -1;
	}
	//namedWindow("src", WINDOW_NORMAL);
	imshow("src", src);

	cv::Mat rotated_image;
	// 图像src的中心点坐标
	cv::Point2f center(src.cols/2.0, src.rows/2.0);
	// 定义一个角度
	double angle = 45.0;
	// 定义了一个旋转矩阵
	cv::Mat rotation_matrix = cv::getRotationMatrix2D(center, angle, 1.0);
	// 将图像按照定义的rotation_matrix旋转变换的矩阵信息,进行旋转
	cv::warpAffine( src, rotated_image, rotation_matrix, src.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 255) );

	cv::imshow("Rotated Image", rotated_image);

	waitKey();
	destroyAllWindows();
	return 0;
}

上面例子旋转后图像并不能保证完全可见,还需要计算旋转后图像的宽度和高度,以及旋转后中心点坐标
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
	//读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
		printf("could not load image..../n");
		return -1;
	}
	//namedWindow("src", WINDOW_NORMAL);
	imshow("src", src);

	cv::Mat dst;
	int w = src.cols;
	int h = src.rows;
	// 图像src的中心点坐标
	cv::Point2f center(w/2.0, h/2.0);
	// 定义一个角度
	double angle = 45.0;
	// 定义了一个旋转矩阵
	cv::Mat M = cv::getRotationMatrix2D(center, angle, 1.0);
	// 下几行代码用于调整旋转后图像的位置,确保旋转后图像完全可见
	double cos = abs(M.at<double>(0, 0));
	double sin = abs(M.at<double>(0, 1)); 
	// 旋转后图像的宽度nw和高度nh
	int nw = int( abs(cos)*w + abs(sin)*h );
	int nh = int( abs(sin)*w + abs(cos)*h );
	// 旋转后图像的中心点位置
	M.at<double>(0, 2) += (nw/2 - w/2);
	M.at<double>(1, 2) += (nh/2 - h/2);
	// 由于计算出的 nw 和 nh 可能是浮点数,但 cv::warpAffine()函数的第四个参数(目标图像的大小)需要整数类型
	cv::Size newSize(nw, nh);
	// 将图像按照定义的rotation_matrix旋转变换的矩阵信息,进行旋转
	cv::warpAffine( src, dst, M, newSize, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 255, 255) );

	cv::imshow("Rotated Image", dst);

	waitKey();
	destroyAllWindows();
	return 0;
}

更多推荐

bloaty

安装教程参考:https://github.com/google/bloatyBloaty是一个用于分析二进制文件大小的工具,它可以深入分析二进制文件,使用自定义的ELF、DWARF和Mach-O解析器,将二进制文件的每个字节准确地归因于生成它的符号或编译单元。以下是一些使用Bloaty的基本步骤:安装Bloaty:你

【C++】STL详解(六)—— list的模拟实现

​​📝个人主页:@Sherry的成长之路🏠学习社区:Sherry的成长之路(个人社区)📖专栏链接:C++学习🎯长路漫漫浩浩,万事皆有期待上一篇博客:【C++】STL详解(五)——list的介绍及使用文章目录list的三个类及其成员函数接口总览结点类的模拟实现构造函数迭代器类的模拟实现迭代器类存在的意义迭代器类的

[Qt/C/C++]JSON和程序发布

文章摘于爱编程的大丙文章目录1.JSON1.1Json数组1.2Json对象1.3注意事项2.Qt中JSON操作2.1QJsonValue2.2QJsonObject2.3QJsonArray2.4QJsonDocument2.5举例2.5.1写文件2.5.2读文件3.cjson库的使用3.1cJSON结构体3.2cJ

华为OD机考算法题:分积木

目录题目部分解读与分析代码实现题目部分题目分积木难度难题目说明Solo和koko是两兄弟,妈妈给了他们一大堆积木,每块积木上都有自己的重量。现在他们想要将这些积木分成两堆。哥哥Solo负责分配,弟弟koko要求两个人获得的积木总重量“相等”(根据Koko的逻辑),个数可以不同,不然就会哭,但koko只会先将两个数转成二

Linux 系统目录结构 & 终端

系统目录结构Linux或Unix操作系统中,所有文件和目录呈一个以根节点为始的倒置的树状结构。文件系统的最顶层是根目录,用/来表示根目录。在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件。如此,就构成了一个庞大的文件系统。在命令窗口下输入命令:ls/,显示根目录下的文件:树状目录结构:目录解

从零开始搭建成绩查询系统

在当前的数字化时代,教育行业借助技术手段不断推动教学效果的提升。作为教师,搭建一个专属的成绩查询系统可以更好地管理学生成绩,并即时向家长反馈。本文将详细介绍如何从零开始搭建一个成绩查询系统,以提升教学管理的便捷性和效率。当然,对于非技术型的教师来说,使用现成工具是个更快速实用的选择。易查分等工具被许多教师用来制作查分网

(VS报错)已在 xxxxx.exe 中执行断点指令(__debugbreak()语句或类似调用)-解决方法&&C++创建对象四种方式

上述报错困扰了我好几天,在网上搜了一天,到最后还是没有解决问题试过通过项目属性->C/C+±>代码生成->启用增强指令集->选择AVX,这种方法也没用但问题出现在创建对象时内存分配问题上方法一:如果是这样创建对象,并且写了析构函数会报错,把析构函数删去之后程序就能正常运行了。方法二:创建对象的方式改为这样,程序也可以正

第九章(2):长短期记忆网络(Long short-term memory, LSTM)与pytorch示例(简单字符级语言模型训练器)

第九章(2):长短期记忆网络(Longshort-termmemory,LSTM)与pytorch示例(简单字符级语言模型训练器)作者:安静到无声个人主页作者简介:人工智能和硬件设计博士生、CSDN与阿里云开发者博客专家,多项比赛获奖者,发表SCI论文多篇。Thanks♪(・ω・)ノ如果觉得文章不错或能帮助到你学习,可

Python计算机二级知识点整理

1.当一个进程在运行过程中释放了系统资源后要调用唤醒进程原语唤醒进程原语是把进程从等待队列里移出到就绪队列并设置进程为就绪状态,当一个进程在运行过程中释放了系统资源后进入就绪状态,调用唤醒进程原语。2.3.4.在希尔排序法中,每经过一次数据交换后能消除多个逆序在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数

机械寿命预测(基于NASA C-MAPSS数据的剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)

1.效果视频:机械寿命预测(NASA涡轮风扇发动机剩余使用寿命RUL预测,Python代码,CNN_LSTM模型,有详细中文注释)_哔哩哔哩_bilibili环境库版本:2.数据来源:https://www.nasa.gov/intelligent-systems-division数据文件夹数据介绍:当前基于机器学习的

计算机是如何工作的下篇

操作系统(OperatingSystem)操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有:Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等.操作系统由两个基本功能:对下,要管理硬件设备.对上,要给软件提供稳定的运行环境.因此,操作系统是软件硬件用户之

热文推荐