Wechat: yu389741| Email: gisdqy@163.com

Shop:https://www.giserdqy.com/shop

GDAL-读取影像的金字塔,生成快视图


之前使用GDAL提取快视图时,使用的是直接读取原始影像的方式,但之前遇到一次原始影像有坏块的情况,无法读取,所以想试试通过读取金字塔来生成快视图
 
我觉得从原理上来说,这样也应该会更快一些,不过没有验证过
经测试,GDAL自身在RASTERIO时,如果有抽稀的操作,会自动去读取金字塔,这种实现没有意义!这个思路是错误的,仅留作存档
 
        /// <summary>
        /// 读取影像的金字塔,从中提取取一个合适的级别,转成JPG格式,从而生成快视图
        /// </summary>
        /// <param name=”dsin”>源影像</param>
        /// <param name=”quickshowPath”>生成JPG文件的路径</param>
        /// <param name=”scale”>输入的参考比例(例如,输入10,表示生成一个长宽均为源影像1/10的格式,但由于各级金字塔的比例不一定与该值完全相等,为避免进行重采样计算,程序会找一个最接近的等级,所以最终的快视图比例与这个值不一定相等)</param>
        /// <param name=”quickShowWidth”>生成的快视图宽度方向像素数</param>
        /// <param name=”quickShowHeight”>生成的快视图高度方向像素数</param>
        /// <param name=”errMsg”>错误信息</param>
        /// <returns>是否生成成功</returns>
        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<Band> bands = new List<Band>();    //金字塔波段的列表
            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;
        }

转载自:https://blog.csdn.net/rrrrssss00/article/details/12224571