当前位置: 首页 > 知识库问答 >
问题:

旋转位矩阵

锺离刚洁
2023-03-14

假设我使用大小为8的字符数组来表示图像的碰撞掩码。字符的每一位代表一个像素。实际上,对于64x64矩阵,我将使用长[64]阵列。

因此,框将显示为:

00000000
01111110
01111110
01111110
01111110
01111110
01111110
00000000

45度的示例输出应该是这样的,尽管旋转可以是任何角度。这个形状对于45度旋转可能不准确,因为我是用手做的。

00011000
00111100
01111110
11111111
11111111
01111110
00111100
00011000

另一个例子是向右旋转10度?这些值可能是错误的,因为从数学上讲,我不知道它将如何精确旋转,但我认为可以安全地假设,如果每个位的覆盖率超过旧形状的50%,那么它将是1。

00000000
00111111
01111111
01111110
01111110
11111110
11111100
00000000

在没有旋转的情况下,使用stackoverflow回复中定义的位移位快速查找这些位掩码之间的冲突:https://stackoverflow.com/a/336615/4595736

现在,在过去我使用了Path2D、矩形、形状等。。。并使用仿射变换旋转对象。Path2D是唯一一个提供我想要的复杂形状的类,但它访问每个点的“链表式”行为并没有我想要的那么快。

在Java中旋转二进制地图的最佳方式是什么?

此外,矩阵的Java库似乎也不是最快的。

共有2个答案

呼延升
2023-03-14

我同意通常最好映射输出的条目,但这足以检测冲突。您可以将内部点设置为0,使其更加稀疏(如果您没有可以跳入其他对象的非常小的对象):

...

// simple algorithm to remove inner 1s with a sliding window,
// here shown with 3x3 but I think it has to be 5x5 (you can omit the corners)
int[][] inputSparse = new int[input.length][input[0].length];
// assuming the border is 0 anyway
// not the best way to implement it, but it shows the idea and it only has to be done once
for (int i = 1; i < inputSparse.length - 1; i++) {
  for (int j = 1; j < inputSparse[0].length - 1; j++) {
    if (input[i-1][j-1] != 1 || input[i-1][j] != 1 || input[i-1][j+1] !=1 ||
        input[i][j-1] != 1 || input[i][j] != 1 || input[i][j+1] != 1 ||
        input[i+1][j-1] != 1 || input[i+1][j] != 1 || input[i+1][j+1] !=1) {
      inputSparse[i][j] = input[i][j];
    } else {
      inputSparse[i][j] = 0; // just to show that a one is removed, you don't need the else
    }
  }
}
...
output = rotate(inputSparse, 10); // example
...
private int[][] rotate(int[][] input, double degrees) {
  double rad = Math.toRadians(degrees);
  double sin = Math.sin(rad);
  double cos = Math.cos(rad);
  int[][] output = new int[input.length][input[0].length];
  for (int i = 0;  i < input.length; i++) {
    double oldY = i - (input.length - 1) / 2.0;
    for (int j = 0; j < input[0].length; j++) {
      if (input[i][j] == 1) { // <-- this is the big gain !!!
        double oldX = j - (input[0].length - 1) / 2.0;
        int x = (int)(cos * oldX + sin * oldY + input[0].length / 2.0);
        int y = (int)(-sin * oldX + cos * oldY + input.length / 2.0);
        output[y][x] = 1;
      }
    }
  }
  return output;
}

旧答案:我不知道这是否足够好,但你只能转换一个,希望它有任何意义,我不知道你是否会得到“洞”(在一个之间的0),而且这只有当你在一周围有足够的0或者索引将超出界限时才行得通,无论如何,我的建议是:

int[][] input = {{0, 0, 0, 0, 0, 0, 0, 0},
                 {0, 0, 0, 0, 0, 0, 0, 0},
                 {0, 0, 1, 1, 1, 1, 0, 0},
                 {0, 0, 1, 1, 1, 1, 0, 0},
                 {0, 0, 1, 1, 1, 1, 0, 0},
                 {0, 0, 1, 1, 1, 1, 0, 0},
                 {0, 0, 0, 0, 0, 0, 0, 0},
                 {0, 0, 0, 0, 0, 0, 0, 0}};

