【问题标题】:Homographic image transformation distortion issue单应图像变换失真问题
【发布时间】:2013-08-20 23:26:16
【问题描述】:

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

我正在使用 Hartley 和 Zisserman 第 13 章中给出的平面诱导单应性公式 H=R-t*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

【问题讨论】:

  • 如果我的回答有帮助,您介意将其标记为答案吗?谢谢。
  • @klurie 你用imagehomog函数得到结果了吗?

标签: matlab computer-vision


【解决方案1】:

公式 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

图像同源程序的结果以及 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)];

【讨论】:

  • 你使用imagehomog显示的图片是60度旋转的?
  • 因为我使用了H,它的值为 60 度。但它在输出端显示了一个小框,而不是这张图片
  • @AadnanFarooqA,我编辑并更正了答案,以便它可以与 imagehomog 一起使用以获得适当的结果。
【解决方案2】:

嗯...我不是 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 选项重新定义为 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; 

【讨论】:

  • 围绕原点(rx,ry)旋转图像:平移(-rx,-ry),旋转,然后平移回(rx,ry)。这些步骤可以单独应用,也可以对矩阵进行预乘。
  • 感谢您花时间看这个,弗雷德里克。我的目标不是绕 z 轴旋转,而是绕 x(或 y)轴旋转,这应该使图像脱离页面平面。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多