1

我想寫我自己的圖像旋轉功能,使用線性插值(見下面的代碼)。在示例256x256圖像上運行我的代碼需要大約8秒,或每像素大約0.12ms。在相同的圖像上使用雙線性插值運行Matlab的旋轉函數需要大約0.2秒,或每像素約0.003毫秒 - 大約提高一百倍。Matlab的速度如此之快?

我猜想有一些vectorisation優化,我失蹤,但我不知道在哪裏。任何建議,非常感謝。

下面的代碼;

function [ output ] = rot_input_img_by_angle(input_img, angle) 
%rot_input_img_by_angle Rotates the given image by angle about position 
% Given an image in the format [y, x, c], rotates it by the given angle 
% around the centre of the image 

    if(nargin < 2) 
     error('input_img and angle parameters are both required'); 
    end 

    if(angle == 0) 
     output = input_img; 
     return; 
    end 

    position = [0 0]; 

    [height, width, channels] = size(input_img); 
    num_pixels = height * width; 
    half_width = width/2 - 0.5; 
    half_height = height/2 - 0.5; 

    % Compute the translation vector to move from a top-left origin to a 
    % centred-origin 
    T = [-half_width half_height]'; 

    % A lambda function for creating a 2D rotation matrix 
    rotmat = @(th) [cos(th) -sin(th); sin(th) cos(th)]; 

    % Convert angle to radians and generate rotation matrix R for CR 
    % rotation 
    R = rotmat(deg2rad(angle)); 

    output = zeros(height, width, channels); 

    for y=1:height 

     for x=1:width 

      loc = [x-1 y-1]'; 

      % Transform the current pixel location into the 
      % origin-at-centre coordinate frame 
      loc = loc .* [1; -1] + T; 

      % Apply the inverse rotation mapping to this ouput pixel to 
      % determine the location in the original input_img that this pixel 
      % corresponds to 
      loc = R * loc; 

      % Transform back from the origin-at-centre coordinate frame to 
      % the original input_img's origin-at-top-left frame 
      loc = (loc - T) .* [1; -1] + [1; 1]; 


      if((loc(1) < 1) || (loc(1) > width) || (loc(2) < 1) || (loc(2) > height)) 
       % This pixel falls outside the input_img - leave it at 0 
       continue; 
      end 

      % Linearly interpolate the nearest 4 pixels 
      left_x = floor(loc(1)); 
      right_x = ceil(loc(1)); 
      top_y = floor(loc(2)); 
      bot_y = ceil(loc(2)); 

      if((left_x == right_x) & (top_y == bot_y)) 

       % The sample pixel lies directly on an original input_img pixel 
       output(y, x, :) = input_img(y, x, :); 

      else 

       % The sample pixel lies inbetween several pixels 

       % Location of the nearest 4 pixels 
       px_locs = [left_x right_x left_x right_x; top_y top_y bot_y bot_y]; 

       px_dists = distance(loc, px_locs); 
       px_dists = px_dists ./ sum(px_dists); 

       % Take the linearly interpolated average of each color 
       % channel's value 
       for c=1:channels 
        output(y, x, c) = ... 
         px_dists(1) * input_img(px_locs(1, 1), px_locs(2, 1), c) + ... 
         px_dists(2) * input_img(px_locs(1, 2), px_locs(2, 2), c) + ... 
         px_dists(3) * input_img(px_locs(1, 3), px_locs(2, 3), c) + ... 
         px_dists(4) * input_img(px_locs(1, 4), px_locs(2, 4), c); 
       end 
      end 

     end 

    end 

    output = cast(output, class(input_img)); 


end 
+0

的緩慢最有可能是由於嵌套的for循環,在內部循環中運行大量代碼(創建變量,計算矩陣,評估函數,if語句分支等)。我猜想Matlab的'imrotate'大部分速度是由於使用優化的編譯代碼(在'mex'函數中)。如果你真的想改進你的代碼,運行Matlab分析器來找出什麼是最慢的部分。然而,如果你的目標是速度,你可能會開心地使用內置的'imrotate'。 – nibot

回答

3

你可以看到通過使用

edit imrotate 

而且輸入功能的MATLAB使用,該文件說:

% Performance Note 
% ---------------- 
% This function may take advantage of hardware optimization for datatypes 
% uint8, uint16, and single to run faster. 

matlab在這種情況下調用imrotatemex,那就是有C代碼被編譯爲從Matlab調用,並且通常更快。我不知道你的形象和系統,所以我不能說這是否發生。

您仍然可以通過矢量化來顯着加速代碼。除了循環遍歷圖像中的每個x和y值,還可以使用meshgrid構建包含x和y的所有組合的數組,並將操作應用於數組。這太問題包括最近鄰插值旋轉的MATLAB的實現,是矢量化:

Image rotation by Matlab without using imrotate