C# GDAL将16位影像重采样2%线性拉伸并生成8位JPG影像

不多BB,直接上代码

private static void Resample()
        {
            Gdal.AllRegister();
            string fileName = @"D:\test.tif";
            string outFile = @"D:\result.jpg";
            Dataset ds = Gdal.Open(fileName, Access.GA_ReadOnly);
            OSGeo.GDAL.Driver drv = Gdal.GetDriverByName("JPEG");
            OSGeo.GDAL.Driver driver = Gdal.GetDriverByName("MEM");  // 内存类型,做数据中转
            int bandCount = ds.RasterCount;
            string strWkt = ds.GetProjectionRef();
            DataType dt = ds.GetRasterBand(1).DataType;
            double ratio = (double)ds.RasterXSize / ds.RasterYSize;
            double descX = 1024D / ds.RasterXSize;
            double descY = descX / ratio;
            int ySize = (int)(ds.RasterYSize * descY);
            Dataset newDs = driver.Create("mem", 1024, ySize, 3, DataType.GDT_Byte, null);
            Dataset newDsCopy = newDs;  // 复制一个Dataset,用来存储2%线性拉伸后的数据
            double[] geoTran = new double[6];
            ds.GetGeoTransform(geoTran);
            geoTran[1] = geoTran[1] / descX;
            geoTran[5] = geoTran[5] / descY;
            newDs.SetGeoTransform(geoTran);
            newDs.SetProjection(ds.GetProjection());
            newDsCopy.SetGeoTransform(geoTran);
            newDsCopy.SetProjection(ds.GetProjection());
            double[] scanLine = new double[1024 * ySize * Gdal.GetDataTypeSize(dt)];
            ds.GetRasterBand(1).ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize, scanLine, 1024, ySize, 0, 0);  //做数据重采样,转8位图并不需要重采样,我这里是因为项目需要
            double maxValue;
            double minValue;
            int hasValue;
            ds.GetRasterBand(1).GetMaximum(out maxValue, out hasValue);
            ds.GetRasterBand(1).GetMinimum(out minValue, out hasValue);
            for (int i = 0; i < scanLine.Length; i++)
            {
                if (scanLine[i] == 0) // 跳过无数据值,否则会出现负值
                {
                    continue;
                }
                scanLine[i] -= minValue;
                scanLine[i] /= maxValue;
                scanLine[i] *= 255;
            }

            newDs.GetRasterBand(1).WriteRaster(0, 0, 1024, ySize, scanLine, 1024, ySize, 0, 0);
            double[] scanLine2 = new double[1024 * ySize * Gdal.GetDataTypeSize(dt)];
            ds.GetRasterBand(2).ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize, scanLine2, 1024, ySize, 0, 0);
            ds.GetRasterBand(2).GetMaximum(out maxValue, out hasValue);
            ds.GetRasterBand(2).GetMinimum(out minValue, out hasValue);
            for (int i = 0; i < scanLine2.Length; i++)
            {
                if (scanLine2[i] == 0)
                {
                    continue;
                }
                scanLine2[i] -= minValue;
                scanLine2[i] /= maxValue;
                scanLine2[i] *= 255;
            }

            newDs.GetRasterBand(2).WriteRaster(0, 0, 1024, ySize, scanLine2, 1024, ySize, 0, 0);
            double[] scanLine3 = new double[1024 * ySize * Gdal.GetDataTypeSize(dt)];
            ds.GetRasterBand(3).ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize, scanLine3, 1024, ySize, 0, 0);
            ds.GetRasterBand(3).GetMaximum(out maxValue, out hasValue);
            ds.GetRasterBand(3).GetMinimum(out minValue, out hasValue);
            for (int i = 0; i < scanLine3.Length; i++)
            {
                if (scanLine3[i] == 0)
                {
                    continue;
                }
                scanLine3[i] -= minValue;
                scanLine3[i] /= maxValue;
                scanLine3[i] *= 255;
            }

            newDs.GetRasterBand(3).WriteRaster(0, 0, 1024, ySize, scanLine3, 1024, ySize, 0, 0);
            Dataset stretchSet = Liner2PercentStretch(newDs, newDsCopy, 0, 0, 1024, ySize, 1024, ySize);  // 进行2%线性拉伸
            drv.CreateCopy(outFile, stretchSet, 0, null, null, string.Empty);  // 将内存里数据保存到具体的文件里
            newDs.Dispose();
            stretchSet.Dispose();
            ds.Dispose();
            drv.Dispose();
            driver.Dispose();
            GC.Collect();
        }
