How to rotate image around the center of object in matlab? - matlab

imrotate function in matlab rotates the image around the center. How to rotate image by custom coordinates?
For example center of blob in binary mask. If using imcrop and place blob in the center, how to reshape that to same as original image?
Code
% create binary mask
clc;
clear;
mask= zeros(400,600,'logical');
positein = [280,480];
L = 40;
x = positein (1);
y = positein (2);
mask(x,y-L:y+L) = 1;
for i =1:8
mask(x+i,y-L:y+L) = 1;
mask(x-i,y-L:y+L) = 1;
end
Angle = 45;
mask_after_rotation = imrotate(mask,-Angle,'crop');
figure,
subplot(1,2,1),imshow(mask),title('before rotation');
subplot(1,2,2),imshow(mask_after_rotation),title('after rotate 45');

This is generally performed by constructing an affine transform which translates the point about which we want to rotate to the origin, then performs a rotation, then translates back.
For example, to rotate by -45 degrees like in your example we could do the following
% create binary mask
mask = zeros(400, 600,'logical');
positein = [480, 200];
W = 40; H = 8;
x = positein(1); y = positein(2);
mask(y-H:y+H, x-W:x+W) = 1;
angle = -45;
% translate by -positein, rotate by angle, then translate back by pt
T = [1 0 0; 0 1 0; -positein 1];
R = [cosd(angle) -sind(angle) 0; sind(angle) cosd(angle) 0; 0 0 1];
Tinv = [1 0 0; 0 1 0; positein 1];
tform = affine2d(T*R*Tinv);
mask_rotated = imwarp(mask, tform, 'OutputView', imref2d(size(mask)));
figure(1); clf(1);
subplot(1,2,1),imshow(mask),title('before rotation');
subplot(1,2,2),imshow(mask_rotated),title('after rotate 45');
Alternatively you can set the reference object so that the desired coordinate is at the origin
% Set origin to positein, then rotate
xlimits = 0.5 + [0, size(mask,2)] - positein(1);
ylimits = 0.5 + [0, size(mask,1)] - positein(2);
ref = imref2d(size(mask), xlimits, ylimits);
R = [cosd(angle) -sind(angle) 0; sind(angle) cosd(angle) 0; 0 0 1];
tform = affine2d(R);
mask_rotated = imwarp(mask, ref, tform, 'OutputView', ref);

You could do a series of transformation to achieve the rotation around an arbitrary point, which are: 1) Move the arbitrary point to the center of the image, 2) Rotate the image by a predefined angle, & 3) Translate it back to the original position. For example, if you want to rotate the mask around the center of the blob in your case, then you could carry out the following steps.
trns_mask = imtranslate(mask, [-180, -80]); % Move to the origin
trns_mask_rotated = imrotate(trns_mask,-Angle,'crop'); % Rotate
mask_after_rotation = imtranslate(trns_mask_rotated, [180, 80]); % Move back
There are options for the function imtranslate() which you could play with to make sure you are not losing any image information during the transformation.

Related

Calculate objects circumscribed radius and inscribed radius - Matlab

