Image rotation causes distortion



  • Hi

    I making some image to rotate each 10 degrees. Rotation itself works fine. My problem is related to image. After some iterations image gets distorted. This occurs with any degree value.
    My guess is because image bounding box. If so, is there a way to maintain proportions?

    Original Image:
    !http://imageshack.us/a/img268/6365/ship1p.png(Original image)!

    Distorted Image:
    !http://imageshack.us/a/img266/8501/ship2.png(Distorted Image)!

    This is my code:
    @
    void Ship::Move(int x, int y)
    {
    QPixmap rotatePixmap(shipPixels.size());
    rotatePixmap.fill(Qt::transparent);

    QPainter p(&rotatePixmap);
    p.translate(rotatePixmap.size().width() / 2, rotatePixmap.size().height() / 2);
    p.rotate(degree);
    p.translate(-rotatePixmap.size().width() / 2, -rotatePixmap.size().height() / 2);
    
    p.drawPixmap(0, 0, shipPixels);
    p.end();
    
    shipPixels = rotatePixmap;
    this->setPixmap(shipPixels);
    this->move(QPoint(x, y));
    degree = 0;
    

    }
    @

    Thanks for replies.



  • I would assume it is because you are accumulating errors with every rotation. You rotate the image and replace the original (line 14), then rotate that rotated image, then rotate that image etc. Rotation maths is precise but pixels are in discrete locations so each rotation introduces more error.

    You should start from the same, unrotated image and rotate it once by the cumulative amount of rotation desired. If the increments are fixed then you should probably also do this once only and cache the 36 (or whatever) images.



  • Did you play around with the flags that can be set via QPainter::setRenderHint() ????

    Those look related:

    • QPainter::Antialiasing
    • QPainter::SmoothPixmapTransform
    • QPainter::HighQualityAntialiasing


  • Mulder I tried these hints before. They just smooth the error.
    ChrisW67, based on your comment, if I do this I'll continue to accumulate the error eve if I unrotate the image. For me Qt did the translation and preserves the image quality



  • Well, bitmap (pixel-based) images have a limited resolution by nature. You can't rotate such an image in an "exact" way, except for rotating by multiples of 90°. For other rotations degrees the output has to be interpolated. What you call "distorted" looks like a "nearest neighbor" sampling. Using a "bilinear" or "bicubic" transform will create a more "smooth" result. This usually is much preferred for "natural" images. It may not look that great for a "synthetic" image like yours. Keep in mind that your original image already looks rather "pixelated"...

    (I think for what you are doing it might be the better solution to work with vector-based graphics, not bitmaps)



  • [quote author="qtBeginner" date="1349895757"]
    ChrisW67, based on your comment, if I do this I'll continue to accumulate the error ever if I unrotate the image.[/quote]
    I didn't say unrotate then re-rotate. I said start with the same, original, unrotated image every time.

    See the difference between the two in this example:
    @
    #include <QtGui>
    #include <QDebug>

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    QPainter p;

    // Original image
    QPixmap original("ship1p.png");
    
    // Original rotated once to 30 degrees
    QPixmap test1(original.size());
    test1.fill(Qt::transparent);
    p.begin(&test1);
    p.translate(original.width() / 2, original.height() / 2);
    p.rotate(30);
    p.translate(-original.width() / 2, -original.height() / 2);
    p.drawPixmap(0, 0, original);
    p.end();
    
    test1.save("test1.png");
    
    // Original rotated to 30 degrees in 5 degree steps
    QPixmap test2(original);
    for (int i = 0; i < 6; ++i) {  // each loop accumulates errors
        QPixmap temp(test2.size());
        temp.fill(Qt::transparent);
        p.begin(&temp);
        p.translate(test2.width() / 2, test2.height() / 2);
        p.rotate(5);
        p.translate(-test2.width() / 2, -test2.height() / 2);
        p.drawPixmap(0, 0, test2);
        p.end();
        test2 = temp;
    }
    test2.save("test2.png");
    
    return 0;
    

    }
    @

    Test1: One rotation
    !http://s16.postimage.org/9pft7dp7l/test1.png(Test1 One rotation)!
    Test 2: Accumulated rotations
    !http://s16.postimage.org/rtits0mw1/test2.png(Test2 Accumulated rotation)!

    So, track to total rotation the image requires and do a single rotation from a known good image rather than accumulate errors by continually rotating an image.

    MulderR's point about vector graphics is worth considering if it fits your requirements.



  • That's correct. My bad. I'll try your code right now.
    Thanks for both of you.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.