Why is my image rotation algorithm not working? - math

Attempts 1 & 2:
Note: Removed first attempts to cut down on question size. See community wiki for previous attempts.
Attempt 3:
As per fuzzy-waffle's example, I have implemented the following, which doesn't appear to work correctly. Any ideas what I could be doing wrong?
ImageMatrix ImageMatrix::GetRotatedCopy(VDouble angle)
{
// Copy the specifications of the original.
ImageMatrix &source = *this;
ImageMatrix &target = CreateEmptyCopy();
double centerX = ((double)(source.GetColumnCount()-1)) / 2;
double centerY = ((double)(source.GetRowCount()-1)) / 2;
// Remember: row = y, column = x
for (VUInt32 y = 0; y < source.GetRowCount(); y++)
{
for (VUInt32 x = 0; x < source.GetColumnCount(); x++)
{
double dx = ((double)x) - centerX;
double dy = ((double)y) - centerY;
double newX = cos(angle) * dx - sin(angle) * dy + centerX;
double newY = cos(angle) * dy + sin(angle) * dx + centerY;
int ix = (int)round(newX);
int iy = (int)round(newY);
target[x][y][0] = source[ix][iy][0];
}
}
return target;
}
With this prototype matrix...
1 2 1
0 0 0
-1 -2 -1
... prototype.GetRotatedCopy(0) (which is correct) ...
1 2 1
0 0 0
-1 -2 -1
... prototype.GetRotatedCopy(90) (incorrect) ...
-2 0 0
-2 0 2
0 0 2
... prototype.GetRotatedCopy(180) (incorrect - but sort of logical?) ...
0 -1 -2
1 0 -1
2 1 0
... prototype.GetRotatedCopy(270) (incorrect - why is this the same as 0 rotation?) ...
1 2 1
0 0 0
-1 -2 -1
Solution:
As pointed out by Mark Ransom, I should be using radians, not degrees; I have adjusted my code as follows:
ImageMatrix ImageMatrix::GetRotatedCopy(VDouble degrees)
{
// Copy the specifications of the original.
ImageMatrix &source = *this;
ImageMatrix &target = CreateEmptyCopy();
// Convert degree measurement to radians.
double angle = degrees / 57.3;
// ... rest of code as in attempt #3 ...
Thanks for all your help guys!
1 2 1
0 0 0
-1 -2 -1
1 2 1
0 0 0
-1 -2 -1
-1 0 1
-2 0 2
-1 0 1
-1 -2 -1
0 0 0
1 2 1
1 0 -1
2 0 -2
1 0 -1

The algorithm, unless I read it wrong, seems to rotate around the point 0,0 which is not what you want. Maybe you need to add height/2 and width/2 to your row and column values before you plug them in.
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 10; x++) {
VUInt32 newX = (cos(angle) * (x-5)) - (sin(angle) * (y-5));
VUInt32 newY = (sin(angle) * (x-5)) + (cos(angle) * (y-5));
target[newY][newX][0] = source[y][x][0];
}
}
This basically adjusts the rotation center from the upper left corner to the center of the image.

Here is a complete example I hacked up:
I think among other things you may have not been using radians (which we all should use and love). I keep the new coordinates in doubles which seemed to make it less finicky. Note that I am not doing bounds checking which I should but I was lazy.
If you need a faster rotation you can always use shearing like this example.
#include <math.h>
#include <stdio.h>
#define SIZEX 3
#define SIZEY 3
int source[SIZEX][SIZEY] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
int target[SIZEX][SIZEY];
int main () {
double angle = M_PI/2.0;
memset(target,0,sizeof(int)*SIZEX*SIZEY);
double centerX = ((double)(SIZEX-1))/2.0;
double centerY = ((double)(SIZEY-1))/2.0;
for (int y = 0; y < SIZEY; y++) {
for (int x = 0; x < SIZEX; x++) {
double dx = ((double)x)-centerX;
double dy = ((double)y)-centerY;
double newX = cos(angle)*dx-sin(angle)*dy+centerX;
double newY = cos(angle)*dy+sin(angle)*dx+centerY;
int ix = (int) round(newX);
int iy = (int) round(newY);
target[x][y] = source[ix][iy];
}
}
for (int i=0;i<SIZEY;i++) {
for (int j=0;j<SIZEX;j++) {
printf("%d ", target[j][i]);
}
printf("\n");
}
}

short answer: you're doing it wrong.
This is essentially a problem in interpolation, and the way you've approached it introduces discontinuities. Fundamentally this is because rotating a lattice (the regular grid your image is laid out on) does not result in another sampling on the same lattice except for very special cases.
There is no single correct way to do this, by the way, but there are various trade offs with respect to speed and accuracy and also what can be assumed about the original signal (image).
So what are your design parameters? Do you need this to be very fast or very accurate? How do you want to handle aliasing?

your formulas for newRow and newColumn are switched. Remember that row = y and column = x.
Rotation

The problem is that your memory accesses are out of bounds.
After rotation your NewRow and NewColumn may be larger than the original width/height of the image. They may even be negative. If you don't take care about that fact, you'll end up with garbage data (best case) or crashes.
The most common way to deal with this is to just ignore all such pixels. You could also clamp or wrap around the valid intervals. This get's a padding or tiling effect.
Here it's shown with ignoring outside pixels.
int width = 10;
int height = 10;
for (int row = 0; row < height; row++)
{
for (int column = 0; column < width; column++)
{
int newRow = (cos(angle) * row) - (sin(angle) * column);
int newColumn = (sin(angle) * row) + (cos(angle) * column);
if ((newRow >=0) && (newRow < width) &&
(newColumn >=0) && (newColumn < height))
{
target[row][column][0] = source[newRow][newColumn][0];
}
}
}

Related

Game Of Life ends quickly (Java)

I've created a basic version of the Game Of Life: each turn, the board is simulated by a 2D array of 1's and 0's, after which another class creates a drawing of it for me using the 2d array
I've read all the other questions here regarding this game, but no answer seems to work out for me....sorry if I'm beating a dead horse here.
I think I have a problem with my algorithm, thus maybe the board gets filled with the wrong amount of dead and alive cells and thus ends rather quickly (5-10 turns).
I've found an algorithm here to scan all the neighbors and even added a count = -1 in case it a cell in the grid scans itself as it's own neighbor, but I think I'm missing something here.
public static void repaint(board game, int size,int[][] alive, int[][] newGeneration)
{
int MIN_X = 0, MIN_Y = 0, MAX_X =9, MAX_Y =9, count;
for ( int i = 0; i < size; i++ )
{
for (int j = 0; j < size; j++) //here we check for each matrix cell's neighbors to see if they are alive or dead
{
count = 0;
if (alive[i][j] == 1)
count = -1;
int startPosX = (i - 1 < MIN_X) ? i : i - 1;
int startPosY = (j - 1 < MIN_Y) ? j : j - 1;
int endPosX = (i + 1 > MAX_X) ? i : i + 1;
int endPosY = (j + 1 > MAX_Y) ? j : j + 1;
for (int rowNum = startPosX; rowNum <= endPosX; rowNum++)
{
for (int colNum = startPosY; colNum <= endPosY; colNum++)
{
if (alive[rowNum][colNum] == 1)
count++;
}
}
if (alive[i][j] == 0 && count == 3) //conditions of the game of life
newGeneration[i][j] = 1; //filling the new array for the next life
if (alive[i][j] == 1 && count < 2)
newGeneration[i][j] = 0;
if (alive[i][j] == 1 && count >= 4)
newGeneration[i][j] = 0;
if (alive[i][j] == 1 && count == 3)
newGeneration[i][j] = 1;
}
}
game.setAlive(newGeneration); //we created a new matrix with the new lives, now we set it
SetupGUI(game,size); //re drawing the panel
}
}
What am I doing wrong? thanks for the help.

Converting grid coordinates

So I have a grid which is in one form and im trying to get the X and Y.
Is there a formula where I could turn for example 12 into 2,2 or 14 to 2,3
Also is there a name for this type of grid?
static int getX(int z)
{
int count = 0;
int res = 0;
int curr = 0;
for(int temp = z; temp > 0; temp >>= 1)
{
if(count % 2 ==0)
{
res += ((temp & 1) << curr);
curr++;
}
count++;
}
return res;
}
static int getY(int z)
{
int count = 0;
int res = 0;
int curr = 0;
for(int temp = z; temp > 0; temp >>= 1)
{
if(count % 2 ==1)
{
res += ((temp & 1) << curr);
curr++;
}
count++;
}
return res;
}
As Sneftel observed, this looks like a Z-order curve. As such, you can convert coordinates by interleaving binary representations. So your examples are
0 1 0 x=2 0 1 0 x=2
0 1 0 y=2 0 1 1 y=3
001100 p=12 001110 p=14
So to get x and y coordinates from the cell number p, you assign the bits of p alternatingly to x and y. This kind of bit arithmetic is pretty hard to express using elementary arithmetic operations, and there is no generally recognized formula symbol for this that I'm aware of, but the idea is quite simple.

(JavaFX) - Snake Iteration 2D Matrix at Snakes and Ladders game

I am creating the game "Snakes And Ladders". I am using a GridPane to represent the game board and obviously I want to move through the board in a "snake" way. Just like that: http://prntscr.com/k5lcaq .
When the dice is rolled I want to move 'dice_num' moves forward + your current position, so I am calculating the new index using an 1D array and I convert this index to 2D coordinates (Reverse Row-Major Order).
gameGrid.add(pieceImage, newIndex % ROWS, newIndex / ROWS);
Where gameGrid is the ID of my grid pane, newIndex % ROWS represents the column coordinate and newIndex / ROWS the row coordinate.
PROBLEM 1: The grid pane is iterating in its own way. Just like that: https://prnt.sc/k5lhjx.
Obviously when the 2D array meets coordinates [0,9] , next position is [1,0] but what I actually want as next position is [1,9] (going from 91 to 90).
PROBLEM 2: I want to start counting from the bottom of the grid pane (from number 1, see screenshots) and go all the way up till 100. But how am I supposed to reverse iterate through a 2D array?
You can easily turn the coordinate system upside down with the following conversion:
y' = maxY - y
To get the "snake order", you simply need to check, if the row the index difference is odd or even. For even cases increasing the index should increase the x coordinate
x' = x
for odd cases you need to apply a transformation similar to the y transformation above
x' = xMax - x
The following methods allow you to convert between (x, y) and 1D-index. Note that the index is 0-based:
private static final int ROWS = 10;
private static final int COLUMNS = 10;
public static int getIndex(int column, int row) {
int offsetY = ROWS - 1 - row;
int offsetX = ((offsetY & 1) == 0) ? column : COLUMNS - 1 - column;
return offsetY * COLUMNS + offsetX;
}
public static int[] getPosition(int index) {
int offsetY = index / COLUMNS;
int dx = index % COLUMNS;
int offsetX = ((offsetY & 1) == 0) ? dx : COLUMNS - 1 - dx;
return new int[] { offsetX, ROWS - 1 - offsetY };
}
for (int y = 0; y < ROWS; y++) {
for (int x = 0; x < COLUMNS; x++, i++) {
System.out.print('\t' + Integer.toString(getIndex(x, y)));
}
System.out.println();
}
System.out.println();
for (int j = 0; j < COLUMNS * ROWS; j++) {
int[] pos = getPosition(j);
System.out.format("%d: (%d, %d)\n", j, pos[0], pos[1]);
}
This should allow you to easily modify the position:
int[] nextPos = getPosition(steps + getIndex(currentX, currentY));
int nextX = nextPos[0];
int nextY = nextPos[1];

How to get a logarithmic distribution from an interval