I am trying to calculate two objects circumscribed radius and inscribed radius using the code below. I used for the inscribedRadius parameter from this script and for the circumscribed radius I used this function
I do not understand why I get for the box shape that the inscribed radius is bigger than the circumscribed radius. Any idea what is wrong? And how to fix it?
Image
Code:
clc;
clear;
RGB = imcomplement(imread('https://i.stack.imgur.com/8WLAt.jpg'));
I = rgb2gray(RGB);
bw = imbinarize(I);
bw = imfill(bw,'holes');
imshow(bw)
hold on;
[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Centroid','MajorAxisLength');
for i = 1 : numel(stats)
b = B{i};
c = stats(i).Centroid;
y = b(:,1);
x = b(:,2);
plot( b(:,2),b(:,1),'Color','red','linewidth',2);
text(c(1),c(2),num2str(i),'Color','red');
xMin = min(x);
xMax = max(x);
yMin = min(y);
yMax = max(y);
scalingFactor = 1000 / min([xMax-xMin, yMax-yMin]);
x2s = (x - xMin) * scalingFactor + 1;
y2s = (y - yMin) * scalingFactor + 1;
mask = poly2mask(x2s, y2s, ceil(max(y2s)), ceil(max(x2s)));
edtImage = bwdist(~mask);
inscribedRadius = max(edtImage(:));
[yCenter, xCenter] = find(edtImage == inscribedRadius);
xCenter = (xCenter - 1)/ scalingFactor + xMin;
yCenter = (yCenter - 1)/ scalingFactor + yMin;
inscribedRadius = inscribedRadius / scalingFactor
[circumscribedCenter,circumscribedRadius] = minboundcircle(x,y); % from https://www.mathworks.com/matlabcentral/fileexchange/34767-a-suite-of-minimal-bounding-objects?focused=3820656&tab=function
circumscribedRadius
end
The results are:
Object 1: inscribedRadius = 264, cumscribedRadius = 186.6762
Object 2: inscribedRadius = 130.4079, circumscribedRadius = 132.3831
The values of object 1 (box) are wrong as the inscribedRadius can not be bigger than the cumscribedRadius. They are fine for object 2 (circle)
If you look at the mask image, you'll notice that the square shape is drawn touching the right and bottom edges of the image. There's background only along the left and top of the shape. The distance transform bwdist(~mask) subsequently computes the distance to the background for each pixel within the shape, but since there's background only to the left and top, the pixel at the bottom right of the shape has a distance of 1000, rather than 1. The distance transform is supposed to have a maximum in the middle, at a point equidistant to at least the three nearest shape edge points.
The solution is simple: poly2mask must create an image that is one pixel wider and taller:
mask = poly2mask(x2s, y2s, ceil(max(y2s)) + 1, ceil(max(x2s)) + 1);
^^^ ^^^
With this change, the computed inscribedRadius for the square is 132, as expected.

how can I Rotate the image around the center using transformPointsForward and Getting the coordinates of the four corners of the changed image؟

I want to rotate the image arround the center.I usesd transformPointForward function for do this.I want to getting the coordinate of the four corners of the changed image.in below you can see my code.thanks for your help.
theta=+50;
tform = affine2d([cosd(theta) -sind(theta) 0;sind(theta) cosd(theta) 0; 0 0
1]);
A = imread('pout.tif');
corners = [1,1;1,size(A,2);size(A,1),1;size(A,1),size(A,2)];
X = transformPointsForward(tform,corners);
Rin = imref2d(size(A))
Rin.XWorldLimits = Rin.XWorldLimits-mean(Rin.XWorldLimits);
Rin.YWorldLimits = Rin.YWorldLimits-mean(Rin.YWorldLimits);
[out,ref] = imwarp(A,Rin,tform);
figure,
subplot(1,2,1),imshow(A,[])
subplot(1,2,2),imshow(out,[])
X(:,1) = X(:,1) - ref.XWorldLimits(1);
X(:,2) = X(:,2) - ref.YWorldLimits(1);

Problems with performing image translation in MATLAB

I'm trying to do image translation using MATLAB, and the image doesn't move at all. My code is:
myPic = imread('pic.jpg');
x = 250;
y = 375;
trans = affine2d([1 0 0; 0 1 0; x y 1]);
outputPic = imwarp(myPic, trans);
imshow(myPic)
axis on
figure()
imshow(outputPic)
axis on
isequal(myPic,outputPic) %evaluates to 1!!!
When I do the same for a rotation affine matrix, it worked. Why doesn't this work?
here's what happens when I print both pics:
In order for this to work, you'll need to define an 'OutputView' parameter.
This parameter sets the size and location of the output image in world coordinate system, using imref2d function.
Example:
myPic = imread('peppers.png');
x = 250;
y = 375;
%defines transformations
trans = affine2d([1 0 0; 0 1 0; x y 1]);
eyeTrans= affine2d([1 0 0; 0 1 0; 0 0 1]);
%initializes imref2d object
outView = imref2d([size(myPic,1)+y,size(myPic,2)+x]);
outputPic1 = imwarp(I,trans,'OutputView',outView)
outputPic2 = imwarp(I,eyeTrans,'OutputView',outView)
%display result
figure,
subplot(1,2,1); imshow(outputPic2); title('original')
subplot(1,2,2); imshow(outputPic1); title('translated')
Result:

How to straighten a tilted square shape in an image?

How can I straighten a tilted square shape in an image?
I do not know the angle with which it is tilted and the code must calculate it and then rotate it automatically.
For example, I have the following image:
which should be rotated to give the following output image:
One way:
I = imread('img.jpg');
I = rgb2gray(I);
Ibw = I<threshold; %find the good threshold
se = strel('square',sizesquare); %find the good size for the strel function.
Ibw = imdilate(Ibw,se); %fill the hole
imshow(Ibw);
stat = regionprops(Ibw,'Extrema'); %extrema detection of the image.
point = stat.Extrema;
hold on
for i = 2:2:length(stat.Extrema)
x = point(i,1);
y = point(i,2);
plot(x,y,'o');
text(x,y,num2str(i),'color','w')
end
%construct the triangle that will help us to determine the shift angle.
P2 = [point(8,1),point(2,2)];
P1 = [point(8,1),point(8,2)];
P0 = [point(2,1),point(2,2)];
ang = atan2(abs(det([P2-P0;P1-P0])),dot(P2-P0,P1-P0))*180/pi
close all
imshow(imrotate(I,-ang))
STEP 1
STEP 2
STEP 3
A simple way using only the top and bottom corners. Note that this approach relies on the upper and lower most corners:
i = imread('sq.jpg');
i_bw = im2bw(i)==0;
% Modify the strel as required
se = strel('square', 10);
i_ed = imopen(i_bw, se);
limits = sum(i_ed, 2);
top_y = find(limits>0, 1);
bottom_y = find(limits>0, 1, 'last');
top_x = round(mean(find(i_ed(top_y, :)>0)));
bottom_x = round(mean(find(i_ed(bottom_y, :)>0)));
slope = -1 * (top_y - bottom_y)/(top_x - bottom_x);
rot_angle = 2 * pi * atan(slope);
i2 = imrotate(i, -rot_angle);
imshow(i2)
BEFORE
AFTER

3D rotation of a sphere around a fixed point in Matlab

I have a sphere centered on the origin of the axes. I use the rotate3d function to allow its rotation. However, when I rotate it, it seems to move in the space with having a fixed point for the rotation. I would like to fix the origin as rotation center. How can I achieve it?
Here is my code:
function ex
global state;
fh = figure('Menu','none','Toolbar','none','Units','characters',...
'Renderer','OpenGL');
hPanAni = uipanel('parent',fh,'Units','characters','Position',...
[22.6 10.4 53 23],'title','Controls','FontSize',11,...
'FontAngle','italic','FontWeight','bold');
hIniAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.75 0.5 0.12],'String','Spin',...
'FontSize',10,'Callback',#hIniAniCallback);
hFinAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.5 0.5 0.12],'String','Stop',...
'FontSize',10,'Callback',#hFinAniCallback);
hResetAni = uicontrol(hPanAni,'Style','pushbutton','Units','normalized',...
'Position',[0.14 0.25 0.5 0.12],'String','Reset',...
'FontSize',10,'Callback',#hResetAniCallback);
hPantSim = uipanel('Parent',fh,'Units','characters',...
'Position',[107.87 8 157.447 42],'BorderType','none','title',...
'Screen','FontSize',11,'FontAngle','italic',...
'FontWeight','bold');
hPantSimInt = uipanel('Parent',hPantSim,'Units','normalized','Position',...
[0 0 1 1],'BorderType','line','BackgroundColor','k');
axes('units','normalized','position',[0,0,1,1],'Parent',...
hPantSimInt);
stars = rand(60,2);
scatter(stars(:,1),stars(:,2),6,'y','Marker','+');
axis off;
ah4 = axes('Parent',hPantSimInt,'Units','normalized','Position',...
[0 0 1 1],'Color','none','Visible','off','DataAspectRatio',...
[1 1 1],'NextPlot','add');
T1 = 0:pi/1000:2*pi;
Fin = numel(T1);
if (Fin>1000)
Incr = floor(Fin/1000);
else
Incr = 1;
end
Y = zeros(numel(T1),3);
Y(:,1) = 7000*cos(T1);
Y(:,2) = 7000*sin(T1);
R_esf = 6378;
[x_esf,y_esf,z_esf] = sphere(50);
x_esf = R_esf*x_esf;
y_esf = R_esf*y_esf;
z_esf = R_esf*z_esf;
props.FaceColor= 'texture';
props.EdgeColor = 'none';
props.Parent = ah4;
surface(x_esf,y_esf,z_esf,props);
handles.psat = line('parent',ah4,'XData',Y(1,1), 'YData',Y(1,2),...
'ZData',Y(1,3),'Marker','o', 'MarkerSize',10,'MarkerFaceColor','b');
line([0 1.5*R_esf],[0 0],[0 0],'LineWidth',3,'Color','g');
line([0 0],[0 1.5*R_esf],[0 0],'LineWidth',3,'Color','g');
line([0 0],[0 0],[0 1.5*R_esf],'LineWidth',3,'Color','g');
pbaspect([1 1 1]);
axis vis3d;
rotate3d(ah4);
view([atan2(Y(1,2),Y(1,1)),0]);
az = 0;
k = 2;
ind_ini = 0;
state = 0;
function hIniAniCallback(hObject,evt)
tic;
if (ind_ini == 1)
return;
end
ind_ini = 1;
state = 0;
while (k<=Fin)
set(handles.psat,'XData',Y(k,1),'YData',Y(k,2),'ZData',Y(k,3));
pause(0.002);
if (k == Fin)
toc;
end
k = k + Incr;
if (state == 1)
state = 0;
break;
end
end
end
function hFinAniCallback(hObject,evt)
ind_ini = 0;
state = 1;
end
function hResetAniCallback(hObject,evt)
set([handles.psat],'Visible','off');
ind_ini = 0;
state = 1;
az = 0;
k = 2;
handles.psat = line('parent',ah4,'XData',Y(1,1), 'YData',Y(1,2),...
'ZData',Y(1,3),'Marker','o', 'MarkerSize',10,'MarkerFaceColor','b');
end
end
The problem is that the 3d rotation is done with respect to the center of your axes, and not with respect to the origin. After you add the green lines along the axes, the limits of the x,y,z axes is automatically changed, the center of sphere is no longer positioned in the center of the figure. Add the following line after drawing all the lines:
ax_limits = 2*[-R_esf R_esf];
set (ah4, 'xlim', ax_limits, 'ylim', ax_limits, 'zlim', ax_limits)
The '2' factor is just to prevent the sphere from filling your axes tightly. You can set it to whatever value you need.