文章目录
-
-
- [opencv 图像的缩放(放大,缩小),翻转,旋转](#opencv 图像的缩放(放大,缩小),翻转,旋转)
-
- 1、图像的缩放,旋转过程中为什么需要插值:
- 2、常见的插值算法包括:
- 3、图像的缩放,翻转,旋转:
-
- [(1)图像的缩放 cv2::resize(),用于改变图像大小的函数,它可以用于图像的放大、缩小操作:](#(1)图像的缩放 cv2::resize(),用于改变图像大小的函数,它可以用于图像的放大、缩小操作:)
- [(2)图像的翻转 cv2::flip(),用于实现图像翻转(镜像)操作的函数,它可以在水平方向、垂直方向或者同时在两个方向上进行翻转:](#(2)图像的翻转 cv2::flip(),用于实现图像翻转(镜像)操作的函数,它可以在水平方向、垂直方向或者同时在两个方向上进行翻转:)
- [(3)图像的旋转 cv2::warpAffine(),用于实现图像仿射变换的函数(图像仿射变换是指对图像进行平移、旋转、缩放、翻转等几何变换的操作)](#(3)图像的旋转 cv2::warpAffine(),用于实现图像仿射变换的函数(图像仿射变换是指对图像进行平移、旋转、缩放、翻转等几何变换的操作))
-
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 适合放大操作
);
示例:将一个图像缩小为原来的一半
cpp
#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轴翻转(对角线翻转)
);
示例:将一个图像沿水平方向进行翻转
cpp
#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是一个常量引用,即在函数中不能对其进行修改;
示例:将一个图像按照指定角度进行旋转
cpp
#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;
}
上面例子旋转后图像并不能保证完全可见,还需要计算旋转后图像的宽度和高度,以及旋转后中心点坐标
cpp
#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;
}