You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用C#读取多波段(多光谱)图像的非RGB波段?

嘿,我完全懂你现在的处境——用System.Drawing.Bitmap读常规RGB图像顺手得很,但碰到带红外、近红外这些额外波段的卫星/多光谱图像就卡壳了对吧?别慌,我给你整理几个实际项目里验证过的靠谱方案,都是能直接上手的:

用C#读取多波段(多光谱)图像的实用方案

为什么System.Drawing.Bitmap搞不定?

首先得掰扯清楚:System.Drawing.Bitmap是为常规RGB/ARGB图像设计的,它只支持固定的像素格式,没法直接解析包含红外、近红外等额外波段的图像(比如TIFF、ENVI格式的卫星图)。这类图像的波段数据是独立存储的,必须用专门的地理空间图像处理库来读取。

方案1:使用GDAL(最主流的选择

GDAL是开源的地理空间数据处理神器,对多波段图像的支持堪称全能,几乎能啃下所有常见的卫星图像格式(TIFF、GeoTIFF、ENVI、JP2等等)。

上手步骤:

  1. 先通过NuGet安装对应版本的GDAL绑定包,比如.NET Core用GDAL.NetCore,.NET Framework找适配的GDAL包。
  2. 初始化GDAL驱动:
Gdal.AllRegister(); // 注册所有支持的图像格式驱动
  1. 打开图像并读取目标波段:
// 打开多波段图像文件
Dataset dataset = Gdal.Open(@"C:\your_satellite_image.tif", Access.GA_ReadOnly);
if (dataset == null)
{
    Console.WriteLine("无法打开目标图像,请检查路径或格式");
    return;
}

// 获取图像总波段数
int totalBands = dataset.RasterCount;
Console.WriteLine($"当前图像包含 {totalBands} 个波段");

// 读取第4个波段(注意GDAL的波段索引从1开始,通常第4波段是红外)
Band targetBand = dataset.GetRasterBand(4);
int imgWidth = targetBand.XSize;
int imgHeight = targetBand.YSize;

// 存储波段像素数据的数组(卫星图像常用浮点型/16位整数,这里用float示例)
float[] bandPixelData = new float[imgWidth * imgHeight];
targetBand.ReadRaster(0, 0, imgWidth, imgHeight, bandPixelData, imgWidth, imgHeight, 0, 0);

// 访问(x,y)位置的像素值:bandPixelData[y * imgWidth + x]
  1. 用完记得释放资源:
targetBand.Dispose();
dataset.Dispose();

方案2:使用ImageSharp(轻量.NET跨平台选择

如果你用的是.NET Core/.NET 5+,ImageSharp是个轻量灵活的选择,它支持扩展格式,也能处理多波段TIFF。

上手步骤:

  1. NuGet安装SixLabors.ImageSharpSixLabors.ImageSharp.Formats.Tiff
  2. 读取并提取波段数据:
using (Image image = Image.Load(@"C:\your_multiband_image.tif"))
{
    int bandCount = image.PixelType.ComponentCount;
    Console.WriteLine($"图像共有 {bandCount} 个波段");

    // 遍历每个波段(这里以16位灰度波段为例,可根据图像格式调整)
    for (int bandIndex = 0; bandIndex < bandCount; bandIndex++)
    {
        using (Image<Gray16> singleBandImage = new Image<Gray16>(image.Width, image.Height))
        {
            image.ProcessPixelRows(sourceAccessor =>
            {
                singleBandImage.ProcessPixelRows(targetAccessor =>
                {
                    for (int y = 0; y < image.Height; y++)
                    {
                        Span<Color> sourceRow = sourceAccessor.GetRowSpan(y);
                        Span<Gray16> targetRow = targetAccessor.GetRowSpan(y);
                        for (int x = 0; x < image.Width; x++)
                        {
                            // 提取当前波段的像素值
                            targetRow[x] = new Gray16(sourceRow[x].GetComponent(bandIndex));
                        }
                    }
                });
            });

            // 可将单波段图像保存或进一步处理
            // singleBandImage.Save($"extracted_band_{bandIndex+1}.tif");
        }
    }
}

方案3:使用FreeImage(老牌图像处理库

FreeImage是个老牌开源库,支持多种图像格式,包括多波段TIFF。你可以通过NuGet安装FreeImage.NET快速上手。

简单示例:

// 初始化FreeImage
FreeImage.Initialize();

// 打开多波段TIFF图像
FIBITMAP dib = FreeImage.Load(FREE_IMAGE_FORMAT.FIF_TIFF, @"C:\your_multiband_image.tif", FREE_IMAGE_LOAD_FLAGS.DEFAULT);
if (dib == IntPtr.Zero)
{
    Console.WriteLine("打开图像失败,请检查文件");
    return;
}

// 获取波段数量(FreeImage中多波段TIFF按"页"存储)
int bandCount = FreeImage.GetPageCount(dib);
Console.WriteLine($"共有 {bandCount} 个波段");

// 读取第3个波段(索引从0开始)
FIBITMAP bandBitmap = FreeImage.LockPage(dib, 2);
int width = FreeImage.GetWidth(bandBitmap);
int height = FreeImage.GetHeight(bandBitmap);

// 提取像素数据(假设是16位波段)
byte[] pixelBuffer = new byte[width * height * 2];
FreeImage.ConvertToRawBits(pixelBuffer, bandBitmap, width * 2, 16, 0, 1, 2, false);

// 处理完成后释放资源
FreeImage.UnlockPage(dib, bandBitmap, false);
FreeImage.Unload(dib);
FreeImage.Deinitialize();

小提醒

  • 不同多光谱图像的存储方式有差异:GeoTIFF通常把所有波段存在同一个文件,ENVI则是分.hdr头文件和.dat数据文件,GDAL都能完美适配这些情况。
  • 卫星图像的像素值一般不是0-255的RGB范围,多是16位整数或浮点型,读取时要选对应的数据类型,别用byte数组存储,否则会丢失精度。

内容的提问来源于stack exchange,提问作者Tolga Evcimen

火山引擎 最新活动