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

时间:2015-04-12 05:02:50

标签: c bitmap rotation bmp

我已经建立了一个很好的旋转位图的功能。 在一些优化之后发生的问题是输出图像在旋转期间稍微重新定位。

我已经录制了一个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;
}

导致这种不雅行为的原因是什么?

2 个答案:

答案 0 :(得分:1)

我无法在视频中看到你的问题,但我认为在各种部分旋转中可以实现完整的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,以强制执行正确的索引计算。相反,您应该将所有像素的实际坐标视为该像素的中间位置:

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;

我们的想法是将像素坐标视为源和目标空间中的像素中心。当收敛到整数时,通过向零舍入,自动实现目标空间中的正确表示。

答案 1 :(得分:0)

这可能是与舍入相关的问题。我过去在项目中也遇到过这种问题。请检查&#34;整数到其他类型&#34;的行。或&#34;其他类型为整数&#34;转换发生。