尝试使用旋转矩阵,但失败了

Trying to use a rotation matrix, and failing

本文关键字:失败 旋转      更新时间:2023-10-16

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

下面的代码分为两部分:实际旋转,以及向上移动图片以使其出现在正确的位置(需要将其所有点都保持在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;
    }
}

我更愿意自己解决这个问题,但已经一个多星期没能解决了。我不明白为什么函数不旋转输入像素阵列的位置信息。如果有人能看一看,也许能发现为什么我的逻辑不起作用,我会非常感激。非常感谢。

似乎你只是在旋转矩阵本身犯了一个错误:

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

首先,这是一个错误:

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

>>>sin<<<应该是cos。这可以解释得到剪切而不是旋转。

其他评论:在位图数据中存储像素坐标是解决位图旋转问题的一种极其昂贵的方法。更好的方法是逆变换采样。对于源图像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 );