Есть ли в Qt способ найти ограничительную рамку изображения?
Учитывая .png
изображение с прозрачным фоном, я хочу найти ограничивающую рамку непрозрачных данных. Использование вложенных for
петли с QImage.pixel()
мучительно медленно Есть ли встроенный способ сделать это в Qt?
2 ответа
Если pixel() слишком медленный для вас, рассмотрите более эффективную построчную адресацию данных, учитывая 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;
}
}
Я сомневаюсь, что это будет быстрее, чем это.
Есть один вариант, который предполагает использование QGraphicsPixmapItem
и запрашивая ограничивающую рамку непрозрачной области (QGraphicsPixmapItem::opaqueArea().boundingRect()
). Не уверен, что это лучший способ, но он работает:) Возможно, стоит покопаться в исходном коде Qt, чтобы увидеть, какой код лежит в его основе.
Следующий код распечатает ширину и высоту изображения, а затем ширину и высоту непрозрачных частей изображения:
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;
Самое простое и относительно быстрое решение - это сделать следующее:
QRegion(QBitmap::fromImage(image.createMaskFromColor(0x00000000))).boundingRect()
Если у тебя есть QPixmap
скорее, чем QImage
, тогда вы можете использовать:
QRegion(pixmap.createMaskFromColor(Qt::transparent)).boundingRect()
QPixmap::createMaskFromColor
внутренне преобразует растровое изображение в изображение и сделает то же, что и выше. Еще более короткое решение дляQPixmap
является:
QRegion(pixmap.mask()).boundingRect()
В этом случае QPixmap
без альфа-канала приведет к пустой области, поэтому вам может потребоваться явно проверить это. Кстати, это тоже то, чтоQGraphicsPixmapItem::opaqueArea
упомянутый @Arnold Spence основан на.
Вы также можете попробовать QImage::createAlphaMask
, хотя точка отсечки будет не при 0 альфа, а где-то наполовину непрозрачности.