QT QImage, как извлечь RGB?

Я хочу извлечь RGB из каждого пикселя в QImage. В идеале я хочу использовать функцию img.bits().

QImage img;

if( img.load("Red.jpg") )
{
    uchar *bits = img.bits();

    for (int i = 0; i < 12; i++)
    {
        std::cout << (int) bits[i] << std::endl;
    }
}

Как манипулировать возвращаемыми битами? Я ожидал, что все будет красным, потому что изображение чисто красного цвета, созданное в Paint. Однако я получаю 36, 27, 237, 255, 36 и т. д.


person SmallChess    schedule 12.09.2012    source источник
comment
Чтение с помощью bits() сильно зависит от формата изображения. Попробуйте преобразовать формат во что-то более подходящее для вашего сценария, например. img = img.convert(QImage::Format_ARGB32). Тогда байты должны выйти как 0, 255, 0, 0, [loop], если я не ошибаюсь.   -  person Stefan Majewsky    schedule 12.09.2012


Ответы (4)


QImage img( "Red.jpg" );

if ( false == img.isNull() )
{
    QVector<QRgb> v = img.colorTable(); // returns a list of colors contained in the image's color table.

    for ( QVector<QRgb>::const_iterator it = v.begin(), itE = v.end(); it != itE; ++it )
    {
        QColor clrCurrent( *it );
        std::cout << "Red: " << clrCurrent.red()
                  << " Green: " << clrCurrent.green()
                  << " Blue: " << clrCurrent.blue()
                  << " Alpha: " << clrCurrent.alpha()
                  << std::endl;
    }
}

Однако приведенный выше пример возвращает таблицу цветов. Таблица цветов не включает одни и те же цвета дважды. Они будут добавлены один раз в порядке появления.
Если вы хотите получить цвет каждого пикселя, вы можете использовать следующие строки:

for ( int row = 1; row < img.height() + 1; ++row )
    for ( int col = 1; col < img.width() + 1; ++col )
    {
        QColor clrCurrent( img.pixel( row, col ) );

        std::cout << "Pixel at [" << row << "," << col << "] contains color ("
                  << clrCurrent.red() << ", "
                  << clrCurrent.green() << ", "
                  << clrCurrent.blue() << ", "
                  << clrCurrent.alpha() << ")."
                  << std::endl;
    }
person Pie_Jesu    schedule 12.09.2012
comment
Почему вы начали с строки = 1, а не строки = 0? - person SmallChess; 13.09.2012
comment
Потому что я помнил, что изображение или растровое изображение начинают индексироваться с 1, а не с 0. Вероятно, ошибаюсь. Вы пробовали это? Начинается с 0 или как? - person Pie_Jesu; 13.09.2012
comment
Пробовал на QT5. row и col должны быть в диапазоне от 0 до width-1/height-1. А еще вы перепутали width() и height() в циклах for. - person Astronavigator; 26.08.2016
comment
В документации Qt сказано, что QImage::pixel()/setPixel() работают медленно. Рекомендуется использовать bits() или scanLine() (и их соответствующие константные версии), если вы планируете обрабатывать большое количество пикселей. - person Paulo Carvalho; 21.05.2020

Справочник по bits() говорит:

Возвращает указатель на данные первого пикселя. Это эквивалентно scanLine(0).

Поэтому, если вы проверите ссылку на scanLine()

Если вы обращаетесь к данным изображения в формате 32 бита на пиксель, приведите возвращенный указатель к QRgb* (QRgb имеет 32-разрядный размер) и используйте его для чтения/записи значения пикселя. Вы не можете использовать указатель uchar* напрямую, потому что формат пикселей зависит от порядка байтов на базовой платформе. Используйте qRed(), qGreen(), qBlue() и qAlpha() для доступа к пикселям.

Еще одним вариантом, вероятно, будет функция-член pixel().

Надеюсь, это поможет.

person jrok    schedule 12.09.2012

Одна из проблем с использованием функции bits() заключается в том, что вам необходимо знать формат исходного изображения. Вы должны преобразовать его в RGB, используя convertToFormat.

img = img.convertToFormat(QImage::Format_RGB888);

Теперь, когда вы вызываете bits(), данные будут в формате RGB с правильным выравниванием данных.

uchar *bits = img.bits();

for (int i = 0; i < (img.width() * img.height() * 3); i++)
{
    std::cout << (int) bits[i] << std::endl;
}
person Keith    schedule 12.09.2012
comment
к вашему сведению: вы можете привести img.bits() к указателю типа QRgb. Таким образом, вам не нужно знать тип изображения. Просто перебирайте каждый пиксель и используйте qRed(), qGreen(), qBlue... и т.д. - person 501 - not implemented; 01.06.2015
comment
@ 501-notimplemented, как вы это используете? Я пытаюсь const QRgb *rawPixelData = static_cast<const QRgb *>(pixelSource.constBits());, но, видимо, это недопустимое статическое приведение... - person Troyseph; 26.05.2016
comment
привет @Troyseph, ты можешь использовать QRgb *rawPixelData= (QRgb*)(pixelSource.bits()) без static_cast. - person 501 - not implemented; 27.05.2016
comment
@ 501-notimplemented приведение в стиле C... грубо =P, разве это не становится переинтерпретацией_приведения? - person Troyseph; 27.05.2016
comment
это должен быть реинтерпретатор_каст. Так что используйте приведение в стиле C! - person Петър Петров; 21.03.2019

В Qt 5.6 был введен метод QColor QImage::pixelColor(int x, int y), поэтому вы можете напрямую получать информацию о цвете из пикселя изображения.

person Andrey Azazello Yaromenok    schedule 20.06.2020