目录
[1. cv::warpAffine():稠密仿射变换(Dense affine transformations)](#1. cv::warpAffine():稠密仿射变换(Dense affine transformations))
[1.1 参数说明](#1.1 参数说明)
[1.2 C++ 代码](#1.2 C++ 代码)
[1.3 代码说明](#1.3 代码说明)
[1.4 运行结果](#1.4 运行结果)
[2. cv::transform():稀疏仿射变换(Sparse affine transformations)](#2. cv::transform():稀疏仿射变换(Sparse affine transformations))
对于仿射变换,存在两种情况。第一种情况是,我们有一幅图像(或感兴趣区域),我们希望对其进行变换;而第二种情况是,我们有一个点的列表,我们想计算变换结果。这两种情况在概念上非常类似,但就实践实现而言,却非常不同。因此,OpenCV 在处理这两种情况时,分别使用了两个不同的函数。
1. cv::warpAffine():稠密仿射变换(Dense affine transformations)
在第一种情况下,输入输出格式都是图像,而隐含的要求是,该变形(warp)假设变换的像素是底层图像的稠密表示。这意味着,图像变形必须处理插值,以使得输出图像平滑从而看起来自然。而OpenCV 提供的稠密变换函数是 cv::warpAffine(...):
cpp
void cv::warpAffine(
InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags=INTER_LINEAR,
int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
1.1 参数说明
(1) src------输入图像
(2) dst------输出图像
(3) M ------ 一个 2 × 3 变换矩阵
(4) 对于旋转,可以使用函数 cv::getRotationMatrix2D 获得旋转矩阵,而对于一般仿射变换,可以通过提供3对对应点而使用 cv::getAffineTransform 求得变换矩阵。这3对点可以是原图像内的任意3点。
(5) dsize ------输出图像的大小(width,height)。
(6) flags------(内)插值方法(例如,INTER_LINEAR, INTER_NEAREST)的组合及可选项 WARP_INVERSE_MAP 标识。
(7) borderValue------这些设置决定了在变换后,如何填充落在原始图像边界之外的像素。
1.2 C++ 代码
cpp
const char* source_window = "Source image";
const char* warp_window = "Warp";
const char* warp_rotate_window = "Warp + Rotate";
void Test_warpAffine()
{
Point2f srcTri[3];
Point2f dstTri[3];
Mat rot_mat(2, 3, CV_32FC1);
Mat warp_mat(2, 3, CV_32FC1);
Mat src, warp_dst, warp_rotate_dst;
src = imread("D:\\TestVideo\\Flower6-2.jpg", IMREAD_COLOR);
warp_dst = Mat::zeros(src.rows, src.cols, src.type());
srcTri[0] = Point2f(0, 0);
srcTri[1] = Point2f(src.cols - 1.f, 0);
srcTri[2] = Point2f(0, src.rows - 1.f);
dstTri[0] = Point2f(src.cols * 0.0f, src.rows * 0.33f);
dstTri[1] = Point2f(src.cols * 0.85f, src.rows * 0.25f);
dstTri[2] = Point2f(src.cols * 0.15f, src.rows * 0.7f);
warp_mat = getAffineTransform(srcTri, dstTri);
warpAffine(src, warp_dst, warp_mat, warp_dst.size());
Point center = Point(warp_dst.cols / 2, warp_dst.rows / 2);
double angle = -50.0;
double scale = 0.6;
rot_mat = getRotationMatrix2D(center, angle, scale);
warpAffine(warp_dst, warp_rotate_dst, rot_mat, warp_dst.size());
namedWindow(source_window, WINDOW_AUTOSIZE);
imshow(source_window, src);
namedWindow(warp_window, WINDOW_AUTOSIZE);
imshow(warp_window, warp_dst);
namedWindow(warp_rotate_window, WINDOW_AUTOSIZE);
imshow(warp_rotate_window, warp_rotate_dst);
waitKey(0);
}
1.3 代码说明
(1) 将目标图像初始化为与源图像具有相同的大小和类型:
warp_dst = Mat::zeros(src.rows, src.cols, src.type());
(2) 将目标图像初始化为与源图像具有相同的大小和类型:
warp_dst = Mat::zeros(src.rows, src.cols, src.type());
(3) 仿射变换:我们需要两组各包含 3 个点的点集(它们分别定义了两个平行四边形 ),才能推导出仿射变换关系:
srcTri[0] = Point2f(0, 0);
srcTri[1] = Point2f(src.cols - 1.f, 0);
srcTri[2] = Point2f(0, src.rows - 1.f);
dstTri[0] = Point2f(src.cols * 0.0f, src.rows * 0.33f);
dstTri[1] = Point2f(src.cols * 0.85f, src.rows * 0.25f);
dstTri[2] = Point2f(src.cols * 0.15f, src.rows * 0.7f);
(4) 利用这两组点,我们调用 OpenCV 函数 cv::getAffineTransform 来计算仿射变换:
该函数的返回值是一个 2 × 3 矩阵 。本质上,函数 getAffineTransform 中的两个点数组src 和 dst定义了两个平行四边形 。
1.4 运行结果
变换前图像:

仿射变换后的图像(扭曲状):

仿射变换后再绕图像中心旋转后的图像:

2. cv::transform():稀疏仿射变换(Sparse affine transformations)
对于稀疏映射(即单点列表映射),最好使用函数 cv::transform(),其函数原型为:
cpp
void cv::transform(cv::InputArray src, // N × 1 数组(数据通道)
cv::OutputArray dst, // N × 1 数组(数据通道)
cv::InputArray mtx); // 变换矩阵
使用示例 (注意:不同的 OpenCV 版本可能有所差异 ):
cpp
void Test_transform()
{
// 1. Create a set of points (e.g., vertices of a triangle)
std::vector<cv::Point2f> srcPoints = { {0, 0}, {100, 0}, {50, 100} };
std::vector<cv::Point2f> dstPoints;
// 2. Define a 2x3 transformation matrix (Affine)
// This matrix rotates by 45 degrees and translates by (10, 20)
cv::Matx23f transMat(0.707, -0.707, 10,
0.707, 0.707, 20);
// 3. Apply the transformation
cv::transform(srcPoints, dstPoints, transMat);
// Output transformed points
for (const auto& p : dstPoints) {
std::cout << "Point: (" << p.x << ", " << p.y << ")" << std::endl;
}
}