2012-06-13 70 views
0

我想使用EasyBMP旋转BMP图像。当角度介于0和90或270和360之间时,旋转很好。但是当在180到270之间时,边界矩形被拉伸,并且在90和180之间的角度出现分段故障。我确信问题来自于EasyBMP以任意角度旋转图像

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)); 
     } 
    } 
} 
+0

至少如果你在Windows上这样做,我会正常显示bmp,并使用['SetWorldTransform'](http://msdn.microsoft.com/en-us/library/windows /desktop/dd145104.aspx)做旋转。 –

回答

0

以下是我如何解决这个问题。 TL; DR:旋转变换在0,0左右,所以如果图像坐标将0,0设置为左下角,则需要首先将图像翻译为以0,0为中心。另外,罪和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)ceil(fabs(maxx-minx)); outHeight =(int)ceil(fabs(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; 
}