【问题标题】:Trying to use a rotation matrix, and failing尝试使用旋转矩阵,但失败了
【发布时间】:2025-12-06 11:20:08
【问题描述】:

我一直在尝试使用旋转矩阵来旋转图像。下面是我一直在使用的代码。几天来我一直在尝试这样做,每次似乎都有问题,但我看不出我做错了什么。例如,我的图像变得倾斜,而不是旋转...

下面的代码分为两部分:实际旋转和向上移动图片以使其出现在正确的位置(需要将其所有点都在0以上才能正确保存)。它需要一个像素数组(包含位置信息(x,y)和颜色信息(r,g,b)),图像(仅用于获取其像素数,即数组大小和宽度)作为输入,以及旋转的弧度值。

负责旋转本身的部分是在线上方的部分,而在线下方的部分负责计算图像中的最低点,并将所有像素向上或向右移动以使所有像素都适合(我需要当图像旋转 45 度或类似时,仍然要实现改变图像大小的功能。

void Rotate( Pixel *p_pixelsToRotate, prg::Image* img, float rad )
{
    int imgLength = img->getPixelCount();
    int width = img->getWidth();

    int x { 0 }, y { 0 };

    for( int i = 0; i < imgLength; i++ )
    {   
        x = p_pixelsToRotate[i].x;
        y = p_pixelsToRotate[i].y;

        p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );   
        p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
    }

===========================================================================

    Pixel* P1 = &p_pixelsToRotate[ width - 1 ];     // Definitions of these are in the supporting docs
    Pixel* P3 = &p_pixelsToRotate[ imgLength - 1 ];

    int xDiff = 0;
    int yDiff = 0;  

    if( P1->x < 0 || P3->x < 0 )
    {
        (( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
    }

    if( P1->y < 0 || P3->y < 0 )
    {
        (( P1->y < P3->y )) ? ( yDiff = abs( P1->y )) : ( yDiff = abs( P3->y ));
    }

    for( int i = 0; i < imgLength; i++ )
    {
        p_pixelsToRotate[i].x += xDiff;
        p_pixelsToRotate[i].y += yDiff;
    }
}

我更愿意自己解决这个问题,但一个多星期以来一直无法解决。我不明白为什么该函数没有旋转输入像素数组的位置信息。如果有人可以看看,也许能发现我的逻辑为什么不起作用,我将不胜感激。谢谢。

【问题讨论】:

  • 你考虑过使用 Qt 吗?它是跨平台的,并且有这样的东西(在许多其他东西中)......
  • 您是否要围绕点 0,0 旋转?顺便说一句,我可以理解 Qt 并不适用于所有情况。
  • 您可能想查看此链接以更广泛地介绍msdn.microsoft.com/en-us/library/windows/desktop/… 这些类型的转换

标签: c++ arrays image math rotation


【解决方案1】:

看来您只是在旋转矩阵本身中犯了一个错误:

p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
                                                ^^^---------------change to cos

【讨论】:

    【解决方案2】:

    一方面,这是一个错误:

        p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );   
        p_pixelsToRotate[i].y = round( sin( rad ) * x + >>>sin<<<( rad ) * y );
    

    &gt;&gt;&gt;sin&lt;&lt;&lt; 应该是 cos。这可以解释得到剪切而不是旋转。

    其他 cmets:在位图数据中存储像素坐标是解决位图旋转问题的一种极其昂贵的方法。更好的方法是逆变换采样。使用源图像 X 并希望使用变换 R 对其进行旋转以获得 Y,您目前正在考虑

    Y = R X
    

    其中 X 和 Y 具有显式存储的像素坐标。要使用逆采样,请考虑将同一方程两边都乘以 R 的倒数。

    R^(-1) Y = X 
    

    坐标是隐式的。也就是说,要产生 Y[j][i],用逆 R^(-1) 变换 (j,i) 以获得 X 图像中的坐标 (x,y)。使用它对 X 中最近的像素 X[round(x)][round(y)] 进行采样,并将其指定为 Y[j][i]。

    (实际上,与简单的舍入相比,更复杂的算法将对 (x,y) 周围的 X 像素进行加权平均以获得更平滑的结果。如何选择权重是一个很大的附加主题。)

    完成这项工作后,您可以更进一步。代替对每个像素进行完整的矩阵向量乘法,一些代数将表明可以更新先前的采样坐标以获得相邻的坐标(靠近右侧或左侧,向上或向下),只需几个加法即可。这大大加快了速度。

    旋转的逆计算很简单!只需否定旋转角度。

    最后要注意的是,您使用三元运算符o ? o : o 来选择赋值是一种非常糟糕的风格。而不是这个:

    (( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
    

    xDiff = ( P1->x < P3->x ) ? abs( P1->x ) : abs( P3->x );
    

    【讨论】: