我正在尝试使用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));
}
}
}
答案 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;
}