Calculate image rotation based on old and new positions of two points - matlab

I have images of faces in different positions. I want to rotate them, to make the line connecting the eyes always be horizontal. But I don't know how to do this in MATLAB.
And how can I calculate the angle of rotation?
Descriptive drawing of problem:

If you already have the locations of the eyes, then it's easy :) Here's an outline:
%// left eye - right eye
pos = [ 30 90 %// X
80 40]; %// Y
%// The angle equals the arctangent of dy/dx
angle = atan2(diff(pos(2,:)), diff(pos(1,:)));
%// Rotate in the opposite direction
img = imrotate(img, -angle);

Since you seem to have the Image Processing Toolbox, you can also look into the built-in landmark-based registration functions (especially if your transform is not limited to pure rotation), in particular cpselect with a syntax like:
cpselect(moving,fixed)
And then use fitgeotrans to construct the geometrical transform and imwarp to warp the moving image.

Related

How can I rotate connected components so that they are upright in Matlab?

Currently I am working with a sudoku grid and I have the binary image. I am using Regionprops to get the area of the connected components and then turn the rest of the image black. After this I call the OCR method to try and read the sudoku numbers. The problem is that this only works if the sudoku grid in the image is straight and upright. If it is rotated even a little bit I am not able to pull the numbers. This is the code I have so far:
% get grid connected parts
conn_part = bwconncomp(im_binary);
% blacken area outside
stats = regionprops(conn_part,'Area');
im_out = im_binary; % Make mask
im_out(vertcat(conn_part.PixelIdxList{[stats.Area] < 825 | [stats.Area] > 2500})) = 0;
imagesc(im_out);
title("Numbers pulled");
sudokuNum = ocr(im_out,'TextLayout','Block','CharacterSet','0123456789');
sudokuNum.Text;
Where im_binary is the binary image
im_out is the output image
stats is the object returned from regionprops containing the area of the connected components
I know I can rotate the image before getting the OCR results by doing:
im_out = imrotate(im_out, angle)
However I don't know what angle the grid is at since this is part of a function that loops through for multiple images. I looked into the regionprops method because there is an attribute 'Orientation' which I can pull from there but I don't understand how I would actually use it. It also states that regionprops will return a value between -90 and 90, but my image could be rotated by more than 90 degrees.
Don't rotate the connected component or the binary image. First use the binary image to determine the rotation, then rotate the original grey-scale or color input image, and then binarize the rotated image. You'll be able to transform with interpolation, which will improve your results greatly. It does require to do the binarization step twice, but I don't think this step usually is too expensive.
The regionprops orientation feature is computed by "fitting" an ellipse to the shape. This is meaningful only for elongated objects. For a square sudoku grid this will not yield any valuable information.
Instead, look at the angle at which the smallest Feret diameter was obtained. The Feret diameters are the lengths of the projections at arbitrary angles. At one angle, this projection is smallest. By necessity it will be at an angle corresponding to one of the principal axes of the square. Here is more information about how to compute Feret diameters in MATLAB.
A different alternative is e.g. to use the Hough transform to detect the lines of the grid.
Do note that the geometry of the puzzle will never tell you about which side is up. The angle you get here should be taken modulo π/2 (i.e. constrain to the range -π/4 to π/4).
To know what direction is up you might do by trying to read the text, if it fails, rotate by 90 degrees and try again.

How do I interpret the orientation of the gradient when using imgradient in MATLAB?

