Search code examples
c++qtgdal

create an RBG Color QImage from a GDALDataSet


I use GDAL to read some imagery files and want to display them using Qt. So far I managed to create a gray scale QImagefor each GDALRasterBand in my GDALDataSet, but I don't know how to create a single RGB image.

Here's what I've done :

#include <gdal_priv.h>
#include <QtGui\QImage>

int main(int argc, char *argv[])
{
    GDALAllRegister();

    GDALDataset* dataset = static_cast<GDALDataset*>(GDALOpen("path_to_some_image.tif", GA_ReadOnly));
    int size_out = 200;

    for (int i = 1; i <= 3; ++i)
    { 
        GDALRasterBand* band = dataset->GetRasterBand(i);

        std::vector<uchar> band_data(size_out * size_out);
        band->RasterIO(GF_Read, 0, 0, size_out, size_out, band_data.data(), size_out, size_out, GDT_Byte, 0, 0);

        QImage band_image(band_data.data(), size_out, size_out, QImage::Format_Grayscale8);
        band_image.save(QString("C:\\band_%1.png").arg(i));
    }

    return 0;
}

How do I read the data so I can create a single RGB QImage ?


Solution

  • You are nearly there. The first item is that the QImage takes a buffer with the format flag. As a result, that format flag needs to either match the image you are loading from file, or else needs to be transformed. The example below assumes a 4-channel image.

    QImage Format Flag Docs: http://doc.qt.io/qt-5/qimage.html#Format-enum

    The next component is that GDAL's RasterIO method handles each band separately, meaning you have to interleave the pixels separately or lose the efficiency that comes with loading the raster band-by-band.

    RasterIO: http://gdal.org/classGDALRasterBand.html#a30786c81246455321e96d73047b8edf1

    I like OpenCV's merge method for this. Just create a grayscale image for each band and merge them together.

    OpenCV Merge: http://docs.opencv.org/3.0.0/d2/de8/group__core__array.html#ga61f2f2bde4a0a0154b2333ea504fab1d

    For example, given an RGBA GeoTiff,

    // OpenCV Libraries
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    // GDAL Libraries
    #include <gdal.h>
    
    // QT Libraries
    #include <QtGui\QImage>
    
    using namespace cv;
    
    
    int main( int argc, char* argv[] )
    {
    
        // Initialize GDAL
        GDALAllRegister();
    
        // Load image
        GDALDataset* dataset = GDALOpen("path_to_some_image.tif", GA_ReadOnly);
    
        // Get raster image size
        int rows = dataset->GetRasterYSize();
        int cols = dataset->GetRasterXSize();
        int channels = dataset->GetRasterCount();
    
        // Create each separate image as grayscale
        std::vector<cv::Mat> image_list(channels, cv::Mat( rows, cols, CV_8UC1 ));
        cv::Mat output_image;
    
        // Iterate over each channel
        for (int i = 1; i <= channels; ++i)
        { 
            // Fetch the band
            GDALRasterBand* band = dataset->GetRasterBand(i);
    
            // Read the data
            band->RasterIO( GF_Read, 0, 0, 
                            cols, rows, 
                            image_list[i-1].data, 
                            cols, rows, 
                            GDT_Byte, 0, 0);
    
        }
    
        // Merge images
        cv::merge( image_list, output_image );
    
        // Create the QImage
        QImage qt_image( band_data.data(), 
                         cols, 
                         rows,
                         QImage::Format_RGBA8888);
    
        // Do some stuff with the image
    
        return 0;
     }