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");

    // 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.
    int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
     byte[] rgbValues = new byte[bytes];

    // Copy the RGB values into the array.
    System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

    // Set every third value to 255. A 24bpp bitmap will look red.
    for (int counter = 2; 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);

}

原文给出的例子已经可以理解出部分意思了,按照土鳖国王本人实验然后理解如下,如有误还请大神斧正
C#专门为图像处理提供了BitmapData,这个是真正的对位图的处理,首先将位图锁定到内存中,然后对位图的每一个像素进行处理,效率还是非常高的,下面先给出偶自己转化图像灰度值的例子,以函数的形式给出
以便需要的朋友直接可以使用,可以说是任何操作都是依次为基础的,如果觉得注释太多,可将注释直接删除,然后将代码烤白可直接使用,指针法效率更高,这里只给出内存法先理解,然后便可大展身手了,哈哈

/// 获取灰度值返回byte[]
/// <summary>
/// 获取灰度值返回byte[]
/// </summary>
/// <param name="srcBmp">源图像</param>
/// <param name="rect">要锁定的图像区域</param>
/// <returns>返回byte[]</returns>
public static byte[] GetGrayArray(Bitmap srcBmp, Rectangle rect)
{
    //将Bitmap锁定到系统内存中
    //rect是指源图像中需要锁定那一块矩形区域进行处理
    //ImageLockMode.ReadWrite是指对图像出操作的权限,枚举有只读,只写,用户输入缓冲区,还是读写
    //PixelFormat.Format24bppRgb
    //参数确定了该图像信息时rgb存储还是Argb存储,如果是Format24ppRgb则处理的图像像素就是BGR方式存储,我们这里没有特别指出,均是Format24bppRgb方式存储处理
    BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    //位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
    IntPtr srcPtr = srcBmpData.Scan0;
    //将Bitmap对象的信息存放到byte数组中
    //假设本图像的宽度和高度为5*3
    /*
    1  2  3  4  5  6  7  8  9  10  11 12 13 14 15  //这里存储为一维数组,所以是一行,
    宽度为5,高度为3,则像素总数为15,这里要清楚,每一个像素是rgb三个值,故而,一维数组中
    存储为
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
    15...44
    这里分行是为了便于理解,一维数组存储类似是一行,但是我们的图像的宽度是5也就是我们图像的第一行是0123...到14,下一行是15...29,下一行是30...44,高度为3,所以就是3行
    012 345 678 91011 121314
    bgr bgr bgr  bgr   bgr
    151617  181920  ...
    bgr      bgr    ...
    这样存储
    */
    //所以才有了这里的*3就是指一个像素是三个分量值
    int scanWidth = rect.Width * 3;
    //而每行的实际的字节数将变成大于等于它的那个离它最近的4的整倍数,此时的实际字节数就是Stride,如果上面的第三个参数Format24ppRgb如果设置为Format32ppRgb,这个时候存储的时候就是4位存储一个像素,如果是Format32bppArgb同样也是4为存储一个像素,这4位除了bgr三个分量之外还有透明度A的值
    //至于为什么是24,32,这是因为计算机存储数据为8bit存储1个字节,
    //bgr3个就是3*8=24,4个就是4*8=32了,为什么是16,8位等,索引图等原理是一样的
    //int srcStride = srcBmpData.Stride;
    int src_bytes = scanWidth * rect.Height;  //这里就是计算出了需要存储的像素所占用的空间大小
    byte[] srcValues = new byte[src_bytes];  //定义源图像的元信息
    byte[] grayValues = new byte[rect.Width * rect.Height];  //定义转化为灰度后需要存储的数组
    //复制GRB信息到byte数组,将从srcPtr开始的第一个扫描行开始扫描信息,然后读取到srcValues数组中
    Marshal.Copy(srcPtr, srcValues, 0, src_bytes);
    //解锁位图
    srcBmp.UnlockBits(srcBmpData);  //读取完元信息,这里就不用了,一定要记得解锁,否则会报错
    //下面就是你想怎么处理都成了,,灰度化,转换空间模式,除噪声,腐蚀,膨胀,反色,二值化等等均可
    //灰度化处理
    int m = 0, j = 0;
    int k = 0;
    byte gray;
    //根据重要性及其它指标,将三个分量以不同的权值进行加权平均。由于人眼对绿色的敏感最高,对蓝色敏感最低,因此,按下式对RGB三分量进行加权平均能得到较合理的灰度图像
    //根据Y = 0.299*R + 0.587*G + 0.114*B  //加权平均法
    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;  //将灰度值存到double的数组中
            m++;
        }
    }
    return grayValues;
}

