很多遥感卫星数据使用的量化级别都要比8bit高,比如常用的WorldView用的是12bit的量化,对于一些图像处理软件,是不能直接处理12bit量化的图像,所以需要将12bit的数据转为16bit数据或者8bit数据来进行处理。
下面写了一个简单的函数来进行处理,具体原理很简单,就是使用GDAL将12bit的数据读进来,然后再使用线性拉伸为8bit存出去,或者直接保存为16bit数据。注意12bit的数据在GDAL中读取的时候会显示为16bit数据,就好比2bit的数据在GDAL中是8bit一样,因为在C或者C++中很难找到一个类型来表示2bit或者12bit的东西,最小的char是8bit,short是16bit。代码如下,首先是头文件:
/*************************************************************************** * * Time: 2012-02-23 * Project: 遥感平台 * Purpose: 将12bit数据转换为8bit或者16bit * Author: 李民录 * Copyright (c) 2012, liminlu0314@gmail.com * Describe:将12bit数据转换为8bit或者16bit * ****************************************************************************/ #ifndef DATARESCALE_H #define DATARESCALE_H /*! 8U */ typedef unsigned char DT_8U; /*! 16U */ typedef unsigned short DT_16U; /** * @brief 释放数组 */ #define RELEASE(x) if(x!=NULL) {delete []x; x = NULL;} /** * @brief 图像转换,将图像存为16bit,前提确保输入的数据是12bit的 * @param pszSrcFile 输入文件路径 * @param pszDstFile 输出文件路径 * @param bTo8 是否转为8位,false为专为16bit数据,true表示转为8bit数据 * @param pszFormat 输出文件格式,详细参考GDAL支持数据类型 * @return 返回值,表示计算过程中出现的各种错误信息 */ int ImageDataRescale216(const char* pszSrcFile, const char* pszDstFile, bool bTo8 = true, const char* pszFormat = "GTiff"); #endif /* DATARESCALE_H */下面是函数实现代码:
/*************************************************************************** * * Time: 2012-02-23 * Project: 遥感平台 * Purpose: 将12bit数据转换为8bit或者16bit * Author: 李民录 * Copyright (c) 2012, liminlu0314@gmail.com * Describe:将12bit数据转换为8bit或者16bit * ****************************************************************************/ #include "DataRescale.h" #include "gdal_priv.h" /** * @brief 图像转换,将图像存为16bit,前提确保输入的数据是12bit的 * @param pszSrcFile 输入文件路径 * @param pszDstFile 输出文件路径 * @param bTo8 是否转为8位,false为专为16bit数据,true表示转为8bit数据 * @param pszFormat 输出文件格式,详细参考GDAL支持数据类型 * @return 返回值,表示计算过程中出现的各种错误信息 */ int ImageDataRescale(const char* pszSrcFile, const char* pszDstFile, bool bTo8 = true, const char* pszFormat = "GTiff") { //判断输入路径是否为空 if(pszSrcFile == NULL || pszDstFile == NULL) return -1; GDALAllRegister(); GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszSrcFile, GA_ReadOnly ); if( poSrcDS == NULL ) { //图像打开失败 return -2; } GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat); if( poDriver == NULL ) { //不能创建制定类型的文件,请检查该文件类型GDAL是否支持创建 GDALClose( (GDALDatasetH) poSrcDS ); return -3; } //获取图像宽高和波段数 int iXSize = poSrcDS->GetRasterXSize(); int iYSize = poSrcDS->GetRasterYSize(); int iBandCount = poSrcDS->GetRasterCount(); //确定输出图像的位数 GDALDataType eDT = GDT_UInt16; if(bTo8) eDT = GDT_Byte; else eDT = GDT_UInt16; //创建16bit的数据 GDALDataset *poDstDS = poDriver->Create(pszDstFile, iXSize, iYSize, iBandCount, eDT, NULL); double dGeoTrans[6] = {0}; //设置仿射变换参数 poSrcDS->GetGeoTransform(dGeoTrans); poDstDS->SetGeoTransform(dGeoTrans); //设置图像投影信息 poDstDS->SetProjection(poSrcDS->GetProjectionRef()); //用于保存读取的12bit数据 DT_16U *pSrcData = new DT_16U[iXSize]; if(bTo8) //转换为8bit { //定义结果数据存储空间 DT_8U *pDstData = new DT_8U[iXSize]; //循环波段 for(int iBand=1; iBand<=iBandCount; iBand++) { GDALRasterBand *pSrcBand = poSrcDS->GetRasterBand(iBand); GDALRasterBand *pDstBand = poDstDS->GetRasterBand(iBand); for(int i=0; i<iYSize; i++) //循环图像高 { //将数据读出来 pSrcBand->RasterIO(GF_Read, 0, i, iXSize, 1, pSrcData, iXSize, 1, GDT_UInt16, 0, 0); //循环,将12bit数据专为8bit数据,使用线性拉伸方式 for(int j=0; j<iXSize; j++) { double dTemp = pSrcData[j] * 255.0 / 4095.0; if(dTemp > 255.0) pDstData[j] = 255; else pDstData[j] = (DT_8U)dTemp; } pDstBand->RasterIO(GF_Write, 0, i, iXSize, 1, pDstData, iXSize, 1, GDT_Byte, 0, 0); } } RELEASE(pDstData); //释放内存 } else //转换为16bit数据 { //循环波段 for(int iBand=1; iBand<=iBandCount; iBand++) { GDALRasterBand *pSrcBand = poSrcDS->GetRasterBand(iBand); GDALRasterBand *pDstBand = poDstDS->GetRasterBand(iBand); for(int i=0; i<iYSize; i++) //循环图像高 { //将数据读出来,然后写入结果数据 pSrcBand->RasterIO(GF_Read, 0, i, iXSize, 1, pSrcData, iXSize, 1, GDT_UInt16, 0, 0); pDstBand->RasterIO(GF_Write, 0, i, iXSize, 1, pSrcData, iXSize, 1, GDT_UInt16, 0, 0); } } } RELEASE(pSrcData); //关闭原始图像和结果图像 GDALClose( (GDALDatasetH) poDstDS ); GDALClose( (GDALDatasetH) poSrcDS ); return 0; }
对于上面的实现做一个简单的说明,12bit的数据读进来,对于16bit的直接写到结果图像里面,没有拉伸到16bit的范围,这样就是完全保留了原始数据的所有图像信息,对于保存为8bit的数据,肯定会造成部分信息的丢失,使用最简单的线性方程进行拉伸,将0~4095的范围拉伸到0~255的范围。