【转】使用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类型的数组.所以这时候我们用到的是图片的存储的数据,也就是图片属性中的大小.我们并不 ...
随机推荐
- 为什么推荐你用 Kotlin语言?
谷歌大牛说:为什么 Kotlin 比你们用的那些垃圾语言都好 原标题:谷歌大牛说:为什么 Kotlin 比你们用的那些垃圾语言都好 编译:伯乐在线/黄小非 [伯乐在线/程序员的那些事 导读]:5月18 ...
- 启动supervisord 生成openvpn用于android的证书
service supervisord start netstat -anp | grep 你的端口号 生成证书: 进入到openvpn的证书生成文件夹,通常在/etc/openvpn/easy-r ...
- Caffe搭建:常见问题解决办法和ubuntu使用中遇到问题(持续更新)
严正声明: 在linux下面使用命令行操作时,一定要懂得命令行的意思,然后再执行,要不然在不知道接下来会发生什么的情况下输入一通命令,linux很有可能崩掉. 因为在linux下面,使用sudo以及r ...
- linux杀掉tomcat应用进程。停止tomcat应用
ps -ef |grep tomcat |grep -v grep |awk '{print $2}' |xrags kill -9
- Atitti 固化数据库表结构方案
Atitti 固化数据库表结构方案 1. 固化数据库表结的重要意义1 2. 如何固化表结构1 2.1. 向上抽象一层,以动词有目标,以名词为存储对象.1 2.2. 数据类型datatype字段:这个用 ...
- Vue 常见问题汇总
Q:我给组件内的原生控件添加事件,怎么不生效了!!! <!--比如用了第三方框架,或者一些封装的内置组件; 然后想绑定事件--> <!--// 错误例子1--> <el- ...
- 行为类模式(五):中介者(Mediator)
定义 定义一个中介对象来封装系列对象之间的交互.中介者使各个对象不需要显示地相互引用,从而使其耦合性松散,而且可以独立地改变他们之间的交互. 试想一下,如果多个类之间相互都有引用,那么当其中一个类修改 ...
- HTTPS演变小图
HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全.为了保证这些隐私数据能加密传输,网景公司设计了SSL(Se ...
- matlab: Attempt to execute SCRIPT *** as a function 错误
编写matlab程序时,出现了“Attempt to execute SCRIPT mean as a function”,其实这是“Attempt to execute SCRIPT *** as ...
- iOS开发-Tom猫
// // ViewController.m // 20-tom猫 // // Created by hongqiangli on 2017/8/1. // Copyright © 李洪强. ...