double rad = Math.toRadians(10); // 10 * Math.PI / 180;
double sin = Math.sin(rad);
double cos = Math.cos(rad);

int[][] output = new int[8][8];
// or: int[][] output = new int[input.lengh][input[0].lengh];

for (int i = 0;  i < 8; i++) {
  double oldX = i - 3.5; // move to center
  for (int j = 0; j < 8; j++) {
   if (input[i][j] == 1) {
     double oldY = j - 3.5; // move to center
     int x = (int)(cos * oldX + sin * oldY + 4); // + 3.5 to shift back, +0.5 to simulate rounding
     int y = (int)(-sin * oldX + cos * oldY + 4);
     output[x][y] = 1;
   }
  }
}
顾承平
2023-03-14

该解决方案基于先验答案。它不是将输入点映射到输出点,而是将输出点映射到输入矩阵空间中的位置。

在这个版本中,它只是使用最接近的整数索引点的值。通过使用相邻点的距离加权值和进行更复杂的值计算,可能会得到更好的结果。

以下是一些结果:

Angle: 10.0 degrees
00000000 00000000
00000000 00000000
00111100 00011000
00111100 00011110
00111100 00111110
00111100 00111100
00000000 00001100
00000000 00000000

Angle: 45.0 degrees
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000001000000000
00000000000000000000 00000000011100000000
00000111111111100000 00000000111110000000
00000111111111100000 00000001111111000000
00000111111111100000 00000011111111100000
00000111111111100000 00000111111111110000
00000111111111100000 00001111111111111000
00000111111111100000 00011111111111111100
00000111111111100000 00001111111111111000
00000111111111100000 00000111111111110000
00000111111111100000 00000011111111100000
00000111111111100000 00000001111111000000
00000000000000000000 00000000111110000000
00000000000000000000 00000000011100000000
00000000000000000000 00000000001000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000

Angle: 10.0 degrees
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000111111111100000 00000011111000000000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000111111111110000
00000111111111100000 00000111111111100000
00000111111111100000 00000111111111100000
00000111111111100000 00000111111111100000
00000111111111100000 00000111111111100000
00000000000000000000 00000000001111100000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000

Angle: 90.0 degrees
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000111111111100000 00000011111111110000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000
00000000000000000000 00000000000000000000

测试程序:

public class Test {
  public static void main(String args[]) {
    int[][] input1 = { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 1, 1, 1, 1, 0, 0 }, { 0, 0, 1, 1, 1, 1, 0, 0 },
        { 0, 0, 1, 1, 1, 1, 0, 0 }, { 0, 0, 1, 1, 1, 1, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } };

    testit(input1, 10);

    int[][] input2 = new int[20][20];
    for(int i=5; i<15; i++){
      for(int j = 5; j<15; j++){
        input2[i][j] = 1;
      }
    }

