Есть ли в 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 альфа, а где-то наполовину непрозрачности.

Другие вопросы по тегам