I have been trying to use a rotation matrix to rotate an image. Below is the code I've been using. I have been trying to do so for days now, and everytime it seems there is something wrong, but I can't see what I am doing wrong. For example, my image is getting slanted, instead of rotating...
The code below is divided in two parts: the actual rotation, and moving the picture upwards to make it appear in the correct spot (it needs to have all its point above 0 to be saved properly). It takes as input an array of pixels (containing position information (x, y), and colour information (r, g, b)), an image (used solely to get its pixel count, aka the array size, and the width), and a value in radians for the rotation.
The part responsible for the rotation itself is the one above the line, while the part below the line is responsible for calculating the lowest point in the image, and moving all pixels up or to the right so the all fit (I need still to implement a function to change the image size when an image is rotated by 45 degrees, or similar).
void Rotate( Pixel *p_pixelsToRotate, prg::Image* img, float rad )
{
int imgLength = img->getPixelCount();
int width = img->getWidth();
int x { 0 }, y { 0 };
for( int i = 0; i < imgLength; i++ )
{
x = p_pixelsToRotate[i].x;
y = p_pixelsToRotate[i].y;
p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );
p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
}
===========================================================================
Pixel* P1 = &p_pixelsToRotate[ width - 1 ]; // Definitions of these are in the supporting docs
Pixel* P3 = &p_pixelsToRotate[ imgLength - 1 ];
int xDiff = 0;
int yDiff = 0;
if( P1->x < 0 || P3->x < 0 )
{
(( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
}
if( P1->y < 0 || P3->y < 0 )
{
(( P1->y < P3->y )) ? ( yDiff = abs( P1->y )) : ( yDiff = abs( P3->y ));
}
for( int i = 0; i < imgLength; i++ )
{
p_pixelsToRotate[i].x += xDiff;
p_pixelsToRotate[i].y += yDiff;
}
}
I would prefer fixing this myself, but have been unable to do so for more than a week now. I don't see why the function is not rotating the position information for the array of input pixel. If someone could have a look, and maybe spot why my logic isn't working, I would be immensely grateful. Thank you.
Seems you just made a mistake in the rotation matrix itself:
p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
^^^---------------change to cos
For one thing, this is a mistake:
p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );
p_pixelsToRotate[i].y = round( sin( rad ) * x + >>>sin<<<( rad ) * y );
The >>>sin<<< should be cos. This would explain getting a shear rather than a rotation.
Other comments: Storing pixel coordinates in bitmap data is an extremely expensive way to solve the problem of bitmap rotation. The better way is inverse transform sampling. With a source image X and wishing to rotate it with transform R to get Y, you are currently thinking
Y = R X
where X and Y have the pixel coordinates explicitly stored. To use inverse sampling, think instead of the same equation multiplied on both sides by the inverse of R.
R^(-1) Y = X
where the coordinates are implicit. That is, to produce Y[j][i], transform (j,i) with the inverse R^(-1) to get a coordinate (x,y) in the X image. Use this to sample the nearest pixel X[round(x)][round(y)] in X and assign that as Y[j][i].
(Actually, rather than simple rounding, a more sophisticated algorithm will take a weighted average of the X pixels around (x,y) to get a smoother result. How to choose the weights is a big additional topic.)
After you have this working, you can go a step farther. Instead of doing a full matrix-vector multiplication for each pixel, some algebra will show that the previous sampling coordinate can be updated to get an adjacent one (next to the right or left, up or down) with just a couple of additions. This speeds things up considerably.
The inverse of a rotation is trivial to compute! Just negate the rotation angle.
A last note is that your use of ternary operators o ? o : o to select assignments is truly terrible style. Instead of this:
(( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
say
xDiff = ( P1->x < P3->x ) ? abs( P1->x ) : abs( P3->x );
Related
I want to draw an arc with opengl. The arc should start from an specific point and ends at a given point. Given are radius, centre of the arc and arc length, start angle and end angle.
I have tried following function:
for (double theta = start_angle1; theta < end_angle1; theta += angle_increment)
{
glVertex2f((arcCenX+ r * sinf(theta)),(arcCenY+ r * cosf(theta)));
}
This functions gives arc properly, but starting point of arc is different.
How to specify a starting point of an arc?
Edit: I also have tried this
for ( angleIndex = 0; angleIndex < arc_len; angleIndex = angleIndex+arcSegmentIndex )
{
glVertex2f((x + ( cosf( start_angle1 + angleIndex ) )* r),
(y + ( sinf( start_angle1 + angleIndex ) )* r));
}
But it also not working.
It should be
glVertex2f((arcCenX+ r * cosf(theta)),(arcCenY+ r * sinf(theta)));
Its bascially the parametric equation of the circle so
x = r cos(0)
y = r sin(0)
where "r" is the radius of the circle. You have your x and y coordinates swapped maybe that's what's causing the problem.
Edit:- to clear it up, the starting point of the arc depends on the first theta value you put in. so if for example the first value that goes into theta is 90 degrees then the arc starts directly above the center of the circle at a distance r.
I'm trying to generate fractals using five different transformations that I have implemented from skeleton code, translate, rotate, scale, non-uniform scale, and image. These transformations are all 3x3 matrices, for example:
Matrix rotate ( Pt p, float theta )
{
Matrix rvalue;
rvalue.data[0][0] = cos(theta);
rvalue.data[0][1] = -sin(theta);
rvalue.data[0][2] = p.x + p.y*sin(theta) - p.x*cos(theta);
rvalue.data[1][0] = sin(theta);
rvalue.data[1][1] = cos(theta);
rvalue.data[1][2] = p.y - p.y*cos(theta) - p.x*sin(theta);
rvalue.data[2][0] = 0;
rvalue.data[2][1] = 0;
rvalue.data[2][2] = 1;
return rvalue;
}
where Matrix is defined as
class Matrix
{
public:
float data [ 3 ] [ 3 ];
Matrix ( void )
{
int i, j;
for ( i = 0; i < 3; i++ )
{
for ( j = 0; j < 3; j++ )
{
data [ i ] [ j ] = 0;
}
}
}
};
In a test file, there is the following code that is supposed to generate Serpinski's Triangle
vector<Matrix> iat;
iat.push_back ( scale ( Pt ( -.9, -.9 ), 0.5 ) );
iat.push_back ( scale ( Pt ( .9, -.9 ), 0.5 ) );
iat.push_back ( scale ( Pt ( 0, .56 ), 0.5 ) );
setIATTransformations ( iat );
Where Pt is defined as:
class Pt
{
public:
float x, y;
Pt ( float newX, float newY )
{
x = newX;
y = newY;
}
Pt ( void )
{
x = y = 0;
}
};
How should I implement setIATTransformations? Multiply the matrices until there is one transformation matrix and loop it a number of times to generate the fractal?
you want sierpinski triangle or fractal generator driven by input script ?
1.triangle
is easy enough
no rotations translations or what so ever are needed
just create the points according to sierpinski rule http://en.wikipedia.org/wiki/Sierpinski_triangle
all sides of triangles are divided to half
so the new points are just average of start and end point of each line
and then fill the sub triangles
if you want just wire-frame then even the point list is not needed
2.generator
you did not provide any rules,commands for the control script
the only thing I see in your script is input of the 3 vertexes of the triangle
and that is all
I do not see any rule for triangle division
or which part is filled or not
how many recursions are used
the only thing you mentioned was that you use 5 transformation matrices 3x3 for rotation,scale and translation
but did not specify when and why
You will have to implement the chaos game. That is, you randomly select one of the transformations and apply it to the iteration point. Do it a number (30, 50 or 100) without painting the point and after that mark all the points. The resulting point cloud will in time fill the fractal.
Your operation scale( Pt (a,b), s) should realize the operation
(x',y')=s*(x,y)+(1-s)*(a,b), that is, in matrix terms
| x' | | s 0 (1-s)*a| | x |
| y' | = | 0 s (1-s)*b| * | y |
| 1 | | 0 0 1 | | y |
I have been trying to implement a simple Gaussian blur algorithm, for my image editing program. However, I have been having some trouble making this work, and I think the problem lies in the below snippet:
for( int j = 0; j < pow( kernel_size, 2 ); j++ )
{
int idx = ( i + kx + ( ky * img.width ));
//Try and overload this whenever possible
valueR += ( img.p_pixelArray[ idx ].r * kernel[ j ] );
valueG += ( img.p_pixelArray[ idx ].g * kernel[ j ] );
valueB += ( img.p_pixelArray[ idx ].b * kernel[ j ] );
if( kx == kernel_limit )
{
kx = -kernel_limit;
ky++;
}
else
{
kx++;
}
}
kx = -kernel_limit;
ky = -kernel_limit;
A brief explanation of the code above: kernel size is the size of the kernel (or matrix) generated by the Gaussian blur formula. kx and ky are variables to be used for iterating over the kernel. i is the parent loop, that nests this one, and goes over every pixel in the image. Each value variable simply holds a float R, G, or B value, and is used afterwards to obtain the final result. The if-else is used to increase kx and ky. idx is used to find the correct pixel. kernel limit is a variable set to
(*kernel size* - 1) / 2
So I can have kx going from -1 ( with a 3x3 kernel ) to +1, and the same thing with ky. I think the problem lies with the line
int idx = ( i + kx + ( ky * img.width ));
But I am not sure. The image I get is:
As can be seen, the color is blurred in a diagonal direction, and looks more like some kind of motion blur than Gaussian blur. If someone could help out, I would be very grateful.
EDIT:
The way I fill the kernel is as follows:
for( int i = 0; i < pow( kernel_size, 2 ); i++ )
{
// This. Is. Lisp.
kernel[i] = (( 1 / ( 2 * pi * pow( sigma, 2 ))) * pow (e, ( -((( pow( kx, 2 ) + pow( ky, 2 )) / 2 * pow( sigma, 2 ))))));
if(( kx + 1 ) == kernel_size )
{
kx = 0;
ky++;
}
else
{
kx++;
}
}
Few problems:
Your Gaussian misses brackets (even though you already have plenty..) around 2 * pow( sigma, 2 ). Now you multiply by variance instead of divide.
But what your problem is, is that your gaussian is centered at kx = ky = 0, as you let it run from 0 to kernel_size, instead of from -kernel_limit to kernel_limit. This results in the diagonal blurring. Something like the following should work better
kx = -kernel_limit;
ky = -kernel_limit;
int kernel_size_sq = kernel_size * kernel_size;
for( int i = 0; i < kernel_size_sq; i++ )
{
double sigma_sq = sigma * sigma;
double kx_sq = kx * kx;
double ky_sq = ky * ky;
kernel[i] = 1.0 / ( 2 * pi * sigma_sq) * exp(-(kx_sq + ky_sq) / (2 * sigma_sq));
if(kx == kernel_limit )
{
kx = -kernel_limit;
ky++;
}
else
{
kx++;
}
}
Also note how I got rid of your lisp-ness and some improvements: use some intermediate variables for clarity (compiler will optimize them away if anyway you ask it to); simple multiplication is faster than pow(x, 2); pow(e, x) == exp(x).
Distance from point to point: dist = sqrt(dx * dx + dy * dy);
But sqrt is too slow and I can't accept that. I found a method called Taylor McLaughlin Series to estimate the distance of two points on the book. But I can't comprehend the following code. Thanks for anyone who helps me.
#define MIN(a, b) ((a < b) ? a : b)
int FastDistance2D(int x, int y)
{
// This function computes the distance from 0,0 to x,y with 3.5% error
// First compute the absolute value of x, y
x = abs(x);
y = abs(y);
// Compute the minimum of x, y
int mn = MIN(x, y);
// Return the distance
return x + y - (mn >> 1) - (mn >> 2) + (mn >> 4);
}
I have consulted related data about McLaughlin Series, but I still can't comprehend how the return value use McLaughlin Series to estimate the value. Thanks for everyone~
This task is almost duplicate of another one:
Very fast 3D distance check?
And there was link to great article:
http://www.azillionmonkeys.com/qed/sqroot.html
In the article you can find different aproaches for approximation of root. For example maybe this one is suitable for you:
int isqrt (long r) {
float tempf, x, y, rr;
int is;
rr = (long) r;
y = rr*0.5;
*(unsigned long *) &tempf = (0xbe6f0000 - *(unsigned long *) &rr) >> 1;
x = tempf;
x = (1.5*x) - (x*x)*(x*y);
if (r > 101123) x = (1.5*x) - (x*x)*(x*y);
is = (int) (x*rr + 0.5);
return is + ((signed int) (r - is*is)) >> 31;
}
If you can calculate root operation fast, then you can calculate distance in regular way:
return isqrt(a*a+b*b)
And one more link:
http://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml
u32 approx_distance( s32 dx, s32 dy )
{
u32 min, max;
if ( dx < 0 ) dx = -dx;
if ( dy < 0 ) dy = -dy;
if ( dx < dy )
{
min = dx;
max = dy;
} else {
min = dy;
max = dx;
}
// coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min )
return ((( max << 8 ) + ( max << 3 ) - ( max << 4 ) - ( max << 1 ) +
( min << 7 ) - ( min << 5 ) + ( min << 3 ) - ( min << 1 )) >> 8 );
}
You are right sqrt is quite a slow function. But do you really need to compute the distance?
In a lot of cases you can use the distance² instead.
E.g.
If you want to find out what distance is shorter, you can compare the squares of the distance as well as the real distances.
If you want to check if a 100 > distance you can as well check 10000 > distanceSquared
Using the ditance squared in your program instead of the distance you can often avoid calculating the sqrt.
It depends on your application if this is an option for you, but it is always worth to be considered.
In C++ we can rotate a point about an arbitrary axis:
void radRotateAxis( float a, float b, float c, float theta )
{
float newX = (
x*( a*a*(1-cos(theta)) + cos(theta) ) +
y*( a*b*(1-cos(theta)) - c*sin(theta) ) +
z*( a*c*(1-cos(theta)) + b*sin(theta) ) );
float newY = (
x*( a*b*(1-cos(theta)) + c*sin(theta) ) +
y*( b*b*(1-cos(theta)) + cos(theta) ) +
z*( b*c*(1-cos(theta)) - a*sin(theta) ) );
float newZ = (
x*( a*c*(1-cos(theta)) - b*sin(theta) ) +
y*( b*c*(1-cos(theta)) + a*sin(theta) ) +
z*( c*c*(1-cos(theta)) + cos(theta) ) );
x = newX ;
y = newY ;
z = newZ ;
}
But as we walk theta 0 -> 2PI this takes the point around a "unit circle" around the axis you're rotating about
How can we make it so as theta 0 -> 2PI the results are about an ellipse of width a, height b?
I do not want to apply transformation matrices to the points after rotating them about the axis - what I'm looking for is an "elliptical" rotation matrix, if anyone knows of such a thing!
Define a matrix A to scale the target ellipse to a suitable unit circle.
Then the composition of A, the rotation matrix, and the inverse of A is your elliptical rotation matrix.