7.4仿射变换

基础概念

在OpenCV中,仿射变换(Affine Transformation)是一种重要的(图像处理)几何变换技术,它包括平移、旋转、缩放、错切等多种变换。仿射变换通常用于图像处理和计算机视觉中,例如图像配准、视角变换等。仿射变换可以通过一个2×3的矩阵来描述,这个矩阵包含六个自由度,对应于变换后的图像的三个顶点位置(对于矩形来说,任意三个顶点的位置足以定义整个变换)。

仿射变换的数学基础仿射变换可以用一个2x3的矩阵来表示,这个矩阵包含六个参数

OpenCV中的仿射变换函数

OpenCV中的仿射变换在OpenCV中,仿射变换可以通过 warpAffine 函数来实现。这个函数需要一个2x3的变换矩阵来指定变换。

OpenCV提供了getAffineTransformwarpAffine两个函数来处理仿射变换。

getAffineTransform函数

用于计算仿射变换矩阵。你需要提供三组对应点,即原图像中的三个点和它们变换后的三个点。

Mat getAffineTransform(
    const Point2f src[],
    const Point2f dst[]
);

src: 原始图像中的三个点。
dst: 变换后图像中的三个点。

warpAffine

这个函数用于应用仿射变换。

void warpAffine(
    InputArray src,
    OutputArray dst,
    InputArray M,
    Size dsize,
    int flags = INTER_LINEAR,
    int borderMode = BORDER_CONSTANT,
    const Scalar& borderValue = Scalar()
);

src: 输入图像。
dst: 输出图像。
M: 一个2x3的仿射变换矩阵。
dsize: 输出图像的大小。
flags: 插值方法,默认为INTER_LINEAR。(双线性插值)
borderMode: 边缘填充方式,默认为BORDER_CONSTANT。
borderValue: 如果边缘填充方式为BORDER_CONSTANT,则指定边缘填充的颜色值。

示例代码1

示例代码下面是一个使用OpenCV C++实现仿射变换的示例代码:
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void applyAffineTransform(const Mat &src, Mat &dst, const Mat &M, Size dsize) 
{
	warpAffine(src, dst, M, dsize, INTER_LINEAR, BORDER_CONSTANT, Scalar(0));
}

int main(int argc, char** argv) 
{
	/*if (argc != 2) {
		cout << "Usage: ./AffineTransform <Image Path>" << endl;
		return -1;
	}*/

	// 加载图像
	Mat img = imread("02.png");
	if (!img.data) {
		cout << "Error opening image" << endl;
		return -1;
	}

	// 定义仿射变换矩阵
	Mat M = (Mat_<float>(2, 3) << 
						0.8, -0.2, 0,
						0.2, 0.8, 0);  // 示例变换矩阵

	// 定义输出图像大小
	Size dsize = Size(img.cols, img.rows);

	// 初始化输出矩阵
	Mat transformed;

	// 应用仿射变换
	applyAffineTransform(img, transformed, M, dsize);

	// 显示结果
	namedWindow("Original Image", WINDOW_NORMAL);
	imshow("Original Image", img);
	namedWindow("Transformed Image", WINDOW_NORMAL);
	imshow("Transformed Image", transformed);

	waitKey(0);
	destroyAllWindows();

	return 0;
}


代码解释
1. 加载图像:使用 imread 函数加载图像。
2. 定义仿射变换矩阵:创建一个2x3的矩阵,包含旋转和平移的参数。
3. 定义输出图像大小:保持输出图像大小不变。
4. 初始化输出矩阵:创建一个新的矩阵来存储变换后的图像。
5. 应用仿射变换:使用 warpAffine 函数应用仿射变换。
6. 显示结果:使用 imshow 函数显示原始图像和变换后的图像。

运行结果1

示例代码2

下面是一个简单的示例,展示如何使用OpenCV在C++中进行仿射变换:

#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;


