1

我正在尝试编写自己的使用线性插值的图像旋转函数(参见下面的代码)。在示例 256x256 图像上运行我的代码大约需要 8 秒,即每像素约 0.12 毫秒。在同一张图像上使用双线性插值运行 Matlab 的 imrotate 函数大约需要 0.2 秒,或每像素约 0.003 毫秒 - 大约提高了一百倍。

我猜我缺少一些矢量化优化,但我不知道在哪里。非常感谢任何建议。

代码如下;

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
4

2 回答 2

3

您可以通过键入 using 查看 matlab 使用的函数

edit imrotate

此外,文档说:

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

在这种情况下,Matlab 调用 imrotatemex,即编译为从 Matlab 调用的 C 代码,通常速度更快。我不知道你的形象和系统,所以我不能说这是否正在发生。

您仍然可以通过矢量化来显着加速您的代码。不是循环遍历图像中的每个 x 和 y 值,而是使用 meshgrid 构建包含 x 和 y 的所有组合的数组,并将操作应用于数组。这个 SO 问题包含 matlab 中向量化的最近邻插值旋转的实现:

Matlab的图像旋转而不使用imrotate

于 2014-03-30T08:19:29.153 回答
0

我认为当 MATLAB 使用英特尔的 IPP 库时会发生奇迹:

http://software.intel.com/en-us/intel-ipp

于 2014-04-11T13:24:46.393 回答