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?
views:
54answers:
2
+2
A:
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;
Arnold Spence
2010-09-15 21:38:52
opaqueArea() constructs a whole Path describing the area. That should be slower than simple bounding rectangle computation.
ypnos
2010-09-15 21:43:59
Hopefully the OP can post some timing results. I'd be interested to see how much time both options take. But yes, for complicated images I can only imagine it being slower.
Arnold Spence
2010-09-15 21:51:33
I did a few rough timings of my over-all task without creating a micro-benchmark. This approach used essentially the same amount of wall-clock time as my nested for-loops, but took less cpu time.
retracile
2010-09-15 23:31:47
Thanks for the feedback and congrats on your new voting power :)
Arnold Spence
2010-09-15 23:37:40
+2
A:
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.
ypnos
2010-09-15 21:55:43
It's not like Qt docs are advertising it well. Took me half a year to find out about it.
ypnos
2010-09-15 22:05:19
I did a few rough timings of my over-all task without creating a micro-benchmark. This approach used essentially the same amount of cpu-time as Arnold's solution, but reduced wall-clock time.
retracile
2010-09-15 23:33:18