在 MATLAB 中围绕其中心旋转图像矩阵
Rotating an image matrix around its center in MATLAB
假设我有一个 2x2 矩阵,其中填充了代表一个平面的值。现在我想在 "z-Direction" 中以 3-D 方式围绕自身旋转飞机。为了更好地理解,请参见下图:
我想知道这是否可以通过一个简单的仿射矩阵实现,因此我创建了以下简单脚本:
%Create a random value matrix
A = rand*ones(200,200);
%Make a box in the image
A(50:200-50,50:200-50) = 1;
现在我可以简单地通过旋转矩阵在二维房间中应用变换,如下所示:
R = affine2d([1 0 0; .5 1 0; 0 0 1])
tform = affine3d(R);
transformed = imwarp(A,tform);
但是,这不会产生上述所需的输出,我不太确定如何创建二维仿射矩阵来创建此类行为。
我想 3-D 仿射矩阵可以解决问题。但是,如果我定义一个 3-D 仿射矩阵,我将无法再使用该矩阵的 2-D 表示,因为 MATLAB 会抛出错误:
The number of dimensions of the input image A must be 3 when the
specified geometric transformation is 3-D.
那么如何使用仿射矩阵对所需的输出进行编码?
您可以执行投影变换,该投影变换可以使用第一张和第二张图像中角的位置进行估计。
originalP='peppers.png';
original = imread(originalP);
imshow(original);
s = size(original);
matchedPoints1 = [1 1;1 s(1);s(2) s(1);s(2) 1];
matchedPoints2 = [1 1;1 s(1);s(2) s(1)-100;s(2) 100];
transformType = 'projective';
tform = fitgeotrans(matchedPoints1,matchedPoints2,'projective');
outputView = imref2d(size(original));
Ir = imwarp(original,tform,'OutputView',outputView);
figure; imshow(Ir);
这是上面代码的结果:
原图:
转换图像:
correctly addresses how you would apply the transformation you want: using fitgeotrans
with a 'projective'
transform, thus requiring that you specify 4 control points (i.e. 4 pairs of corresponding points in the input and output image). You can then apply this transform using imwarp
.
那么,问题是如何你select这些点对来创建你想要的转换,在这种情况下是创建一个perspective projection.如下所示,透视投影考虑到观察位置(即 "camera")将具有定义圆锥视野的给定视角。通过获取此锥体内的所有 3-D 点并将它们投影到观察平面上来渲染场景,观察平面是位于相机目标处的平面,该平面垂直于连接相机及其目标的线。
让我们首先假设您的图像位于观察平面中,并且角由标准化参考框架描述,因此它们在每个方向上跨越 [-1 1]
。我们需要先 select 通过选择一个视角来获得我们想要的透视度,然后计算相机和观察平面之间的距离。 45度左右的视角可以模拟人正常视觉的透视感,所以用视平面的角定义圆锥视场的边缘,我们可以计算相机距离如下:
camDist = sqrt(2)./tand(viewAngle./2);
现在我们可以使用它来生成一组用于转换的控制点。我们先申请一个3-D rotation to the corner points of the viewing plane, rotating around the y axis by an amount theta
. This rotates them out of plane, so we now project the corner points back onto the viewing plane by defining a line from the camera through each rotated corner point and finding the point where it intersects the plane。我将省去数学推导(您可以从上面链接中的公式自己实现它们),但在这种情况下,一切都简化为以下一组计算:
term1 = camDist.*cosd(theta);
term2 = camDist-sind(theta);
term3 = camDist+sind(theta);
outP = [-term1./term2 camDist./term2; ...
term1./term3 camDist./term3; ...
term1./term3 -camDist./term3; ...
-term1./term2 -camDist./term2];
并且 outP
现在在输出图像中包含标准化的控制点集。给定大小为 s
的图像,我们可以创建一组输入和输出控制点,如下所示:
scaledInP = [1 s(1); s(2) s(1); s(2) 1; 1 1];
scaledOutP = bsxfun(@times, outP+1, s([2 1])-1)./2+1;
您可以像这样应用转换:
tform = fitgeotrans(scaledInP, scaledOutP, 'projective');
outputView = imref2d(s);
newImage = imwarp(oldImage, tform, 'OutputView', outputView);
您可能遇到的唯一问题是旋转 90 度(即从图像平面的端部看)会产生一组共线点,这会导致 fitgeotrans
出错。在这种情况下,从技术上讲,您只需要一张空白图像,因为从侧面看时您看不到二维对象。
下面是一些代码,通过动画旋转图像来说明上述转换:
img = imread('peppers.png');
s = size(img);
outputView = imref2d(s);
scaledInP = [1 s(1); s(2) s(1); s(2) 1; 1 1];
viewAngle = 45;
camDist = sqrt(2)./tand(viewAngle./2);
for theta = linspace(0, 360, 360)
term1 = camDist.*cosd(theta);
term2 = camDist-sind(theta);
term3 = camDist+sind(theta);
outP = [-term1./term2 camDist./term2; ...
term1./term3 camDist./term3; ...
term1./term3 -camDist./term3; ...
-term1./term2 -camDist./term2];
scaledOutP = bsxfun(@times, outP+1, s([2 1])-1)./2+1;
tform = fitgeotrans(scaledInP, scaledOutP, 'projective');
spinImage = imwarp(img, tform, 'OutputView', outputView);
if (theta == 0)
hImage = image(spinImage);
set(gca, 'Visible', 'off');
else
set(hImage, 'CData', spinImage);
end
drawnow;
end
这是动画:
假设我有一个 2x2 矩阵,其中填充了代表一个平面的值。现在我想在 "z-Direction" 中以 3-D 方式围绕自身旋转飞机。为了更好地理解,请参见下图:
我想知道这是否可以通过一个简单的仿射矩阵实现,因此我创建了以下简单脚本:
%Create a random value matrix
A = rand*ones(200,200);
%Make a box in the image
A(50:200-50,50:200-50) = 1;
现在我可以简单地通过旋转矩阵在二维房间中应用变换,如下所示:
R = affine2d([1 0 0; .5 1 0; 0 0 1])
tform = affine3d(R);
transformed = imwarp(A,tform);
但是,这不会产生上述所需的输出,我不太确定如何创建二维仿射矩阵来创建此类行为。
我想 3-D 仿射矩阵可以解决问题。但是,如果我定义一个 3-D 仿射矩阵,我将无法再使用该矩阵的 2-D 表示,因为 MATLAB 会抛出错误:
The number of dimensions of the input image A must be 3 when the
specified geometric transformation is 3-D.
那么如何使用仿射矩阵对所需的输出进行编码?
您可以执行投影变换,该投影变换可以使用第一张和第二张图像中角的位置进行估计。
originalP='peppers.png';
original = imread(originalP);
imshow(original);
s = size(original);
matchedPoints1 = [1 1;1 s(1);s(2) s(1);s(2) 1];
matchedPoints2 = [1 1;1 s(1);s(2) s(1)-100;s(2) 100];
transformType = 'projective';
tform = fitgeotrans(matchedPoints1,matchedPoints2,'projective');
outputView = imref2d(size(original));
Ir = imwarp(original,tform,'OutputView',outputView);
figure; imshow(Ir);
这是上面代码的结果:
原图:
转换图像:
fitgeotrans
with a 'projective'
transform, thus requiring that you specify 4 control points (i.e. 4 pairs of corresponding points in the input and output image). You can then apply this transform using imwarp
.
那么,问题是如何你select这些点对来创建你想要的转换,在这种情况下是创建一个perspective projection.如下所示,透视投影考虑到观察位置(即 "camera")将具有定义圆锥视野的给定视角。通过获取此锥体内的所有 3-D 点并将它们投影到观察平面上来渲染场景,观察平面是位于相机目标处的平面,该平面垂直于连接相机及其目标的线。
让我们首先假设您的图像位于观察平面中,并且角由标准化参考框架描述,因此它们在每个方向上跨越 [-1 1]
。我们需要先 select 通过选择一个视角来获得我们想要的透视度,然后计算相机和观察平面之间的距离。 45度左右的视角可以模拟人正常视觉的透视感,所以用视平面的角定义圆锥视场的边缘,我们可以计算相机距离如下:
camDist = sqrt(2)./tand(viewAngle./2);
现在我们可以使用它来生成一组用于转换的控制点。我们先申请一个3-D rotation to the corner points of the viewing plane, rotating around the y axis by an amount theta
. This rotates them out of plane, so we now project the corner points back onto the viewing plane by defining a line from the camera through each rotated corner point and finding the point where it intersects the plane。我将省去数学推导(您可以从上面链接中的公式自己实现它们),但在这种情况下,一切都简化为以下一组计算:
term1 = camDist.*cosd(theta);
term2 = camDist-sind(theta);
term3 = camDist+sind(theta);
outP = [-term1./term2 camDist./term2; ...
term1./term3 camDist./term3; ...
term1./term3 -camDist./term3; ...
-term1./term2 -camDist./term2];
并且 outP
现在在输出图像中包含标准化的控制点集。给定大小为 s
的图像,我们可以创建一组输入和输出控制点,如下所示:
scaledInP = [1 s(1); s(2) s(1); s(2) 1; 1 1];
scaledOutP = bsxfun(@times, outP+1, s([2 1])-1)./2+1;
您可以像这样应用转换:
tform = fitgeotrans(scaledInP, scaledOutP, 'projective');
outputView = imref2d(s);
newImage = imwarp(oldImage, tform, 'OutputView', outputView);
您可能遇到的唯一问题是旋转 90 度(即从图像平面的端部看)会产生一组共线点,这会导致 fitgeotrans
出错。在这种情况下,从技术上讲,您只需要一张空白图像,因为从侧面看时您看不到二维对象。
下面是一些代码,通过动画旋转图像来说明上述转换:
img = imread('peppers.png');
s = size(img);
outputView = imref2d(s);
scaledInP = [1 s(1); s(2) s(1); s(2) 1; 1 1];
viewAngle = 45;
camDist = sqrt(2)./tand(viewAngle./2);
for theta = linspace(0, 360, 360)
term1 = camDist.*cosd(theta);
term2 = camDist-sind(theta);
term3 = camDist+sind(theta);
outP = [-term1./term2 camDist./term2; ...
term1./term3 camDist./term3; ...
term1./term3 -camDist./term3; ...
-term1./term2 -camDist./term2];
scaledOutP = bsxfun(@times, outP+1, s([2 1])-1)./2+1;
tform = fitgeotrans(scaledInP, scaledOutP, 'projective');
spinImage = imwarp(img, tform, 'OutputView', outputView);
if (theta == 0)
hImage = image(spinImage);
set(gca, 'Visible', 'off');
else
set(hImage, 'CData', spinImage);
end
drawnow;
end
这是动画: