Rotating a square TBitmap on its center
Asked Answered
P

1

0

I am trying to find the simplest way to rotate and display a TBitmap on its center by any given angle needed. The TBitmap is square and any clipping that might occur is not important so long as the rotated bitmap's center point remains constant. The image is very small, only around 50 x 50 pixels so speed isn't an issue. Here is the code I have so far which rotates a TBitmap to 90 degrees, which is simple, the any angle thing less so.

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()); 

See revised code... This allows for rotation but the copy creates a hazy image and the rotation point is at the top left.

Phyllotaxis answered 27/5, 2017 at 5:41 Comment(10)
@Raw N well the question is there... do you mean edit my post to include the answer as well?Phyllotaxis
You want to implement a rotation matrix. Most graphic packages have a matrix transform library readily available.Mesopause
#10633900Mesopause
There's no free lunch. You need to learn the matrix primitives for rotation and position. (Or just adjust the code I pointed you to do handle the centering issue). Any textbook on graphics will teach you the principals of using matrices for such operations. A stack of matrix operations is the foundation of any graphics library package. You'll likely also want interpolation and smoothing of your rotated image since each transformed pixel location won't be on an integer boundary. So learn the principals, or get a library to do it for you.Mesopause
Even if you don't use a matrix, you'll have to extract the mddle from the x and y coordinates before you multiply with the sine/cosine (and add them back later, in transformed form), otherwise your center is not the rotation center indeed. But simply heed the advise to use matrices and/or a graphics package. That is much easier and will probably create much sharper images. This is not as easy as it may look, at first sight.God
well I can rotate the bmp to any angle and I also took care of the missing pixel problems so all that's left is to get the rotated bmp centered....Phyllotaxis
@ selbie I don't see any code or even a formula for handling centering in the link.. I do see an illustration of moving the graphic to the center axis but I am still unsure of how to code that. since the code I have does a perfect scaled rotation I can't see abandoning this to a library or api... the rotation is smooth and accurate... it just needs centering. is this really such a big deal?Phyllotaxis
@Phyllotaxis - Review this book. Do the "Look Inside" thing and peruse chapter 6 (Transformation Matrices).Mesopause
@ selbie - I'll check out the book... But I already solved this.. It was working, rotating smooth with a downsize scale, to keep center I just did another copy with revised coordinates for center...Phyllotaxis
transform matrices are overkill for such trivial thing as image rotation ... see my answer if the result is too pixelated for you add bilinear filteringMaratha
M
1

you are doing this the other way around so there may be present holes in the resulting image because you are looping the source pixels with 1 pixel step .... to remedy this loop the target pixels instead...

  1. loop through bitmap2 pixels (x2,y2)
  2. for each compute rotated-back (x1,y1) position in bitmap1
  3. copy pixel value if (x1,y1) is outside bitmap1 then use backgroun color like clBlack instead.

To improve speed use TBitmap->ScanLine[y] property that will improve speed at least 1000x times if used right see:

After I put all this together I got this:

#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;
    }

usage:

// 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;

Here example output:

example

On the left is bmp1 and on the right rotated bmp2

Maratha answered 1/6, 2017 at 6:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.