6

3D 変換マトリックスを使用して画像を変換しようとしており、カメラが正規直交であると想定しています。

Hartley and Zisserman Chapter 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 のピンホール カメラ モデルを使用していることを意味します。

しかし、あなたのケースでは、カメラをよりリアルにし、コードを機能させるために、焦点距離を 1 よりもはるかに大きい正の数に設定する必要があります (焦点距離は、カメラの中心から画像平面までの距離です)。

これを行うには、焦点距離を処理するキャリブレーション マトリックス K を定義します。数式を H=KR inv(K) - 1/d K t n' inv(K)に変更するだけです 。ここで、K は 3 行 3 列の恒等行列で、対角線に沿った最初の 2 つの要素が焦点に設定されています。長さ (例: 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) を中心に回転しています。

EDIT 2質問者のコメントに応えて、もう一度やり直しました。
今回はいくつか修正しました。元の質問と同じ変換行列 (約 x) を使用しています。画像の中心でs (0,0,0 を入れる) を
やり直すことで、画像の中心を中心に回転しました。ndgridまた、画像の 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; 

新しいバージョン

于 2013-08-21T15:37:26.817 に答える
1

x軸を中心に回転を実行しています。行列では、最初のコンポーネント (x) は回転行列によって変更されません。これは、例の透視変形によって確認されます。

実際の変形量は、カメラとイメージ プレーンの間の距離 (より正確には、カメラの焦点距離に対する値) に依存します。これは、カメラマンのイメージ プレーンがカメラの近くにある場合に重要です。

于 2013-08-21T06:37:25.377 に答える