answer from m3tho 正确地说明了您将如何应用所需的转换:使用 fitgeotrans 和 'projective' transform,因此需要您指定 4 个控制点(即 4 对对应点在输入和输出图像中)。然后,您可以使用 imwarp 应用此转换。
那么,问题是如何选择这些点对来创建所需的转换,在本例中是创建perspective projection。如下所示,透视投影考虑到观察位置(即“相机”)将具有定义圆锥视野的给定视角。场景是通过获取该圆锥内的所有 3-D 点并将它们投影到查看平面上来渲染的,该平面位于摄像机目标处,该平面垂直于连接摄像机及其目标的线。
让我们首先假设您的图像位于观察平面中,并且角由标准化参考框架描述,以便它们在每个方向上跨越 [-1 1]。我们需要首先通过选择视角来选择我们想要的透视度,然后计算相机和观察平面之间的距离。 45度左右的视角可以模拟正常人类视线的透视感,因此使用观察平面的角来定义圆锥视野的边缘,我们可以计算相机距离如下:
camDist = sqrt(2)./tand(viewAngle./2);
现在我们可以使用它来为转换生成一组控制点。我们首先将3-D rotation 应用于观察平面的角点,围绕y 轴旋转theta。这会将它们旋转到平面外,因此我们现在通过定义从相机穿过每个旋转角点和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
这是动画: