How can I rotate a 2d array smaller than 90 °, in the best approximation?

Let's say I have an array that is stored at 0 ° rotation:

0 0 1 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 

And I want it to come back in a good approximation, if I pass, for example 30 ° as a parameter, it will be something like this:

 0 0 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 

45 ° would be

 1 0 0 0 1 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 

I am aware of the solutions placed to rotate 90 °. But I do not think this will help me here?

I don't have an example code because I don’t even know where to start looking. If there are any keywords, I can point to google, which point me in the directions of some formula that I can adapt for this, which would also be great.

Solution for ghost code in C #:

  class Rotation { public Rotation() { A = new int[xs,ys]{ {0,0,0,9,0,0,0}, {0,0,0,9,0,0,0}, {0,0,0,9,0,0,0}, {9,9,9,9,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, }; B = new int[xs, ys]; deg = (float)(Math.PI / 180.0); } public const int xs = 7; // matrix size public const int ys = 7; const int x0 = 3; // rotation center cell const int y0 = 3; readonly float deg; public int[,] A; public int[,] B; //--------------------------------------------------------------------------- public void rotcv(float ang) { rotcw(Rotation.x0, Rotation.y0, ang); } private void rotcw(int x0, int y0, float ang) // rotate A -> B by angle ang around (x0,y0) CW if ang>0 { int x, y, ix0, iy0, ix1, iy1, q; double xx, yy, fx, fy, c, s; // circle kernel c = Math.Cos(-ang); s = Math.Sin(-ang); // rotate for (y = 0; y < ys; y++) for (x = 0; x < xs; x++) { // offset so (0,0) is center of rotation xx = x - x0; yy = y - y0; // rotate (fx,fy) by ang fx = ((xx * c) - (yy * s)); fy = ((xx * s) + (yy * c)); // offset back and convert to ints and weights fx += x0; ix0 = (int)Math.Floor(fx); fx -= ix0; ix1 = ix0 + 1; if (ix1 >= xs) ix1 = ix0; fy += y0; iy0 = (int)Math.Floor (fy); fy -= iy0; iy1 = iy0 + 1; if (iy1 >= ys) iy1 = iy0; // bilinear interpolation A[fx][fy] -> B[x][y] if ((ix0 >= 0) && (ix0 < xs) && (iy0 >= 0) && (iy0 < ys)) { xx = (A[ix0,iy0]) + ((A[ix1,iy0] - A[ix0,iy0]) * fx); yy = (A[ix0,iy0]) + ((A[ix1,iy0] - A[ix0,iy0]) * fx); xx = xx + ((yy - xx) * fy); q =(int) xx; } else q = 0; B[x,y] = q; } } } 

Test:

  static void Main(string[] args) { Rotation rot = new Rotation(); for (int x = 0; x < Rotation.xs; x++) { for (int y = 0; y < Rotation.xs; y++) { Console.Write(rot.A[x,y] + " "); } Console.WriteLine(); } Console.WriteLine(); float rotAngle = 0; while (true) { rotAngle += (float)(Math.PI/180f)*90; rot.rotcv(rotAngle); for (int x = 0; x < Rotation.xs; x++) { for (int y = 0; y < Rotation.xs; y++) { Console.Write(rot.B[x, y] + " "); } Console.WriteLine(); } Console.WriteLine(); Console.ReadLine(); } } 
+5
source share
3 answers

Well, that’s how it was promised. The first C ++ code :

 //--------------------------------------------------------------------------- #include <math.h> //--------------------------------------------------------------------------- const int xs=7; // matrix size const int ys=7; const int x0=3; // rotation center cell const int y0=3; const float deg=M_PI/180.0; int A[xs][ys]= { {0,0,0,9,0,0,0}, {0,0,0,9,0,0,0}, {0,0,0,9,0,0,0}, {9,9,9,9,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, }; int B[xs][ys]; //--------------------------------------------------------------------------- void rotcw(int x0,int y0,float ang) // rotate A -> B by angle ang around (x0,y0) CW if ang>0 { int x,y,ix0,iy0,ix1,iy1,q; float xx,yy,fx,fy,c,s; // circle kernel c=cos(-ang); s=sin(-ang); // rotate for (y=0;y<ys;y++) for (x=0;x<xs;x++) { // offset so (0,0) is center of rotation xx=x-x0; yy=y-y0; // rotate (fx,fy) by ang fx=float((xx*c)-(yy*s)); fy=float((xx*s)+(yy*c)); // offset back and convert to ints and weights fx+=x0; ix0=floor(fx); fx-=ix0; ix1=ix0+1; if (ix1>=xs) ix1=ix0; fy+=y0; iy0=floor(fy); fy-=iy0; iy1=iy0+1; if (iy1>=ys) iy1=iy0; // bilinear interpolation A[ix0+fx][iy0+fy] -> B[x][y] if ((ix0>=0)&&(ix0<xs)&&(iy0>=0)&&(iy0<ys)) { xx=float(A[ix0][iy0])+(float(A[ix1][iy0]-A[ix0][iy0])*fx); yy=float(A[ix0][iy0])+(float(A[ix1][iy0]-A[ix0][iy0])*fx); xx=xx+((yy-xx)*fy); q=xx; } else q=0; B[x][y]=q; } } //--------------------------------------------------------------------------- 

Here is a 7x7 preview of 15 deg steps:

preview

It may take a little adjustment of the center to half the cell or something (the center bleeds too much to my liking)

Matrix A is the source and B is the target ...

You can also add tresholding ... like:

 if (q>=5) q=9; else q=0; 
+1
source

Imagine your matrix is ​​a 2D world, where its beginning (0, 0) is the pixel in the middle. Then, for example, the coordinates of the point in the upper left corner will be (-2, 2). If you multiply this vector by a two-dimensional rotation matrix, you will get new coordinates in a rotating world. Here you can get closer as you like (round, floor, ciel, ...).

Here is the definition of the rotation matrix:

  | cos a -sin a| | sin a cos a | 

where a is your angle of rotation. Here is how you multiply:

https://wikimedia.org/api/rest_v1/media/math/render/svg/50622f9a4a7ba2961f5df5f7e0882983cf2f1d2f

In this image (x, y), the initial coordinates (for example, (-2, 2) for the upper left corner pixel) and (x ', y') are the new (approximate) coordinates.

+1
source

It has already been implemented many times for image processing in Photoshop, GIMP, ... and Imagemagick.

You can use a library (e.g. Python with numpy) to convert from a matrix to a bitmap, ImageMagick to rotate it x degrees and read the result from the rotated image back to the matrix. You will need to decide what to do with the corners, they will be truncated if you want to rotate the n * n grid into the n * n grid.

This can be done in several lines, you do not need to reinvent the wheel, and you will get gray values ​​around the rotated point, if they do not fall exactly into the cell.

Mini shots: enter image description here enter image description here

Reading Results Using Python:

 import matplotlib.image as img image = img.imread('matrix.png') print image[:,:,0] # Only reads grayscale information. # Original [[ 0. 0. 1. 0. 0.] [ 0. 0. 1. 0. 0.] [ 1. 1. 1. 0. 0.] [ 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0.]] # Rotated by 30° [[ 0.07450981 0. 0.08235294 0.8509804 0. ] [ 0.68627453 0.82745099 0.53725493 0.78039217 0. ] [ 0. 0.50980395 0.97647059 0.22745098 0. ] [ 0. 0. 0.05882353 0. 0. ] [ 0. 0. 0. 0. 0. ]] 

For a Java solution, AffineTransform can help you. Here is an example.

+1
source

Source: https://habr.com/ru/post/1259712/


All Articles