1、GDAL库初始化
// 初始化
GDALAllRegister();
// 设置支持中文路径和文件名
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
在此之前记得引用头文件
#include <gdal_priv.h>
2、加载tiff图像文件
void gdalLoadTiffImage()
{
QString filePath = QFileDialog::getOpenFileName(this,
QString::fromLocal8Bit("选择图像"),
"",
QString::fromLocal8Bit("图像文件(*.tif *.tiff)"));
if (filePath.isEmpty())
return;
GDALDataset *dataset = (GDALDataset *)GDALOpen(filePath.toLocal8Bit().constData(), GA_ReadOnly);
if (!dataset) {
// 错误处理
return;
}
int width = dataset->GetRasterXSize();
int height = dataset->GetRasterYSize();
int bands = dataset->GetRasterCount();
// 分配QImage的内存
QImage::Format format = QImage::Format_RGB888;
QImage image = QImage(width, height, format);
// 假设我们总是处理RGB图像,并且波段顺序是红、绿、蓝
int redBand = 1, greenBand = 2, blueBand = 3;
if (bands == 1) {
redBand = greenBand = blueBand = 1;
}
// 读取波段数据并转换为QImage
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
uint8_t red, green, blue;
GDALRasterBand *bandRed = dataset->GetRasterBand(redBand);
GDALRasterBand *bandGreen = dataset->GetRasterBand(greenBand);
GDALRasterBand *bandBlue = dataset->GetRasterBand(blueBand);
// 像素值范围
int success = 0;
double minimum = bandRed->GetMinimum(&success);
double maximum = bandRed->GetMaximum(&success);
double noData = bandRed->GetNoDataValue(&success);
GDALDataType dataType = bandRed->GetRasterDataType();
switch (dataType) {
case GDT_Byte:{
bandRed->RasterIO(GF_Read, x, y, 1, 1, &red, 1, 1, GDT_Byte, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &green, 1, 1, GDT_Byte, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blue, 1, 1, GDT_Byte, 0, 0);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
} break;
case GDT_UInt16: {
uint16_t red16, green16, blue16;
bandRed->RasterIO(GF_Read, x, y, 1, 1, &red16, 1, 1, GDT_UInt16, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &green16, 1, 1, GDT_UInt16, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blue16, 1, 1, GDT_UInt16, 0, 0);
// 假设值在0-65535之间,缩放到0-255
red = static_cast<uint8_t>(red16 * 255.0 / 65535.0);//65535.0 -> (maximum - minimum));
green = static_cast<uint8_t>(green16 * 255.0 / 65535.0);
blue = static_cast<uint8_t>(blue16 * 255.0 / 65535.0);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
case GDT_Int16: {
int16_t red16, green16, blue16;
bandRed->RasterIO(GF_Read, x, y, 1, 1, &red16, 1, 1, GDT_Int16, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &green16, 1, 1, GDT_Int16, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blue16, 1, 1, GDT_Int16, 0, 0);
// 假设值在-32768到32767之间,先转换为0-65535再缩放到0-255
// 注意这里需要处理负数,并可能需要进行偏移和缩放
uint16_t redUnsigned = static_cast<uint16_t>(red16 + 32768);
uint16_t greenUnsigned = static_cast<uint16_t>(green16 + 32768);
uint16_t blueUnsigned = static_cast<uint16_t>(blue16 + 32768);
red = static_cast<uint8_t>(redUnsigned * 255.0 / 65535.0);
green = static_cast<uint8_t>(greenUnsigned * 255.0 / 65535.0);
blue = static_cast<uint8_t>(blueUnsigned * 255.0 / 65535.0);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
case GDT_UInt32:{
uint32_t red32, green32, blue32;
bandRed->RasterIO(GF_Read, x, y, 1, 1, &red32, 1, 1, GDT_UInt32, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &green32, 1, 1, GDT_UInt32, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blue32, 1, 1, GDT_UInt32, 0, 0);
// 假设值在0-4294967295之间,缩放到0-255
red = static_cast<uint8_t>(red32 * 255.0 / 4294967295.0);
green = static_cast<uint8_t>(green32 * 255.0 / 4294967295.0);
blue = static_cast<uint8_t>(blue32 * 255.0 / 4294967295.0);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
case GDT_Int32:{
int32_t red32, green32, blue32;
bandRed->RasterIO(GF_Read, x, y, 1, 1, &red32, 1, 1, GDT_Int32, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &green32, 1, 1, GDT_Int32, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blue32, 1, 1, GDT_Int32, 0, 0);
// 假设值在-2147483648到2147483647之间,先转换为0-4294967295再缩放到0-255
uint32_t redUnsigned = static_cast<uint32_t>(red32 + 2147483648);
uint32_t greenUnsigned = static_cast<uint32_t>(green32 + 2147483648);
uint32_t blueUnsigned = static_cast<uint32_t>(blue32 + 2147483648);
red = static_cast<uint8_t>(redUnsigned * 255.0 / 4294967295.0);
green = static_cast<uint8_t>(greenUnsigned * 255.0 / 4294967295.0);
blue = static_cast<uint8_t>(blueUnsigned * 255.0 / 4294967295.0);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
case GDT_Float32:{
float redFloat, greenFloat, blueFloat;
bandRed->RasterIO(GF_Read, x, y, 1, 1, &redFloat, 1, 1, GDT_Float32, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &greenFloat, 1, 1, GDT_Float32, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blueFloat, 1, 1, GDT_Float32, 0, 0);
// 假设值在0.0到1.0之间,直接乘以255
// 如果不是0.0到1.0,你需要知道数据的具体范围并进行适当的缩放
red = static_cast<uint8_t>(redFloat * 255.0);
green = static_cast<uint8_t>(greenFloat * 255.0);
blue = static_cast<uint8_t>(blueFloat * 255.0);
// 如果需要处理可能的超出范围的值
red = qMin(qMax((uint8_t)red, (uint8_t)0), (uint8_t)255);
green = std::min(std::max(green, (uint8_t)0), (uint8_t)255);
blue = std::min(std::max(blue, (uint8_t)0), (uint8_t)255);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
case GDT_Float64:{
double redDouble, greenDouble, blueDouble;
bandRed->RasterIO(GF_Read, x, y, 1, 1, &redDouble, 1, 1, GDT_Float64, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, &greenDouble, 1, 1, GDT_Float64, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, &blueDouble, 1, 1, GDT_Float64, 0, 0);
// 假设值在0.0到1.0之间,直接乘以255
// 如果不是0.0到1.0,你需要知道数据的具体范围并进行适当的缩放
red = static_cast<uint8_t>(redDouble * 255.0);
green = static_cast<uint8_t>(greenDouble * 255.0);
blue = static_cast<uint8_t>(blueDouble * 255.0);
// 如果需要处理可能的超出范围的值
red = std::min(std::max(red, (uint8_t)0), (uint8_t)255);
green = std::min(std::max(green, (uint8_t)0), (uint8_t)255);
blue = std::min(std::max(blue, (uint8_t)0), (uint8_t)255);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
// 对于复数类型(GDT_CInt16, GDT_CInt32, GDT_CFloat32, GDT_CFloat64),
// GDAL通常不直接用于存储图像数据(如RGB),而是用于科学计算。
case GDT_CInt16:{
int16_t redComplexValue[2], greenComplexValue[2], blueComplexValue[2]; // 数组中的第一个元素是实部,第二个元素是虚部
bandRed->RasterIO(GF_Read, x, y, 1, 1, redComplexValue, 1, 1, GDT_CInt16, 0, 0);
bandGreen->RasterIO(GF_Read, x, y, 1, 1, greenComplexValue, 1, 1, GDT_CInt16, 0, 0);
bandBlue->RasterIO(GF_Read, x, y, 1, 1, blueComplexValue, 1, 1, GDT_CInt16, 0, 0);
// 只使用实部,并像GDT_Int16那样处理
int16_t red16 = redComplexValue[0];
int16_t green16 = greenComplexValue[0];
int16_t blue16 = blueComplexValue[0];
// 假设值在-32768到32767之间,先转换为0-65535再缩放到0-255
// 注意这里需要处理负数,并可能需要进行偏移和缩放
uint16_t redUnsigned = static_cast<uint16_t>(red16 + 32768);
uint16_t greenUnsigned = static_cast<uint16_t>(green16 + 32768);
uint16_t blueUnsigned = static_cast<uint16_t>(blue16 + 32768);
red = static_cast<uint8_t>(redUnsigned * 255.0 / 65535.0);
green = static_cast<uint8_t>(greenUnsigned * 255.0 / 65535.0);
blue = static_cast<uint8_t>(blueUnsigned * 255.0 / 65535.0);
// 设置QImage的像素值
QRgb pixel = qRgb(red, green, blue);
image.setPixel(x, y, pixel);
break;
}
case GDT_CInt32:{
// 参考GDT_CInt16
break;
}
case GDT_CFloat32:{
// 参考GDT_CInt16
break;
}
case GDT_CFloat64:{
// 参考GDT_CInt16
break;
}
}
}
}
GDALClose(dataset);
}
3、GDAL库资源释放
GDALDestroyDriverManager();
在QT安装路径下有个tif文件目录可供测试使用:C:\Qt\Qt5.15.2\5.15.2\Src\qtimageformats\tests\shared\images\tiff
按照常理来说,如果波段为1,数据类型是GDT_Byte,数据范围正常来说应该是0~255,最终显示出来的图像是灰度图,但是如下图片的数据范围却为0~65535,用自己代码显示当然也是灰度图像,但是用其它工具软件显示确实彩色图像(如PS),究竟是哪里出了问题,有待日后去研究了!!!