使用lockbits方法处理图像 from http://blog.sina.com.cn/s/blog_4e3e2ce4010009on.html

使用lockbits方法处理图像
    许多图像处理任务即时是最简单的文件类型转换,例如从32位深度到8位深度的格式转化,直接获得像素阵列要比使用GetPixel和SetPixel等方法的效率高得多。
    你可能会发现DotNet采用托管机制,大多数情况下微软会推荐你使用托管代码,理由是便捷和安全。实际应用中,直接操作内存中的数据块是很少见的,尽管如此,图像处理恰恰是这类为数不多的情况之一,因为使用托管代码的效率低的难以忍受,特别是对巨幅图像来说,在此,我们讨论一下一种新的方法。
     如何使用非托管代码是因语言而异的,在C#中我们可以通过unsafe关键字来调用指针,从而直接操作内存中的位图数据;VB则使用Marshal类中的方法,它会导致一部分的性能损失,因此效率不如前者。
 
锁定比特流
    Bitmap类使用LockBits和UnLockBits方法来将位图的数据矩阵保存在内存中、直接对它进行操作,最后用修改后的数据代替位图中的原始数据。 LockBits返回以各BitmapData的类用已描述数据在已锁定的矩阵中的位置和分布。
    BitmapData类包括以下几个重要的属性:
  • Scan0:数据矩阵在内存中的地址。
  • Stride:数据矩阵中的行宽,以byte为单位。可能会扩展几个Byte,后面会介绍。
  • PixelFormat:像素格式,这对矩阵中字节的定位很重要。
  • Width:位图的宽度。
  • Height:位图的高度。

   具体关系见下图:

C#中使用lockbits方法处理图像(译文)

 
    如上图所示,stride属性表示位图数据矩阵的行宽,以byte为单位。出于效率考虑,矩阵的行宽并非刚好是每行像素数的整数倍,系统往往会将其封装成4的整数倍。举例来说,对于一幅24位深17像素宽的图像,其stride属性为52;每行的数据量为17*3=51,系统将其自动封装一个字节,所以它的stride为52byte(或13*4byte)。对于一幅17像素宽的4位索引图,其stride为12,其中9byte(准确地说是8.5个byte)用来记录数据信息,每行再自动添加3(3.5)个byte保证其为4的整数倍。
    具体数据的分布因其pixel format而异。24位深的图像每隔3个byte包含一组RGB信息;32位深的图像每隔4个byte包含一组RGBA信息。那些每个字节包含多个像素的pixel format,比如4位索引图像或1位索引图像,必须经过仔细处理,从而保证同一字节中的相邻byte不会混淆。
指针的准确定位
  • 32位RGB:假设X、Y为位图中像素的坐标,则其在内存中的地址为scan0+Y*stride+X*4。此时指针指向蓝色,其后分别是绿色、红色,alpha分量。
  • 24位RGB:scan0+Y*stride+X*3。此时指针指向蓝色,其后分别是绿色和红色。
  • 8位索引:scan0+Y*stride+X。当前指针指向图像的调色盘。
  • 4位索引:scan0+Y*stride+(X/2)。当前指针所指的字节包括两个像素,通过高位和低位索引16色调色盘,其中高位表示左边的像素,低位表示右边的像素。
  • 1位索引:scan0+Y*stride+X/8。当前指针所指的字节中的每一位都表示一个像素的索引颜色,调色盘为两色,最左边的像素为8,最右边的像素为0

像素间使用迭代器

    下面这个范例将一幅32位深的图像中所有像素的蓝色分量设为最大(255):

    BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10),   System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);

      int PixelSize=4;

 

      for(int y=0; y<bmd.Height; y++)

      {

        byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);

        for(int x=0; x<bmd.Width; x++)

        {

          row[x*PixelSize]=255;

        }

      }

 

      处理4位索引图,高低位应分开处理,代码如下:

      int offset = (y * bmd.Stride) + (x >> 1);

      byte currentByte = ((byte *)bmd.Scan0)[offset];

      if((x&1) == 1)

      {

        currentByte &= 0xF0;

        currentByte |= (byte)(colorIndex & 0x0F);

      }

      else

      {

        currentByte &= 0x0F;

        currentByte |= (byte)(colorIndex << 4);

      }

      ((byte *)bmd.Scan0)[offset]=currentByte;

 

      处理1位索引的代码:

      byte* p=(byte*)bmd.Scan0.ToPointer();

      int index=y*bmd.Stride+(x>>3);

      byte mask=(byte)(0x80>>(x&0x7));

      if(pixel)

        p[index]|=mask;

      else

        p[index]&=(byte)(mask^0xff);

 

      最后在进行完所有处理后马不要忘记使用Unlockbits命令解锁。

转载于:https://www.cnblogs.com/songtzu/archive/2013/01/03/2843454.html

在易语言中,调用.NET Framework System.Drawing命名空间里的LockBits方法需要使用.NET框架调用(也称为P/Invoke),因为易语言本身并不直接支持所有.NET API。以下是基本的调用流程: 1. 引入所需库:首先,你需要在程序中引入System.Drawing命名空间,虽然易语言不会像C#那样显式声明,但可以在引用时隐式使用。 ```易语言 Use System.Drawing ``` 2. 定义必要的结构和函数:你需要定义BitmapData结构和Get/SetPixel函数来间接调用LockBits和UnlockBits。 ```易语言 Structure BitmapData { Public IntPtr Scan0 Public Int32 Stride Public SizeT Width Public SizeT Height Public PixelFormat Format } Public Function LockBits(Bitmap As Image, Rect As Rectangle, ImageLockMode Mode As ImageLockMode) As BitmapData Return Bitmap.LockBits(Rect, Mode) End Function Public Sub UnlockBits(BitmapData As BitmapData) Bitmap.UnlockBits(BitmapData) End Sub ``` 3. 使用LockBits和UnlockBits:现在你可以像这样使用LockBits方法来获取和修改位图数据,然后调用UnlockBits释放资源。 ```易语言 Dim bitmap As Image = Image.FromFile("path_to_your_image.jpg") Dim lockBits As BitmapData = LockBits(bitmap, New Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite) For x As Integer = 0 To lockBits.Width - 1 Step 1 For y As Integer = 0 To lockBits.Height - 1 Step 1 Dim color As Color = Color.FromArgb(BitConverter.ToInt32(lockBits.Scan0 + (y * lockBits.Stride + x) * 4)) ' 修改像素... color.R = color.R + 50 ' ...然后保存回原始位置 Next Next UnlockBits(lockBits) ``` 注意:这只是一个示例,实际使用时你需要处理可能出现的异常,以及确保在完成后正确地解锁位图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值