【问题标题】:Why is my image rotation algorithm not working?为什么我的图像旋转算法不起作用?
【发布时间】:2010-10-16 09:36:00
【问题描述】:

尝试 1 和 2:

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

尝试 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 

【问题讨论】:

  • 您的输出是指 newRow 和 newColumn(不是 targetRow 和 targetColumn)吗?
  • 您是否有可能使用度数而不是弧度来表示角度?仔细阅读模糊华夫饼的答案。
  • 啊,是的 - 刚刚用方法调用更新了我的问题。我会尝试使用弧度。
  • 旁注:最好将 sin(angle) 和 cos(angle) 移出循环,因为它们不会改变。

标签: math image image-processing


【解决方案1】:

简短回答:你做错了。

这本质上是插值中的一个问题,您处理它的方式引入了不连续性。从根本上说,这是因为旋转格子(您的图像放置在其上的规则网格)不会导致在同一格子上再次采样,除非是非常特殊的情况。

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

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

【讨论】:

  • 这是学术上的第一次尝试,所以就设计要求而言,我会说“我能做什么”......
  • 好吧 r3n,这很好,但您必须意识到旋转图像与旋转图像的 i,j 索引不同。试试这个只是为了学习 1)反转旋转,走你的目标图像,而不是源图像。 2)使用最接近的源值。这不“正确”,但试试吧。
【解决方案2】:

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

如果您需要更快的旋转,您可以随时使用像 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");
  } 
}

【讨论】:

  • 非常感谢您的努力,我会尽快尝试。
  • @fuzzy-waffle:我尝试实现您的图像旋转代码,但没有成功。请问您能给我一些指导吗?谢谢!
  • @fuzzy-waffle:顺便看看我的回答中的尝试#3。
【解决方案3】:

除非我读错了,否则该算法似乎围绕点 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]; 
   } 
} 

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

【讨论】:

  • for (int y = 0; y
  • 只需将 newX 和 newY 计算中的 x 和 y 替换为 x-(width/2) 和 y-(height/2)
【解决方案4】:

您的 newRow 和 newColumn 公式已切换。记住 row = y 和 column = x。

Rotation

【讨论】:

    【解决方案5】:

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

    旋转后,您的 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];
                    }
            }
    }
    

    【讨论】:

    • 或者他可以只计算旋转图像的新长度和高度
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    相关资源
    最近更新 更多