0

Sorry for my bad English.

I'm learning Matlab for image processing so I tried to clone the default "imrotate" function.

The first version I wrote involved using for-loop to traverse the whole matrix so it's very very slow.

Then I read this thread: Image rotation by Matlab without using imrotate and try to vectorize my program and it became "much" faster.

But it is still very slow compared to the default imrotate implementation consuming more than 1 second to rotate the image(resolution is 1920x1080), while the default implementation do the job in less than 50 millisecond.

So I wonder there would be still something wrong with my code or it is "normal" in matlab? Here is my code:

(P.S. there is some ugly code (value11=...;value12=...value21=...) because I am not familiar with Matlab and unable to figure out shorter code not using loop.

function result=my_imRotate(image,angel,method)
    function result=my_imRotateSingleChannel(image,angel,method)
        angel=-angel/180*pi; %transform the angel from deg to rad
        [height,width]=size(image); %get the image size
        trMatrix=[cos(angel),-sin(angel);sin(angel),cos(angel)]; %the transformation matrix
        imgSizeVec=[width,height;width,-height]; %the "size vector" to be transformed to caluclate the new size
        newImgSizeVec=imgSizeVec*trMatrix;
        newWidth=ceil(max(newImgSizeVec(:,1)));
        newHeight=ceil(max(newImgSizeVec(:,2))); %caluculate the new size
        [oldX,oldY]=meshgrid(1:newWidth,1:newHeight);
        oldX=oldX-newWidth/2;
        oldY=oldY-newHeight/2;
        temp=[oldX(:) oldY(:)]*trMatrix;
        oldX=temp(:,1);
        oldY=temp(:,2);
        oldX=oldX+width/2;
        oldY=oldY+height/2;
        switch(method)
        case 'nearest'
            oldX=round(oldX);
            oldY=round(oldY);
            condition=( oldX>=1 & oldX<=width & oldY>=1 & oldY<=height );
            result(condition)=image((oldX(condition)-1)*height+oldY(condition));
            result(~condition)=0;
            result=reshape(result,newHeight,newWidth);
        case 'bilinear'
            x1=floor(oldX);
            x2=x1+1;
            y1=floor(oldY);
            y2=y1+1;
            condition11=(x1>=1&x1<=width&y1>=1&y1<=height);
            condition12=(x1>=1&x1<=width&y2>=1&y2<=height);
            condition21=(x2>=1&x2<=width&y1>=1&y1<=height);
            condition22=(x2>=1&x2<=width&y2>=1&y2<=height);
            value11(condition11)=double(image((x1(condition11)-1)*height+y1(condition11)));
            value12(condition12)=double(image((x1(condition12)-1)*height+y2(condition12)));
            value21(condition21)=double(image((x2(condition21)-1)*height+y1(condition21)));
            value22(condition22)=double(image((x2(condition22)-1)*height+y2(condition22)));
            value11(~condition11)=0;
            value12(~condition12)=0;
            value21(~condition21)=0;
            value22(~condition22)=0;
            result=uint8(value22.'.*(oldX-x1).*(oldY-y1)+value11.'.*(x2-oldX).*(y2-oldY)+value21.'.*(oldX-x1).*(y2-oldY)+value12.'.*(x2-oldX).*(oldY-y1));
            result=reshape(result,newHeight,newWidth);
        otherwise
            disp('Sorry, unsupported algorithm. Only nearest/bilinear is supported.');
        end
    end
    imageInfo=size(image);
    imageType=size(imageInfo);
    if(imageType(2)==2)
        result=my_imRotateSingleChannel(image,angel,method);
    elseif(imageType(2)==3&&imageInfo(3)==3)
        temp=my_imRotateSingleChannel(image(:,:,1),angel,method);
        [newHeight,newWidth]=size(temp);
        result=temp(:);
        temp=my_imRotateSingleChannel(image(:,:,2),angel,method);
        result=[result temp(:)];
        temp=my_imRotateSingleChannel(image(:,:,2),angel,method);
        result=[result temp(:)];
        result=reshape(result,newHeight,newWidth,3);
    else
        disp('Sorry, unsupported input matrix. Only grey/rgb image is supported.');
    end
end
Community
  • 1
  • 1
littleTan
  • 1
  • 1

2 Answers2

1

The bulk of the work in imrotate is done by the internal imrotatemex command, which is implemented in compiled C code.

Sam Roberts
  • 23,951
  • 1
  • 40
  • 64
  • Thank you , but is the 20x slow down normal? – littleTan Mar 24 '14 at 16:53
  • I'm afraid I haven't closely looked through your MATLAB code. There may well be inefficiencies in it that prevent it from being as fast as the fastest MATLAB implementation. But there's no reason that a C implementation, which is compiled, couldn't itself be 20x faster than a MATLAB implementation, which is interpreted (although the JIT compiler should speed that up). Although @Shai makes a good suggestion to use the profiler to check where the bottlenecks are, be careful, as using the profiler disables many JIT optimisations. – Sam Roberts Mar 24 '14 at 17:04
0

Your code creates numerous temporary arrays that are as big as the original image. This is typical of vectorized Matlab code. Memory allocation takes a little bit of time but nothing close to 1sec. I'm guessing the main issue is that each new array is not in the cache, so you are constantly reading and writing from "cold" main memory. In comparison, the compiled C code uses a for loop, probably similar to your original implementation, keeping all the necessary data in CPU registers or on the stack, performing much better with the cache.

But @Shai is right - you should profile and find out which parts are slow. 1 second sounds too slow for rotating an HD image.

japreiss
  • 11,111
  • 2
  • 40
  • 77