GDAL包提供了诸多处理栅格影像的方法,本文就将详细介绍基于GDAL包和C#语言如何实现栅格影像的读取和显示,这种实现是在VS2015的开发环境中完成。
要想实现栅格影像数据的读取和显示,首先得弄清楚栅格影像的数据结构,栅格影像主要分为两类,一类是灰度影像,一类是彩色影像。但是这两类影像有一个共同的特点,他们都是由像元构成,每一个像元由像元值表示该像元的属性,不过灰度影像的像元属性有一个值(0-255)确定,而彩色影像一般是由三个值确定,分别对听R,G,B三类原色的值(0-255),就是说只要我们知道了每一个像元对应的属性值,那么就可以实现该影像的显示或者其他操作。
由于GDAL是一个包,因此在正式开始之前需要配置环境,具体配置方法我已经发布过相应的博客,大家如果在这里有问题的话可以参考下面的连接
GDAL配置
到这里就假装认为大家配置环境都木有问题了啊,咱们就开始码代码了,首先就是引用包的基本操作,得获取包的相应许可,也就是下面这句话啦,这句话是很简单,但是这是添加的引用的情况下,大家配置好环境后一定要添加相应的引用,接下来本文会附上本文代码所用到的所有引用,供大家参考。
Gdal.AllRegister();
//引用
using System;
using System.Drawing;
using System.Windows.Forms;
using OSGeo.GDAL;
好了不说废话了,一句句解释太累了,直接上代码吧,下面是第一部分,环境的初始化,包括栅格文件的选择和初始环境的配置,这种配置主要是针对pictrueBox控件,该控件将用来显示栅格影像。代码中有两个函数,分别是initial()和ReadImage(),initial()大家不用在意,这个没么之用,只是我个人觉得窗体打开后pictrueBox对应的区域一片空白有点不爽,所以写了一个函数把pictrueBox对应的image也初始化,代码我后面也会粘上去;而ReadImage()就重要了,包括了读取栅格影像的具体代码,主要包括三个部分,分别是读取影像的相关信息、对图像进行缩放(为了防止图像变形,需要按照影像的宽高比对缓冲区的宽高比进行调整)、读取影像数据,其中读取影像数据包括两个部分,即灰度影像的像元值读取和彩色影像的像元值读取。
initial();
//文件路径
string fileName = "";
OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = "所有文件|*.*|Tiff文件|*.tif|Erdas img文件|*.img|Bmp文件|*.bmp|jpeg文件|*.jpg";
if (openFile.ShowDialog() == DialogResult.OK)
{
fileName = openFile.FileName;
}
else
{
MessageBox.Show("影像路径不能为空","注意",
MessageBoxButtons.OKCancel,MessageBoxIcon.Information);
return;
}
textBox1.Text = fileName;
//创建Dataset
Gdal.AllRegister();
Dataset ds = null;
try
{
ds = Gdal.Open(fileName, Access.GA_ReadOnly);
}
catch (Exception ex)
{
MessageBox.Show("打开影像失败"+ex.Message);
}
if (ds == null)
{
MessageBox.Show("影像无效");
return;
}
//创建包络矩形
Rectangle rec = new Rectangle();
rec.Width = this.pictureBox1.Width;
rec.Height = this.pictureBox1.Height;
//调用ReadImage方法获取图像并显示
Bitmap map = ReadImage(ds, rec);
pictureBox1.Image = map;
下面是 ReadImage()函数对应的代码。
#region 获取图像信息
int imageWidth = ds.RasterXSize;
int imageHeight = ds.RasterYSize;
float imgRatio = imageWidth / (float)imageHeight;
//图像颜色模式
int model;
model = ds.RasterCount;
double[] dd = new double[4];
ds.GetGeoTransform(dd);
string prj = ds.GetProjection();
string str = string.Format("波段数目:{0}\n行数:{1};列数:{2}\n坐标参考:{3},{4},{5},{6}\n", ds.RasterCount, ds.RasterXSize, ds.RasterYSize, dd[0], dd[1], dd[2], dd[3]);
str += prj + "\n";
for (int i = 1; i <= ds.RasterCount; ++i)
{
OSGeo.GDAL.Band band = ds.GetRasterBand(i);
str += "波段" + i + ":" + band.DataType.ToString();
}
infoText.Text = str;
#endregion
#region 对图像进行缩放
//依据矩形尺寸设置buffer的尺寸
int boxWidth = rec.Width;
int boxHeight = rec.Height;
float boxRatio = boxWidth / (float)boxHeight;
int bufferHeight, bufferWidth;
if (imgRatio >= boxRatio)
{
bufferWidth = boxWidth;
bufferHeight = (int)(boxWidth / imgRatio);
}
else
{
bufferHeight = boxHeight;
bufferWidth = (int)(boxHeight * imgRatio);
}
#endregion
Bitmap map = new Bitmap(bufferWidth, bufferHeight,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
#region 读取图像波段数据
//如果图像颜色模式为灰度
if (model == 1)
{
Band band1 = ds.GetRasterBand(1);
double[] maxmin1 = { 0, 0 };
band1.ComputeRasterMinMax(maxmin1, 0);
int[] info = new int[bufferHeight * bufferWidth];
band1.ReadRaster(0, 0, imageWidth,
imageHeight, info, bufferWidth, bufferHeight, 0, 0);
int i, j;
for (i = 0; i < bufferHeight; i++)
for (j = 0; j < bufferWidth; j++)
{
int val = info[i * bufferWidth + j];
val = (int)(((val - maxmin1[0]) / (maxmin1[1] - maxmin1[0])) * 255);
Color newColor = Color.FromArgb(val, val, val);
map.SetPixel(j, i, newColor);
}
}
//如果图像颜色模式为彩色
if (model != 1)
{
Band band1 = ds.GetRasterBand(1);
double[] maxmin1 = { 0, 0 };
band1.ComputeRasterMinMax(maxmin1, 0);
int[] r = new int[bufferHeight * bufferWidth];
band1.ReadRaster(0, 0, imageWidth,
imageHeight, r, bufferWidth, bufferHeight, 0, 0);
Band band2 = ds.GetRasterBand(2);
double[] maxmin2 = { 0, 0 };
band2.ComputeRasterMinMax(maxmin2, 0);
int[] g = new int[bufferHeight * bufferWidth];
band2.ReadRaster(0, 0, imageWidth,
imageHeight, g, bufferWidth, bufferHeight, 0, 0);
Band band3 = ds.GetRasterBand(3);
double[] maxmin3 = { 0, 0 };
band3.ComputeRasterMinMax(maxmin3, 0);
int[] b = new int[bufferHeight * bufferWidth];
band3.ReadRaster(0, 0, imageWidth,
imageHeight, b, bufferWidth, bufferHeight, 0, 0);
int i, j;
for (i = 0; i < bufferHeight; i++)
for (j = 0; j < bufferWidth; j++)
{
int rval = r[i * bufferWidth + j];
rval = (int)(((rval - maxmin1[0]) / (maxmin1[1] - maxmin1[0])) * 255);
int gval = g[i * bufferWidth + j];
gval = (int)(((gval - maxmin2[0]) / (maxmin2[1] - maxmin2[0])) * 255);
int bval = b[i * bufferWidth + j];
bval = (int)(((bval - maxmin3[0]) / (maxmin3[1] - maxmin3[0])) * 255);
Color newColor = Color.FromArgb(rval, gval, bval);
map.SetPixel(j, i, newColor);
}
}
return map;
#endregion
以上就是所有的关键代码了,哦,对了,还有一个initial()方法对应的代码块,代码如下。
int xSize = this.pictureBox1.Width;
int ySize = this.pictureBox1.Height;
Bitmap map = new Bitmap(xSize, ySize, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
for (int i = 0; i < xSize; i++)
for (int j = 0; j < ySize; j++)
{
Random rd = new Random((int)DateTime.Now.Ticks);
Color newColor = Color.FromArgb(rd.Next(0,255), rd.Next(0, 255), rd.Next(0, 255));
map.SetPixel(i, j, newColor);
}
pictureBox1.Image = map;
下面附几张程序的运行效果图吧。
本文对应程序的所有文档已经全部上传到csdn网站上,如果大家有需求的话请自行下载(程序亲测有用),不过还是希望大家自己完成,个人觉得我这个小程序不值5个积分,但是我也么的办法,链接见下。
基于GDAL和C#语言读取栅格影像