GDAL RasterIO字节对齐问题

由于C#版本的GDAL对无法很好的支持中文路径,导致出现很多乱码,使得程序在读取含有中文路径或者名称包含中文字符的文件时不能正常工作。因此采用C++封装需要的GDAL功能(dll),进行底层数据处理,然后采用C# winform做界面并调用封装后的dll文件。

但是在winform中调用封装后的dll文件进行图像数据读取显示的时候出现变形、断层等问题。于是到网上寻求答案,在这位同仁的http://www.cnblogs.com/Romi/archive/2012/03/29/2424073.html看到,在使用RasterIO进行读取栅格数据时,

有时,需要每行进行字节对齐,即每行的字节数为8的倍数,即位数为32的倍数(32位系统一个内存单元是32位),原文中可能是作者笔误的原因bytePerLine=(sizeX*8=31)/32*4,将8后面的加号打成了等号,改正后应该是:bytePerLine=(sizeX*8+31)/32*4。

下面的代码是封装后调用RasterIO进行图像读取的使用实例:

C++封装的代码:

extern "C" __declspec(dllexport) void  CS_RasterIO(
    GDALRasterBand* band, //需要读取数据的波段
    int     eRWFlag,    //读写标志。GF_Read:读取数据到缓存 GF_Write:将缓存中数据写入数据集的波段
    int     nXOff,   //起始X方向像素位置
    int     nYOff,   //起始Y方向像素位置
    int     nXSize,  //数据的X方向像素大小
    int     nYSize,  //数据的Y方向像素大小     注:以上四个参数制定了要读取数据的位置和大小
    unsigned char* pData,
    int     nBufXSize,  //缓存的X方向像素大小
    int     nBufYSize,  //缓存的Y方向像素大小
    int  nPixelSpace,   //读取每个像素的字节偏移量,即下一个读取的的像素与此时读取的像素的字节距离,默认为0
    int  nLineSpace     //读取每一行像素的字节偏移量,默认为0
    )
{
    GDALRWFlag _eRWFlag;

    if (eRWFlag == 0)
        _eRWFlag = GF_Read;
    else
        _eRWFlag = GF_Write;

    band->RasterIO(_eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, GDT_Byte, nPixelSpace, nLineSpace);
}