    testit(input2, 45);
    testit(input2, 10);
    testit(input2, 90);
  }

  private static void testit(int[][] input, double degrees) {
    int[][] output = rotate(input, degrees);
    System.out.println("Angle: "+degrees+" degrees");
    for (int i = 0; i < input.length; i++) {
      for (int j = 0; j < input[i].length; j++) {
        System.out.print(input[i][j]);
      }
      System.out.print(" ");
      for (int j = 0; j < output[i].length; j++) {
        System.out.print(output[i][j]);
      }
      System.out.println();
    }
    System.out.println();
  }

  private static int[][] rotate(int[][] input, double degrees) {

    double rad = Math.toRadians(degrees);
    double sin = Math.sin(-rad);
    double cos = Math.cos(-rad);

    int[][] output = new int[input.length][input[0].length];

    for (int i = 0; i < output.length; i++) {
      double oldX = i - output.length / 2.0; // move to center
      for (int j = 0; j < input[i].length; j++) {
        {
          double oldY = j - output[i].length / 2.0; // move to center
          double x = (int) (cos * oldX + sin * oldY + input.length / 2.0);
          double y = (int) (-sin * oldX + cos * oldY + input[i].length / 2.0);
          output[i][j] = getNearestVal(input, x, y);
        }
      }
    }
    return output;
  }

  private static int getNearestVal(int[][] input, double x, double y) {
    int xLow = (int) Math.floor(x);
    int xHigh = (int) Math.ceil(x);
    int yLow = (int) Math.floor(y);
    int yHigh = (int) Math.ceil(y);
    int[][] points = { { xLow, yLow }, { xLow, yHigh }, { xHigh, yLow },
        { xHigh, yHigh } };
    double minDistance = Double.POSITIVE_INFINITY;
    int minDistanceValue = 0;
    for (int[] point : points) {
      double distance = (point[0] - x) * (point[0] - x) + (point[1] - y)
          * (point[1] - y);
      if (distance < minDistance) {
        minDistance = distance;
        if (point[0] >= 0 && point[0] < input.length && point[1] >= 0
            && point[1] < input[point[0]].length) {
          minDistanceValue = input[point[0]][point[1]];
        } else {
          minDistanceValue = 0;
        }
      }
    }
    return minDistanceValue;
  }
}
 类似资料:
  • 嗨,假设您有两个不同的独立的64位二进制矩阵和()(是其自身的转置版本,使用转置版本的矩阵允许在乘法期间对的行而不是列进行操作,这对于二进制算术来说非常酷),并且您想要对这些矩阵进行乘法,唯一的问题是矩阵乘法结果被截断为64位,如果您在某个特定的矩阵单元中屈服于大于的值,则生成的矩阵单元将包含,否则 二进制和传统乘法结果: 你如何用上面描述的最有效物质的方法,将这些矩阵相乘? 我试图利用二进制(即

  • 问题内容: 我到处搜索,但找不到答案。 如何在Java中旋转矩形? 这是我的一些代码: 我尝试了g2d.rotate(100D); 但它没有用。提前致谢。 这是我编辑的代码: 问题答案: 对于图像,必须将Graphics2D的drawImage方法与相对的AffineTransform一起使用。 对于形状,您可以旋转Graphics2D本身: 顺便说一句,您应该重写paintComponent方法

  • 问题内容: 我需要创建围绕其中心旋转的矩形(因此它们不必平行于坐标系的轴)。因此,基本上每个矩形都可以由 center-X , center-Y , width , height 和 angle定义 。然后,我要做的是对这些矩形中是否包含某些点进行计算(因此不会涉及任何绘图)。我想我不能使用该类,因为这些矩形将始终与坐标系的x和y轴平行。是通过编写自己的矩形类来获得此功能的唯一方法,还是可以使用任

  • 我刚开始使用JavaFX,有一个问题。在我的项目中,我想使用旋转矩形。但矩形只围绕其中心旋转,我希望它围绕其左上角旋转。 就像这张照片(从这里开始): 下面是我的项目中的一些代码: 在这种情况下,如果按下箭头键,矩形会旋转。

  • 我有两个带枢轴的矩形, 我需要根据红色矩形的旋转来附加绿色矩形的位置 结果应该如图所示: 我尝试了不同的公式,但没有成功 红色矩形: 绿色矩形: 我尝试了这样的方法: 非常感谢所有帮助过我的人!

  • 我正在尝试在虚拟桌面程序的API中编写脚本(javascript),以便我可以操作一些令牌(Car Wars :))。 我正在寻找答案,但似乎我正在挣扎并重新发明轮子,所以我想我会寻求帮助。我感到困惑的一个原因是程序返回基于y是向下的结果,Deg顺时针方向,这与所有trig公式想要的(逆时针方向和y是向上的)不同。 这是我可以访问的内容。矩形围绕中心、中心点 (x,y)、宽度、高度和旋转旋转。我有