在其中心旋转方形 TBitmap

Posted

技术标签:

【中文标题】在其中心旋转方形 TBitmap【英文标题】:Rotating a square TBitmap on its center 【发布时间】:2017-10-28 01:01:28 【问题描述】:

我正在尝试找到最简单的方法来旋转 TBitmap 在其中心按所需的任何给定角度显示。 TBitmap 是方形的,只要旋转位图的中心点保持不变,任何可能发生的剪切都不重要。图像非常小,只有大约 50 x 50 像素,所以速度不是问题。这是我到目前为止的代码,它将TBitmap 旋转到 90 度,这很简单,任何角度的事情都不那么简单。

std::auto_ptr<Graphics::TBitmap> bitmap1(new Graphics::TBitmap);
std::auto_ptr<Graphics::TBitmap> bitmap2(new Graphics::TBitmap);

bitmap1->LoadFromFile("c:/myimage.bmp");
bitmap1->Transparent = true;
bitmap1->TransparentColor = bitmap1->Canvas->Pixels[50][50];
bitmap2->Width=bitmap1->Height;
bitmap2->Height=bitmap1->Width;
double x1 = 0.0;
double y1 = 0.0;

for (int x = 0;x < bitmap1->Width; x++)

    for(int y = 0;y < bitmap1->Height;y++)
    
        x1 = std::cos(45.0) * x - std::sin(45.0) * y;
        y1 = sin(45.0) * x + cos(45.0) * y;

        bitmap2->Canvas->Pixels[x1][y1] =
        bitmap1->Canvas->Pixels[x][y];
    

Form1->Canvas->Draw( 500, 200, bitmap2.get()); 

查看修改后的代码...这允许旋转,但副本会创建模糊图像并且旋转点位于左上角。

【问题讨论】:

@Raw N 问题就在那里......你的意思是编辑我的帖子以包含答案吗? 你想实现一个rotation matrix。大多数图形包都有一个现成的矩阵变换库。 ***.com/questions/10633400/… 天下没有免费的午餐。您需要学习用于旋转和位置的矩阵图元。 (或者只是调整我指出您处理居中问题的代码)。任何有关图形的教科书都会教您使用矩阵进行此类运算的原理。一堆矩阵运算是任何图形库包的基础。您可能还需要对旋转图像进行插值和平滑处理,因为每个转换后的像素位置都不会位于整数边界上。因此,学习原理,或者找一个图书馆为你做这件事。 即使您不使用矩阵,也必须先从 x 和 y 坐标中提取 mddle,然后再与正弦/余弦相乘(稍后以转换后的形式将它们添加回来),否则您的中心确实不是旋转中心。但只需注意使用矩阵和/或图形包的建议。这要容易得多,并且可能会创建更清晰的图像。乍一看,这并不像看起来那么容易。 【参考方案1】:

您正在以相反的方式执行此操作,因此结果图像中可能存在孔,因为您正在以 1 个像素步长循环源像素 .... 以修复此循环而不是目标像素...

    循环遍历bitmap2像素(x2,y2) 对于bitmap1 中的每个计算旋转回(x1,y1) 位置 复制像素值 如果 (x1,y1) 在 bitmap1 之外,则使用 clBlack 等背景颜色。

若要提高速度,请使用TBitmap-&gt;ScanLine[y] 属性,如果使用正确,该属性将至少提高速度1000x 倍,请参阅:

Display an array of color in C

在我把所有这些放在一起之后,我得到了这个:

#include <math.h> // just for cos,sin

// rotate src around x0,y0 [pixels] by angle [rad] and store result in dst
void rotate(Graphics::TBitmap *dst,Graphics::TBitmap *src,double x0,double y0,double angle)
    
    int x,y,xx,yy,xs,ys;
    double s,c,fx,fy;
    // resize dst to the same size as src
    xs=src->Width;
    ys=src->Height;
    dst->SetSize(xs,ys);
    // allow direct pixel access for src
    src->HandleType=bmDIB;
    src->PixelFormat=pf32bit;
    DWORD **psrc=new DWORD*[ys];
    for (y=0;y<ys;y++) psrc[y]=(DWORD*)src->ScanLine[y];
    // allow direct pixel access for dst
    dst->HandleType=bmDIB;
    dst->PixelFormat=pf32bit;
    DWORD **pdst=new DWORD*[ys];
    for (y=0;y<ys;y++) pdst[y]=(DWORD*)dst->ScanLine[y];
    // precompute variables
    c=cos(angle);
    s=sin(angle);
    // loop all dst pixels
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        
        // compute position in src
        fx=x;       // convert to double
        fy=y;
        fx-=x0;     // translate to center of rotation
        fy-=y0;
        xx=double(+(fx*c)+(fy*s)+x0);   // rotate and translate back
        yy=double(-(fx*s)+(fy*c)+y0);
        // copy pixels
        if ((xx>=0)&&(xx<xs)&&(yy>=0)&&(yy<ys)) pdst[y][x]=psrc[yy][xx];
         else pdst[y][x]=0; // black
        
    // free memory
    delete[] psrc;
    delete[] pdst;
    

用法:

// init
Graphics::TBitmap *bmp1,*bmp2;
bmp1=new Graphics::TBitmap;
bmp1->LoadFromFile("image.bmp");
bmp1->HandleType=bmDIB;
bmp1->PixelFormat=pf32bit;
bmp2=new Graphics::TBitmap;
bmp2->HandleType=bmDIB;
bmp2->PixelFormat=pf32bit;

// rotate
rotate(bmp2,bmp1,bmp1->Width/2,bmp1->Height/2,25.0*M_PI/180.0);
// here render bmp2 or whatever

// exit
delete bmp1;
delete bmp2;

此处示例输出:

左边是bmp1,右边是旋转的bmp2

【讨论】:

以上是关于在其中心旋转方形 TBitmap的主要内容,如果未能解决你的问题,请参考以下文章

围绕其中心旋转 UIImageView

如何计算围绕其中心旋转的矩形的边界框?

如何使用 Pygame 围绕其中心旋转图像?

当围绕其中心旋转图像时,为啥需要添加/减去质心?

在其中心旋转图形位图

围绕其中心旋转 GLUT 位图/笔划字符串?