Matlab image translation matrix - matlab

I'm very new to Matlab. I'm learning some image manipulation basics, and I'm a bit confused on how to write a translation without using imtranslate.
this is my code but it just displays a black background. Thank you.
img = imread('name2.png');
figure(1);
% pixel matrix
[orig_x, orig_y,z] = size(img);
final_x = 600;
final_y = 600;
% define the final array with calculated dimensions and fill the array with zeros ie.,black
final_img = uint8(zeros([final_x final_y 3 ]));
for i = 1 : size(final_img, 1)
for j = 1 : size(final_img, 2)
new_x = img(i) + 5;
new_y = img(j) + 5;
% fprintf('X: %f\n',new_x); % prints 255
final_img(i) = new_x;
final_img(j) = new_y;
end
end
imshow(final_img);

This is one solution for 'translation only' transformation.
I = imread('Lenna.png');
shiftX = 5; % shift columns
shiftY = 5; % shift rows
% Assigning empty matrix for result, expected to be shiftX-1 larger in rows and shiftY-1 larger in columns
nI = uint8( zeros(size(I,1)+shiftY-1, size(I,2)+shiftX-1, size(I,3));
% Translate
nI(shiftY:end, shiftX:end, :) = I;
imshow(nI)
Now the image will start from (x,y) = (5,5) instead of (1,1). Also note that in matlab image coordinate system, x and y axis start from upper left corner (documentation).

final_img:
You've defined "final_img" with new x and new y but you haven't replaced the zeros in the red/green/blue values. It's all black because of your initialisation filling the final_img with all zeros.
Maybe try this instead of what you've written:
%{
[X,map] = imread('name2.png');
figure(1);
% X should be 600 by 600
%Translate X however you wish, e.g.:
X = X +5;
%Verify that the colormap, map, is not empty, and convert
%the data in X to RGB and store as your final_img.
if ~isempty(map)
final_img = ind2rgb(X,map);
end
%}
I am also not sure if you want to be indexing img with just a single i without the the other dimensions like you have:
new_x = img(i) + 5;
?

For the problems in your specific code, I wrote in the comments some of them.
A short way to achieve image translation is by 2D convolution with a filter of zeros and just one 1, that will preserve the values of the image, but relocate them according to the size of the filter and the position of the 1 in it.
That seems you want to move the image but preserve the size of the total image, if I get it right. So:
r=3; c=5; % number of rows and columns to move
filt=zeros(r*2+1, c*2+1); filt(end)=1; % the filetr
img2=conv2(img,filt,'same'); % the translated image
Just for the example, lets translate "cameraman" with 20 rows and columns:
img=imread('cameraman.tif');
imshow(img)
r=20; c=20;
filt=zeros(r*2+1, c*2+1); filt(end)=1;
img2=conv2(img,filt,'same');
figure; imshow(img2,[])

Related

Convert Matlab code into Simulink

I would like to convert a image processing program(part of the program below) from Matlab to Simulink and possibly convert the simulink diagram into C code later on. I have 0 experience in Simulink and was wondering if there's any limitations on the types of matlab program/functions that can be converted and how I would go about doing this. Thanks.
clear all
clc
% Read in an image 1
C1 = imread('cloud1.jpg');
Cloud1 = C1(:,:,1); % use only one color
%Cloud1 = Cloud1'; % transpose to get (x,y) instead of (y,x)
Cloud1_xsize = size(Cloud1,2); % get x size of image
Cloud1_ysize = size(Cloud1,1); % get y size of image
%figure(3), imshow(Cloud1) % to plot you need to transpose back to their coordinate system
%hold on
% Read in an image 2
C2 = imread('cloud2.jpg');
Cloud2 = C2(:,:,1); % use only one color
%Cloud2 = Cloud2'; % transpose to get (x,y) instead of (y,x)
Cloud2_xsize = size(Cloud2,2); % get x size of image
Cloud2_ysize = size(Cloud2,1); % get y size of image
%figure(2), imshow(Cloud2)
%hold on
% show the shift in the initial images several times
num = 0;
for k = 1:4
num=num+1;
pause(.5)
figure(1), h1=imshow(C1)
xlabel('FIGURE 1')
F(num) = getframe(gcf);
%image(F.cdata)
%colormap(F.colormap)
pause(0.25)
figure(1), h2=imshow(C2)
xlabel('FIGURE 2')
num=num+1;
F(num) = getframe(gcf);
%image(F.cdata)
%colormap(F.colormap)
end
% Play the movie twenty times
%movie(F,20)
%%%% Set the template size %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% First calc the number of pixels in the shortest direction of the image (usually y direction)
MinSize = min(Cloud1_xsize, Cloud1_ysize); % number of pixels in shortest direction
%%% N is the minimum number of boxes in the shorter direction (usually y direction).
%%% In the shorter axis (usually y)there will be N-2 boxes analyzed.
%%% This is because the top and bottom boxes are considered too close to the edge to use.
%%% In the larger direction (usually x) there may be more boxes.
N = 6;
EdgeBoxSize = 1; % the number of edge boxes along each edge
TempWidth = floor(MinSize / N); % the pixel width of each template box
TempHeight = TempWidth; % make the template height and width the same size so corr part works good
%%% Now calculate the exact number of boxes in x and y directions
%%% This depends on the number of x versus y pixels.
Nx = floor(Cloud1_xsize/TempWidth);
Ny = floor(Cloud1_ysize/TempWidth);

How can i render lineseries/contour/etc objects to array of pixel data?

I have an array of pixel data frames for use with VideoWriter. I want to overlay lineseries/contour objects into each frame. I don't want to make the movie by iteratively drawing each frame to a figure and capturing it with getframe, because that gives poor resolution and is slow. I tried using getframe on a plot of just the contour, but that returns images scaled to the wrong size with weird margins, especially when using 'axis equal,' which I need.
Updated to accommodate feedback from OP
Getting the contour data as pixel data is not trivial (if possible at all) since using getframe doesn't yield predictable results
What we can do is to extract the contour data and then overlay it on the pixel data frames, forcing them to be to the same scale and then do a getframe on the resultant merged image. This will at least ensure that they two data sets area aligned.
The following code shows the principle though you'd need to modify it for your own needs:
%% Generate some random contours to use
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
[~,h] = contour(X,Y,Z);
This yields the following contours
Now we get the handles of the children of this image. These will all be 'patch' type objects
patches = get(h,'Children');
Also get the axis limits for the contours
lims = axis;
Next, create a new figure and render the pixel frame data into it
In this example I'm just loading an image but you get the idea.
%% Render frame data
figure
i = imread( some_image_file_png );
This image is actually 194 x 259 x 3. I can display it and rescale the X and Y axes using
%% Set image axes
image(flipdim(i,1),'XData',[lims(1) lims(2)],'YData',[lims(4) lims(3)]);
Note the use of flipdim() to vertically flip the image since the image Y-axis runs in the opposite sense to the contour Y axis. This gives me:
Now I can plot the contours (patches) form the contour plot over the top of the image in the same coordinate space
%% Plot patches
for p =1:length(patches)
xd = get( patches(p), 'XData' );
yd = get( patches(p), 'YData' );
% This causes all contours to be rendered in white. You may
% want to play with this a little
cd = zeros(size(xd));
patch( xd, yd, cd, 'EdgeColor', 'w');
end
This yields
You can now use getframe to extract the frame. If it's important to have coloured contours, you will need to extract colour data from the original contour map and use it to apply an appropriate colouring in the overlaid image.
As a short cut, it's also possible to compile all patch data into a single MxN matrix and render with a single call to patch but I wrote it this way to demonstrate the process.
Well, here's a Bresenham-esque solution based on the ContourMatrix. Not ideal cuz doesn't handle line width, antialiasing, or any more than a single color. But it's pretty efficient (not quite Bham efficient).
function renderContour
clc
close all
x = randn(100,70);
[c,h] = contour(x,[0 0],'LineColor','r');
axis equal
if ~isnumeric(h.LineColor)
error('not handled')
end
cs = nan(size(c,2),4);
k = 0;
ci = 1;
for i = 1:size(c,2)
if k <= 0
k = c(2,i);
else
if k > 1
cs(ci,:) = reshape(c(:,i+[0 1]),[1 4]);
ci = ci + 1;
end
k = k - 1;
end
end
pix = renderLines(cs(1:ci-1,:),[1 1;fliplr(size(x))],10,h.LineColor);
figure
image(pix)
axis equal
end
function out = renderLines(cs,rect,res,color)
% cs = [x1(:) y1(:) x2(:) y2(:)]
% rect = [x(1) y(1);x(2) y(2)]
% doesnt handle line width, antialiasing, etc
% could do those with imdilate, imfilter, etc.
test = false;
if test
if false
cs = [0 0 5 5; 0 5 2.5 2.5];
rect = [0 0; 10 10];
else
cs = 100 * randn(1000,4);
rect = 200 * randn(2);
end
res = 10;
color = [1 .5 0];
end
out = nan(abs(res * round(diff(fliplr(rect)))));
cs = cs - repmat(min(rect),[size(cs,1) 2]);
d = [cs(:,1) - cs(:,3) cs(:,2) - cs(:,4)];
lens = sqrt(sum(d.^2,2));
for i = 1:size(cs,1)
n = ceil(sqrt(2) * res * lens(i));
if false % equivalent but probably less efficient
pts = linspace(0,1,n);
pts = round(res * (repmat(cs(i,1:2),[length(pts) 1]) - pts' * d(i,:)));
else
pts = round(res * [linspace(cs(i,1),cs(i,3),n);linspace(cs(i,2),cs(i,4),n)]');
end
pts = pts(all(pts > 0 & pts <= repmat(fliplr(size(out)),[size(pts,1) 1]),2),:);
out(sub2ind(size(out),pts(:,2),pts(:,1))) = 1;
end
out = repmat(flipud(out),[1 1 3]) .* repmat(permute(color,[3 1 2]),size(out));
if test
image(out)
axis equal
end
end

Sorting two column vectors into 3D matrix based on position

Using the imfindcircles function in MATLAB to track circles in two images. I start with approximately a grid of circles which deforms. I am trying to sort the two column vector from imfindcircles into matrices so that neighbouring circles are neighbouring elements in the matrices. The first image the circles conform to a grid and the following code works:
[centXsort,IX] = sortrows(centres1,1); %sort by x
centYsort =zeros(289,2); %preallocate
for i = 1:17:289
[sortedY,IY] = sortrows(centXsort(i:i+16,:),2); %sort by y within individual column
centYsort(i:i+16,:) = sortedY;
end
cent1mat = reshape(centYsort,17,17,2); %reshape into centre matrices
This doesn't work for the second image as some of the circles overlap in the x or y direction, but neighbouring circles never overlap. This means that in the second set of matrices the neighbouring circles aren't neighbouring elements after sorting.
Is there a way to approximate a scatter of points into a matrix?
This answer doesn't work in every single case, but it seems good enough for situations where the points don't vary too wildly.
My idea is to start at the grid corners and work our way along the outside diagonals of the matrix, trying to "grab" the nearest points that seem like they fit into the grid-points based any surrounding points we've already captured.
You will need to provide:
The number of rows (rows) and columns (cols) in the grid.
Your data points P arranged in a N x 2 array, rescaled to the unit square on [0,1] x [0,1]. (I assume the you can do this through visual inspection of the corner points of your original data.)
A weight parameter edge_weight to tell the algorithm how much the border points should be attracted to the grid border. Some tests show that 3-5 or so are good values.
The code, with a test case included:
%// input parameters
rows = 11;
cols = 11;
edge_weight = 4;
%// function for getting squared errors between the points list P and a specific point pt
getErr =#(P,pt) sqrt( sum( bsxfun(#minus,P,pt(:)').^2, 2 ) ); %'
output_grid = zeros(rows,cols,2); %// output grid matrix
check_grid = zeros(rows,cols); %// matrix flagging the gridpoints we have covered
[ROW,COL] = meshgrid(... %// coordinate points of an "ideal grid"
linspace(0,1,rows),...
linspace(0,1,cols));
%// create a test case
G = [ROW(:),COL(:)]; %// the actual grid-points
noise_factor = 0.35; %// noise radius allowed
rn = noise_factor/rows;
cn = noise_factor/cols;
row_noise = -rn + 2*rn*rand(numel(ROW),1);
col_noise = -cn + 2*cn*rand(numel(ROW),1);
P = G + [row_noise,col_noise]; %// add noise to get points
%// MAIN LOOP
d = 0;
while ~isempty(P) %// while points remain...
d = d+1; %// increase diagonal depth (d=1 are the outer corners)
for ii = max(d-rows+1,1):min(d,rows)%// for every row number i...
i = ii;
j = d-i+1; %// on the dth diagonal, we have d=i+j-1
for c = 1:4 %// repeat for all 4 corners
if i<rows & j<cols & ~check_grid(i,j) %// check for out-of-bounds/repetitions
check_grid(i,j) = true; %// flag gridpoint
current_gridpoint = [ROW(i,j),COL(i,j)];
%// get error between all remaining points and the next gridpoint's neighbours
if i>1
errI = getErr(P,output_grid(i-1,j,:));
else
errI = edge_weight*getErr(P,current_gridpoint);
end
if check_grid(i+1,j)
errI = errI + edge_weight*getErr(P,current_gridpoint);
end
if j>1
errJ = getErr(P,output_grid(i,j-1,:));
else
errJ = edge_weight*getErr(P,current_gridpoint);
end
if check_grid(i,j+1)
errJ = errJ + edge_weight*getErr(P,current_gridpoint);
end
err = errI.^2 + errJ.^2;
%// find the point with minimal error, add it to the grid,
%// and delete it from the points list
[~,idx] = min(err);
output_grid(i,j,:) = permute( P(idx,:), [1 3 2] );
P(idx,:) = [];
end
%// rotate the grid 90 degrees and repeat for next corner
output_grid = cat(3, rot90(output_grid(:,:,1)), rot90(output_grid(:,:,2)));
check_grid = rot90(check_grid);
ROW = rot90(ROW);
COL = rot90(COL);
end
end
end
Code for plotting the resulting points with edges:
%// plotting code
figure(1); clf; hold on;
axis([-0.1 1.1 -0.1 1.1])
for i = 1:size(output_grid,1)
for j = 1:size(output_grid,2)
scatter(output_grid(i,j,1),output_grid(i,j,2),'b')
if i < size(output_grid,1)
plot( [output_grid(i,j,1),output_grid(i+1,j,1)],...
[output_grid(i,j,2),output_grid(i+1,j,2)],...
'r');
end
if j < size(output_grid,2)
plot( [output_grid(i,j,1),output_grid(i,j+1,1)],...
[output_grid(i,j,2),output_grid(i,j+1,2)],...
'r');
end
end
end
I've developed a solution, which works for my case but might not be as robust as required for some. It requires a known number of dots in a 'square' grid and a rough idea of the spacing between the dots. I find the 'AlphaShape' of the dots and all the points that lie along the edge. The edge vector is shifted to start at the minimum and then wrapped around a matrix with the corresponding points are discarded from the list of vertices. Probably not the best idea for large point clouds but good enough for me.
R = 50; % search radius
xy = centres2;
x = centres2(:,1);
y = centres2(:,2);
for i = 1:8
T = delaunay(xy); % delaunay
[~,r] = circumcenter(triangulation(T,x,y)); % circumcenters
T = T(r < R,:); % points within radius
B = freeBoundary(triangulation(T,x,y)); % find edge vertices
A = B(:,1);
EdgeList = [x(A) y(A) x(A)+y(A)]; % find point closest to origin and rotate vector
[~,I] = min(EdgeList);
EdgeList = circshift(EdgeList,-I(3)+1);
n = sqrt(length(xy)); % define zeros matrix
matX = zeros(n); % wrap x vector around zeros matrix
matX(1,1:n) = EdgeList(1:n,1);
matX(2:n-1,n) = EdgeList(n+1:(2*n)-2,1);
matX(n,n:-1:1) = EdgeList((2*n)-1:(3*n)-2,1);
matX(n-1:-1:2,1) = EdgeList((3*n)-1:(4*n)-4,1);
matY = zeros(n); % wrap y vector around zeros matrix
matY(1,1:n) = EdgeList(1:n,2);
matY(2:n-1,n) = EdgeList(n+1:(2*n)-2,2);
matY(n,n:-1:1) = EdgeList((2*n)-1:(3*n)-2,2);
matY(n-1:-1:2,1) = EdgeList((3*n)-1:(4*n)-4,2);
centreMatX(i:n+i-1,i:n+i-1) = matX; % paste into main matrix
centreMatY(i:n+i-1,i:n+i-1) = matY;
xy(B(:,1),:) = 0; % discard values
xy = xy(all(xy,2),:);
x = xy(:,1);
y = xy(:,2);
end
centreMatX(centreMatX == 0) = x;
centreMatY(centreMatY == 0) = y;

Code efficiency, Rotating image without imrotate [duplicate]

I am trying to rotate an image with Matlab without using imrotate function. I actually made it by using transformation matrix.But it is not good enough.The problem is, the rotated image is "sliding".Let me tell you with pictures.
This is my image which I want to rotate:
But when I rotate it ,for example 45 degrees, it becomes this:
I am asking why this is happening.Here is my code,is there any mathematical or programming mistakes about it?
image=torso;
%image padding
[Rows, Cols] = size(image);
Diagonal = sqrt(Rows^2 + Cols^2);
RowPad = ceil(Diagonal - Rows) + 2;
ColPad = ceil(Diagonal - Cols) + 2;
imagepad = zeros(Rows+RowPad, Cols+ColPad);
imagepad(ceil(RowPad/2):(ceil(RowPad/2)+Rows-1),ceil(ColPad/2):(ceil(ColPad/2)+Cols-1)) = image;
degree=45;
%midpoints
midx=ceil((size(imagepad,1)+1)/2);
midy=ceil((size(imagepad,2)+1)/2);
imagerot=zeros(size(imagepad));
%rotation
for i=1:size(imagepad,1)
for j=1:size(imagepad,2)
x=(i-midx)*cos(degree)-(j-midy)*sin(degree);
y=(i-midx)*sin(degree)+(j-midy)*cos(degree);
x=round(x)+midx;
y=round(y)+midy;
if (x>=1 && y>=1)
imagerot(x,y)=imagepad(i,j); % k degrees rotated image
end
end
end
figure,imagesc(imagerot);
colormap(gray(256));
The reason you have holes in your image is because you are computing the location in imagerot of each pixel in imagepad. You need to do the computation the other way around. That is, for each pixel in imagerot interpolate in imagepad. To do this, you just need to apply the inverse transform, which in the case of a rotation matrix is just the transpose of the matrix (just change the sign on each sin and translate the other way).
Loop over pixels in imagerot:
imagerot=zeros(size(imagepad)); % midx and midy same for both
for i=1:size(imagerot,1)
for j=1:size(imagerot,2)
x= (i-midx)*cos(rads)+(j-midy)*sin(rads);
y=-(i-midx)*sin(rads)+(j-midy)*cos(rads);
x=round(x)+midx;
y=round(y)+midy;
if (x>=1 && y>=1 && x<=size(imagepad,2) && y<=size(imagepad,1))
imagerot(i,j)=imagepad(x,y); % k degrees rotated image
end
end
end
Also note that your midx and midy need to be calculated with size(imagepad,2) and size(imagepad,1) respectively, since the first dimension refers to the number of rows (height) and the second to width.
NOTE: The same approach applies when you decide to adopt an interpolation scheme other than nearest neighbor, as in Rody's example with linear interpolation.
EDIT: I'm assuming you are using a loop for demonstrative purposes, but in practice there is no need for loops. Here's an example of nearest neighbor interpolation (what you are using), keeping the same size image, but you can modify this to produce a larger image that includes the whole source image:
imagepad = imread('peppers.png');
[nrows ncols nslices] = size(imagepad);
midx=ceil((ncols+1)/2);
midy=ceil((nrows+1)/2);
Mr = [cos(pi/4) sin(pi/4); -sin(pi/4) cos(pi/4)]; % e.g. 45 degree rotation
% rotate about center
[X Y] = meshgrid(1:ncols,1:nrows);
XYt = [X(:)-midx Y(:)-midy]*Mr;
XYt = bsxfun(#plus,XYt,[midx midy]);
xout = round(XYt(:,1)); yout = round(XYt(:,2)); % nearest neighbor!
outbound = yout<1 | yout>nrows | xout<1 | xout>ncols;
zout=repmat(cat(3,1,2,3),nrows,ncols,1); zout=zout(:);
xout(xout<1) = 1; xout(xout>ncols) = ncols;
yout(yout<1) = 1; yout(yout>nrows) = nrows;
xout = repmat(xout,[3 1]); yout = repmat(yout,[3 1]);
imagerot = imagepad(sub2ind(size(imagepad),yout,xout,zout(:))); % lookup
imagerot = reshape(imagerot,size(imagepad));
imagerot(repmat(outbound,[1 1 3])) = 0; % set background value to [0 0 0] (black)
To modify the above to linear interpolation, compute the 4 neighboring pixels to each coordinate in XYt and perform a weighted sum using the fractional components product as the weights. I'll leave that as an exercise, since it would only serve to bloat my answer further beyond the scope of your question. :)
The method you are using (rotate by sampling) is the fastest and simplest, but also the least accurate.
Rotation by area mapping, as given below (this is a good reference), is much better at preserving color.
But: note that this will only work on greyscale/RGB images, but NOT on colormapped images like the one you seem to be using.
image = imread('peppers.png');
figure(1), clf, hold on
subplot(1,2,1)
imshow(image);
degree = 45;
switch mod(degree, 360)
% Special cases
case 0
imagerot = image;
case 90
imagerot = rot90(image);
case 180
imagerot = image(end:-1:1, end:-1:1);
case 270
imagerot = rot90(image(end:-1:1, end:-1:1));
% General rotations
otherwise
% Convert to radians and create transformation matrix
a = degree*pi/180;
R = [+cos(a) +sin(a); -sin(a) +cos(a)];
% Figure out the size of the transformed image
[m,n,p] = size(image);
dest = round( [1 1; 1 n; m 1; m n]*R );
dest = bsxfun(#minus, dest, min(dest)) + 1;
imagerot = zeros([max(dest) p],class(image));
% Map all pixels of the transformed image to the original image
for ii = 1:size(imagerot,1)
for jj = 1:size(imagerot,2)
source = ([ii jj]-dest(1,:))*R.';
if all(source >= 1) && all(source <= [m n])
% Get all 4 surrounding pixels
C = ceil(source);
F = floor(source);
% Compute the relative areas
A = [...
((C(2)-source(2))*(C(1)-source(1))),...
((source(2)-F(2))*(source(1)-F(1)));
((C(2)-source(2))*(source(1)-F(1))),...
((source(2)-F(2))*(C(1)-source(1)))];
% Extract colors and re-scale them relative to area
cols = bsxfun(#times, A, double(image(F(1):C(1),F(2):C(2),:)));
% Assign
imagerot(ii,jj,:) = sum(sum(cols),2);
end
end
end
end
subplot(1,2,2)
imshow(imagerot);
Output:
Rotates colored image according to angle given by user without any cropping of image in matlab.
Output of this program is similar to output of inbuilt command "imrotate" .This program dynamically creates background according to angle input given by user.By using rotation matrix and origin shifting, we get relation between coordinates of initial and final image.Using relation between coordinates of initial and final image, we now map the intensity values for each pixel.
img=imread('img.jpg');
[rowsi,colsi,z]= size(img);
angle=45;
rads=2*pi*angle/360;
%calculating array dimesions such that rotated image gets fit in it exactly.
% we are using absolute so that we get positve value in any case ie.,any quadrant.
rowsf=ceil(rowsi*abs(cos(rads))+colsi*abs(sin(rads)));
colsf=ceil(rowsi*abs(sin(rads))+colsi*abs(cos(rads)));
% define an array withcalculated dimensionsand fill the array with zeros ie.,black
C=uint8(zeros([rowsf colsf 3 ]));
%calculating center of original and final image
xo=ceil(rowsi/2);
yo=ceil(colsi/2);
midx=ceil((size(C,1))/2);
midy=ceil((size(C,2))/2);
% in this loop we calculate corresponding coordinates of pixel of A
% for each pixel of C, and its intensity will be assigned after checking
% weather it lie in the bound of A (original image)
for i=1:size(C,1)
for j=1:size(C,2)
x= (i-midx)*cos(rads)+(j-midy)*sin(rads);
y= -(i-midx)*sin(rads)+(j-midy)*cos(rads);
x=round(x)+xo;
y=round(y)+yo;
if (x>=1 && y>=1 && x<=size(img,1) && y<=size(img,2) )
C(i,j,:)=img(x,y,:);
end
end
end
imshow(C);
Check this out.
this is fastest way that you can do.
img = imread('Koala.jpg');
theta = pi/10;
rmat = [
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1];
mx = size(img,2);
my = size(img,1);
corners = [
0 0 1
mx 0 1
0 my 1
mx my 1];
new_c = corners*rmat;
T = maketform('affine', rmat); %# represents translation
img2 = imtransform(img, T, ...
'XData',[min(new_c(:,1)) max(new_c(:,1))],...
'YData',[min(new_c(:,2)) max(new_c(:,2))]);
subplot(121), imshow(img);
subplot(122), imshow(img2);

Image rotation by Matlab without using imrotate

I am trying to rotate an image with Matlab without using imrotate function. I actually made it by using transformation matrix.But it is not good enough.The problem is, the rotated image is "sliding".Let me tell you with pictures.
This is my image which I want to rotate:
But when I rotate it ,for example 45 degrees, it becomes this:
I am asking why this is happening.Here is my code,is there any mathematical or programming mistakes about it?
image=torso;
%image padding
[Rows, Cols] = size(image);
Diagonal = sqrt(Rows^2 + Cols^2);
RowPad = ceil(Diagonal - Rows) + 2;
ColPad = ceil(Diagonal - Cols) + 2;
imagepad = zeros(Rows+RowPad, Cols+ColPad);
imagepad(ceil(RowPad/2):(ceil(RowPad/2)+Rows-1),ceil(ColPad/2):(ceil(ColPad/2)+Cols-1)) = image;
degree=45;
%midpoints
midx=ceil((size(imagepad,1)+1)/2);
midy=ceil((size(imagepad,2)+1)/2);
imagerot=zeros(size(imagepad));
%rotation
for i=1:size(imagepad,1)
for j=1:size(imagepad,2)
x=(i-midx)*cos(degree)-(j-midy)*sin(degree);
y=(i-midx)*sin(degree)+(j-midy)*cos(degree);
x=round(x)+midx;
y=round(y)+midy;
if (x>=1 && y>=1)
imagerot(x,y)=imagepad(i,j); % k degrees rotated image
end
end
end
figure,imagesc(imagerot);
colormap(gray(256));
The reason you have holes in your image is because you are computing the location in imagerot of each pixel in imagepad. You need to do the computation the other way around. That is, for each pixel in imagerot interpolate in imagepad. To do this, you just need to apply the inverse transform, which in the case of a rotation matrix is just the transpose of the matrix (just change the sign on each sin and translate the other way).
Loop over pixels in imagerot:
imagerot=zeros(size(imagepad)); % midx and midy same for both
for i=1:size(imagerot,1)
for j=1:size(imagerot,2)
x= (i-midx)*cos(rads)+(j-midy)*sin(rads);
y=-(i-midx)*sin(rads)+(j-midy)*cos(rads);
x=round(x)+midx;
y=round(y)+midy;
if (x>=1 && y>=1 && x<=size(imagepad,2) && y<=size(imagepad,1))
imagerot(i,j)=imagepad(x,y); % k degrees rotated image
end
end
end
Also note that your midx and midy need to be calculated with size(imagepad,2) and size(imagepad,1) respectively, since the first dimension refers to the number of rows (height) and the second to width.
NOTE: The same approach applies when you decide to adopt an interpolation scheme other than nearest neighbor, as in Rody's example with linear interpolation.
EDIT: I'm assuming you are using a loop for demonstrative purposes, but in practice there is no need for loops. Here's an example of nearest neighbor interpolation (what you are using), keeping the same size image, but you can modify this to produce a larger image that includes the whole source image:
imagepad = imread('peppers.png');
[nrows ncols nslices] = size(imagepad);
midx=ceil((ncols+1)/2);
midy=ceil((nrows+1)/2);
Mr = [cos(pi/4) sin(pi/4); -sin(pi/4) cos(pi/4)]; % e.g. 45 degree rotation
% rotate about center
[X Y] = meshgrid(1:ncols,1:nrows);
XYt = [X(:)-midx Y(:)-midy]*Mr;
XYt = bsxfun(#plus,XYt,[midx midy]);
xout = round(XYt(:,1)); yout = round(XYt(:,2)); % nearest neighbor!
outbound = yout<1 | yout>nrows | xout<1 | xout>ncols;
zout=repmat(cat(3,1,2,3),nrows,ncols,1); zout=zout(:);
xout(xout<1) = 1; xout(xout>ncols) = ncols;
yout(yout<1) = 1; yout(yout>nrows) = nrows;
xout = repmat(xout,[3 1]); yout = repmat(yout,[3 1]);
imagerot = imagepad(sub2ind(size(imagepad),yout,xout,zout(:))); % lookup
imagerot = reshape(imagerot,size(imagepad));
imagerot(repmat(outbound,[1 1 3])) = 0; % set background value to [0 0 0] (black)
To modify the above to linear interpolation, compute the 4 neighboring pixels to each coordinate in XYt and perform a weighted sum using the fractional components product as the weights. I'll leave that as an exercise, since it would only serve to bloat my answer further beyond the scope of your question. :)
The method you are using (rotate by sampling) is the fastest and simplest, but also the least accurate.
Rotation by area mapping, as given below (this is a good reference), is much better at preserving color.
But: note that this will only work on greyscale/RGB images, but NOT on colormapped images like the one you seem to be using.
image = imread('peppers.png');
figure(1), clf, hold on
subplot(1,2,1)
imshow(image);
degree = 45;
switch mod(degree, 360)
% Special cases
case 0
imagerot = image;
case 90
imagerot = rot90(image);
case 180
imagerot = image(end:-1:1, end:-1:1);
case 270
imagerot = rot90(image(end:-1:1, end:-1:1));
% General rotations
otherwise
% Convert to radians and create transformation matrix
a = degree*pi/180;
R = [+cos(a) +sin(a); -sin(a) +cos(a)];
% Figure out the size of the transformed image
[m,n,p] = size(image);
dest = round( [1 1; 1 n; m 1; m n]*R );
dest = bsxfun(#minus, dest, min(dest)) + 1;
imagerot = zeros([max(dest) p],class(image));
% Map all pixels of the transformed image to the original image
for ii = 1:size(imagerot,1)
for jj = 1:size(imagerot,2)
source = ([ii jj]-dest(1,:))*R.';
if all(source >= 1) && all(source <= [m n])
% Get all 4 surrounding pixels
C = ceil(source);
F = floor(source);
% Compute the relative areas
A = [...
((C(2)-source(2))*(C(1)-source(1))),...
((source(2)-F(2))*(source(1)-F(1)));
((C(2)-source(2))*(source(1)-F(1))),...
((source(2)-F(2))*(C(1)-source(1)))];
% Extract colors and re-scale them relative to area
cols = bsxfun(#times, A, double(image(F(1):C(1),F(2):C(2),:)));
% Assign
imagerot(ii,jj,:) = sum(sum(cols),2);
end
end
end
end
subplot(1,2,2)
imshow(imagerot);
Output:
Rotates colored image according to angle given by user without any cropping of image in matlab.
Output of this program is similar to output of inbuilt command "imrotate" .This program dynamically creates background according to angle input given by user.By using rotation matrix and origin shifting, we get relation between coordinates of initial and final image.Using relation between coordinates of initial and final image, we now map the intensity values for each pixel.
img=imread('img.jpg');
[rowsi,colsi,z]= size(img);
angle=45;
rads=2*pi*angle/360;
%calculating array dimesions such that rotated image gets fit in it exactly.
% we are using absolute so that we get positve value in any case ie.,any quadrant.
rowsf=ceil(rowsi*abs(cos(rads))+colsi*abs(sin(rads)));
colsf=ceil(rowsi*abs(sin(rads))+colsi*abs(cos(rads)));
% define an array withcalculated dimensionsand fill the array with zeros ie.,black
C=uint8(zeros([rowsf colsf 3 ]));
%calculating center of original and final image
xo=ceil(rowsi/2);
yo=ceil(colsi/2);
midx=ceil((size(C,1))/2);
midy=ceil((size(C,2))/2);
% in this loop we calculate corresponding coordinates of pixel of A
% for each pixel of C, and its intensity will be assigned after checking
% weather it lie in the bound of A (original image)
for i=1:size(C,1)
for j=1:size(C,2)
x= (i-midx)*cos(rads)+(j-midy)*sin(rads);
y= -(i-midx)*sin(rads)+(j-midy)*cos(rads);
x=round(x)+xo;
y=round(y)+yo;
if (x>=1 && y>=1 && x<=size(img,1) && y<=size(img,2) )
C(i,j,:)=img(x,y,:);
end
end
end
imshow(C);
Check this out.
this is fastest way that you can do.
img = imread('Koala.jpg');
theta = pi/10;
rmat = [
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1];
mx = size(img,2);
my = size(img,1);
corners = [
0 0 1
mx 0 1
0 my 1
mx my 1];
new_c = corners*rmat;
T = maketform('affine', rmat); %# represents translation
img2 = imtransform(img, T, ...
'XData',[min(new_c(:,1)) max(new_c(:,1))],...
'YData',[min(new_c(:,2)) max(new_c(:,2))]);
subplot(121), imshow(img);
subplot(122), imshow(img2);