int main()
{
	// 加载图片
	Mat src = imread("01.png");
	if (src.empty()) 
	{
		std::cout << "Could not open or find the image" << std::endl;
		return -1;
	}

	// 定义源图像和目标图像中的点
	Point2f srcTri[] = { Point2f(0, 0), Point2f(src.cols - 1, 0), Point2f(0, src.rows - 1) };
	Point2f dstTri[] = { Point2f(src.cols*0.0, src.rows*0.33),
		Point2f(src.cols*0.85, src.rows*0.25),
		Point2f(src.cols*0.15, src.rows*0.7) };

	// 获取仿射变换矩阵
	Mat warp_mat = getAffineTransform(srcTri, dstTri);

	// 进行仿射变换
	Mat warp_dst;
	warpAffine(src, warp_dst, warp_mat, Size(src.cols, src.rows));

	// 显示结果
	namedWindow("Input", WINDOW_NORMAL);
	imshow("Input", src);
	namedWindow("Output", WINDOW_NORMAL);
	imshow("Output", warp_dst);

	waitKey();
	return 0;
}


在这个示例中,我们定义了源图像和目标图像中的三个点,
通过getAffineTransform得到仿射变换矩阵,
然后使用warpAffine来应用这个变换。


注意事项
在选择变换前后对应的点时,要确保这三个点不是共线的,否则无法构成有效的仿射变换。
根据变换的需求选择合适的插值方法和边缘填充模式,以获得更好的效果。
处理大图像时,注意性能问题,适当的优化可以提高处理速度。

运行结果2

实验代码3

// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 

//全局变量
String src_windowName = "原图像";
String warp_windowName = "仿射变换";
String warp_rotate_windowName = "仿射旋转变换";
String rotate_windowName = "图像旋转";

int main()
{
	Point2f srcTri[3];
	Point2f dstTri[3];

	Mat rot_mat(2, 3, CV_32FC1);
	Mat warp_mat(2, 3, CV_32FC1);
	Mat srcImage, warp_dstImage, warp_rotate_dstImage, rotate_dstImage;

	//加载图像
	srcImage = imread("023.jpeg");

	//判断文件是否加载成功
	if (srcImage.empty())
	{
		cout << "图像加载失败!" << endl;
		return -1;
	}
	else
		cout << "图像加载成功!" << endl << endl;

	//创建仿射变换目标图像与原图像尺寸类型相同
	warp_dstImage = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type());

	//设置三个点来计算仿射变换
	srcTri[0] = Point2f(0, 0);
	srcTri[1] = Point2f(srcImage.cols - 1, 0);
	srcTri[2] = Point2f(0, srcImage.rows - 1);

	dstTri[0] = Point2f(srcImage.cols*0.0, srcImage.rows*0.33);
	dstTri[1] = Point2f(srcImage.cols*0.85, srcImage.rows*0.25);
	dstTri[2] = Point2f(srcImage.cols*0.15, srcImage.rows*0.7);

	//计算仿射变换矩阵
	warp_mat = getAffineTransform(srcTri, dstTri);

	//对加载图形进行仿射变换操作
	warpAffine(srcImage, warp_dstImage, warp_mat, warp_dstImage.size());

	//计算图像中点顺时针旋转50度,缩放因子为0.6的旋转矩阵
	Point center = Point(warp_dstImage.cols / 2, warp_dstImage.rows / 2);
	double angle = -50.0;
	double scale = 0.6;

	//计算旋转矩阵
	rot_mat = getRotationMatrix2D(center, angle, scale);

	//旋转已扭曲图像
	warpAffine(warp_dstImage, warp_rotate_dstImage, rot_mat, warp_dstImage.size());

	//将原图像旋转
	warpAffine(srcImage, rotate_dstImage, rot_mat, srcImage.size());

	//显示变换结果
	namedWindow(src_windowName, WINDOW_NORMAL);
	imshow(src_windowName, srcImage);

	namedWindow(warp_windowName, WINDOW_NORMAL);
	imshow(warp_windowName, warp_dstImage);

	namedWindow(warp_rotate_windowName, WINDOW_NORMAL);
	imshow(warp_rotate_windowName, warp_rotate_dstImage);

	namedWindow(rotate_windowName, WINDOW_NORMAL);
	imshow(rotate_windowName, rotate_dstImage);

	waitKey(0);

	return 0;
}
 

运行结果3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值