C# BitmapData和Marshal.Copy()用法

//此函数用法例子如下:

public static byte[] GetGrayArray(Bitmap srcBmp, Rectangle rect)
{
    //将Bitmap锁定到系统内存中,获得BitmapData
    //这里的第三个参数确定了该图像信息时rgb存储还是Argb存储
    BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    //位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
    IntPtr srcPtr = srcBmpData.Scan0;
    //将Bitmap对象的信息存放到byte数组中
    int scanWidth = srcBmpData.Width * 3;
    int src_bytes = scanWidth * rect.Height;
    //int srcStride = srcBmpData.Stride;
    byte[] srcValues = new byte[src_bytes];
    byte[] grayValues = new byte[rect.Width * rect.Height];
    //RGB[] rgb = new RGB[srcBmp.Width * rows];
    //复制GRB信息到byte数组
    Marshal.Copy(srcPtr, srcValues, 0, src_bytes);
    //LogHelper.OutputArray(srcValues, rect.Width * 3, rect.Height, true);
    //Marshal.Copy(dstPtr, dstValues, 0, dst_bytes);
    //解锁位图
    srcBmp.UnlockBits(srcBmpData);
    //灰度化处理
    int m = 0, j = 0;
    int k = 0;
    byte gray;
    //根据Y = 0.299*R + 0.587*G + 0.114*B,intensity为亮度
    for (int i = 0; i < rect.Height; i++)  //行
    {
        for (j = 0; j < rect.Width; j++)  //列
        {
            //注意位图结构中RGB按BGR的顺序存储
            k = 3 * j;
            gray = (byte)(srcValues[i * scanWidth + k + 2] * 0.299
                 + srcValues[i * scanWidth + k + 1] * 0.587
                 + srcValues[i * scanWidth + k + 0] * 0.114);
            grayValues[m] = gray;  //将灰度值存到byte一维数组中
            m++;
        }
    }
    return grayValues;
}

  

/*
以上方法,主要是实现一个图像指定矩形区域的信息进行处理,
以一维数组形式返回指定矩形区域的灰度值,
此方法会遇到一个很棘手的问题
假设一张图像的大小256*256,想要处理图像的上下部分区域为256*10,左右部分区域10*256的信息,
则创建矩形区域为:
*/
// 上部分区域:
Rectangle rectTop = new Rectangle(0,0,256,10);
// 下部分区域:
Rectangle rectBottom = new Rectangle(0,256-10,256,10);
// 左部分区域:
Rectangle rectLeft = new Rectangle(0,0,10,256);
// 有部分区域:
Rectangle rectRight = new Rectangle(256-10,0,10,256);

/*
此时上下部分没有问题,左右部分则会出现问题,原因很简单
阐述如下:
是BitmapData,Marshal.Copy()函数造成的
C#处理图像时使用BitmapData,这个是将处理的图像锁定到内存中,为了提高效率,将图像锁定要内存
IntPtr srcPtr = srcBmpData.Scan0;这个是指向锁定图像的第一个地址,然后按照顺序读取像素数据
,这时,左右部分区域的宽度只有10,如果这一行读取完之后,应该此时换行读取下一行像素数据,
但是实际上它没有,而是一直按照顺序读取,没有换行,此时问题就出现了,
因为左区域是图像的一部分,整个图像比方如下:
“-”表示左区域,即要处理的部分;“+”表示图像的剩余部分
---+++++++++++++++++++++++
---+++++++++++++++++++++++
---+++++++++++++++++++++++
---+++++++++++++++++++++++
---+++++++++++++++++++++++
---+++++++++++++++++++++++
扫描时第一行读取到第三个“-”号之后,应该换行,但是没有,它继续读取“++++”,一直读取到行尾,
这才换行,问题就是这么产生的,
上图如果没有理解的,接下来我画一个图如下:

思考一下,两种办法如下
[A]首先,想到的最好的办法我要锁定哪一部分区域就要取得相应区域的像素数据,但是目前这个
我没有实现
[B]其次,我用了两外一种方法解决了,就是将源图像的要计算的区域或者要处理的区域图像裁切好,
因为源图像后面是要用的,所以裁切后得到的图像另保存之,传递给方法,然后将上述方法修改为
*/

///这里的srcBmp是裁切后要处理的区域的图像
public static byte[] GetGrayArray(Bitmap srcBmp)
{
    //将Bitmap锁定到系统内存中,获得BitmapData
    //这里的第三个参数确定了该图像信息时rgb存储还是Argb存储
    Rectangle rect = new Rectangle(0,0,srcBmp.Width,srcBmp.Height);  //表示要锁定全图
    BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    //位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
    IntPtr srcPtr = srcBmpData.Scan0;
    //将Bitmap对象的信息存放到byte数组中
    int scanWidth = srcBmpData.Width * 3;
    int src_bytes = scanWidth * rect.Height;
    //int srcStride = srcBmpData.Stride;
    byte[] srcValues = new byte[src_bytes];
    byte[] grayValues = new byte[rect.Width * rect.Height];
    //RGB[] rgb = new RGB[srcBmp.Width * rows];
    //复制GRB信息到byte数组
    Marshal.Copy(srcPtr, srcValues, 0, src_bytes);
    //LogHelper.OutputArray(srcValues, rect.Width * 3, rect.Height, true);
    //Marshal.Copy(dstPtr, dstValues, 0, dst_bytes);
    //解锁位图
    srcBmp.UnlockBits(srcBmpData);
    //灰度化处理
    int m = 0, j = 0;
    int k = 0;
    byte gray;
    //根据Y = 0.299*R + 0.587*G + 0.114*B,intensity为亮度
    for (int i = 0; i < rect.Height; i++)  //行
    {
        for (j = 0; j < rect.Width; j++)  //列
        {
            //注意位图结构中RGB按BGR的顺序存储
            k = 3 * j;
            gray = (byte)(srcValues[i * scanWidth + k + 2] * 0.299
                 + srcValues[i * scanWidth + k + 1] * 0.587
                 + srcValues[i * scanWidth + k + 0] * 0.114);
            grayValues[m] = gray;  //将灰度值存到byte一维数组中
            m++;
        }
    }
    return grayValues;
}

  

