在处理遥感影像的渲染时,经常需要处理单波段影像。单波段影像没有任何颜色,只有一个波段的值。渲染时只能采用色带拉伸、离散颜色、唯一值渲染这几种方式。直接将单波段影像转成三波段的影像,并将三个波段转为颜色对应的rgb值,这样可以加速渲染、切片的过程。这里我有一张单波段影像,需要按照唯一值的方式,进行渲染,这里记录一下实现过程。
Java依赖
<dependency><groupId>org.gdal</groupId><artifactId>gdal</artifactId><version>3.5.0</version></dependency>
注意我本地部署的是gdal3以上的版本,不同版本的api会有不同
实现代码
package map.tile.server.tool;import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.Driver;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;import java.awt.*;import java.util.HashMap;
import java.util.Map;import static org.gdal.gdalconst.gdalconstConstants.GDT_Byte;public class RasterTool {public static void main(String[] args) throws Exception {// 注册所有支持的格式gdal.AllRegister();String inputFile = "E:\\栅格\\2023_20230430.tif";Dataset dataset = gdal.Open(inputFile, gdalconstConstants.GA_ReadOnly);if (dataset == null) {System.out.println("无法打开输入图像");return;}int width = dataset.GetRasterXSize();int height = dataset.GetRasterYSize();Band band = dataset.GetRasterBand(1);System.out.println(band.GetRasterDataType());//设立每类值对应样式,样色Color colorLevel1 = new Color(0, 92, 230);Color colorLevel2 = new Color(56, 168, 0);Color colorLevel3 = new Color(85, 255, 0);Color colorLevel4 = new Color(255, 170, 0);Map<Short, Color> styles = new HashMap<>(4);styles.put((short) 1, colorLevel1);styles.put((short) 2, colorLevel2);styles.put((short) 3, colorLevel3);styles.put((short) 4, colorLevel4);// 创建新的RGB图像对象Double[] noDataValue = new Double[1];band.GetNoDataValue(noDataValue);Driver driver = gdal.GetDriverByName("GTiff");Dataset rgbDataset = driver.Create("E:\\栅格\\output_rgb_image.tif", width, height, 3, GDT_Byte);rgbDataset.SetProjection(dataset.GetProjection());rgbDataset.SetGeoTransform(dataset.GetGeoTransform());for (int i = 0; i < 3; ++i) {Band outputBand = rgbDataset.GetRasterBand(i + 1);outputBand.SetNoDataValue(noDataValue[0]);short[] buffer = new short[width];// 一次读取一行,防止数据溢出for (int j = 0; j < height; j++) {band.ReadRaster(0, j, width, 1, buffer);// 转换颜色processData(buffer, i + 1, styles);outputBand.WriteRaster(0, j, width, 1, buffer);}outputBand.FlushCache();outputBand.delete();}rgbDataset.FlushCache();rgbDataset.delete();dataset.delete();}private static void processData(short[] buffer, int bandIndex, Map<Short, Color> styles) {if (bandIndex == 1) {for (int i = 0; i < buffer.length; i++) {Color color = styles.get(buffer[i]);if (color != null) {buffer[i] = (short) color.getRed();}}} else if (bandIndex == 2) {for (int i = 0; i < buffer.length; i++) {Color color = styles.get(buffer[i]);if (color != null) {buffer[i] = (short) color.getGreen();}}} else if (bandIndex == 3) {for (int i = 0; i < buffer.length; i++) {Color color = styles.get(buffer[i]);if (color != null) {buffer[i] = (short) color.getBlue();}}}}
}
效果对比
将转换后的文件,直接拖入拖入QGIS展示效果如下:
- 转换前
- 转换后
注意,如果使用ArcGIS查看效果的话,需要将拉伸类型选择“无”,将应用Gamma拉伸取消勾选。
感想
- GDAL的Java交互真的不太友好
- 太大的影像居然没有办法直接读取,整张影像读取,因为可能或超过数组的长度限制。