2

MATLABで画像を回転させるコード、つまりimrotateと同等のコードを書こうとしています。行列乗算を使用して、新しい画像を入力画像に逆マッピングします。ただし、同等の方程式を明示的に書き出すよりもはるかに時間がかかります。この乗算を実行するより良い方法はありますか?

変換行列 を置き換えることで他の変換に同じコードを使用できるため、行列乗算を使用することをお勧めしますRT

im1 = imread('file.jpg');
[h, w, p] = size(im1);
theta = -pi/6;
hh = round( h*cos(theta) + w*abs(sin(theta)));
ww = round( w*cos(theta) + h*abs(sin(theta)));

R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
T = [w/2; h/2];
RT = [inv(R) T; 0 0 1];
for z = 1:p
    for x = 1:ww
        for y = 1:hh
            % Using matrix multiplication
            i = zeros(3,1);
            i = RT*[x-ww/2; y-hh/2; 1];

            %Using explicit equations
            %i(1) = ( (x-ww/2)*cos(theta)+(y-hh/2)*sin(theta)+w/2);
            %i(2) = (-(x-ww/2)*sin(theta)+(y-hh/2)*cos(theta)+h/2);

            %% Nearest Neighbour
            i = round(i);
            if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
                im2(y,x,z) = im1(i(2),i(1),z);
            end
        end
    end
end

%Revised code
im1 = imread('file.jpg');
[h, w, p] = size(im1);
theta = (pi)/3;
hh = round(h*abs(cos(theta)) + w*abs(sin(theta)));
ww = round(w*abs(cos(theta)) + h*abs(sin(theta)));
im2 = zeros([hh,ww,p], class(im1));

R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
T = [w/2; h/2];
RT = [inv(R) T; 0 0 1];

x=1:ww;
y=1:hh;

[X, Y] = meshgrid(x,y);
orig_pos = [X(:)' ; Y(:)' ; ones(1,numel(X))];
orig_pos_2 = [X(:)'-(ww/2) ; Y(:)'-(hh/2) ; ones(1,numel(X))];

new_pos = round(RT*orig_pos_2); % Round to nearest neighbour

% Check if new positions fall from map:
valid_pos = new_pos(1,:)>=1 & new_pos(1,:)<=w & new_pos(2,:)>=1 & new_pos(2,:)<=h;

orig_pos = orig_pos(:,valid_pos);
new_pos = new_pos(:,valid_pos);

siz = size(im1);
siz2 = size(im2);

% Expand the 2D indices to include the third dimension.
ind_orig_pos = sub2ind(siz2,orig_pos(2*ones(p,1),:),orig_pos(ones(p,1),:), (1:p)'*ones(1,length(orig_pos)));
ind_new_pos  = sub2ind(siz, new_pos(2*ones(p,1),:), new_pos(ones(p,1),:), (1:p)'*ones(1,length(new_pos)));

im2(ind_orig_pos) = im1(ind_new_pos);
imshow(im2);
4

1 に答える 1

1

for ループをベクトル化する必要がありますが、それほど難しいことではないようです。それはあなたに多くをもたらします。最もトリッキーなのは、位置の計算と、回転後に画像から外れる位置を無視することです。

解決:

x=1:ww
y=1:hh

[X, Y] = meshgrid(x,y);
orig_pos = [X(:)' ; Y(:)' ; ones(1,numel(X))];

new_pos = round(RT*orig_pos); % round to nearest neighbour

% check if new positions fall from map:
valid_pos = new_pos(1,:)>=1 & new_pos(1,:)<=w & new_pos(2,:)>=1 & new_pos(2,:)<=h;

結果の行列への割り当てを for ループで実行して、無視する位置を処理するか、ソース行列からそれらを削除して、割り当てを 1 回で実行できます。

orig_pos = orig_pos(:,valid_pos);
new_pos = new_pos(:,valid_pos);

siz = size(im1);
im2 = zeros(siz,class(im1));

% expand the 2d indices to include the third dimension
ind_orig_pos = sub2ind(siz,orig_pos(2*ones(siz(3),1),:),orig_pos(ones(siz(3),1),:), (1:siz(3))'*ones(1,N));
ind_new_pos  = sub2ind(siz, new_pos(2*ones(siz(3),1),:), new_pos(ones(siz(3),1),:), (1:siz(3))'*ones(1,N));

im2(ind_orig_pos) = im1(ind_new_pos);

im2初期化しないため、必要に応じて実行時に展開されるため、コードもおそらく遅くなります。

参考:「peppers.png」をソース画像として使用すると、このコードブロック全体が私のPCで0.12秒かかり、コードは数分かかりました..最終結果は同じでした.

于 2012-10-10T08:21:48.717 に答える