//这样也能解决上述问题,求哪位大神赐教方法[A]的实现,谢谢,这个问题先记录到此。

时间: 2024-11-08 08:52:36

C# BitmapData和Marshal.Copy()用法的相关文章

使用Marshal.Copy把Txt行数据转为Struct类型值

添加重要的命名空间: using System.Runtime.InteropServices; 先建立结构相同(char长度相同)的Struct类型用于转换: [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Employee { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public char[] EmployeeId; [MarshalAs(Unmana

c#中Marshal.Copy()方法的使用

c#中Marshal.Copy方法的使用 Marshal.copy()方法用来在托管对象(数组)和非托管对象(IntPtr)之间进行内容的复制 函数有很多重载,如下所示: Copy(array<Byte>[]()[], Int32, IntPtr, Int32) 将一维的托管 8 位无符号整数数组中的数据复制到非托管内存指针. Copy(array<Char>[]()[], Int32, IntPtr, Int32) 将数据从一维的托管字符数组复制到非托管内存指针. Copy(ar

黑马程序员——OC学习总结--copy用法

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- copy的使用 copy 和 mutableCopy 当一个对象 使用  copy 和 mutableCopy 方法可以创建对象的副本 copy 需实现NSCopying协议 创建不可变副本 mutableCopy 需实现NSMutableCopying协议 创建不可变副本 深拷贝: 内容拷贝  源对象和副本指向不同的两个对象,源对象引用计数器不变,副本计数器设置为1 浅拷贝 :指针拷贝  源

shutil.copy()用法

shutil.copyfile(src, dst):复制文件内容(不包含元数据)从src到dst. DST必须是完整的目标文件名; 如果src和dst是同一文件,就会引发错误shutil.Error. dst必须是可写的,否则将引发异常IOError.如果dst已经存在,它会被替换. 特殊文件,例如字符或块设备和管道不能使用此功能,因为copyfile会打开并阅读文件. src和dst的是字符串形式的路径名. shutil.ignore_patterns(*patterns) 为copytree

(转)C#进行图像处理的几种方法(Bitmap,BitmapData,IntPtr)

转自 http://blog.sina.com.cn/s/blog_628821950100wh9w.html C#进行图像处理的几种方法 本文讨论了C#图像处理中Bitmap类.BitmapData类和unsafe代码的使用以及字节对齐问题. Bitmap类 命名空间:System.Drawing 封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成.Bitmap 是用于处理由像素数据定义的图像的对象. 利用C#类进行图像处理,最方便的是使用Bitmap类,使用该类的GetPixel(

验证码图片二值化问题 BitmapData 怎么解决

对不起,这算是一篇求助啦,先上图,防止不清楚,放大了一点,下面是图片,上面是没有二值化的,下面是二值化之后的,我其实不懂什么是二值化啦,就是一定范围变黑,变白 问题: 为什么我的结果上面还是有很多彩色的小点点呢?原来都是没有的-- 谁能帮我看看代码怎么改!谢谢大牛们帮忙!! Bitmap bit1 = new Bitmap(bit); Rectangle rect1 = new Rectangle(0, 0, bit1.Width, bit1.Height); BitmapData bitd =

C#中Image , Bitmap 和 BitmapData

先说Image,Image 就是个图像,不能实例化,提供了位图和源文件操作的函数.本篇文章他就是来打酱油的,这里提供一个Bitmap转成BitmapSource的方法. 1 [DllImport("gdi32")] 2 static extern int DeleteObject(IntPtr o); 3 /// <summary> 4 /// bitmap转换为bitmapsource 以适应wpf的image 5 /// </summary> 6 /// &

C# BitmapData使用

msdn关于BitmapData原文解释地址: http://msdn.microsoft.com/zh-cn/library/5ey6h79d(v=vs.110).aspx 以下是msdn原文给出的例子 private void LockUnlockBitsExample(PaintEventArgs e) { // Create a new bitmap. Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg"); // Lock the bitma

C# BitmapData使用说明

C# BitmapData使用说明msdn关于BitmapData原文解释地址:http://msdn.microsoft.com/zh-cn/library/5ey6h79d(v=vs.110).aspx以下是msdn原文给出的例子 private void LockUnlockBitsExample(PaintEventArgs e) { // Create a new bitmap. Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg"); //