zoukankan      html  css  js  c++  java
  • 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的使用介绍,首先融会贯通,其次举一反三,方可熟能生巧

  • 相关阅读:
    Spring HttpIvoker实现Java的远程调用
    基于struts2框架文件的上传与下载
    12月9号linux学习
    2019.7.7 练习题
    题解 儿童节继续欢乐赛
    Winfroms看看吧客官~
    group by应用
    基于Windows Azure 搭建基于SharePoint 2010 Intranet、Extranet、Internet (1): 安装SharePoint 2010
    基于Windows Azure 搭建基于SharePoint 2010 Intranet、Extranet、Internet (2): 创建并发布SharePoint Intranet站点
    Inside Microsoft SharePoint 2010 简译(1): SharePoint 2010开发者路线图
  • 原文地址:https://www.cnblogs.com/ching2009/p/4235766.html
Copyright © 2011-2022 走看看