retracile
retracile

Reputation: 12339

Does Qt have a way to find bounding box of an image?

Given a .png image with a transparent background, I want to find the bounding box of the non-transparent data. Using nested for loops with QImage.pixel() is painfully slow. Is there a built-in method of doing this in Qt?

Upvotes: 8

Views: 2803

Answers (3)

Thorbjørn Lindeijer
Thorbjørn Lindeijer

Reputation: 2112

The easiest and also relatively fast solution is to do as follows:

QRegion(QBitmap::fromImage(image.createMaskFromColor(0x00000000))).boundingRect()

If you have a QPixmap rather than QImage, then you can use:

QRegion(pixmap.createMaskFromColor(Qt::transparent)).boundingRect()

QPixmap::createMaskFromColor internally will convert the pixmap to an image and do the same as above. An even shorter solution for QPixmap is:

QRegion(pixmap.mask()).boundingRect()

In this case, a QPixmap without alpha channel will result in an empty region, so you may need to check for that explicitly. Incidentally, this is also what QGraphicsPixmapItem::opaqueArea mentioned by @Arnold Spence is based on.

You may also want to try QImage::createAlphaMask, though the cutoff point will not be at 0 alpha but rather somewhere at half opacity.

Upvotes: 1

ypnos
ypnos

Reputation: 52337

If pixel() is too slow for you, consider more efficient row-wise data adressing, given a QImage p:

int l =p.width(), r = 0, t = p.height(), b = 0;
for (int y = 0; y < p.height(); ++y) {
    QRgb *row = (QRgb*)p.scanLine(y);
    bool rowFilled = false;
    for (int x = 0; x < p.width(); ++x) {
        if (qAlpha(row[x])) {
            rowFilled = true;
            r = std::max(r, x);
            if (l > x) {
                l = x;
                x = r; // shortcut to only search for new right bound from here
            }
        }
    }
    if (rowFilled) {
        t = std::min(t, y);
        b = y;
    }
}

I doubt it will get any faster than this.

Upvotes: 4

Arnold Spence
Arnold Spence

Reputation: 22272

There is one option that involves using a QGraphicsPixmapItem and querying for the bounding box of the opaque area (QGraphicsPixmapItem::opaqueArea().boundingRect()). Not sure if it is the best way but it works :) It might be worth digging into Qt's source code to see what code is at the heart of it.

The following code will print out the width and height of the image followed by the width and height of the opaque portions of the image:

QPixmap p("image.png");
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(p);
std::cout << item->boundingRect().width() << "," << item->boundingRect().height() << std::endl;
std::cout << item->opaqueArea().boundingRect().width() << "," << item->opaqueArea().boundingRect().height() << std::endl;

Upvotes: 5

Related Questions