c# 中1bpp,8bpp,24bpp等不同图像的格式,及如何遍历图片所有像素
(2012-09-17 21:22:45)
标签:
杂谈 |
分类: .Net |
本文转自:
http://hi.baidu.com/jackeyrain/blog/item/9f1803ea6b6660dbd439c93b
本文讨论了C#图像处理中Bitmap类、BitmapData类和unsafe代码的使用以及字节对齐问题。
1)Bitmap类
命名空间:System.Drawing 封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成。Bitmap
是用于处理由像素数据定义的图像的对象。
利用C#类进行图像处理,最方便的是使用Bitmap类,使用该类的GetPixel()与SetPixel()来访问图像的每个像素点。下面是MSDN中的示例代码:
public void GetPixel_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap("Grapes.jpg");
// Get the color of a pixel within myBitmap.
Color pixelColor = myBitmap.GetPixel(50, 50);
// Fill a rectangle with pixelColor.
SolidBrush pixelBrush = new SolidBrush(pixelColor);
e.Graphics.FillRectangle(pixelBrush, 0, 0, 100, 100);
}
2)BitmapData类
命名空间:System.Drawing.Imaging
指定位图图像的属性。BitmapData 类由 Bitmap 类的 LockBits 和
UnlockBits
方法使用。不可继承。
好在我们还有BitmapData类,通过BitmapData BitmapData LockBits ( )可将 Bitmap 锁定到系统内存中。该类的公共属性有:
-
Width
获取或设置 Bitmap 对象的像素宽度。这也可以看作是一个扫描行中的像素数。 -
Height
获取或设置 Bitmap 对象的像素高度。有时也称作扫描行数。 - PixelFormat 获取或设置返回此 BitmapData 对象的 Bitmap 对象中像素信息的格式。
-
Scan0
获取或设置位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行。 -
Stride
获取或设置 Bitmap 对象的跨距宽度(也称为扫描宽度)。
private void LockUnlockBitsExample(PaintEventArgs e)
{// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg"); // Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap.
// This code is specific to a bitmap with 24 bits per pixels.
int bytes = bmp.Width * bmp.Height * 3;
byte[] rgbValues = new byte[bytes]; // Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); // Set every red value to 255.
for (int counter = 0; counter < rgbValues.Length; counter+=3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); // Unlock the bits.
bmp.UnlockBits(bmpData); } // Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
3)unsafe代码
而在实际中上面的做法仍然不能满足我们的要求,图像处理是一种运算量比较大的操作,不同于我们写的一般的应用程序。我们需要的是一种性能可以同C++程序相媲美的图像处理程序。C++是怎么提高效率的呢,答曰:指针。幸运的是.Net也允许我们使用指针,只能在非安全代码块中使用指针。
何谓非安全代码?
- 方法、类型和可被定义为不安全的代码块。
- 在某些情况下,通过移除数组界限检查,不安全代码可提高应用程序的性能。
- 当调用需要指针的本机函数时,需要使用不安全代码。
- 使用不安全代码将引起安全风险和稳定性风险。
- 在 C# 中,为了编译不安全代码,必须用 /unsafe 编译应用程序。
//创建图像
Bitmap image = new Bitmap( "c:\\images\\image.gif" );
//获取图像的BitmapData对像
BitmapData data = image.LockBits( new Rectangle( 0 , 0 , image.Width , image.Height ) , ImageLockMode.ReadWrite , PixelFormat.Format24bppRgb );
//循环处理
unsafe
{
byte* ptr = ( byte* )( data.Scan0 );
for( int i = 0 ; i < data.Height ; i ++ )
{
for( int j = 0 ; j < data.Width ; j ++ )
{
// write the logic implementation here
ptr += 3;
}
ptr += data.Stride - data.Width * 3;
}
}
字节对齐问题
|-------Stride-----------|
|-------Width---------| |
Scan0:
BGR BGR BGR BGR BGR BGR XX
BGR BGR BGR BGR BGR BGR XX
BGR BGR BGR BGR BGR BGR XX
.
.
.
备注:
Format24bppRgb(彩色图像):每个像素占24个字节,包含三个颜色通道信息,B、G、R每个占8个字节;*ptr每一位存储一个像素的一个颜色通道信息
eg:*ptr = 3
,
PixelValue(0)= RGB(3,3,3)
Format8bppRgb(灰度图像):每个像素占8个字节,包含一个灰度信息,存储0-255之间的一个灰度值;*ptr每一位存储1个像素的灰度信息
eg:*ptr = 3
PixelValue(0)= 3
Format1bppRgb(二值图像):每个像素占1个字节,存储0或者1;*ptr每一位存储8个像素的信息
eg:*ptr = 3(二进制:00000011)
PixelValue(0)= 0,PixelValue(1)= 0,PixelValue(2)= 0,PixelValue(3)= 0,PixelValue(4)= 0,
PixelValue(5)= 0,PixelValue(6)= 0,PixelValue(7)= 1,PixelValue(8)= 1

加载中…