I am currently trying to cut an interval into not equal-width slices. In fact I want the width of each slice to follow a logarithmic rule. For instance the first interval is supposed to be bigger than the second one, etc.
I have a hard time remembering my mathematics lectures. So assuming I know a and b which are respectively the lower and upper boundaries of my interval I, and n is the number of slices:
how can I find the lower and upper boundaries of each slice (following a logarithmic scale)?
In other word, here's what I have done to get equal-width interval:
for (i = 1; i< p; i++) {
start = lower + i -1 + ((i-1) * size_piece);
if (i == p-1 ) {
end = upper;
} else {
end = start + size_piece;
}
//function(start, end)
}
Where: p-1= number of slices, and size_piece = |b-a|.
What I want to get now is start and end values, but following a logarithmic scale instead of an arithmetic scale (which are going to be called in some function in the for loop).
Thanks in advance for your help.
If I have understood your question, this C++ program will show you a practical example of the algorithm that can be used:
#include <iostream>
#include <cmath>
void my_function( double a, double b ) {
// print out the lower and upper bounds of the slice
std::cout << a << " -- " << b << '\n';
}
int main() {
double start = 0.0, end = 1.0;
int n_slices = 7;
// I want to create 7 slices in a segment of length = end - start
// whose extremes are logarithmically distributed:
// | 1 | 2 | 3 | 4 | 5 |6 |7|
// +-----------------+----------+------+----+---+--+-+
// start end
double scale = (end - start) / log(1.0 + n_slices);
double lower_bound = start;
for ( int i = 0; i < n_slices; ++i ) {
// transform to the interval (1,n_slices+1):
// 1 2 3 4 5 6 7 8
// +-----------------+----------+------+----+---+--+-+
// start end
double upper_bound = start + log(2.0 + i) * scale;
// use the extremes in your function
my_function(lower_bound,upper_bound);
// update
lower_bound = upper_bound;
}
return 0;
}
The output (the extremes of the slices) is:
0 -- 0.333333
0.333333 -- 0.528321
0.528321 -- 0.666667
0.666667 -- 0.773976
0.773976 -- 0.861654
0.861654 -- 0.935785
0.935785 -- 1

Determine position of number in a grid of numbers centered around 0 and increasing in spiral

I've got the following grid of numbers centered around 0 and increasing in spiral. I need an algorithm which would receive number in spiral and return x; y - numbers of moves how to get to that number from 0. For example for number 9 it would return -2; -1. For 4 it would be 1; 1.
25|26|... etc.
24| 9|10|11|12
23| 8| 1| 2|13
22| 7| 0| 3|14
21| 6| 5| 4|15
20|19|18|17|16
This spiral can be slightly changed if it would help the algorithm to be better.
Use whatever language you like. I would really appreciate mathematical explanation.
Thank you.
First we need to determine which cycle (distance from center) and sector (north, east, south or west) we are in. Then we can determine the exact position of the number.
The first numbers in each cycle is as follows: 1, 9, 25
This is a quadratic sequence: first(n) = (2n-1)^2 = 4n^2 - 4n + 1
The inverse of this is the cycle-number: cycle(i) = floor((sqrt(i) + 1) / 2)
The length of a cycle is: length(n) = first(n+1) - first(n) = 8n
The sector will then be:
sector(i) = floor(4 * (i - first(cycle(i))) / length(cycle(i)))
Finally, to get the position, we need to extrapolate from the position of the first number in the cycle and sector.
To put it all together:
def first(cycle):
x = 2 * cycle - 1
return x * x
def cycle(index):
return (isqrt(index) + 1)//2
def length(cycle):
return 8 * cycle
def sector(index):
c = cycle(index)
offset = index - first(c)
n = length(c)
return 4 * offset / n
def position(index):
c = cycle(index)
s = sector(index)
offset = index - first(c) - s * length(c) // 4
if s == 0: #north
return -c, -c + offset + 1
if s == 1: #east
return -c + offset + 1, c
if s == 2: #south
return c, c - offset - 1
# else, west
return c - offset - 1, -c
def isqrt(x):
"""Calculates the integer square root of a number"""
if x < 0:
raise ValueError('square root not defined for negative numbers')
n = int(x)
if n == 0:
return 0
a, b = divmod(n.bit_length(), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y
Example:
>>> position(9)
(-2, -1)
>>> position(4)
(1, 1)
>>> position(123456)
(-176, 80)
Do you mean something like this? I did not implement any algorithm and the code can be written better but it works - that's always a start :) Just change the threshold value for whatever you wish and you'll get the result.
static int threshold=14, x=0, y=0;
public static void main(String[] args) {
int yChange=1, xChange=1, count=0;
while( !end(count) ){
for (int i = 0; i < yChange; i++) {
if( end(count) )return;
count++;
y--;
}
yChange++;
for (int i = 0; i < xChange; i++) {
if( end(count) )return;
count++;
x++;
}
xChange++;
for (int i = 0; i < yChange; i++) {
if( end(count) )return;
count++;
y++;
}
yChange++;
for (int i = 0; i < xChange; i++) {
if( end(count) )return;
count++;
x--;
}
xChange++;
}
}
public static boolean end(int count){
if(count<threshold){
return false;
}else{
System.out.println("count: "+count+", x: "+x+", y: "+y);
return true;
}
}

Resources