在处理遥感影像的渲染时,经常需要处理单波段影像。单波段影像没有任何颜色,只有一个波段的值。渲染时只能采用色带拉伸、离散颜色、唯一值渲染这几种方式。直接将单波段影像转成三波段的影像,并将三个波段转为颜色对应的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交互真的不太友好
- 太大的影像居然没有办法直接读取,整张影像读取,因为可能或超过数组的长度限制。