Let's say I have image, which I need to rotate 90 degrees in any direction and I just can't understand how to do that clear. I need to work with matrix, where Width - it's X, and Height - it's Y. I've already done rotating an image 180 degrees, but can't figure out 90 degrees.
Here are the examples. Let's say I have an image 3x4 pixels. Width = 3, Height = 4, the amount of data in each cell - N = Width * Height = 3 * 4 = 12. Let's make the matrix:
The formula to easily go through the matrix is y*Width + x. And the formula for our rotating 180 degrees is:
N - Width + x - y * Width
So we have:
DataOut [y * Width + x] = DataIn [N - Width + x - y * Width]
Using this formula we get:
But I can't come up with the formula of rotating 90 degrees. Can you help me, please?
you can simply rotate the matrix by this:
for(int i=0; i<cols; i++)
{
for(int j=1; j<=rows; j++)
{
datOut[i][j]= datIn[rows-j][i];
}
}
and in 1-D array:
for(int i=0; i<cols; i++)
{
for(int j=1; j<=rows; j++)
{
datOut[i * rows + j]= datIn[(rows-j) * cols + i];
}
}
You can easily convert the (x + y * width) to a simpler (x, y) representation.
using P = point_data_type;
P point(int x, int y){
return DataIn[x + y * width]; // N - ...?
}
Now a right angle rotation is just a coordinate switch and maybe a sign correction.
P rotate90(int x, int y){
return point(y, x);
}
This is a positive rotation in a left-handed system.
Subtract x from Width if the rotation is in the wrong direction.
Related
Dears,
With the below code, I rotate my cv::Mat object (I'm not using any Cv's functions, apart from load/save/convertionColor.., as this is a academic project) and I receive a cropped Image
rotation function:
float rads = angle*3.1415926/180.0;
float _cos = cos(-rads);
float _sin = sin(-rads);
float xcenter = (float)(src.cols)/2.0;
float ycenter = (float)(src.rows)/2.0;
for(int i = 0; i < src.rows; i++)
for(int j = 0; j < src.cols; j++){
int x = ycenter + ((float)(i)-ycenter)*_cos - ((float)(j)-xcenter)*_sin;
int y = xcenter + ((float)(i)-ycenter)*_sin + ((float)(j)-xcenter)*_cos;
if (x >= 0 && x < src.rows && y >= 0 && y < src.cols) {
dst.at<cv::Vec4b>(i ,j) = src.at<cv::Vec4b>(x, y);
}
else {
dst.at<cv::Vec4b>(i ,j)[3] = 0;
}
}
I would like to know, How I can keep my Full image every time I want to rotate it.
Am I missing something in my function maybe?
thanks in advance
The rotated image usually has to be large than the old image to store all pixel values.
Each point (x,y) is translated to
(x', y') = (x*cos(rads) - y*sin(rads), x*sin(rads) + y*cos(rads))
An image with height h and width w, center at (0,0) and corners at
(h/2, w/2)
(h/2, -w/2)
(-h/2, w/2)
(-h/2, -w/2)
has a new height of
h' = 2*y' = 2 * (w/2*sin(rads) + h/2*cos(rads))
and a new width of
w' = 2*x' = 2 * (w/2*cos(rads) + h/2*sin(rads))
for 0 <= rads <= pi/4. It is x * y <= x' * y' and for rads != k*pi/2 with k = 1, 2, ... it is x * y < x' * y'
In any case the area of the rotated image is same size as or larger than the area of the old image.
If you use the old size, you cut off the corners.
Example:
Your image has h=1, w=1 and rads=pi/4. You need a new image with h'=sqrt(2)=1.41421356237 and w'=sqrt(2)=1.41421356237 to store all pixel values. The pixel from (1,1) is translated to (0, sqrt(2)).
I want to implement the following using OpenCV (I'll post my attempt at the bottom of the post). I am aware that OpenCV has a function for something like this, but I want to try to write my own.
In an image (Mat) (the coordinate system is at the top left, since it is an image) of width width and height height, I want to display a filled ellipsewith the following properties:
it should be centered at (width/2, height/2)
the image should be binary, so the points corresponding to the ellipse should have a value of 1 and others should be 0
the ellipse should be rotated by angle radians around the origin (or degrees, this does not matter all that much, I can convert)
ellipse: semi-major axis parameter is a and semi-minor axis parameter is b and these two parameters also represent the size of these axes in the picture, so "no matter" the width and height, the ellipse should have a major axis of size 2*a and a minor axis of size 2*b
Ok, so I've found an equation similar to this (https://math.stackexchange.com/a/434482/403961) for my purpose. My code is as follows.. it does seem to do pretty well on the rotation side, but, sadly, depending on the rotation angle, the SIZE (major axis, not sure about the minor) visibly increases/decreases, which is not normal, since I want it to have the same size, independent of the rotation angle.
NOTE The biggest size is seemingly achieved when the angle is 45 or -45 degrees and the smallest for angles like -90, 0, 90.
Code:
inline double sqr(double x)
{
return x * x;
}
Mat ellipticalElement(double a, double b, double angle, int width, int height)
{
// just to make sure I don't use some bad values for my parameters
assert(2 * a < width);
assert(2 * b < height);
Mat element = Mat::zeros(height, width, CV_8UC1);
Point center(width / 2, height / 2);
for(int x = 0 ; x < width ; x++)
for(int y = 0 ; y < height ; y++)
{
if (sqr((x - center.x) * cos(angle) - (y - center.y) * sin(angle)) / sqr(a) + sqr((x - center.x) * sin(angle) - (y - center.y) * cos(angle)) / sqr(b) <= 1)
element.at<uchar>(y, x) = 1;
}
return element;
}
A pesky typo sneaked in your inequality. The first summand must be
sqr((x - center.x) * cos(angle) + (y - center.y) * sin(angle)) / sqr(a)
Note the plus sign instead of minus.
Given two (very simplified) classes:
class Rectangle {
public:
int iL,jL; // lower left point of rectangle
int width, length; // width: in i-direction, length: in j-direction
};
class Circle {
public:
int iC,jC; // center-point of circle
int radius;
};
If I want to iterate over all elements in a Rectangle, I can simply do that by:
for (int i = iL; i < iL-width; i--)
for (int j = jL; j < jL+length; j++)
doSomething();
My problem is to implement a smart way of iterating over all elements in Circle. My current solution looks as follows:
for (int i = iC-radius; i <= iC+radius; i++)
for (int j = jC-radius; j <= jC+radius; j++)
if ( sqrt(pow(i-iC,2)+pow(j-jC,2)) <= r ) // checking if (i,j) lies within the circle (or its boundary)
doSomething();
However, for radius getting large my current solution is very time-expensive (since I touch many elements which aren't in the Circle and since I always need to evaluate pow). Can you think of a more intelligent and efficient way of iteration over all Circle-elements?
For every line find the first column that belongs to the circle, and walk from this column to one mirrored relative to the circle center. Pseudo code
for (int iy = - radius to radius; iy++)
dx = (int) sqrt(radius * radius - iy * iy)
for (int ix = - dx to dx; ix++)
doSomething(CX + ix, CY + iy);
Let the radius of the circle be r. Consider a Square of size (2r+1)*(2r+1) around the circle to be drawn. So equidistant points in square are stored in 2D array .
Now walk through every point inside the square. For every point (x,y), if (x, y) lies inside the circle (or x^2+ y^2 < r^2), then print it. For example, equidistant points form a 10x10 array, and a chosen "center" of the array at (x,y):
for i from 0 to 9 {
for j from 0 to 9 {
a = i - x
b = j - y
if a*a + b*b <= r*r {
// Do something here
}
}
}
I have a game where there is a 2D compass from 0-360 degrees that tells you the angle the camera is facing regardless of height.
I am trying to figure out how to get that angle using the model-view matrix. My algorithm works but not 100% of the time.
I have the following code for grabbing the angles from the model-view matrix.
Vector3D<float> GetEulerAngles(float ModelView[16])
{
float X = atan2(ModelView[9], ModelView[10]) * (180 / PI);
float Y = atan2(-ModelView[8], sqrt(pow(ModelView[0], 2) + pow(ModelView[4], 2))) * (180 / PI);
float Z = atan2(ModelView[4], ModelView[0]) * (180 / PI);
return {X < 0 ? 360 - X : X, Y < 0 ? 360 - Y : Y, Z < 0 ? 360 - Z : Z};
}
/*
Works so long as the camera is at its highest point (looking down on the player - 66deg angle)
-------
OR any height and: 90 < CompassAngle < 360 is true.
*/
int GetCompassAngle()
{
glGetFloatv(GL_MODELVIEW_MATRIX, &ModelView[0]);
Vector3D<float> angles = GetEulerAngles(ModelView);
return round(to_degrees(Z));
}
/*
Works so long as the camera is at any height (and: 0 < CompassAngle < 90)
*/
int GetCompassAngle()
{
glGetFloatv(GL_MODELVIEW_MATRIX, &ModelView[0]);
Vector3D<float> angles = GetEulerAngles(ModelView);
return round(360 - to_degrees(Y));
}
When I lower the camera, the second GetCompassAngle works. It reads the "Y" from the euler angles. However, if the camera is at the highest point, it reads the "Z" from the euler angles.
These work but when rotating and changing the camera angle changes the value and sometimes it gives me the wrong compass angle.
How can I combine them in some way or get the compass angle regardless of camera height?
Here are some numbers if it helps my case:
CompassHeight (Max - 65 deg from floor):
CompassDeg (X, Y, Z):
0deg: 65.0537253622628 358.814165052872 1.07537657735905
90deg: 88.1642315504792 312.258382165551 85.6596194029266
180deg: 115.286564608444 358.615368311296 178.747763300624
270deg: 90.1881102037367 47.9243745800853 269.562655218025
//Notice the "Z" values are the right compass angle or close enough.
CompassHeight (Low - 13 deg from floor):
CompassDeg (X, Y, Z):
0deg: 13.7624148875505 1.69169652884413 359.597596807979
90deg: 77.9527238194348 283.654247204305 77.5930785465022
180deg: 166.486754945655 355.694293448629 178.99462624173
270deg: 87.8507577921787 77.1021010565408 272.207848194156
I have a euclidean vector a sitting at the coordinates (0, 1).
I want to rotate a by 90 degrees (clockwise) around the origin: (0, 0).
If I have a proper understanding of how this should work, the resultant (x, y) coordinates after the rotation should be (1, 0).
If I were to rotate it by 45 degrees (still clockwise) instead, I would have expected the resultant coordinates to be (0.707, 0.707).
theta = deg2rad(angle);
cs = cos(theta);
sn = sin(theta);
x = x * cs - y * sn;
y = x * sn + y * cs;
Using the above code, with an angle value of 90.0 degrees, the resultant coordinates are: (-1, 1).
And I am so damn confused.
The examples seen in the following links represent the same formula shown above surely?
What have I done wrong?
Or have I misunderstood how a vector is to be rotated?
Rotating a vector 90 degrees is particularily simple.
(x, y) rotated 90 degrees around (0, 0) is (-y, x).
If you want to rotate clockwise, you simply do it the other way around, getting (y, -x).
you should remove the vars from the function:
x = x * cs - y * sn; // now x is something different than original vector x
y = x * sn + y * cs;
create new coordinates becomes, to avoid calculation of x before it reaches the second line:
px = x * cs - y * sn;
py = x * sn + y * cs;
Rotate by 90 degress around 0,0:
x' = -y
y' = x
Rotate by 90 degress around px,py:
x' = -(y - py) + px
y' = (x - px) + py
Sounds easier to do with the standard classes:
std::complex<double> vecA(0,1);
std::complex<double> i(0,1); // 90 degrees
std::complex<double> r45(sqrt(2.0),sqrt(2.0));
vecA *= i;
vecA *= r45;
Vector rotation is a subset of complex multiplication. To rotate over an angle alpha, you multiply by std::complex<double> { cos(alpha), sin(alpha) }
You're calculating the y-part of your new coordinate based on the 'new' x-part of the new coordinate. Basically this means your calculating the new output in terms of the new output...
Try to rewrite in terms of input and output:
vector2<double> multiply( vector2<double> input, double cs, double sn ) {
vector2<double> result;
result.x = input.x * cs - input.y * sn;
result.y = input.x * sn + input.y * cs;
return result;
}
Then you can do this:
vector2<double> input(0,1);
vector2<double> transformed = multiply( input, cs, sn );
Note how choosing proper names for your variables can avoid this problem alltogether!