【转】使用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的整数倍。
具体数据的分布因其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命令解锁。
原文在这里http://blog.sina.com.cn/s/blog_4e3e2ce4010009on.html
【转】使用lockbits方法处理图像的更多相关文章
- C#中使用lockbits方法处理图像
转自 使用lockbits方法处理图像(转) 许多图像处理任务即时是最简单的文件类型转换,例如从32位深度到8位深度的格式转化,直接获得像素阵列要比使用GetPixel和SetPixel等方法的效率高 ...
- 类库探源——System.Drawing.Bitmap
一.System.Drawing.Bitmap Bitmap 类: 封装GDI+ 位图,此位图由图形图像及其属性的像素数据组成.Bitmap 是用于处理由像素定义的图像的对象 命名空间: System ...
- C#中的bitmap类和图像像素值获取方法
一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetP ...
- c#图像处理入门(-bitmap类和图像像素值获取方法) 转
一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetP ...
- c#图像处理入门(-bitmap类和图像像素值获取方法)
c#图像处理入门 -bitmap类和图像像素值获取方法 一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义 ...
- OpenCV ——遍历图像方法
转自http://blog.csdn.net/daoqinglin/article/details/23628125 ; y < testImage->height; y++) { uch ...
- [Swift通天遁地]五、高级扩展-(8)ImageView(图像视图)的各种扩展方法
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- C#数字图像处理的3种方法
本文主要通过彩色图象灰度化来介绍C#处理数字图像的3种方法,Bitmap类.BitmapData类和Graphics类是C#处理图像的的3个重要的类. Bitmap只要用于处理由像素数据定义的图像的对 ...
- [C#编程参考]把图像转换为数组的两种实现
当一个程序和一个图片放在一起,无非有两种操作: 第一种,就是传输这个图片,在传输图片之前要首先把这个图片变成byte类型的数组.所以这时候我们用到的是图片的存储的数据,也就是图片属性中的大小.我们并不 ...
随机推荐
- .net自定义控件Control、WebControl、CompositeControl
一.呈现方法 1.Control主要有以下4个方法用于呈现 //该方法为入口方法 public virtual void RenderControl (HtmlTextWriter writer) { ...
- C++中的#和##运算符
#和##运算符 #:构串操作符 构串操作符#只能修饰带参数的宏的形参,它将实参的字符序列(而不是实参代表的值)转换成字符串常量 #define STRING(x) #x#x#x #define TEX ...
- Android:使用 DownloadManager 进行版本更新
app 以前的版本更新使用的自己写的代码从服务器下载,结果出现了下载完成以后,提示解析包错误的问题,但是呢,找到该 apk 点击安装是可以安装成功的,估计就是最后几秒安装包没有下载完成然后点击了安装出 ...
- 深入浅出HTTPS基本原理
基础知识准备:在了解HTTPS的基本原理之前,需要先了解如下的基本知识. 一.什么是HTTPS,TLS,SSL HTTPS,也称作HTTP over TLS.TLS的前身是SSL,TLS 1.0通常被 ...
- Beef-xss
Beef xss beef安装目录:/usr/share/beef-xss UI URL: http://IP:3000/ui/panel Hook: <script src="htt ...
- Vue.js使用-组件示例(实现数据的CRUD)
1.业务场景 用户(姓名,年龄,性别)的增删改查 2.数据格式 定义字段,name:字段名称,iskey:是否主键(添加,修改数据标志),dataSource:可选列表(下拉框选项) columns: ...
- Asp.Net IIS7.5伪静态设置
注意:先要将应用池设置为集成模式,修改OK后,再改成经典模式.否则,什么托管程序出不来. 1.新建网站,这里不做介绍,很简单.并把网站设置为集成模式 2.添加通配符脚本映射 打开之后显示如下界面,在右 ...
- iframe自适应当前页面高度
<style type="text/css"> *{margin:0;padding:0;list-style-type:none;} </style> & ...
- Git GUI中文乱码问题解决方法
使用Git GUI的查看代码的时候,会出现中文乱码: 在乱码的区域点击鼠标右键,选择Encoding,然后选择Unicode(UTF-8),乱码问题解决:
- 说说Python程序的执行过程
1. Python是一门解释型语言? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在.如果是解释型语言, ...