之前使用GDAL提取快视图时,使用的是直接读取原始影像的方式,但之前遇到一次原始影像有坏块的情况,无法读取,所以想试试通过读取金字塔来生成快视图 我觉得从原理上来说,这样也应该会更快一些,不过没有验证过
经测试,GDAL自身在RASTERIO时,如果有抽稀的操作,会自动去读取金字塔,这种实现没有意义!这个思路是错误的,仅留作存档
////// 读取影像的金字塔,从中提取取一个合适的级别,转成JPG格式,从而生成快视图 ////// 源影像 /// 生成JPG文件的路径 /// 输入的参考比例(例如,输入10,表示生成一个长宽均为源影像1/10的格式,但由于各级金字塔的比例不一定与该值完全相等,为避免进行重采样计算,程序会找一个最接近的等级,所以最终的快视图比例与这个值不一定相等) /// 生成的快视图宽度方向像素数 /// 生成的快视图高度方向像素数 /// 【c#|GDAL-读取影像的金字塔,生成快视图】错误信息 /// 是否生成成功 public bool pyramidToQuickshow(Dataset dsin, string quickshowPath,int scale,out int quickShowWidth,out int quickShowHeight, out string errMsg) { #region 一些基本检查 quickShowWidth = 0;
quickShowHeight = 0;
errMsg = "";
//确认是8BIT的影像数据 if (dsin.GetRasterBand(1).DataType != DataType.GDT_Byte) { errMsg = "暂不支持8位BYTE之外的数据";
return false;
} //确认影像已经有金字塔 string[] files = dsin.GetFileList();
bool findRRD = false;
for (int i = 0;
i < files.Length;
i++) { if (files[i].ToLower().EndsWith(".rrd")) { findRRD = true;
break;
} } int pyramidCount = ds.GetRasterBand(1).GetOverviewCount();
if (!findRRD && pyramidCount == 0) { errMsg = "影像文件未建立金字塔";
return false;
} #endregion //用于输出的Driver,因为GDAL的JPEG Driver似乎不支持直接生成文件并写入,所以用一个内存Driver写入 //并复制一个JPEG Driver drijpg = Gdal.GetDriverByName("JPEG");
Driver drimen = Gdal.GetDriverByName("MEM");
int rasterCount = dsin.RasterCount;
//波段数 #region 找出与输入的scale最接近的金字塔等级,并将其确认为提取的等级,并记录该等级金字塔的长宽 int resLevel = 0, minVal = 0, resScale = 0;
for (int i = 0;
i < pyramidCount;
i++) { Band tmpBand = ds.GetRasterBand(1).GetOverview(i);
if (i == 0) { minVal = Math.Abs(ds.RasterXSize / tmpBand.XSize - scale);
resScale = ds.RasterXSize / tmpBand.XSize;
quickShowWidth = tmpBand.XSize;
quickShowHeight = tmpBand.YSize;
} else { int tmpInt = Math.Abs(ds.RasterXSize / tmpBand.XSize - scale);
if (tmpInt < minVal) { minVal = tmpInt;
resLevel = i;
resScale = ds.RasterXSize / tmpBand.XSize;
quickShowWidth = tmpBand.XSize;
quickShowHeight = tmpBand.YSize;
} } } #endregion #region 读取各波段对应等级的金字塔,保存到一个列表中 List bands = new List();
//金字塔波段的列表 for (int i = 0;
i < rasterCount;
i++) { Band tmpBand = ds.GetRasterBand(i + 1).GetOverview(resLevel);
bands.Add(tmpBand);
} #endregion #region 新建快视图(JPG)对应的Dataset,并向其中写入数据 Dataset dout = drimen.Create(quickshowPath, quickShowWidth,quickShowHeight, rasterCount, DataType.GDT_Byte, null);
//为避免因影像过大无法一次读取并写入完毕,这里按进行读取和写入 //以下为按行读取的一些参数 int rows = 1000000 / quickShowWidth;
//一次读取的行数(正常情况下) int readCount = quickShowHeight / rows;
//读取的次数 if (quickShowHeight % rows != 0) readCount++;
//不能整除的话,还需要多读一次 byte[] raw = null;
//读取和写入用到的数组 //开始读取并写入数据 for (int i = 0;
i < bands.Count ;
i++) { int tmpHeight = rows;
//一次读取的行数 raw = new byte[rows * quickShowWidth];
Band tmpBand2 = dout.GetRasterBand(i + 1);
for (int j = 0;
j < readCount;
j++) { //如果是最后一次读取,且行数不能整除一次读取的行数时,那要对剩余部分作一次单独的读取 if (j == readCount - 1 && quickShowHeight % rows != 0) { raw = null;
tmpHeight = quickShowHeight % rows;
raw = new byte[quickShowWidth * tmpHeight];
} bands[i].ReadRaster(0, j * rows, quickShowWidth, tmpHeight, raw, quickShowWidth, tmpHeight, 0, 0);
tmpBand2.WriteRaster(0, j * rows, quickShowWidth, tmpHeight, raw, quickShowWidth, tmpHeight, 0, 0);
} dout.FlushCache();
} #endregion drijpg.CreateCopy(quickshowPath, dout, 1, null, null, null);
dout.Dispose();
return true;
}
推荐阅读