13

I want to extract RGB from each pixel in QImage. Ideally, I want to use the img.bits() function.

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;
    }
}

How to manipulate the returned bits? I expected all red because the picture is a pure red image created in Paint. However, I get 36, 27, 237, 255, 36 etc...

Pie_Jesu
  • 1,894
  • 3
  • 16
  • 30
ABCD
  • 7,914
  • 9
  • 54
  • 90
  • 2
    Reading with `bits()` depends heavily on the image format. Try to convert the format to something more suitable for your scenario, e.g. `img = img.convert(QImage::Format_ARGB32)`. Then the bytes should come out as `0, 255, 0, 0, [loop]` if I'm not mistaken. – Stefan Majewsky Sep 12 '12 at 09:13

4 Answers4

17
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;
    }
}

However this example above does returns the color table. Color table does not includes same colors twice. They will be added once in order of appearance.
If you want to get each pixels color, you can use next lines:

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;
    }
Pie_Jesu
  • 1,894
  • 3
  • 16
  • 30
  • Why did you start from row = 1, not row = 0? – ABCD Sep 12 '12 at 20:19
  • Cause I was remembering that image or pixmap starts indexing from 1, not 0. Probably mistaking. Did you tried it? Starts from 0 or what? – Pie_Jesu Sep 13 '12 at 05:36
  • Tried it on QT5. `row` and `col` should be in range from 0 to width-1/height-1. And also you mixed up `width()` and `height()` in for loops. – Astronavigator Aug 26 '16 at 00:33
  • 1
    Qt documentation says that `QImage::pixel()` / `setPixel()` are slow. It recommends you to use `bits()` or `scanLine()` (and their respective const versions) if you plan to process a great deal of pixels. – Paulo Carvalho May 21 '20 at 11:59
6

Reference for bits() says:

Returns a pointer to the first pixel data. This is equivalent to scanLine(0).

So if you check reference for scanLine()

If you are accessing 32-bpp image data, cast the returned pointer to QRgb* (QRgb has a 32-bit size) and use it to read/write the pixel value. You cannot use the uchar* pointer directly, because the pixel format depends on the byte order on the underlying platform. Use qRed(), qGreen(), qBlue(), and qAlpha() to access the pixels.

One other option would probably be pixel() member function.

Hope that helps.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
jrok
  • 54,456
  • 9
  • 109
  • 141
4

One of the problems with using the bits() function is that you need to know the format of the original image. You should convert it to RGB by using convertToFormat.

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

Now, when you call bits(), the data will be in the RGB format with the proper data alignment.

uchar *bits = img.bits();

for (int i = 0; i < (img.width() * img.height() * 3); i++)
{
    std::cout << (int) bits[i] << std::endl;
}
Keith
  • 225
  • 1
  • 5
0

In Qt 5.6 was introduced QColor QImage::pixelColor(int x, int y) method, so you can directly get color information from image pixel.