同构图像变换失真问题

时间:2013-08-20 23:26:16

标签: matlab computer-vision

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

我使用平面诱导的单应公式H = R-t * n'/ d(d = Inf so H = R)定义我的单应性,如Hartley和Zisserman第13章所述。

我感到困惑的是当我使用相当适度的旋转时,图像似乎比我预期的扭曲得多(我确信我不会混淆弧度和度数)。

这里可能出现什么问题?

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

Example Output

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

3 个答案:

答案 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

您可以在下图中看到结果: enter image description here

您还可以围绕其中心旋转图像。为了实现这一点,您应该将图像平面原点设置为图像的中心,我认为使用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的一些变化如下所示,这看起来更真实。

enter image description here

新设置为:

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); 

rotation image

我现在的问题是:“你如何改变旋转图像的原点?显然,我在左上角左右旋转(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; 

new version

答案 2 :(得分:1)

您正在 x -axis周围执行旋转:在矩阵中,第一个分量(x)保持不变。这可以通过示例中的透视变形来确认。

实际的变形量将取决于相机与图像平面之间的距离(或者更精确地取决于相对于相机焦距的值)。摄像师图像平面位于摄像机附近时非常重要。