图像变换
调整图像尺寸,翻转,旋转
图像拼接
将两个具有相同高度或宽度的图像连接一起,
纵向拼接
void cv::vconcat ( const Mat * src, // 存放Mat类型的数组,列数相同,数据类型通道数相同
size_t nsrc, // 数组中含有的Mat类型的数目,
OutputArray dst // 输出结果
)
void cv::vconcat ( InputArray src1, // 对两个Mat类型的数据进行连接。
InputArray src2,
OutputArray dst
)
横向拼接
void cv::hconcat ( const Mat * src,
size_t nsrc,
OutputArray dst
)
void cv::hconcat ( InputArray src1, //
InputArray src2,
OutputArray dst
)
using namespace std;
using namespace cv;
int main()
{
//矩阵数组的横竖连接
Mat matArray[] = { Mat(1, 2, CV_32FC1, cv::Scalar(1)),
Mat(1, 2, CV_32FC1, cv::Scalar(2)) };
Mat vout, hout;
vconcat(matArray, 2, vout);
cout << "图像数组竖向连接:" << endl << vout << endl;
hconcat(matArray, 2, hout);
cout << "图像数组横向连接:" << endl << hout << endl;
//矩阵的横竖拼接
Mat A = (cv::Mat_<float>(2, 2) << 1, 7, 2, 8);
Mat B = (cv::Mat_<float>(2, 2) << 4, 10, 5, 11);
Mat vC, hC;
vconcat(A, B, vC);
cout << "多个图像竖向连接:" << endl << vC << endl;
hconcat(A, B, hC);
cout << "多个图像横向连接:" << endl << hC << endl;
//读取4个子图像,00表示左上角、01表示右上角、10表示左下角、11表示右下角
Mat img00 = imread("lena00.png");
Mat img01 = imread("lena01.png");
Mat img10 = imread("lena10.png");
Mat img11 = imread("lena11.png");
if (img00.empty() || img01.empty() || img10.empty() || img11.empty())
{
cout << "请确认图像文件名称是否正确" << endl;
return -1;
}
//显示4个子图像
imshow("img00", img00);
imshow("img01", img01);
imshow("img10", img10);
imshow("img11", img11);
//图像连接
Mat img, img0, img1;
//图像横向连接
hconcat(img00, img01, img0);
hconcat(img10, img11, img1);
//横向连接结果再进行竖向连接
vconcat(img0, img1, img);
//显示连接图像的结果
imshow("img0", img0);
imshow("img1", img1);
imshow("img", img);
waitKey(0);
return 0;
}
尺寸变换
改变长和宽,实现图像的缩放。
void cv::resize ( InputArray src,
OutputArray dst,
Size dsize, // 输出图像的尺寸
double fx = 0, // 水平的比例因子,两倍就是2
double fy = 0, // 以dsize为准
int interpolation = INTER_LINEAR // 插值方法
)
缩小图像,用INTER_AREA , 放大图像 INTER_CUBIC OR INTER_LINEAR。
void cv::flip(InputArray src, // 图像翻转
OutputArray dst,
int flipCode // 大于0 ,y轴翻转 ,等于0 x轴翻转, 小于0两个轴翻转
}
using namespace std;
using namespace cv;
int main()
{
Mat gray = imread("lena.png", 0);
Mat smallImg, bigImg0, bigImg1, bigImg2;
resize(gray, smallImg, Size(15, 15), 0, 0, INTER_AREA); // 先缩小
resize(smallImg, bigImg0, Size(30, 30), 0, 0, INTER_NEAREST); //最近邻差值
resize(smallImg, bigImg1, Size(30, 30), 0, 0, INTER_LINEAR); //双线性差值
resize(smallImg, bigImg2, Size(30, 30), 0, 0, INTER_CUBIC); //双三次差值
namedWindow("smallImg", 0); //图像尺寸太小,一定要设置可以调节窗口大小标志
imshow("smallImg", smallImg);
namedWindow("bigImg0", 0);
imshow("bigImg0", bigImg0);
namedWindow("bigImg1", 0);
imshow("bigImg1", bigImg1);
namedWindow("bigImg2", 0);
imshow("bigImg2", bigImg2);
Mat img_x, img_y, img_xy;
flip(gray, img_x, 0); // 图像翻转,x, y, xy轴对称
flip(gray, img_y, 1);
flip(gray, img_xy, -1);
imshow("img_xy", img_xy);
waitKey(0);
return 0;
}
图像放射变换
图像的旋转,通过仿射实现。首先确定旋转角度和中心,确定旋转矩阵,进行仿射变换。
Mat cv::getRotationMatrix2D ( Point2f center, // 旋转中心位置
double angle, // 角度,单位度,正值逆时针旋转
double scale // 两个轴的比例因子,实现图像的缩放
) // 返回旋转矩阵,Mat类型
得到旋转矩阵后,通过warpAffine() 函数进行仿射变换,实现旋转。
void cv::warpAffine ( InputArray src,
OutputArray dst, // 结果图,类型与输入相同,尺寸与dsize相同
InputArray M, // 得到的旋转矩阵
Size dsize,
int flags = INTER_LINEAR, // 插值方式
int borderMode = BORDER_CONSTANT, //像素边界外推方式
const Scalar & borderValue = Scalar() // 填充边界的值,默认0
)
仿射变换就是旋转,平移,缩放操作的总称,可以表示为线性变换和平移变换的叠加。数学表达就是先乘以一个线性变换矩阵(2 X 2),然后加上一个平移向量(2X1)。所以输入一个(2X3)的变换矩阵。
M
=
[
A
B
]
=
∣
a
00
a
01
b
00
a
10
a
11
b
10
∣
像
素
值
[
x
,
y
]
T
T
=
A
[
x
y
]
+
B
M = [A\quad B]= \left\vert\begin{matrix} a_{00} & a_{01} & b_{00} \\ a_{10} & a_{11} & b_{10} \end{matrix} \right\vert 像素值[x,y]^T \qquad T = A\left[\begin{matrix}x\\y\end{matrix}\right] + B
M=[AB]=∣∣∣∣?a00?a10??a01?a11??b00?b10??∣∣∣∣?像素值[x,y]TT=A[xy?]+B
如果知道变换后两幅图像中3个像素点坐标的对应关系,就可以求得变换矩阵M,getAffineTransform()利用三个对应的像素点确定M。
Mat cv::getAffineTransform ( const Point2f src[], // 原图像的3个像素坐标,与顺序无关
const Point2f dst[]
)
int main()
{
Mat img = imread("lena.png");
Mat rotation0, rotation1, img_warp0, img_warp1;
double angle = 30; //设置图像旋转的角度
Size dst_size(img.rows, img.cols); //设置输出图像的尺寸
Point2f center(img.rows / 2.0, img.cols / 2.0); //设置图像的旋转中心
rotation0 = getRotationMatrix2D(center, angle, 1); //计算放射变换矩阵
warpAffine(img, img_warp0, rotation0, dst_size); //进行仿射变换
imshow("img_warp0", img_warp0);
//根据定义的三个点进行仿射变换
Point2f src_points[3];
Point2f dst_points[3];
src_points[0] = Point2f(0, 0); //原始图像中的三个点,三个角
src_points[1] = Point2f(0, (float)(img.cols - 1));
src_points[2] = Point2f((float)(img.rows - 1), (float)(img.cols - 1));
dst_points[0] = Point2f((float)(img.rows)*0.11, (float)(img.cols)*0.20); //放射变换后图像中的三个点
dst_points[1] = Point2f((float)(img.rows)*0.15, (float)(img.cols)*0.70);
dst_points[2] = Point2f((float)(img.rows)*0.81, (float)(img.cols)*0.85);
rotation1 = getAffineTransform(src_points, dst_points); //根据对应点求取仿射变换矩阵
warpAffine(img, img_warp1, rotation1, dst_size); //进行仿射变换
imshow("img_warp1", img_warp1);
waitKey(0);
return 0;
}
透视变换
将物体投影到新的平面。透视前后的变换关系可以使用一个 3X3 的变换矩阵表示,这个矩阵可以通过两幅图像中4 个对应点的坐标求取。getPerspectiveTransform() warpPerspective() 分别用于获取矩阵,进行透视变换。
Mat cv::getPerspectiveTransform ( const Point2f src[],
const Point2f dst[],
int solveMethod = DECOMP_LU // 默认就行
)
void cv::warpPerspective ( InputArray src,
OutputArray dst,
InputArray M, // 3X3的变换矩阵
Size dsize, // 输出图像的尺寸
int flags = INTER_LINEAR, // 与仿射参数一样
int borderMode = BORDER_CONSTANT,
const Scalar & borderValue = Scalar()
)
Point2f src_points[4];
Point2f dst_points[4];
//通过Image Watch查看的二维码四个角点坐标
src_points[0] = Point2f(94.0, 374.0);
src_points[1] = Point2f(507.0, 380.0);
src_points[2] = Point2f(1.0, 623.0);
src_points[3] = Point2f(627.0, 627.0);
//期望透视变换后二维码四个角点的坐标
dst_points[0] = Point2f(0.0, 0.0);
dst_points[1] = Point2f(627.0, 0.0);
dst_points[2] = Point2f(0.0, 627.0);
dst_points[3] = Point2f(627.0, 627.0);
Mat rotation, img_warp;
rotation = getPerspectiveTransform(src_points, dst_points); //计算透视变换矩阵
warpPerspective(img, img_warp, rotation, img.size()); //透视变换投影
极坐标变换
直角坐标系和极坐标系中的变换,可以将一个圆形图像变成一个矩形图像。可以处理钟表,圆盘等,圆形图案边缘上的文字经过极坐标变换后可以垂直的排列在新图像的边缘,便于对文字进行识别和检测。
void cv::warpPolar ( InputArray src,
OutputArray dst,
Size dsize,
Point2f center, // 极坐标的原点坐标
double maxRadius, // 变换时边界圆的半径,决定了逆变换时的比例参数
int flags // 插值方法,与极坐标映射方法标志,两个方法通过+ |连接
)
int main()
{
Mat img = imread("dial.png");
Mat img1, img2;
Point2f center = Point2f(img.cols / 2, img.rows / 2); //极坐标在图像中的原点
//正极坐标变换
warpPolar(img, img1, Size(300, 600), center, center.x, INTER_LINEAR + WARP_POLAR_LINEAR);
//逆极坐标变换
warpPolar(img1, img2, Size(img.rows, img.cols), center, center.x,
INTER_LINEAR + WARP_POLAR_LINEAR + WARP_INVERSE_MAP);
imshow("原表盘图", img);
imshow("表盘极坐标变换结果", img1);
imshow("逆变换结果", img2);
waitKey(0);
return 0;
}
|