几何变换-平移、镜像、转置
文章目录
图像的几何变换是在不改变图像内容的前提下对图像像素进行相对空间位置移动的一种处理方式,主要包括平移、镜像、转置、缩放和旋转。
1 向前映射与向后映射
1.1 向前映射
图像几何变换用于改变图像中像素与像素之间的空间关系,从而重构图像的空间结构,达到处理图像的目的。图像几何变换就是建立一种源图像像素与变换后图像像素之间的映射关系。通过这种映射关系能够知道源图像任意像素点变换后的坐标,或者变换后图像像素在源图像中的坐标位置,数学描述如下:
{
x
=
U
(
x
0
,
y
0
)
y
=
V
(
x
0
,
y
0
)
\begin{cases} x&=&U(x_{0},y_{0})\\ &&&&\\ y&=&V(x_{0},y_{0})& \end{cases}
⎩⎪⎨⎪⎧xy==U(x0,y0)V(x0,y0)
其中,
x
x
x、
y
y
y表示输出图像像素的坐标,
x
0
x_0
x0、
y
0
y_0
y0表示输入图像像素的坐标,而
U
U
U、
V
V
V表示两种映射关系,通过输入的
x
0
x_0
x0、
y
0
y_0
y0来确定相应的
x
x
x、
y
y
y。
只要给出了图像上任意像素的坐标,都能通过对应的映射关系获得几何变换后的像素坐标位置。这种将输入映射到输出的过程成为向前映射。
通过向前映射能够确定源图像在经过变换后各像素的坐标由于多个输入坐标可以对应同一个输出坐标,所以向前映射是一个满射。
向前映射主要存在以下问题:
- a) 浮点数坐标
数字图像像素坐标是用离散的非负整数表示的,但通过向前映射函数变换后可能产生浮点数的坐标,此时难以确定输出像素的坐标。 - b) 映射不完全和映射重叠
- (1) 映射不完全
映射不完全指输入图像的像素总数小于输出图像的像素总数,这会使得输出图像的部分像素与原始图像没有映射关系。 - (2) 映射重叠
映射重叠指输入图像中的多个像素,经过变换之后对应到输出图像中的同一个位置,此时难以确定输出像素应该使用那个像素值。
- (1) 映射不完全
1.2 向后映射
向后映射的数学表示如下:
{
x
0
=
U
′
(
x
,
y
y
0
=
V
′
(
x
,
y
)
\begin{cases} x_0&=&U^{'}(x,y\\ &&&&\\ y_0&=&V^{'}(x,y)& \end{cases}
⎩⎪⎨⎪⎧x0y0==U′(x,yV′(x,y)
其中,
x
x
x、
y
y
y表示输出图像像素的坐标,
x
0
x_0
x0、
y
0
y_0
y0表示输入图像像素的坐标,而
U
′
U^{'}
U′、
V
′
V^{'}
V′表示两种映射关系,通过输出的
x
x
x、
y
y
y来确定相应的
x
0
x_0
x0、
y
0
y_0
y0。
向后映射与向前映射相反,通过输出图像像素坐标反过来推算该像素在源图像的坐标位置,输出图像的每一个像素都能通过映射找到对应的位置,而不会产生映射不完全和映射重叠的问题。
1.3 适用性
向前映射有效率偏低、映射不完全等缺点,但在一些不改变图像大小的几何变换中,向前映射仍然可用。向后映射主要运用图像的旋转和缩放中,这些几何变换都改变了图像的大小,运用向后映射可以有效的解决大小改变产生的各类映射问题。
2 几何变换的数学描述
由于几何变换都具有统一的形式,可以记为:
[
x
y
1
]
=
[
x
0
y
0
1
]
[
a
1
a
2
0
a
3
a
4
0
a
5
a
6
1
]
[x \space y \space 1]=[x_{0} \space y_{0} \space 1]\begin{bmatrix} a_1&a_2&0\\ a_3&a_4&0\\ a_5&a_6&1\\ \end{bmatrix}
[x y 1]=[x0 y0 1]⎣⎡a1a3a5a2a4a6001⎦⎤
这就是向前映射的矩阵表示法。
[
x
0
y
0
1
]
=
[
x
y
1
]
[
b
1
b
2
0
b
3
b
4
0
b
5
b
6
1
]
[x_0 \space y_0 \space 1]=[x \space y \space 1]\begin{bmatrix} b_1&b_2&0\\ b_3&b_4&0\\ b_5&b_6&1\\ \end{bmatrix}
[x0 y0 1]=[x y 1]⎣⎡b1b3b5b2b4b6001⎦⎤
这是向后映射的矩阵表示。
可以看出,向后映射的矩阵表示正好是向前映射的矩阵表示的逆变换。
3 平移
3.1 平移矩阵
图像的平移变换是将图像中所有像素的坐标分别加上或减去指定的水平偏移量和垂直偏移量,从而使整张图出现位移效果。
设
d
x
dx
dx为水平偏移量,
d
y
dy
dy为垂直偏移量,则平移变换的向后映射关系为:
[ x 0 y 0 1 ] = [ x y 1 ] [ 1 0 0 0 1 0 − d x − d y 1 ] [x_0 \space y_0 \space 1]=[x \space y \space 1]\begin{bmatrix} 1&0&0\\ 0&1&0\\ -dx&-dy&1\\ \end{bmatrix} [x0 y0 1]=[x y 1]⎣⎡10−dx01−dy001⎦⎤
3.2 OpenCV实现
对于图像平移操作,这里我借助OpenCV所提供的进行图像矩阵变换的函数cv::warpAffine
函数来实现,该函数能够根据输入图像和变换矩阵,得出变换后的图像结果。所以,我们将重点放在如何生成变换矩阵上。
void CreateTranslateMatrix(float fXOffset, float fYOffset, cv::Mat& mat)
{
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = 1;
mat.at<float>(0, 2) = -fXOffset; //水平平移量
mat.at<float>(1, 1) = 1;
mat.at<float>(1, 2) = -fYOffset; //竖直平移量
}
//具体使用
cv::Mat mat_translate;
float fXOffset = 5;
float fYOffset = 10;
CreateTranslateMatrix(-50, 100, mat_translate);
cv::Mat res_translate;
cv::warpAffine(srcimg, res_translate, mat_translate, srcimg.size(),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
cv::imshow("res_translate", res_translate);
注意,cv::warpAffine
要求变换矩阵为2×3的矩阵。
将原图向右水平平移50像素,向下垂直平移100像素之后的结果如下图所示。
3.3 Matlab实现
%% 图像平移
xoffset = 100;
yoffset = 50;
res_translate = zeros(size(srcimg));
res_translate = uint8(res_translate);
for i = 1:1:height
for j = 1:1:width
x =j - xoffset;
y = i - yoffset;
if x > 0 && x <=width && y > 0 && y <= height
res_translate(i,j,:)=srcimg(y,x,:);
end
end
end
figure(1),imshow(res_translate);
将原图向右水平平移50像素,向下垂直平移100像素之后的结果如下图所示。
4 镜像
4.1 变换矩阵
图像镜像效果分为水平镜像和垂直镜像,水平镜像是将图像以图像垂直中线为周,将图像的所有像素对换;垂直镜像是将图像以图像水平中线为轴,将图像所有像素对换。
设图像宽度为
w
i
d
t
h
width
width,高度为
h
e
i
g
h
t
height
height,那么图像水平镜像的向前映射关系为
{
x
=
w
i
d
t
h
−
x
0
−
1
y
=
y
0
\begin{cases} x&=&width-x_{0}-1\\ &&&&\\ y&=&y_0& \end{cases}
⎩⎪⎨⎪⎧xy==width−x0−1y0
那么水平镜像的向后映射矩阵表示为:
[
x
0
y
0
1
]
=
[
x
y
1
]
[
−
1
0
0
0
1
0
w
i
d
t
h
−
1
0
1
]
[x_0 \space y_0 \space 1]=[x \space y \space 1]\begin{bmatrix} -1&0&0\\ 0&1&0\\ width-1&0&1\\ \end{bmatrix}
[x0 y0 1]=[x y 1]⎣⎡−10width−1010001⎦⎤
对于垂直镜像,同样可以得到它的变换关系和矩阵表达式:
{
x
=
x
0
y
=
h
e
i
g
h
t
−
y
0
−
1
\begin{cases} x&=&x_{0}\\ &&&&\\ y&=&height-y_0-1& \end{cases}
⎩⎪⎨⎪⎧xy==x0height−y0−1
那么水平镜像的向后映射矩阵表示为:
[
x
0
y
0
1
]
=
[
x
y
1
]
[
1
0
0
0
−
1
0
0
h
e
i
g
h
t
−
1
1
]
[x_0 \space y_0 \space 1]=[x \space y \space 1]\begin{bmatrix} 1&0&0\\ 0&-1&0\\ 0&height-1&1\\ \end{bmatrix}
[x0 y0 1]=[x y 1]⎣⎡1000−1height−1001⎦⎤
4.2 OpenCV实现
//创建水平镜像变换矩阵
void CreateMirrorXMatrix(cv::Mat& img, cv::Mat& mat)
{
int width = img.cols;
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = -1;
mat.at<float>(0, 2) = width-1;
mat.at<float>(1, 1) = 1;
mat.at<float>(1, 2) = 0;
}
//创建垂直镜像变换矩阵
void CreateMirrorYMatrix(cv::Mat& img, cv::Mat& mat)
{
int height = img.rows;
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = 1;
mat.at<float>(0, 2) = 0;
mat.at<float>(1, 1) = -1;
mat.at<float>(1, 2) = height-1;
}
//调用过程如下
cv::Mat mat_XMirror;
CreateMirrorXMatrix(srcimg, mat_XMirror);
cv::Mat res_XMirror;
cv::warpAffine(srcimg, res_XMirror, mat_XMirror, srcimg.size(),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
cv::imshow("res_XMirror", res_XMirror);
cv::Mat mat_YMirror;
CreateMirrorYMatrix(srcimg, mat_YMirror);
cv::Mat res_YMirror;
cv::warpAffine(srcimg, res_YMirror, mat_YMirror, srcimg.size(),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
cv::imshow("res_YMirror", res_YMirror);
4.3 Matlab实现
%% 镜像
res_XMirror =srcimg;
for i = 1:1:width
if i < width-i
temp = res_XMirror(:,i,:);
res_XMirror(:,i,:)=res_XMirror(:,width - i,:);
res_XMirror(:,width - i,:)=temp;
else
break;
end
end
figure(3),imshow(res_XMirror),title('水平镜像结果图');
res_YMirror =srcimg;
for i = 1:1:height
if i < height-i
temp = res_YMirror(i,:,:);
res_YMirror(i,:,:)=res_YMirror(height-i,:,:);
res_YMirror(height-i,:,:)=temp;
else
break;
end
end
figure(4),imshow(res_YMirror),title('垂直镜像结果图');
5 转置
5.1 转置矩阵
图像转置是将图像的横坐标和纵坐标交换位置,转置的操作会使图像的宽度和高度互换。映射矩阵如下:
[
x
0
y
0
1
]
=
[
x
y
1
]
[
0
1
0
1
0
0
0
0
1
]
[x_0 \space y_0 \space 1]=[x \space y \space 1]\begin{bmatrix} 0&1&0\\ 1&0&0\\ 0&0&1\\ \end{bmatrix}
[x0 y0 1]=[x y 1]⎣⎡010100001⎦⎤
5.2 OpenCV实现
两种实现方式,第一种,按照常规套路,创建转置变换矩阵,然后进行变换。注意调用cv::warpAffine
时的第四个参数,该参数指定了输出图像的大小,转置操作需要对原图的长宽互换。
//创建图像转矩矩阵
void CreateTransPositionMatrix(cv::Mat& mat)
{
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = 0;
mat.at<float>(0, 1) = 1;
mat.at<float>(1, 0) = 1;
mat.at<float>(1, 1) = 0;
}
cv::Mat mat_transposition;
CreateTransPositionMatrix(mat_transposition);
cv::Mat res_transposition1;
cv::warpAffine(srcimg, res_transposition1, mat_transposition, cv::Size(srcimg.rows, srcimg.cols),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
第二种,直接将表示图像的矩阵转置。
cv::Mat res_transposition2;
res_transposition2 = srcimg.t();
5.3 Matlab实现
对于多通道图像,无法直接使用MATLAB的转置功能,因此分通道进行转置。
%% 转置
res_transposition = zeros(width,height,3);
res_transposition(:,:,1) = srcimg(:,:,1)';
res_transposition(:,:,2) = srcimg(:,:,2)';
res_transposition(:,:,3) = srcimg(:,:,3)';
res_transposition = uint8(res_transposition);
figure(5),imshow(res_transposition),title('转置结果图');