/// 
        /// 2%线性拉伸.
        /// 
        /// 原始的Dataset数据.
        /// 拉伸后存储数据的Dataset.
        /// ReadRaster函数的X偏移量.
        /// ReadRaster函数的Y偏移量.
        /// 读取后数据的X尺寸.
        /// 读取后数据的Y尺寸.
        /// 读取前数据的X尺寸.
        /// 读取前数据的Y尺寸.
        /// 拉伸后的Dataset.
        private static Dataset Liner2PercentStretch(Dataset srcSet, Dataset desSet, int pylY, int pylX, int buffX, int buffY, int xSize, int ySize)
        {
            for (int i = 1; i < srcSet.RasterCount + 1; i++)
            {
                Band srcBand = srcSet.GetRasterBand(i);
                double max = 0;
                double min = 0;
                int hasValue = 0;
                srcBand.GetMaximum(out max, out hasValue);
                srcBand.GetMinimum(out min, out hasValue);
                Band desBand = desSet.GetRasterBand(i);
                byte[] buffer = new byte[buffX * buffY];
                int[] panHistogram = new int[256];
                double[] ratioHistogram = new double[256];
                srcBand.GetHistogram(-0.5, 255.5, 256, panHistogram, 1, 0, null, null);
                int totalCount = panHistogram.Sum();
                ratioHistogram[0] = (double)panHistogram[0] / totalCount;
                for (int j = 1; j <= 255; j++)
                {
                    ratioHistogram[j] = ratioHistogram[j - 1] + ((double)panHistogram[j] / totalCount);
                }
                srcBand.ReadRaster(pylY, pylX, xSize, ySize, buffer, buffX, buffY, 0, 0);
                int percent2Value = 0;  // 2%处灰度值
                int percent98Value = 0; // 98%处灰度值
                for (int m = 0; m <= 255; m++)
                {
                    if (ratioHistogram[m] <= 0.02)
                    {
                        percent2Value = m;
                    }
                    if (ratioHistogram[m] <= 0.98)
                    {
                        percent98Value = m;
                    }
                }
                for (int n = 0; n < buffer.Length; n++)
                {
                    if (buffer[n] <= percent2Value)
                    {
                        buffer[n] = 0;
                    }
                    else if (buffer[n] >= percent98Value)
                    {
                        buffer[n] = 255;
                    }
                    else
                    {
                        buffer[n] = (byte)(255 / (percent98Value - percent2Value) * (buffer[n] - percent2Value));
                    }
                }
                desBand.WriteRaster(0, 0, buffX, buffY, buffer, buffX, buffY, 0, 0);
            }
            return desSet;
        }

其中下面三行代码是转8位图的关键

scanLine2[i] -= minValue;
scanLine2[i] /= maxValue;
scanLine2[i] *= 255;

可以看到我在最后做了一个2%线性拉伸,这是因为只是单纯的转8位图,最后出来的结果很暗,效果非常不好,所以我做了一下2%线性拉伸。

不做线性拉伸结果:

C# GDAL将16位影像重采样2%线性拉伸并生成8位JPG影像_第1张图片

拉伸后的结果,跟原图简直一毛一样:

C# GDAL将16位影像重采样2%线性拉伸并生成8位JPG影像_第2张图片

你可能感兴趣的:(GDAL)