使用C#调用gdal写了个简单的遥感影像切xyz工具,只能切tiff影像。界面没设计,代码没优化,也没上多线程,有兴趣的自己拿去改。
全部代码如下,切片逻辑参见 MapTile 这个方法 :
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using GDAL = OSGeo.GDAL;
using OGR = OSGeo.OGR;
using System.IO;
namespace MapTileTool
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
}
private void HandleGeoTiffSelect(object sender, EventArgs e)
{
string title = "选择遥感影像";
string filter = "tif文件(*.tif,*.tiff)|*.tif;*.tiff";
string fileName = FileChooserSelect(title, filter);
if (null != fileName) {
this.tifTextBox.Text = fileName;
}
}
private void HandleGeoTiffRest(object sender, EventArgs e)
{
this.tifTextBox.Text = ""; ;
}
private void HandleOutputSelect(object sender, EventArgs e)
{
string outputPath = FoloderChooserSelect("选择输出文件夹");
if (null != outputPath) {
this.outputTextBox.Text = outputPath;
}
}
private void HandleOutputRest(object sender, EventArgs e)
{
this.outputTextBox.Text = "";
}
private void ExecuteMapTile(object sender, EventArgs e)
{
string geoTiffPath = tifTextBox.Text;
string outputPath = outputTextBox.Text;
string zMin = zMinTextBox.Text;
string zMax = zMaxTextBox.Text;
if (string.IsNullOrEmpty(geoTiffPath)
|| string.IsNullOrEmpty(outputPath)
|| string.IsNullOrEmpty(zMin)
|| string.IsNullOrEmpty(zMax)) {
MessageBox.Show("信息填写有误");
return;
}
try
{
int zMinLevel = Convert.ToInt32(zMin);
int zMaxLevel = Convert.ToInt32(zMax);
executeBtn.Enabled = false;
consoleLabel.Text = "正在切片,请稍候。。。";
MapTile(geoTiffPath, outputPath, zMinLevel, zMaxLevel);
consoleLabel.Text = "恭喜,影像切片已完成";
executeBtn.Enabled = true;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
consoleLabel.Text = "切图异常:" + ex.Message;
executeBtn.Enabled = true;
}
}
/**
* 切片处理逻辑
*/
private void MapTile(string geoTiffPath, string outputPath, int zMin, int zMax) {
try
{
OGR.Ogr.RegisterAll();
GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
}
catch (Exception ex)
{
Console.WriteLine("Gdal驱动注册失败:" + ex.Message);
}
OSGeo.GDAL.Dataset dataset = GDAL.Gdal.Open(geoTiffPath, OSGeo.GDAL.Access.GA_ReadOnly);
int width = dataset.RasterXSize;
int height = dataset.RasterYSize;
int bandCount = dataset.RasterCount;
double[] transform = new double[6];
dataset.GetGeoTransform(transform);
double lonMin = transform[0];
double lonMax = transform[0] + (width * transform[1]);
double latMin = transform[3] + (height * transform[5]);
double latMax = transform[3];
if (zMin < 6)
{
zMin = 6;
}
if (zMax > 18)
{
zMax = 18;
}
for (int z = zMin; z <= zMax; z++)
{
int tileRowMin = GetXyTileByZ(lonMin, latMax, z)[0];
int tileRowMax = GetXyTileByZ(lonMax, latMin, z)[0];
int tileColMin = GetXyTileByZ(lonMin, latMax, z)[1];
int tileColMax = GetXyTileByZ(lonMax, latMin, z)[1];
double tempLonMin = GetLngLatByXyz(tileRowMin, tileColMin, z)[0];
double tempLonMax = GetLngLatByXyz(tileRowMin + 1, tileColMin, z)[0];
double tempLatMin = GetLngLatByXyz(tileRowMin, tileColMin + 1, z)[1];
double tempLatMax = GetLngLatByXyz(tileRowMin, tileColMin, z)[1];
// 获取X轴方向分辨率
double xResolution = (tempLonMax - tempLonMin) / 256;
// 获取Y轴方向分辨率
double yResolution = (tempLatMax - tempLatMin) / 256;
for (int x = tileRowMin; x <= tileRowMax; x++)
{
for (int y = tileColMin; y <= tileColMax; y++)
{
double tileLonMin = tempLonMin + (x - tileRowMin) * xResolution * 256;
double tileLatMax = tempLatMax - (y - tileColMin) * yResolution * 256;
try
{
double xTileMax = tileLonMin + 256 * xResolution;
double yTileMin = tileLatMax - 256 * yResolution;
List<int> positionMin = GetPosition(tileLonMin, tileLatMax, transform);
List<int> positionMax = GetPosition(xTileMax, yTileMin, transform);
Boolean contain = positionMin[0] < width && positionMin[0] >= 0
&& positionMin[1] < height && positionMin[1] >= 0
&& positionMax[0] < width && positionMax[0] >= 0
&& positionMax[1] < height && positionMax[1] >= 0;
Bitmap bitmap = new Bitmap(256, 256);
if (contain)
{
int xDistant = positionMax[0] - positionMin[0] + 1;
int yDistant = positionMax[1] - positionMin[1] + 1;
bitmap = new Bitmap(xDistant, yDistant);
if (bandCount == 1)
{
float[] gs = new float[xDistant * yDistant];
dataset.GetRasterBand(1).ReadRaster(positionMin[0], positionMin[1], xDistant, yDistant, gs, xDistant, yDistant, 0, 0);
for (int i = 0; i < xDistant; i++)
{
for (int j = 0; j < yDistant; j++)
{
float g = gs[xDistant * j + i];
if (g < 0)
{
continue;
}
int gray = (int)(255 * g);
Color color = Color.FromArgb(gray, gray, gray);
bitmap.SetPixel(i, j, color);
}
}
}
else
{
int[] rs = new int[xDistant * yDistant];
int[] gs = new int[xDistant * yDistant];
int[] bs = new int[xDistant * xDistant];
dataset.GetRasterBand(1).ReadRaster(positionMin[0], positionMin[1], xDistant, yDistant, rs, xDistant, yDistant, 0, 0);
dataset.GetRasterBand(2).ReadRaster(positionMin[0], positionMin[1], xDistant, yDistant, gs, xDistant, yDistant, 0, 0);
dataset.GetRasterBand(3).ReadRaster(positionMin[0], positionMin[1], xDistant, yDistant, bs, xDistant, yDistant, 0, 0);
for (int i = 0; i < xDistant; i++)
{
for (int j = 0; j < yDistant; j++)
{
int r = rs[xDistant * j + i];
int g = gs[xDistant * j + i];
int b = bs[xDistant * j + i];
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
{
continue;
}
Color color = Color.FromArgb(r, g, b);
bitmap.SetPixel(i, j, color);
}
}
}
}
else
{
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < 256; j++)
{
double tileLon = tileLonMin + i * xResolution;
double tileLat = tileLatMax - j * yResolution;
List<int> position = GetPosition(tileLon, tileLat, transform);
int xPosition = position[0];
int yPosition = position[1];
if (xPosition < 0 || yPosition < 0 || xPosition >= width || yPosition >= height)
{
continue;
}
Color color;
if (bandCount == 1)
{
float[] values = new float[1];
dataset.GetRasterBand(1).ReadRaster(xPosition, yPosition, 1, 1, values, 1, 1, 0, 0);
if (values[0] < 0)
{
continue;
}
int gray = (int)(255 * values[0]);
color = Color.FromArgb(gray, gray, gray);
}
else
{
int[] rs = new int[1];
int[] gs = new int[1];
int[] bs = new int[1];
dataset.GetRasterBand(1).ReadRaster(xPosition, yPosition, 1, 1, rs, 1, 1, 0, 0 );
dataset.GetRasterBand(2).ReadRaster(xPosition, yPosition, 1, 1, gs, 1, 1, 0, 0);
dataset.GetRasterBand(3).ReadRaster(xPosition, yPosition, 1, 1, bs, 1, 1, 0, 0);
int r = rs[0];
int g = gs[0];
int b = bs[0];
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
{
continue;
}
color = Color.FromArgb(r, g, b);
}
bitmap.SetPixel(i, j, color);
}
}
}
try
{
String layerPath = outputPath + "/" + z + "/" + x;
if (!System.IO.Directory.Exists(layerPath))
{
System.IO.Directory.CreateDirectory(layerPath);
}
String imagePath = layerPath + "/" + y + ".png";
bitmap.Save(imagePath);
}
catch (Exception e)
{
Console.WriteLine("切图异常:" + e.Message);
consoleLabel.Text = "切图异常:" + e.Message;
}
}
catch (Exception e)
{
Console.WriteLine("切图异常:" + e.Message);
consoleLabel.Text = "切图异常:" + e.Message;
}
}
}
}
}
/**
* 获取行列号
*
* @param lng
* @param lat
* @param z
*/
public static List<int> GetXyTileByZ(double lng, double lat, int z)
{
List<int> xy = new List<int>(2);
int x = (int)Math.Floor((lng + 180) / 360 * Math.Pow(2, z));
int y = (int)Math.Floor((1 - Math.Log(Math.Tan(Math.PI*lat/180) + 1 / Math.Cos( Math.PI*lat/180)) / Math.PI) / 2 * (Math.Pow(2, z)));
xy.Add(x);
xy.Add(y);
return xy;
}
/**
* 根据经纬度获取影像像素位置
*/
public static List<int> GetPosition(double lng, double lat, double[] transform)
{
double dTemp = transform[1] * transform[5] - transform[2] * transform[4];
int xPix = (int)((transform[5] * (lng - transform[0]) - transform[2] * (lat - transform[3])) / dTemp);
int yPix = (int)((transform[1] * (lat - transform[3]) - transform[4] * (lng - transform[0])) / dTemp);
List<int> xy = new List<int>(2);
xy.Add(xPix);
xy.Add(yPix);
return xy;
}
/**
* 根据切片序列号获取经纬度坐标
* @return
*/
public static List<Double> GetLngLatByXyz(int x, int y, int z)
{
List<Double> xy = new List<Double>(2);
double n = Math.Pow(2, z);
double lng = x / n * 360.0 - 180.0;
double lat = Math.Atan(Math.Sinh(Math.PI * (1 - 2 * y / n)));
lat = lat * 180.0 / Math.PI;
xy.Add(lng);
xy.Add(lat);
return xy;
}
/**
* 选择文件控件
*/
private static string FileChooserSelect(string title, string filter)
{
string fileName = "";
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = true;
fileDialog.Title = title;
fileDialog.Filter = filter;
if (fileDialog.ShowDialog() == DialogResult.OK)
{
fileName = fileDialog.FileName;
}
return fileName;
}
/**
* 选择文件夹控件
*/
private static string FoloderChooserSelect(string title)
{
string folderPath = "";
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
folderDialog.Description = title;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
folderPath = folderDialog.SelectedPath;
}
return folderPath;
}
}
}