//接下来就很简单了,下面在给出获得到灰度值存储为2位数组的方法,按照习惯二维处理起来比较好理解
/// 获取灰度值存到二维double数组中,这个是将rgb转化为灰度值
/// <summary>
/// 获取灰度值存到二维double数组中,这个是将rgb转化为灰度值
/// </summary>
/// <param name="srcBmp"></param>
/// <returns>2Dimension</returns>
public static byte[,] GetGrayArray2D(Bitmap srcBmp,Rectangle rect)
{
    int width = rect.Width;
    int height = rect.Height;

    BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

    IntPtr srcPtr = srcBmpData.Scan0;

    int scanWidth = width * 3;
    int src_bytes = scanWidth * height;
    //int srcStride = srcBmpData.Stride;
    byte[] srcRGBValues = new byte[src_bytes];
    byte[,] grayValues = new byte[height, width];
    //RGB[] rgb = new RGB[srcBmp.Width * rows];
    //复制GRB信息到byte数组
    Marshal.Copy(srcPtr, srcRGBValues, 0, src_bytes);
    //解锁位图
    srcBmp.UnlockBits(srcBmpData);
    //灰度化处理
    int m = 0, i = 0, j = 0;  //m表示行,j表示列
    int k = 0;
    byte gray;

    for (i = 0; i < height; i++)  //只获取图片的rows行像素值
    {
        for (j = 0; j < width; j++)
        {
            //只处理每行中图像像素数据,舍弃未用空间
            //注意位图结构中RGB按BGR的顺序存储
            k = 3 * j;
            gray = (byte)(srcRGBValues[i * scanWidth + k + 2] * 0.299
                 + srcRGBValues[i * scanWidth + k + 1] * 0.587
                 + srcRGBValues[i * scanWidth + k + 0] * 0.114);

            grayValues[m, j] = gray;  //将灰度值存到double的数组中
        }
        m++;
    }

    return grayValues;
}

//此方法是直接得到灰度图
/// 获取灰度图像,将制定图片转化为灰度图
/// <summary>
/// 获取灰度图像,将制定图片转化为灰度图
/// </summary>
/// <param name="srcBmp"></param>
/// <returns></returns>
public static Bitmap GetGrayImage(Bitmap srcBmp)
{
    Rectangle rect = new Rectangle(0, 0, srcBmp.Width, srcBmp.Height);
    BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    IntPtr srcPtr = srcBmpData.Scan0;
    int scanWidth = srcBmpData.Width * 3;
    int src_bytes = scanWidth * srcBmp.Height;
    byte[] srcRGBValues = new byte[src_bytes];
    Marshal.Copy(srcPtr, srcRGBValues, 0, src_bytes);
    //灰度化处理
    int k = 0;
    for (int i = 0; i < srcBmp.Height; i++)
    {
        for (int j = 0; j < srcBmp.Width; j++)
        {
            k = j * 3;
            //0.299*R + 0.587*G + 0.144*B = 亮度或灰度
            //只处理每行中图像像素数据,舍弃未用空间
            //注意位图结构中RGB按BGR的顺序存储
            byte intensity = (byte)(srcRGBValues[i * scanWidth + k + 2] * 0.299
                 + srcRGBValues[i * scanWidth + k + 1] * 0.587
                 + srcRGBValues[i * scanWidth + k + 0] * 0.114);
            srcRGBValues[i * scanWidth + k + 0] = intensity;
            srcRGBValues[i * scanWidth + k + 1] = intensity;
            srcRGBValues[i * scanWidth + k + 2] = intensity;
        }
    }
    Marshal.Copy(srcRGBValues, 0, srcPtr, src_bytes);
    //解锁位图
    srcBmp.UnlockBits(srcBmpData);
    return srcBmp;
}

以上就是C# BitmapData的使用介绍,首先融会贯通,其次举一反三,方可熟能生巧

时间: 2024-11-05 21:35:47

C# BitmapData使用说明的相关文章

Linux系统下安装rz/sz命令及使用说明

对于经常使用Linux系统的人员来说,少不了将本地的文件上传到服务器或者从服务器上下载文件到本地,rz / sz命令很方便的帮我们实现了这个功能,但是很多Linux系统初始并没有这两个命令.今天,我们就简单的讲解一下如何安装和使用rz.sz命令. 1.软件安装 (1)编译安装 root 账号登陆后,依次执行以下命令: 1 cd /tmp 2 wget http://www.ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz 3 tar zxvf lrzsz-0.1

android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明

