我正在尝试使用3D变换矩阵变换图像并假设我的相机是正交的。
我使用平面诱导的单应公式H = R-t * n'/ d(d = Inf so H = R)定义我的单应性,如Hartley和Zisserman第13章所述。
我感到困惑的是当我使用相当适度的旋转时,图像似乎比我预期的扭曲得多(我确信我不会混淆弧度和度数)。
这里可能出现什么问题?
我已附上我的代码和示例输出。
n = [0;0;-1];
d = Inf;
im = imread('cameraman.tif');
rotations = [0 0.01 0.1 1 10];
for ind = 1:length(rotations)
theta = rotations(ind)*pi/180;
R = [ 1 0 0 ;
0 cos(theta) -sin(theta);
0 sin(theta) cos(theta)];
t = [0;0;0];
H = R-t*n'/d;
tform = maketform('projective',H');
imT = imtransform(im,tform);
subplot(1,5,ind) ;
imshow(imT)
title(['Rot=' num2str(rotations(ind)) 'deg']);
axis square
end
答案 0 :(得分:5)
公式 H = R-t * n'/ d 有一个假设在您的情况下不符合:
此公式表示您正在使用焦距= 1的针孔相机型号
但是在您的情况下,为了使您的相机更加真实并且您的代码能够正常工作,您应该将焦距设置为远大于1的正数。(焦距是从相机中心到图像的距离)平面)
为此,您可以定义处理焦距的校准矩阵K.您只需将公式更改为 H = K R inv(K) - 1 / d K t n'inv(K) 其中K是3乘3的单位矩阵,其沿对角线的两个第一元素被设置为焦距(例如f = 300)。如果您假设投影相机,可以很容易地推导出公式。
以下是您的代码的更正版本,其中角度是有意义的。
n = [0;0;-1];
d = Inf;
im = imread('cameraman.tif');
rotations = [0 0.01 0.1 30 60];
for ind = 1:length(rotations)
theta = rotations(ind)*pi/180;
R = [ 1 0 0 ;
0 cos(theta) -sin(theta);
0 sin(theta) cos(theta)];
t = [0;0;0];
K=[300 0 0;
0 300 0;
0 0 1];
H=K*R/K-1/d*K*t*n'/K;
tform = maketform('projective',H');
imT = imtransform(im,tform);
subplot(1,5,ind) ;
imshow(imT)
title(['Rot=' num2str(rotations(ind)) 'deg']);
axis square
end
您可以在下图中看到结果:
您还可以围绕其中心旋转图像。为了实现这一点,您应该将图像平面原点设置为图像的中心,我认为使用matlab(maketform)的方法是不可能的。 您可以改用以下方法。
imT=imagehomog(im,H','c');
请注意,如果您使用此方法,则必须更改n,d,t和R中的某些设置以获得适当的结果。 该方法可在以下网址找到:https://github.com/covarep/covarep/blob/master/external/voicebox/imagehomog.m
带有imagehomog的程序的结果以及n,d,t和R的一些变化如下所示,这看起来更真实。
新设置为:
n = [0 0 1]';
d = 2;
t = [1 0 0]';
R = [cos(theta), 0, sin(theta);
0, 1, 0;
-sin(theta), 0, cos(theta)];
答案 1 :(得分:4)
编辑:我曾尝试过一次不使用内置插件。那是我原来的答案。然后我意识到你可以很容易地按照自己的方式去做:
您问题的简单答案是使用关于 z轴的正确旋转矩阵:
R = [cos(theta) -sin(theta) 0;
sin(theta) cos(theta) 0;
0 0 1];
这是另一种方法(我的原始答案):
我要分享我的所作所为;希望这对你有用。我只在2D中做过(虽然这应该很容易扩展到3D)。请注意,如果要在平面中旋转图像,则需要使用当前编码的不同旋转矩阵。您需要围绕 Z轴旋转。
我没有使用那些matlab内置插件。
我在http://en.wikipedia.org/wiki/Rotation_matrix提到了一些信息。
im = double(imread('cameraman.tif')); % must be double for interpn
[x y] = ndgrid(1:size(im,1), 1:size(im,2));
rotation = 10;
theta = rotation*pi/180;
% calculate rotation matrix
R = [ cos(theta) -sin(theta);
sin(theta) cos(theta)]; % just 2D case
% calculate new positions of image indicies
tmp = R*[x(:)' ; y(:)']; % 2 by numel(im)
xi = reshape(tmp(1,:),size(x)); % new x-indicies
yi = reshape(tmp(2,:),size(y)); % new y-indicies
imrot = interpn(x,y,im,xi,yi); % interpolate from old->new indicies
imagesc(imrot);
我现在的问题是:“你如何改变旋转图像的原点?显然,我在左上角左右旋转(0,0)。
编辑2 在回应提问者的评论时,我再次尝试过。
这次我修了几件事。现在我使用与原始问题相同的变换矩阵(约x)。
我通过重做ndgrid
s(放0,0,0)在图像中心的方式绕着图像的中心旋转。我还决定展示图像的3个平面。这不是原来的问题。中间平面是感兴趣的平面。要获得中间平面,您可以省略零填充并将第3 ndgrid
个选项重新定义为1
而不是-1:1
。
im = double(imread('cameraman.tif')); % must be double for interpn
im = padarray(im, [0 0 1],'both');
[x y z] = ndgrid(-floor(size(im,1)/2):floor(size(im,1)/2)-1, ...
-floor(size(im,2)/2):floor(size(im,2)/2)-1,...
-1:1);
rotation = 1;
theta = rotation*pi/180;
% calculate rotation matrix
R = [ 1 0 0 ;
0 cos(theta) -sin(theta);
0 sin(theta) cos(theta)];
% calculate new positions of image indicies
tmp = R*[x(:)'; y(:)'; z(:)']; % 2 by numel(im)
xi = reshape(tmp(1,:),size(x)); % new x-indicies
yi = reshape(tmp(2,:),size(y)); % new y-indicies
zi = reshape(tmp(3,:),size(z));
imrot = interpn(x,y,z,im,xi,yi,zi); % interpolate from old->new indicies
figure;
subplot(3,1,1);imagesc(imrot(:,:,1)); axis image; axis off;
subplot(3,1,2);imagesc(imrot(:,:,2)); axis image; axis off;
subplot(3,1,3);imagesc(imrot(:,:,3)); axis image; axis off;
答案 2 :(得分:1)
您正在 x -axis周围执行旋转:在矩阵中,第一个分量(x)保持不变。这可以通过示例中的透视变形来确认。
实际的变形量将取决于相机与图像平面之间的距离(或者更精确地取决于相对于相机焦距的值)。摄像师图像平面位于摄像机附近时非常重要。