GDAL载入到Qt项目中,通过QImage显示到UI
说明:此文是通过本人不断摸索,查阅相关的知识实验成功的,如有不妥之处,望告知:kinderzhang@foxmail.com
一、开发环境:
1、opencv 3.4.1 msvc
2、GDAL 2.1 msvc
3、Qt 5.10.1
备注:opencv和gdal均是使用的是msvc的编译器,mingw编译环境也可以,需要自己去配置。
二、开发流程:
1、首先通过GDAL载入一张图片;
2、通过读取图片的波段信息存入缓冲区;
3、将缓冲区赋值到OpenCV中的Mat;(此步骤的好处是使用opencv作为中间交换层,能够将图片转换为QImage)
4、将获取的每个波段的信息进行重新混合;
5、将opencv的Mat转换为QImage;
6、显示QImage。
三、备注:
此代码需要你自己首先配置好你的opencv和GDAL环境,如果没有配置请自己百度配置。
四、代码:
按照第二步的流程,代码如下所示:
bool Dataset2QImage(const QString filePath,QImage &img)
{
//1、check the file format
QStringList formatStr;
formatStr.append(".png");
formatStr.append(".jpg");
formatStr.append(".tif");
formatStr.append(".spe");//myself define format
formatStr.append(".bmp");
bool format_flag=FALSE;
for(int i=0;i<formatStr.size();i++)
{
if(filePath.endsWith(formatStr[i]))
{
format_flag=TRUE;
break;
}
}
if(!format_flag)
return FALSE;
// 2、Initialize GDAL
GDALAllRegister();
// 3、Load image
GDALDataset* dataset = (GDALDataset *)GDALOpen(filePath.toStdString().c_str(), GA_ReadOnly);
// 4、Get raster image size
int rows = dataset->GetRasterYSize();
int cols = dataset->GetRasterXSize();
int channels = dataset->GetRasterCount();
Mat R(rows, cols, CV_8UC1, Scalar(0));//to save R img
Mat G(rows, cols, CV_8UC1, Scalar(0));//to save G img
Mat B(rows, cols, CV_8UC1, Scalar(0));//to save B img
vector<Mat> RGB(channels,cv::Mat( rows, cols, CV_8UC3,Scalar(0)));//create RGB channels
//to init default channel
//Mat hideChannel(rows, cols, CV_8UC1, Scalar(0));//set need hide channel color is black
cv::Mat output_image;
// 6、get data
// Fetch the band 1
GDALRasterBand* band = dataset->GetRasterBand(1);
// Read the band 1 data
band->RasterIO( GF_Read, 0, 0, cols, rows, B.data,
cols, rows,GDT_Byte, 0, 0);
// Fetch the band 2
band = dataset->GetRasterBand(2);
// Read the band 2 data
band->RasterIO( GF_Read, 0, 0, cols, rows, G.data,
cols, rows,GDT_Byte, 0, 0);
// Fetch the band 3
band = dataset->GetRasterBand(3);
// Read the band 3 data
band->RasterIO( GF_Read, 0, 0, cols, rows, R.data,
cols, rows,GDT_Byte, 0, 0);
// 7、set R G B value to vector mat
RGB[0]=R;
RGB[1]=G;
RGB[2]=B;
// 8、Merge images,合并通道数据
cv::merge( RGB, output_image );
//opencv window show the merge channels image
//imshow("RGB",output_image);
// 9、Create the QImage
return Mat2QImage(output_image,img);
}
以上代码注意事项:
1、上述代码中,第一步是检查文件的格式,其中有我自己定义的图片格式,这个看每个人的发挥,不严谨,严禁的写法应该是采用过滤器的方式;
2、在通过GDAL获取每一个波段的数据的时候,采用指定的波段进行获取,按照优化来说,本应该是采用一个for循环来写,但是,经过本人无数次实验,使用for循环混合后的图片是灰白色的,不能还原原图像,不知道为啥,尝试很久,此处优化留在后期思考。
3、在本代码中最后还使用了将Mat转换为QImage,具体的代码如下所示:
bool Mat2QImage(const Mat &mat,QImage &img)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if(mat.type() == CV_8UC1)
{
//qDebug() << "CV_8UC1";
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
// Set the color table (used to translate colour indexes to qRgb values)
image.setColorCount(256);
for(int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = mat.data;
for(int row = 0; row < mat.rows; row ++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
img=image;
return TRUE;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if(mat.type() == CV_8UC3)
{
//qDebug() << "CV_8UC3";
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
img = image.rgbSwapped();
return TRUE;
}
else if(mat.type() == CV_8UC4)
{
//qDebug() << "CV_8UC4";
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
img = image.copy();
return TRUE;
}
else
{
qDebug() << "ERROR: Mat could not be converted to QImage.";
return FALSE;
}
}
此处提供我的源文件,下载导入你的工程,然后调用对应的函数即可。
点击此处下载源文件