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

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;
}

猜你喜欢

转载自blog.csdn.net/qq_33867131/article/details/133086843