以度数旋转位图的功能非常快,但会重新定位输出图像

Function to rotate bitmap in degrees works pretty fast, but repositions output image

我已经构建了一个很好的函数来以度数旋转位图。 一些优化后出现的问题是输出图像在旋转过程中稍微重新定位。

我录制了一个360度旋转video让你明白我的意思。 代码如下:

#define OFFSET_OF_ID        (0x0)
#define OFFSET_OF_SIZE      (0x2)
#define OFFSET_OF_PIXELS    (0xA)
#define OFFSET_OF_NDIB      (0xE)
#define OFFSET_OF_WIDTH     (0x12)
#define OFFSET_OF_HEIGHT    (0x16)
#define OFFSET_OF_BPP       (0x1C)
#define OFFSET_OF_NRAW      (0x22)

typedef unsigned char byte, pixel[3];
typedef unsigned short word;
typedef unsigned long dword;
typedef unsigned long long ddword;

byte*
bmp_rotate
(byte *buffer, float angle)
{
    const dword src_width  = *( (dword*)&buffer[OFFSET_OF_WIDTH]);
    const dword src_height = *( (dword*)&buffer[OFFSET_OF_HEIGHT]);
    const dword src_nraw   = *( (dword*)&buffer[OFFSET_OF_NRAW]);
    const dword src_pixels = *( (dword*)&buffer[OFFSET_OF_PIXELS]);
    const dword src_bpp    = *( (dword*)&buffer[OFFSET_OF_BPP]);

    const dword single = src_bpp / 8;
    const dword row = src_width * single;
    dword rowsize = (row % 4) ? (row + 4 - row % 4) : (row);
    byte *dest = calloc( src_pixels + src_nraw, sizeof(byte) );

    double midX, midY;
    int i, j;
    double sin_angle = sin(angle);
    double cos_angle = cos(angle);

    midX = src_width / 2.0f;
    midY = src_height / 2.0f;
    memcpy(dest, buffer, src_pixels);

    for(j = 0; j < src_height; j++)
    {
        dword dest_offset = src_pixels + j * rowsize;
        double deltaY = j - midY;
        double deltaX = 0 - midX;
        double x_computation, y_computation;

        x_computation = midX + deltaX * cos_angle + deltaY * sin_angle + 0.5f;
        y_computation = midY - deltaX * sin_angle + deltaY * cos_angle + 0.5f;


        for(i = 0; i < src_width; i++)
        {
            ddword rotX = x_computation;
            ddword rotY = y_computation;

            if(rotX >= 0 && rotX < src_width && rotY >= 0 && rotY < src_height)
            {
                ddword src_offset  = src_pixels + rotY * rowsize + rotX * single;

                memcpy(&dest[dest_offset], &buffer[src_offset], sizeof(pixel));

            }
            x_computation += cos_angle;
            y_computation -= sin_angle;
            dest_offset += single;
        }
    }
    return dest;
}

是什么导致了这种不雅行为?

这可能是与舍入相关的问题。我过去在我的项目中也遇到过这种问题。请检查发生 "integer to other types" 或 "other types to integer" 转换的行。

我在视频中看不出你的问题,但我假设在各种局部旋转中实现了完整的 360° 旋转。

如果我们观察 180° 旋转,偏移就会变得清晰:正弦为 0,余弦为 −1。则左上角(0,0)的旋转坐标为:

x' = xm + (x - xm) * cosa + (y - ym) * sina = xm + xm = w
y' = ym - (x - xm) * sina + (y - ym) * cosa = ym + ym = h

坐标(w,h)为独占右下边框

您的工作坐标是实数。整数值描述左坐标和上坐标。将(正)实坐标转换为整数将截断小数部分并产生从零开始的像素索引。

您将 0.5 添加到目标 space 中的工作坐标一次,以执行正确的索引计算。相反,您应该将所有像素的真实坐标视为该像素的中间:

x(i) = i + 0.5
y(j) = j + 0.5

您的所有计算都保持正确,除了:

double deltaY = j + 0.5 - midY;
double deltaX = 0 + 0.5 - midX;

x_computation = midX + deltaX * cos_angle + deltaY * sin_angle;
y_computation = midY - deltaX * sin_angle + deltaY * cos_angle;

想法是将像素坐标视为源和目标中的像素中心 space。目标 space 中的正确表示是通过在转换为整数时向零四舍五入自动实现的。