0

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

1 回答 1

0

以下是我如何解决这个问题。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;
}
于 2012-06-14T02:20:38.753 回答