6

我正在尝试使用 3D 转换矩阵转换图像并假设我的相机是正交的。

我正在使用 Hartley 和 Zisserman 第 13 章中给出的平面诱导单应性公式 H=Rt*n'/d(d=Inf 所以 H=R)来定义我的单应性。

我感到困惑的是,当我使用相当适度的旋转时,图像的失真似乎比我预期的要大得多(我确定我没有混淆弧度和度数)。

这里可能出了什么问题?

我附上了我的代码和示例输出。

示例输出

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
4

3 回答 3

6

公式H = Rt*n'/d有一个假设,在您的情况下不满足:

此公式意味着您使用的是焦距=1 的针孔相机模型

但是在您的情况下,为了让您的相机更真实并且您的代码能够正常工作,您应该将焦距设置为远大于 1 的某个正数。(焦距是从相机中心到图像平面的距离)

为此,您可以定义一个处理焦距的校准矩阵 K。您只需将公式更改为 H=KR 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)];
于 2015-02-04T20:46:40.463 回答
4

嗯...我不是 100% 了解这些东西,但这是一个有趣的问题并且与我的工作相关,所以我想我会尝试一下。

编辑:我试过一次,没有使用内置插件。那是我原来的答案。然后我意识到你可以很容易地做到这一点:

您的问题的简单答案是使用关于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)。
我通过重做我在图像中心执行ndgrids(放置 0,0,0)的方式来围绕图像的中心旋转。我还决定展示图像的 3 个平面。这不在最初的问题中。中间平面是感兴趣的平面。要获得中间平面,您可以省略零填充并将第三个ndgrid选项重新定义为 just1而不是-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; 

新版本

于 2013-08-21T15:37:26.817 回答
1

您正在围绕x轴执行旋转:在您的矩阵中,旋转矩阵保持第一个分量 (x) 不变。您的示例中的透视变形证实了这一点。

然后,实际变形量将取决于相机和图像平面之间的距离(或更准确地说,取决于其相对于相机焦距的值)。当摄影师图像平面位于相机附近时,这一点可能很重要。

于 2013-08-21T06:37:25.377 回答