Reputation: 2519
I use GDAL
to read some imagery files and want to display them using Qt
. So far I managed to create a gray scale QImage
for 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
?
Upvotes: 1
Views: 2675
Reputation: 871
Without OpenCV, using msmith81886 code :
// Load image
GDALDataset* dataset = static_cast<GDALDataset*>(GDALOpen(tifFile.toLocal8Bit().data(), GA_ReadOnly));
// Get raster image size
int rows = dataset->GetRasterYSize();
int cols = dataset->GetRasterXSize();
int channels = dataset->GetRasterCount();
std::vector<std::vector<uchar>> bandData(channels);
for (auto& mat : bandData)
{
mat.resize(size_t(rows * cols));
}
std::vector<uchar> outputImage(size_t(4 * rows * cols));
// 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, bandData[size_t(i - 1)].data(),
cols, rows, GDT_Byte, 0, 0);
}
for (size_t i = 0, j = 0; i < outputImage.size(); i += 4, j += 1)
{
outputImage[i] = bandData[0][j];
outputImage[i + 1] = bandData[1][j];
outputImage[i + 2] = bandData[2][j];
outputImage[i + 3] = bandData[3][j];
}
// Create the QImage (or even a QPixmap suitable for displaying teh image
QImage qtImage(outputImage.data(), cols, rows, QImage::Format_RGBA8888);
Upvotes: 0
Reputation: 2356
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;
}
Upvotes: 4