|
利用OpenCV的函数warpAffine()做图像的仿射变换【实现图像的平移、缩放、旋转、翻转等操作】
图像的仿射变换是指在直角坐标系中将一个二维坐标转换到另外一个二维坐标的过程。
仿射变换是一种线性变换,可以表示为矩阵相乘与平移过程。
通过仿射变换这种线性变换操作,可以实现图像的平移、缩放、翻转、旋转等变换。
设原始图像的坐标(x,y),经过仿射变换后变为(x’,y’),则仿射变换可表示为下面这个式子:
根据上面的式子,我们可以定义仿射变换矩阵M为下面的矩阵:
从上面仿射变换矩阵M的定义式可以看出,它是一个尺寸为2×3的矩阵。
原图像和目标图像之间的变换关系如下:
对于仿射变换矩阵M,我们既可以根据自己的需要自己计算,也可以利用函数getRotationMatrix2D()和函数getAffineTransform()实现仿射变换矩阵的计算。
得到仿射变换矩阵后,再利用函数warpAffine()实现对图像的仿射变换。
下面介绍上面提到的三个函数。
函数getRotationMatrix2D()可以计算用于图像旋转的的仿射变换矩阵,其原型如下:
- Mat cv::getRotationMatrix2D(Point2f center,
- double angle,
- double scale )
复制代码- retval=cv.getRotationMatrix2D(center, angle, scale)
复制代码
参数意义如下:
center---图像旋转的中心。
angle---图像旋转的角度,单位为度,正值代表逆时针旋转。
scale---沿两条轴的缩放比例,可以实现旋转过程中的图像缩放,如果不需要缩放,则这个参数值取1。
函数getAffineTransform()可以通过仿射变换前后像素坐标的对应关系计算仿射变换矩阵,其原型如下:
- Mat cv::getAffineTransform(const Point2f src[],
- const Point2f dst[] )
复制代码- retval=cv.getAffineTransform(src, dst)
复制代码
参数意义如下:
src—原图像中3个像素的坐标。
dst—目标图像中3个像素的坐标。
函数warpAffine()可以根据输入的仿射变换矩阵实现图像的仿射变换,其原型如下:
- void cv::warpAffine(InputArray src,
- OutputArray dst,
- InputArray M,
- Size dsize,
- int flags = INTER_LINEAR,
- int borderMode = BORDER_CONSTANT,
- const Scalar & borderValue = Scalar() )
复制代码- dst=cv.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
复制代码
参数意义如下:
src—输入图像。
M—尺寸为2×3的仿射变换矩阵。
dsize—输出图像的尺寸。
dst—仿射变换后的图像,与输入图像的数据类型相同,但是尺寸由参数dsize指定。
flags—插值方法和正反变换的标志位。
borderMode—像素边界外推方法的标志,详情见博文 https://www.hhai.cc/thread-178-1-1.html
borderValue—边界填充时的填充值,默认情况下为0。
上面三个函数综合使用示例的Python代码如下:
代码中用到的图像下载链接:
https://pan.baidu.com/s/1Kr12nBJPqcIlAuyFp78gUw?pwd=e5sx
[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
# 出处:昊虹AI笔记网(hhai.cc)
# 用心记录计算机视觉和AI技术
# 博主微信/QQ 2487872782
# QQ群 271891601
# 欢迎技术交流与咨询
# OpenCV的版本为4.4.0
import cv2 as cv
import numpy as np
import sys
if __name__ == '__main__':
# 读取图像并判断是否读取成功
img = cv.imread('F:/material/images/2022/2022-12/view1.jpg')
if img is None:
print('Failed to read img.')
sys.exit()
# 设置图像旋转角度、尺寸、旋转中心参数
angle = 30
h, w = img.shape[0:2] # 这句话也可用三帽号规则的高级写法写成 h, w = img.shape[:-1],相当于用索引-1代替索引2,注意左闭右开规则。
size = (w, h)
center = (w / 2.0, h / 2.0)
# 计算仿射变换矩阵
rotation0 = cv.getRotationMatrix2D(center, angle, 1)
# 进行仿射变换
img_warp0 = cv.warpAffine(img, rotation0, size)
# 根据定义的三个点进行仿射变换
src_points = np.array([[0, 0], [0, h - 1], [w - 1, h - 1]], dtype='float32')
dst_points = np.array([[w * 0.11, h * 0.2], [w * 0.15, h * 0.7], [w * 0.81, h * 0.85]], dtype='float32')
rotation1 = cv.getAffineTransform(src_points, dst_points)
img_warp1 = cv.warpAffine(img, rotation1, size)
# 展示结果
cv.imshow('img_src', img)
cv.imshow('img_warp0', img_warp0)
cv.imshow('img_warp1', img_warp1)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果如下:
上面三个函数综合使用示例的C++代码如下:
代码中用到的图像下载链接:
https://pan.baidu.com/s/1Kr12nBJPqcIlAuyFp78gUw?pwd=e5sx
[C++] 纯文本查看 复制代码
//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术
//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询
//OpenCV版本 OpenCV3.0
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
// 读取图像及验证读入正确
cv::Mat srcImage = cv::imread("F:/material/images/2022/2022-12/view1.jpg");
if (!srcImage.data)
return -1;
cv::imshow("srcImage", srcImage);
int nRows = srcImage.rows;
int nCols = srcImage.cols;
//定义仿射变换的二维点数组
//源图像和目标图像对应映射的三点
cv::Point2f srcPoint[3];
cv::Point2f resPoint[3];
srcPoint[0] = cv::Point2f(0, 0);
srcPoint[1] = cv::Point2f(nCols - 1, 0);
srcPoint[2] = cv::Point2f(0, nRows - 1);
resPoint[0] = cv::Point2f(nCols * 0, nRows*0.33);
resPoint[1] = cv::Point2f(nCols*0.85, nRows*0.25);
resPoint[2] = cv::Point2f(nCols*0.15, nRows*0.7);
// 定义仿射变换矩阵2X3
cv::Mat warpMat(cv::Size(2, 3), CV_32F);
cv::Mat resultImage =
cv::Mat::zeros(nRows, nCols, srcImage.type());
// 计算仿射变换矩阵,即仿射变换的2*3数组
warpMat = cv::getAffineTransform(srcPoint, resPoint);
// 根据仿射矩阵计算图像仿射变换
cv::warpAffine(srcImage, resultImage,
warpMat, resultImage.size());
cv::imshow("resultImage1", resultImage);
// 仿射变换参数设置
cv::Point2f centerPoint = cv::Point2f(nCols / 2, nRows / 2);
double angle = -50;
double scale = 0.7;
// 获取仿射变换矩阵
warpMat = getRotationMatrix2D(centerPoint, angle, scale);
// 对原图像角度仿射变换
cv::warpAffine(srcImage, resultImage,
warpMat, resultImage.size());
cv::imshow("resultImage2", resultImage);
cv::waitKey(0);
}
运行结果如下:
另,把上面C++代码中的代码:
- srcPoint[0] = cv::Point2f(0, 0);
- srcPoint[1] = cv::Point2f(nCols - 1, 0);
- srcPoint[2] = cv::Point2f(0, nRows - 1);
- resPoint[0] = cv::Point2f(nCols * 0, nRows*0.33);
- resPoint[1] = cv::Point2f(nCols*0.85, nRows*0.25);
- resPoint[2] = cv::Point2f(nCols*0.15, nRows*0.7);
复制代码
改为:
- srcPoint[0] = cv::Point2f(0, 0);
- srcPoint[1] = cv::Point2f(nCols-1,0 );
- srcPoint[2] = cv::Point2f(0,nRows-1 );
- resPoint[0] = cv::Point2f(nCols-1,0 );
- resPoint[1] = cv::Point2f(0, 0);;
- resPoint[2] = cv::Point2f(nCols-1,nRows-1);
复制代码
即可实现图像的水平镜像变换,运行结果如下图所示:
延伸阅读:
利用OpenCV的仿射变换函数warpAffine()实现图像的亚像素级平移 |
|