涉及到滑动,就涉及到VIEW,大家都知道,android的UI界面都是由一个一个的View以及View的派生类组成,View作为基类,而常用的布局里面的各种布局就是它派生出来的ViewGroup的子类,ViewGroup作为各个组件的容器搭建了整体的UI.以下是android UI的结构示示意图: 查看源码 /** * Implement this to do your drawing. * * @param canvas the canvas on which the background w

Git使用说明

Git是流行的分布式版本控制系统,可以方便的管理多人协作的项目并避免了集中式版本控制系统对服务器的依赖. 简介 版本库(repository)是一个由Git管理的目录,Git将跟踪工作目录下文件的修改并在需要时还原. 在工作目录下.git子目录则维护着版本库 . Git维护三个组件: 工作目录: 保存实际文件 暂存区 : 保存尚未提交的修改 版本库: 保存已提交的修改 HEAD: 指向最后一次提交后的结果(checkout 命令的主要功能就是操作HEAD). Git将每次提交的修改串成一条时间线

软件使用说明

软件使用说明:我们的软件是一款基于在校女大学生的记账软件,根据调查身边的女生,统计出了大部分的女生每个月开销的分类.在我们的软件中按这些分类记录每个人的每天的开销,根据调查结果显示有部分学生还有收入,所以我们的记账软件还增加了收入项.我们软件可以根据你每天输入的开销来计算你每个月的开销,并且你可以在其中设置每个月开销的额度,根据你的开销对你的花销进行提醒.在每天你也可以收到关于你这一天开销的提醒,比如:提醒你录入,提醒你今天的花费是否超标.

IDEA工具使用说明

IDEA使用说明 1.安装 2.开始界面 1)create New Project (新建项目) 2)Import Project  (导入项目) 3)Open (打开已有的项目) 4)Check out from Version Control (从版本控制库中导入项目) 3.新建项目 1)方式一: 说明:左边的列表显示的是IDEA可以的项支持目种类,右边是需要额外添加的构面,选择好相应的构面,点击next. 说明:上面的一部分是制定项目的名称,下面一部分是制定项目中模块的名称.当创建了一个项

中海达RTK使用说明之两个点计算参数

中海达RTK求转换参数操作步骤,中海达GPS四参数计算,中海达HI-Survey参数计算简要操作,已知两个控制点求转换参数, 手薄型号:Ihand20 安卓系统手薄 软件:hi-survey road\elec 仪器:中海达公司任意RTK产品 使用两个点求转换参数流程: 第一步:碎步测量控制点 第二步:把两个控制点已知坐标输入到控制点库 第三步:计算参数 第四步:检核参数精度,测控制点作对比,或点放样控制点 使用两个点如何求转换参数? 如何选取控制点计算参数? 四参数控制范围只是计算选用的两个控

AC6102开发板USB3.0测试和使用说明

AC6102开发板USB3.0测试和使用说明 概述 AC6102上集成了一颗Cypress 推出的高性能USB3.0传输芯片CYUSB3014,Cypress称之为EZ-USBFX3.该芯片性能强劲,功能强大,接口简单,非常适合用于各种需要高速数据传输的场合,以下为摘自EZ-USBFX3数据手册中关于该芯片的介绍: 赛普拉斯EZ-USBFX3是新一代USB3.0外设控制器,具有高度集成的灵活特性,可帮助开发人员为任何系统添加USB3.0功能.EZ-USBFX3具有一个可进行完全配置的并行通用可编

Mallet 使用说明

Mallet:自然语言处理工具包 发表于128 天前 ? 技术, 科研 ? 评论数 6 ? 被围观 1006 Views+ MALLET是基于java的自然语言处理工具箱,包括分档得分类.句类.主题模型.信息抽取等其他机器学习在文本方面的应用,虽然是文本的应用,但是完全可以拿到多媒体方面来,例如机器视觉. MALLET包含了足够的文本分类的算法,还有特征提取的算法等.文本分类的算法像是Na?ve Bayes, Maximum Entropy, and Decision Trees等,而且也对代码

Retrofit结合RxJava使用说明

PS:年后一直没有更新博客,实在是太忙了.今天周六也是终于抽出了时间,就决定写一篇Retrofit结合RxJava使用说明.刚好现在写的的项目中也有用到,趁热打铁简单说说.最近也不知道博客写什么内容,大家有什么想了解的内容,也可以评论告诉我,我尽力解答. 如果对Retrofit不了解可以看我之前的一篇博客:Retrofit 2.0使用 ,这次的内容也是在此基础上的.关于RxJava可以参考:学习RxJava(资料汇总),这里我就不多说了. 1.准备工作 我们需要添加相应的依赖: compile