I am finding the gradient of an image. For now I am simply using a 5 x 5 image. I am more interested in finding the direction of the gradient but I am not getting the results manually on paper as I get them using MATLAB function imgradient. Please refer to the following images to know more about the input images and the Sobel filter that is used here to find the gradient of an image. One of the 3 x 3 sobel operator used here is the one that I get using the function
f1 = fspecial('sobel');
and the other one is obtained by just transposing the f1.
Please note that I am trying to find the direction of only one pixel here that is rounded by red color. Here in the first two cases my result matches with that i obtain using imgradient function but in the third case imgradient gives -135 degree whereas I am getting it to be -45. Please help me find the error.
Also please explain how to interpret the following gradient directions as shown in the follwing image.
Your calculations are correct but it is highly recommended that you don't use the atan(y/x) definition because this calculation is not cognizant of the quadrant that the angle of the gradient resides in. Doing atan(y/x) with your components would falsely report the angle to be -45 degrees when that isn't correct. You should use atan2 instead.
Now the internals of imgradient are quite straight forward. I'd like to point out that the angle reported by imgradient is assuming that the y coordinate is increasing from bottom to top. In addition, imgradient should report the angle of orientation that is pointing to the greatest rate of change. In the case of images, this points in the direction where we progress from dark pixels to light pixels.
First a call to imgradientxy is called and a call to fspecial('sobel') is made if you provide the sobel flag to imgradient. In fact, this portion of imgradientxy is what is important to remember (starting at line 75: MATLAB R2015a):
case 'sobel'
h = -fspecial('sobel'); %// Align mask correctly along the x- and y- axes
Gx = imfilter(I,h','replicate'); %'
if nargout > 1
Gy = imfilter(I,h,'replicate');
end
Notice that the negative of the output of fspecial is performed as well as the comment provided at that line. This is to ensure that the mask to detect horizontal edges (i.e. Gy) is y-down (as it is commonly known in computer graphics). Specifically, the origin of the image is at the top-left corner and not the bottom left.
This is a pictorial representation of how the coordinate system is laid out in y-down:
Source: Wikipedia - Rotation Matrix
As such, when finding the orientation there is an additional requirement to ensure that the angle of the orientation of the gradient is with respect to the y-up coordinate system which is what we're used to. Therefore when you are finding the angle of orientation of the gradient, you need to negate the y coordinate before calculating the angle so that the angle is with respect to the standard convention instead.
Pursuing the definition of the gradient that you seek is the conventional system of the y coordinate increasing from bottom to top. The negation is required and in fact if you examine the source code for imgradient, this is precisely what is being done at line 127 of the code (version R2015a):
Gdir = atan2(-Gy,Gx)*180/pi; %// Radians to degrees
You may be asking yourself why there is a need to negate the mask and again negate the y coordinate after to find the orientation. The reason why is because the modified mask is required to properly capture the magnitude of the gradient and so we negate the mask once and find the gradient magnitude and then we negate the y coordinate so that we can find the angle with respect to the conventional coordinate system.
In your case, given that Gx = 765 and Gy = -765, substituting these quantities into the above equation yields:
>> Gy = 765;
>> Gx = -765;
>> Gdir = atan2(-Gy,Gx)*180/pi
Gdir =
-135
This makes sense because the gradient direction corresponds to the direction towards the greatest rate of change. -135 degrees means that we're pointing to the south west which does make sense as we are progressing from dark pixels to light pixels.
Now if you consult your third example image, the angles reported by imgradient are indeed correct. Simply draw a line from the dark area to the light area and see what angle it makes with the x axis where it is aligned with the columns increasing towards the right. The first angle of +90 degrees makes sense as we are moving from bottom to top to follow the dark area and light. This is a similar situation with the situation where the image is reversed. The third situation is what we have seen before and the fourth situation is simply the third situation rotated by 180 degrees and so naturally the angle of orientation from dark to light is now +45 degrees as opposed to -135 degrees previously.

3D circular motion Matlab

I'm coding circular motion in Matlab, what is the appropriate formula or technique for circular motion in 3D-space, however I make this phenomena by the circle equation of sin and cos but it just rotates the object in circular motion (object itself) without taking its center, I want rotation with center of circle.
My Code:
for ii = 1:3
circular motion = [5*sin(ii) 5 5*cos(ii)];
%I used gain of 5 in order to give its speed.
%matrix circular motion contains XYZ coordinates.
end
Real life scenario of circular motion about center of circle:
Any suggestions or piece of formula that makes my strings unique are welcomed.
Assuming I understand your requirement correctly, to draw a circle in 3 dimensions, you would need to specify the plane on which the circle rests. Let me assume that the plane is z=1 plane.
So, you could plot a circle using:
t = 0:0.01:2*pi;
plot3(sin(t),cos(t),ones(size(t)));
Which gives this:
Bonus:
For a cool animation, try doing:
t = 0:0.01:2*pi;
comet3(sin(t),cos(t),ones(size(t)));

Matlab - Propagate points orthogonally on to the edge of shape boundaries

I have a set of points which I want to propagate on to the edge of shape boundary defined by a binary image. The shape boundary is defined by a 1px wide white edge.
I have the coordinates of these points stored in a 2 row by n column matrix. The shape forms a concave boundary with no holes within itself made of around 2500 points. I have approximately 80 to 150 points that I wish to propagate on the shape boundary.
I want to cast a ray from each point from the set of points in an orthogonal direction and detect at which point it intersects the shape boundary at. The orthogonal direction has already been determined. For the required purposes it is calculated taking the normal of the contour calculated for point, using point-1 and point+1.
What would be the best method to do this?
Are there some sort of ray tracing algorithms that could be used?
Thank you very much in advance for any help!
EDIT: I have tried to make the question much clearer and added a image describing the problem. In the image the grey line represents the shape contour, the red dots the points
I want to propagate and the green line an imaginary orthongally cast ray.
alt text http://img504.imageshack.us/img504/3107/orth.png
ANOTHER EDIT: For clarification I have posted the code used to calculate the normals for each point. Where the xt and yt are vectors storing the coordinates for each point. After calculating the normal value it can be propagated by using the linspace function and the requested length of the orthogonal line.
%#derivaties of contour
dx=[xt(2)-xt(1) (xt(3:end)-xt(1:end-2))/2 xt(end)-xt(end-1)];
dy=[yt(2)-yt(1) (yt(3:end)-yt(1:end-2))/2 yt(end)-yt(end-1)];
%#normals of contourpoints
l=sqrt(dx.^2+dy.^2);
nx = -dy./l;
ny = dx./l;
normals = [nx,ny];
It depends on how many unit vectors you want to test against one shape. If you have one shape and many tests, the easiest thing to do is probably to convert your shape coordinates to polar coordinates which implicitly represent your solution already. This may not be a very effective solution however if you have different shapes and only a few tests for every shape.
Update based on the edited question:
If the rays can start from arbitrary points, not only from the origin, you have to test against all the points. This can be done easily by transforming your shape boundary such that your ray to test starts in the origin in either coordinate direction (positive x in my example code)
% vector of shape boundary points (assumed to be image coordinates, i.e. integers)
shapeBoundary = [xs, ys];
% define the start point and direction you want to test
startPoint = [xsp, ysp];
testVector = unit([xv, yv]);
% now transform the shape boundary
shapeBoundaryTrans(:,1) = shapeBoundary(:,1)-startPoint(1);
shapeBoundaryTrans(:,2) = shapeBoundary(:,2)-startPoint(2);
rotMatrix = [testVector(2), testVector(1); ...
testVector(-1), testVector(2)];
% somewhat strange transformation to keep it vectorized
shapeBoundaryTrans = shapeBoundaryTrans * rotMatrix';
% now the test is easy: find the points close to the positive x-axis
selector = (abs(shapeBoundaryTrans(:,2)) < 0.5) & (shapeBoundaryTrans(:,1) > 0);
shapeBoundaryTrans(:,2) = 1:size(shapeBoundaryTrans, 1)';
shapeBoundaryReduced = shapeBoundaryTrans(selector, :);
if (isempty(shapeBoundaryReduced))
[dummy, idx] = min(shapeBoundaryReduced(:, 1));
collIdx = shapeBoundaryReduced(idx, 2);
% you have a collision with point collIdx of your shapeBoundary
else
% no collision
end
This could be done in a nicer way probably, but you get the idea...
If I understand your problem correctly (project each point onto the closest point of the shape boundary), you can
use sub2ind to convert the "2 row by n column matrix" description to a BW image with white pixels, something like
myimage=zeros(imagesize);
myimage(imagesize, x_coords, y_coords) = 1
use imfill to fill the outside of the boundary
run [D,L] = bwdist(BW) on the resulting image, and just read the answers from L.
Should be fairly straightforward.

Creating a cylinder with axis centered differently

I know Matlab has a function called cylinder to create the points for a cylinder when number of points along the circumference, and the radius length. What if I don't want a unit cylinder, and also don't want it to center at the default axis (for example along z-axis)? What would be the easiest approach to create such a cylinder? Thanks in advance.
The previous answer is fine, but you can get matlab to do more of the work for you (because the results of cylinder separate x,y,z components you need to work a little to do the matrix multiplication for the rotation). To have the center of base of the cylinder at [x0 y0 z0], scaled by [xf yf xf] (use xf=yf unless you want an elliptic cylinder), use:
[x y z] = cylinder;
h=mesh(x*xf+x0,y*yf+y0,z*zf+z0)
If you also want to rotate it so it isn't aligned along the z-axis, use rotate. For example, to rotate about the x-axis by 90 degrees, so it's aligned along the y-axis, use:
rotate(h,[1 0 0],90)
Multiply the points by your favourite combination of a scaling matrix, a translation matrix, and a rotation matrix.