在MATLAB中围绕其中心旋转图像矩阵

Kev*_*n91 3 matlab image matrix affinetransform

假设我有一个2x2矩阵,其中填充了代表平面的值.现在我想在"z方向"中以三维方式围绕自身旋转平面.为了更好地理解,请参见下图:

在此输入图像描述

我想知道这是否可以通过一个简单的仿射矩阵,因此我创建了以下简单的脚本:

%Create a random value matrix
A = rand*ones(200,200);

%Make a box in the image
A(50:200-50,50:200-50) = 1;
Run Code Online (Sandbox Code Playgroud)

现在我可以通过这样的旋转矩阵在二维房间中应用变换:

R = affine2d([1 0 0; .5 1 0; 0 0 1])
tform = affine3d(R);
transformed = imwarp(A,tform);
Run Code Online (Sandbox Code Playgroud)

但是,这不会产生上面所需的输出,我不太确定如何创建2-D仿射矩阵来创建这样的行为.

我猜三维仿射矩阵可以做到这一点.但是,如果我定义一个3-D仿射矩阵,我就不能再使用矩阵的二维表示,因为MATLAB会抛出错误:

The number of dimensions of the input image A must be 3 when the
specified geometric transformation is 3-D.
Run Code Online (Sandbox Code Playgroud)

那么如何用仿射矩阵编码所需的输出呢?

gno*_*ice 7

从m3tho答案正确解决您将如何运用你想要的转换:使用fitgeotrans具有'projective'变换,因此要求您指定的4个控制点(即4中的输入和输出的图像对对应点).然后,您可以使用此变换imwarp.

那么,问题在于如何选择这些点来创建所需的变换,在这种情况下,创建透视投影.如下所示,透视投影考虑到观看位置(即"相机")将具有定义圆锥视场的给定视角.通过获取该锥体内的所有3-D点并将它们投影到观察平面上来渲染场景,观察平面是位于摄像机目标处的平面,该平面垂直于连接摄像机及其目标的线.

来自https://www.mathworks.com/help/matlab/visualize/understanding-view-projections.html

让我们首先假设您的图像位于查看平面中,并且角落由标准化参考框架描述,使得它们跨越[-1 1]每个方向.我们需要首先通过选择视角选择我们想要的透视度,然后计算相机和观察平面之间的距离.大约45度的视角可以模仿正常人类视线的透视感,因此使用观察平面的角来定义圆锥视野的边缘,我们可以如下计算摄像机距离:

camDist = sqrt(2)./tand(viewAngle./2);
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用它来为转换生成一组控制点.我们首先对观察平面的角点应用3-D旋转,围绕y轴旋转一定量theta.这将它们旋转出平面,因此我们现在通过从摄像机到每个旋转的角点定义一条线并找到它与平面相交的点,将角点投影回到观察平面.我将免除你的数学推导(你可以自己从上面的链接中的公式实现它们),但在这种情况下,一切都简化为下面的一组计算:

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];
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

你可以像这样应用转换:

tform = fitgeotrans(scaledInP, scaledOutP, 'projective');
outputView = imref2d(s);
newImage = imwarp(oldImage, tform, 'OutputView', outputView);
Run Code Online (Sandbox Code Playgroud)

您可能遇到的唯一问题是旋转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
Run Code Online (Sandbox Code Playgroud)

这是动画:

在此输入图像描述