EasyBMP以任何角度旋转图像

时间:2012-06-13 22:50:46

标签: c++ bmp

我正在尝试使用EasyBMP旋转bmp图像。当角度在0到90或270和360之间时,旋转很好。但是当在180到270之间时,边界矩形被拉伸,并且对于90到180之间的角度,我得到分段错误。我确信这个问题来自于

int width = image.TellWidth();
int height = image.TellHeight();

float sine= sin(angle);
float cosine=cos(angle);

float x1=-height*sine;
float y1=height*cosine;
float x2=width*cosine-height*sine;
float y2=height*cosine+width*sine;
float x3=width*cosine;
float y3=width*sine;

float minx=min(0,min(x1,min(x2,x3)));
float miny=min(0,min(y1,min(y2,y3)));
float maxx=max(x1,max(x2,x3));
float maxy=max(y1,max(y2,y3));

int outWidth;
int outHeight;


     outWidth=(int)ceil(fabs(maxx)-minx);
     outHeight=(int)ceil(fabs(maxy)-miny);
output.SetSize(outHeight,outWidth);

for(int x=0; x<outWidth; x++)
{
    for(int y=0; y<outHeight; y++)
    {
        int srcX=(int)((x+minx)*cosine+(y+miny)*sine); 
            int srcY=(int)((y+miny)*cosine-(x+minx)*sine);
        if(srcX>=0 &&srcX<width && srcY>=0 && srcY<height)
        {
            output.SetPixel(x,y,image.GetPixel(srcX,srcY));
        }
    }
}

1 个答案:

答案 0 :(得分:0)

以下是我如何解决这个问题。 TL; DR:旋转变换大约为0,0,因此如果图像坐标设置为0到左下角,则需要先将图像平移为0,0。此外,sin和cos期望弧度,而不是度数,所以记得先转换

漫长的道路: 我开始创建一个简单的程序,可以轻松验证答案,找出出错的地方。

我注意到的第一件事是90.0f不会产生任何输出。这看起来很奇怪,所以我打破了“输出图像大小”printf并意识到输出高度计算为-87。显然这是不对的,所以让我们看看为什么会发生这种情况。

稍微向上,outHeight=(int)ceil(fabs(maxy)-miny);让我们弄清楚当减去maxy和miny时我们如何以负输出高度结束。看起来maxy是-0.896 ......并且miny是88.503 ......但是,maxy的绝对值是在减去miny之前得出的,这意味着我们最终得到0.896 - 88.503。哇,那不好!让我们尝试减去然后取绝对值。

重新编译宽度和高度,如下所示:     outWidth =(int)的小区(晶圆厂(MAXX-风骚女子));     outHeight =(int)的小区(晶圆厂(MAXY-MINY));

获得更好的价值观。现在outWidth和outHeight分别为2和90。这是大大改进的,但高度应该是100.我们稍后会解决这个问题。

为了弄清楚数学出错的地方,我重新组织这些术语:x用x,y用y。接下来,我调整了间距并添加了括号,使其更具可读性并确保操作顺序(确保节拍试图查看OoO表;))。由于很明显你正在打破旋转矩阵乘法,我将命名你的变量比x1,x2等更直观。从现在开始,x1是topLeftTransformedX,x2是topRightTransformedX,x3将作为bottomLeftTransformedX存在(总是0),x4将是bottomRightTransformedX,对Y来说也是一样。更长,但更容易知道你在处理什么。

使用这个,在这一点上,我看到你做同样的事情......然后我记得一些东西,基于从这个更干净的代码看到的数字(与你的数学相同,但仍然更容易调试)。

突然间,我对X的数学看起来像这样:     // x = x cos - y sin     float topLeftTransformedX =( - midX * cosine) - (midY * sine);     float topRightTransformedX =(midX * cosine) - (midY * sine);     float bottomLeftTransformedX =( - midX * cosine) - (-midY * sine);     float bottomRightTransformedX =(midX * cosine) - (-midY * sine);

旋转矩阵围绕中心点旋转。您必须将图像转换为围绕该图像进行正确旋转。

然后,当试图找出为什么会给出它的值时,我想起了其他的东西 - 角度需要以弧度为单位。

突然间,它几乎都有效。还有一些事要做,但这应该会让你有95%或更多。希望它有所帮助!

// bmprotate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <math.h>

#define min(x,y) x < y ? x : y
#define max(x,y) x > y ? x : y
#define PI 3.14159

void rotate(int width, int height, float angleInDeg)
{
    float angle = angleInDeg * (PI/180.0f);
    float midX = ((float)width) / 2.0f;
    float midY = ((float)height) / 2.0f;

    float sine = sin(angle);
    float cosine = cos(angle);

    // x = x cos - y sin
    float topLeftTransformedX = (-midX * cosine) - (midY * sine);
    float topRightTransformedX = (midX * cosine) - (midY * sine);
    float bottomLeftTransformedX  = (-midX * cosine) - (-midY * sine);
    float bottomRightTransformedX = (midX * cosine) - (-midY * sine);

    float minx = min( topLeftTransformedX, min(topRightTransformedX, min(bottomLeftTransformedX, bottomRightTransformedX)) );
    float maxx = max( topLeftTransformedX, max(topRightTransformedX, max(bottomLeftTransformedX, bottomRightTransformedX)) );

    // y = x sin + y cos
    float topLeftTransformedY = (-midX * sine) + (midY * cosine);
    float topRightTransformedY = (midX * sine) + (midY * cosine);
    float bottomLeftTransformedY  = (-midX * sine) + (-midY * cosine);
    float bottomRightTransformedY = (midX * sine) + (-midY * cosine);



    float miny = min( topLeftTransformedY, min(topRightTransformedY, min(bottomLeftTransformedY, bottomRightTransformedY)) );
    float maxy = max( topLeftTransformedY, max(topRightTransformedY, max(bottomLeftTransformedY, bottomRightTransformedY)) );

    int outWidth;
    int outHeight;

    printf("(%f,%f) , (%f,%f) , (%f,%f) , (%f,%f)\n", 
        topLeftTransformedX, topLeftTransformedY, 
        topRightTransformedX, topRightTransformedY, 
        bottomLeftTransformedX, bottomLeftTransformedY, 
        bottomRightTransformedX, bottomRightTransformedY);


    outWidth = (int) ceil( fabs(maxx) + fabs(minx));
    outHeight = (int) ceil( fabs(maxy) + fabs(miny) );

    printf("output image size: (%d,%d)\n",outWidth,outHeight);
    for(int x=0; x<outWidth; x++)
    {
        for(int y=0; y<outHeight; y++)
        {
            int srcX=(int)((x+minx)*cosine+(y+miny)*sine); 
            int srcY=(int)((y+miny)*cosine-(x+minx)*sine);

            if(srcX >=0 && srcX < width && srcY >= 0 && srcY < height)
            {
                printf("(x,y) = (%d,%d)\n",srcX, srcY);
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    rotate(100,2,90.0f);
    for (int i = 0; i < 360; i++)
    {

    }
    return 0;
}