转自 使用lockbits方法处理图像(转)

  许多图像处理任务即时是最简单的文件类型转换,例如从32位深度到8位深度的格式转化,直接获得像素阵列要比使用GetPixel和SetPixel等方法的效率高得多。

        你可能会发现DotNet采用托管机制,大多数情况下微软会推荐你使用托管代码,理由是便捷和安全。实际应用中,直接操作内存中的数据块是很少见的,尽管如此,图像处理恰恰是这类为数不多的情况之一,因为使用托管代码的效率低的难以忍受,特别是对巨幅图像来说,在此,我们讨论一下一种新的方法。
        如何使用非托管代码是因语言而异的,在C#中我们可以通过unsafe关键字来调用指针,从而直接操作内存中的位图数据;VB则使用Marshal类中的方法,它会导致一部分的性能损失,因此效率不如前者。
 
锁定比特流

    Bitmap类使用LockBits和UnLockBits方法来将位图的数据矩阵保存在内存中、直接对它进行操作,最后用修改后的数据代替位图中的原始数据。LockBits返回以各BitmapData的类用已描述数据在已锁定的矩阵中的位置和分布。
   BitmapData类包括以下几个重要的属性:
  • Scan0:数据矩阵在内存中的地址。
  • Stride:数据矩阵中的行宽,以byte为单位。可能会扩展几个Byte,后面会介绍。
  • PixelFormat:像素格式,这对矩阵中字节的定位很重要。
  • Width:位图的宽度。
  • Height:位图的高度。

具体关系见下图:

   如上图所示,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的整数倍。
   具体数据的分布因其pixelformat而异。24位深的图像每隔3个byte包含一组RGB信息;32位深的图像每隔4个byte包含一组RGBA信息。那些每个字节包含多个像素的pixelformat,比如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(, , , ), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);
int PixelSize=;
for(int y=; y<bmd.Height; y++)
{
  byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
  for(int x=; x<bmd.Width; x++)
  {
row[x*PixelSize]=;
  }
}

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

int offset = (y * bmd.Stride) + (x >> );
bytecurrentByte = ((byte *)bmd.Scan0)[offset];
if((x&)== )
{
currentByte&= 0xF0;
currentByte|= (byte)(colorIndex & 0x0F);
}
else
{
currentByte&= 0x0F;
currentByte|= (byte)(colorIndex << );
}
((byte*)bmd.Scan0)[offset]=currentByte;

处理1位索引的代码:

byte* p=(byte*)bmd.Scan0.ToPointer();
intindex=y*bmd.Stride+(x>>);
bytemask=(byte)(0x80>>(x&0x7));
if(pixel)
p[index]|=mask;
else
p[index]&=(byte)(mask^0xff);

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

C#中使用lockbits方法处理图像的更多相关文章

  1. 【转】使用lockbits方法处理图像

    许多图像处理任务即时是最简单的文件类型转换,例如从32位深度到8位深度的格式转化,直接获得像素阵列要比使用GetPixel和SetPixel等方法的效率高得多. 你可能会发现DotNet采用托管机制, ...

  2. C#中的bitmap类和图像像素值获取方法

    一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetP ...

  3. SQL SERVER 2008中使用VARBINARY(MAX)进行图像存取的实现方法

          在数据库应用项目开发中,经常会使用一些二进制的图像数据,存储和读取显示图像数据主要采用的是路径链接法和内存流法.路径链接法是将图像文件保存在固定的路径下,数据库中只存储图像文件的路径和名称 ...

  4. SIFT中的尺度空间和传统图像金字塔

    SIFT中的尺度空间和传统图像金字塔 http://www.zhizhihu.com/html/y2010/2146.html 最近自己混淆了好多概念,一边弄明白的同时,也做了一些记录,分享一下.最近 ...

  5. 我的Android进阶之旅------&gt; Android在TextView中显示图片方法

    面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包括图像的文本信息).并简要说明实现方法. 答案:Android SDK支持例如以下显示富文本信息的方式. 1.使用T ...

  6. Dance GAN 迁移不同视频中人物动作的方法

    该研究提出一种迁移不同视频中人物动作的方法.给出两个视频,一个视频中是研究者想要合成动作的目标人物,另一个是被迁移动作的源人物,研究者通过一种基于像素的端到端流程在人物之间进行动作迁移(motion ...

  7. 【转载】OLE控件在Direct3D中的渲染方法

    原文:OLE控件在Direct3D中的渲染方法 Windows上的图形绘制是基于GDI的, 而Direct3D并不是, 所以, 要在3D窗口中显示一些Windows中的控件会有很多问题 那么, 有什么 ...

  8. 我的Android进阶之旅------> Android在TextView中显示图片方法

    面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包含图像的文本信息),并简要说明实现方法. 答案:Android SDK支持如下显示富文本信息的方式. 1.使用Tex ...

  9. 在pyqt5中展示pyecharts生成的图像

    技术背景 虽然现在很少有人用python去做一些图形化的界面,但是不得不说我们在日常大部分的软件使用中都还是有可视化与交互这样的需求的.因此pyqt5作为一个主流的python的GUI框架地位是非常重 ...

随机推荐

  1. 【剑指offer】之字形打印二叉树,C++实现

    原创文章,转载请注明出处! 本题牛客网地址 博客文章索引地址 博客文章中代码的github地址 1.题目 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打 ...

  2. HDU3394Railway Tarjan连通算法

    There are some locations in a park, and some of them are connected by roads. The park manger needs t ...

  3. jdbcTemplate的一些常用方法

    前言 最近的项目中由于只进行查询,所以使用了jdbcTemplate来直接操作sql进行持久层的操作,初次接触jdbcTemplate,从最开始的什么都不知道到现在基本方法都大致知道什么意思,特此记录 ...

  4. Appium+python (3) 异常处理

    有时候定位时会发现无法定位到具体的元素,右侧元素定位处只告诉你这是一个网页视图: 点击里面的具体元素是无法选中的,船长的做法是回到App里点一下元素,再返回要定位的页面,重新点一下Device Scr ...

  5. Oracle11g的服务

    成功安装Oracle 11g数据库后,你会发现自己电脑运行速度会变慢,配置较低的电脑甚至出现非常卡的状况,通过禁止非必须开启的Oracle服务可以提升电脑的运行速度.那么,具体该怎么做呢.按照win7 ...

  6. 修改 CentOS 中的 repo

    修改 CentOS 中的 repo 原因 由于安装 odoo 10 太慢,因为服务器是国外的. 修改 进入 repo 文件夹 cd /etc/yum.repos.d/ ls 可以看到所有的源.

  7. python编程规范系列--建议01~07

    本系列来自<编写高质量代码 改善python程序的91个建议>的读书笔记整理. 本书主要内容     1)容易被忽视的重要概念和常识,如代码的布局和编写函数的原则等:     2)编写py ...

  8. [语法]C语言中二维数组做输入参数

    C语言中二维数组做输入参数时, 可以同时指定各维长度, 可以只指定第二维的长度, 不可以只指定第一维的长度, 不可以各维长度都不指定. 一句话总结:要指定至少指定第二维,都不指定是不行的. 具体栗子如 ...

  9. 【转】MFC对话框和控件

    原文网址:http://www.cnblogs.com/tiwlin/archive/2013/05/08/3067966.html 对话框和控件 对话框是Windows应用程序中一种常用的资源,其主 ...

  10. HDFS(二)

    HDFS的I/O主要是三个方面: 一致性 HDFS在一致性上面主要是通过校验和(checksum)来实现:从client发起写入的时候会校验一下文件内容,但是发生在pipeline的最后一个节点的时候 ...