C#中调用声明:

        [DllImport(@"F:\Project\GDAL\Debug\GDALRasterCharp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "CS_RasterIO")]
        public static extern void CS_RasterIO(
	                               IntPtr band, //需要读取数据的波段
	                               int eRWFlag,    //读写标志。GF_Read=0:读取数据到缓存 GF_Write=1:将缓存中数据写入数据集的波段
	                               int     nXOff,   //起始X方向像素位置
	                               int     nYOff,   //起始Y方向像素位置
	                               int     nXSize,  //数据的X方向像素大小
	                               int     nYSize,  //数据的Y方向像素大小     注:以上四个参数制定了要读取数据的位置和大小
                                   byte[] pdata,
	                               int     nBufXSize,  //缓存的X方向像素大小
	                               int     nBufYSize,  //缓存的Y方向像素大小
	                               int  datatype,//缓存数据类型
	                               int  nPixelSpace=0,   //读取每个像素的字节偏移量,即下一个读取的的像素与此时读取的像素的字节距离,默认为0
	                               int  nLineSpace=0     //读取每一行像素的字节偏移量,默认为0
	                               );

  具体使用(调用封装的函数和字节对齐):

 public Bitmap GetImage(Configuration config,IntPtr pDataset)
        {
            if (config == null)
            {
                return null;
            }

            int imgWidth = config.GetRasterRectWidth();   //影像宽
            int imgHeight = config.GetRasterRectHeight();  //影像高

            float ImgRatio = imgWidth / (float)imgHeight;  //影像宽高比

            //获取显示控件大小
            int BoxWidth = config.GetViewAreaRectWidth();
            int BoxHeight = config.GetViewAreaRectHeight();

            float BoxRatio = BoxWidth / (float)BoxHeight;  //显示控件宽高比

            //计算实际显示区域大小,防止影像畸变显示
            int BufferWidth = 0, BufferHeight = 0;

            if (config.GetZoomRasterRectWidth() == 0)
            {
                if (BoxRatio >= ImgRatio) //判断印象的长宽比
                {
                    BufferHeight = BoxHeight;

                    BufferWidth = (int)(BoxHeight * ImgRatio);
                }
                else
                {
                    BufferWidth = BoxWidth;
                    BufferHeight = (int)(BoxWidth / ImgRatio);
                }
                config.SetZoomRasterRect(0, 0, BufferWidth, BufferHeight);
                config.SetViewDisplayRect(0, 0, BufferWidth, BufferHeight);
            }
            else
            {
                BufferWidth = config.GetZoomRasterRectWidth();
                BufferHeight = config.GetZoomRasterRectHeight();
            }

            int bitmap_X_s = config.GetViewDisplayRectX();//读取图像的起始坐标X
            int bitmap_Y_s = config.GetViewDisplayRectY(); //起始坐标Y
            int bitmap_w = config.GetViewDisplayRectWidth();  //获取显示区域的长宽
            int bitmap_h = config.GetViewDisplayRectHeight();

            int bytePerLine = (bitmap_w * 8 + 31) / 32 * 4;//字节对齐,非常重要,判断需要显示图像的宽度是否是8的倍数

            bitmap_w = bytePerLine;

            float scaleratio = config.GetZoomRasterRectWidth() * 1.0f / config.GetRasterRectWidth();//计算显示区域和图像实际大小的比例

            int orign_x = (int)(bitmap_X_s / scaleratio); //获取缩放后再原始数据中起始位置
            int orign_y = (int)(bitmap_Y_s / scaleratio);

            int orign_width = (int)(bitmap_w / scaleratio);//获取缩放后在原始数据中实际的宽高
            int orign_height = (int)(bitmap_h / scaleratio);

            if (orign_width > config.GetRasterRectWidth())
            {
                orign_width = config.GetRasterRectWidth();
            }

            if (orign_height > config.GetRasterRectHeight())
            {
                orign_height = config.GetRasterRectHeight();
            }

            //构建位图
            Bitmap bitmap = new Bitmap(bitmap_w, bitmap_h,
                                     System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            if (CS_GetGetRasterBandCount(pDataset) >= 3)     //RGB显示
            {
                byte [] _r = new byte[bitmap_w*bitmap_h];
                IntPtr band1 = CS_GetRasterBand(pDataset,1);
                CS_RasterIO(band1, 0, orign_x, orign_y, orign_width, orign_height, _r,bitmap_w, bitmap_h, 0, 0);  //读取图像到内存

                byte[] _g = new byte[bitmap_w * bitmap_h];
                IntPtr band2 = CS_GetRasterBand(pDataset, 2);
                CS_RasterIO(band2, 0, orign_x, orign_y, orign_width, orign_height, _g, bitmap_w, bitmap_h, 0, 0);  //读取图像到内存

                byte[] _b = new byte[bitmap_w * bitmap_h];
                IntPtr band3 = CS_GetRasterBand(pDataset, 3);
                CS_RasterIO(band3, 0, orign_x, orign_y, orign_width, orign_height, _b,bitmap_w, bitmap_h, 0, 0);  //读取图像到内存;

                //要操作的图片区域 操作方式 已经以多少位的方式操作
                BitmapData bmpData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] byColorInfoSrc = new byte[bmpData.Height * bmpData.Stride];
                for (int i = 0; i < bitmap_w; i++)
                {
                    for (int j = 0; j < bitmap_h; j++)
                    {
                        byColorInfoSrc[(i + j * bitmap_w)*3] =_b[i + j * bitmap_w];
                        byColorInfoSrc[(i + j * bitmap_w) * 3+1] = _g[i + j * bitmap_w];
                        byColorInfoSrc[(i + j * bitmap_w) * 3+2] = _r[i + j * bitmap_w];
                    }
                }

                //操作完之后 数据拷贝回去
                Marshal.Copy(byColorInfoSrc, 0, bmpData.Scan0, byColorInfoSrc.Length);
                bitmap.UnlockBits(bmpData);//解除锁定
            }
            else               //灰度显示
            {
                byte[] _r = new byte[bitmap_w * bitmap_h];
                IntPtr band1 = CS_GetRasterBand(pDataset, 1);
                CS_RasterIO(band1, 0, orign_x, orign_y, orign_width, orign_height, _r, bitmap_w, bitmap_h, 0, 0);  //读取图像到内存

                byte[] byColorInfoSrc = new byte[bitmap_w * bitmap_h * 3];

                //要操作的图片区域 操作方式 已经以多少位的方式操作
                BitmapData bmpData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

                for (int i = 0; i < bitmap_w; i++)
                {
                    for (int j = 0; j < bitmap_h; j++)
                    {
                        byColorInfoSrc[(i + j * bitmap_w) * 3] = _r[i + j * bitmap_w];
                        byColorInfoSrc[(i + j * bitmap_w) * 3 + 1] = _r[i + j * bitmap_w];
                        byColorInfoSrc[(i + j * bitmap_w) * 3 + 2] = _r[i + j * bitmap_w];
                    }
                }

                //操作完之后 数据拷贝回去
                Marshal.Copy(byColorInfoSrc, 0, bmpData.Scan0, byColorInfoSrc.Length);
                bitmap.UnlockBits(bmpData);//解除锁定
            }

            return bitmap;
        }

未字节对齐之前的图像显示:

字节对齐之后的图像显示:

很神奇是不是!

第一次写博客,可能有许多表述不清的地方,希望能够谅解!同时欢迎留言讨论交流!!

时间: 2024-08-27 09:15:39

GDAL RasterIO字节对齐问题的相关文章

stm32中字节对齐问题

ARM下的对齐处理   from DUI0067D_ADS1_2_CompLib 3.13 type  qulifiers 有部分摘自ARM编译器文档对齐部分  对齐的使用:  1.__align(num)     这个用于修改最高级别对象的字节边界.在汇编中使用LDRD或者STRD时     就要用到此命令__align(8)进行修饰限制,来保证数据对象是相应对齐.     这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节     对齐,但是不能让4字节的对象2字节对齐.  

字节对齐

今天我们总结在C++和C语言中让我们头疼的字节对齐问题: 一.首先来看什么是字节对其? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任 何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 二: 那么问题就来了为什么要字节对其?以及字节对其的作用? 各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存

C语言:内存字节对齐详解[转载]

一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐

结构体字节对齐问题(转)

原文出处:http://wenku.baidu.com/view/019e26b765ce0508763213e2.html 初学C,对结构体的使用sizeof计算所占字节数不是很明白,看了此篇文章,终于豁然开朗,转载过来,方便以后温故. #include<stdio.h> struct a {   char no[10];   int p;   long int pp;   unsigned int ppp;   char x;   float y;   double h; }xy; voi

关于C/C++的字节对齐

为什么要字节对齐呢?这要从计算机的结构说起,我们知道,在C/C++中定义的变量有单字节(char),双字节(short),四字节(int,float),八字节(long),但是CPU并不一个字节一个字节来读取处理的(8位单片机除外哈),目前常见的CPU都是32位甚至64位,这意味着CPU一次要读取4个字节或者8个字节,并且不能从任意地址开始读取,只能从地址是4或8的倍数地方开始.所以,要是一个int型数据正好被4或8的倍数分成两块呢,那CPU只能分两次来读,效率当然降低了,而如果浪费点内存,把c

结构体字节对齐

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台只能在特定的地址处访问特定类型的数据: 2)提高存取数据的速度.比如有的平台每次都是从偶地址处读取数据,对于一个int型的

C/C++中避免系统的字节对齐

在定义了一个新的Struct后. 系统会按照一定的规则将新生命的类型变量进行字节对齐,如下结构体: typedef struct Test{ int a; char b[6]; }Test; 该结构体类型可能会被对齐为12个字节. 那么,在内存流和文件流操作中可能会出现这样的用法: fwrite(strPtr,1,sizeof(Test)*len,fp); 事实上,被写入了len*12个字节,因为sizeof(Test)实际上不等于10,而是12. 那么,如下简单地操作可以避免在流操作中出现的一

内存字节对齐

写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢?讲讲字节对齐吧 1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储. 2:结构体作为成员:如果一个结构里有某些结构

字节对齐问题

文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透. 32位机器上各种数据类型的长度如下:char:1(有符号无符号同) short:2(有符号无符号同) int:4(有符号无符号同) long:4(有符号无符号同) float:4 double:8 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要