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 = https://www.it610.com/article/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影像
文章图片

拉伸后的结果,跟原图简直一毛一样:
【C# GDAL将16位影像重采样2%线性拉伸并生成8位JPG影像】C# GDAL将16位影像重采样2%线性拉伸并生成8位JPG影像
文章图片

    推荐阅读