为什么我的图像旋转算法不起作用?

时间:2009-03-30 14:45:42

标签: math image image-processing

尝试1& 2:

注意:删除了首次尝试减少问题大小。有关以前的尝试,请参阅社区维基。

尝试3:

根据模糊华夫饼的例子,我实现了以下似乎无法正常工作的内容。我有什么想法可能做错了吗?

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;
}

使用这个原型矩阵......

1 2 1 
0 0 0 
-1 -2 -1 

... prototype.GetRotatedCopy(0)(这是正确的)......

1 2 1 
0 0 0 
-1 -2 -1 

... prototype.GetRotatedCopy(90)(不正确)......

-2 0 0 
-2 0 2 
0 0 2 

... prototype.GetRotatedCopy(180)(不正确 - 但有点逻辑?)......

0 -1 -2 
1 0 -1 
2 1 0 

... prototype.GetRotatedCopy(270)(不正确 - 为什么这与0轮相同?)......

1 2 1 
0 0 0 
-1 -2 -1 

解决方案:

正如Mark Ransom所指出的,我应该使用弧度,而不是度数;我调整了我的代码如下:

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 ...

感谢你们的帮助!

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 

5 个答案:

答案 0 :(得分:4)

算法,除非我读错了,似乎围绕点0,0旋转,这不是你想要的。在插入之前,您可能需要在行和列值中添加height / 2和width / 2.

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]; 
   } 
} 

这基本上调整了从左上角到图像中心的旋转中心。

答案 1 :(得分:3)

以下是我破解的完整示例: 我认为在其他方面你可能没有使用弧度(我们都应该使用和爱)。我将新坐标保持在双打中,这似乎使它不那么挑剔。请注意,我没有做边界检查我应该做什么,但我很懒。

如果您需要更快的旋转,您可以始终使用剪切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");
  } 
}

答案 2 :(得分:2)

切换了newRow和newColumn的公式。请记住,row = y和column = x。

Rotation

答案 3 :(得分:2)

简短的回答:你做错了。

这在插值中基本上是一个问题,而你接近它的方式会引入不连续性。从根本上说,这是因为旋转格子(图像布局的规则网格)不会导致在同一格子上进行另一次采样,除非是非常特殊的情况。

顺便提一下,没有一种正确的方法可以做到这一点,但在速度和准确度方面存在各种权衡,也可以假设原始信号(图像)。

那你的设计参数是什么?你需要这个非常快或非常准确吗?你想如何处理别名?

答案 4 :(得分:1)

问题是您的内存访问超出范围。

旋转后,NewRow和NewColumn可能会大于图像的原始宽度/高度。他们甚至可能是消极的。如果你不关心这个事实,你最终会得到垃圾数据(最好的情况)或崩溃。

处理此问题的最常见方法是忽略所有此类像素。您还可以钳制或包裹有效间隔。这得到了填充或平铺效果。

这里显示忽略外部像素。

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];
                }
        }
}