以下是我如何解决这个问题。TL;DR:旋转变换在 0, 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)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;
}