zoukankan      html  css  js  c++  java
  • 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 /// <param name="pic"></param>
     7 /// <returns></returns>
     8 public static BitmapSource GetMapSource(Bitmap pic)
     9 {
    10     IntPtr ip = pic.GetHbitmap();
    11     BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
    12         ip, IntPtr.Zero, Int32Rect.Empty,
    13         System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
    14     DeleteObject(ip);
    15     return bitmapSource;
    16 }
    复制代码

    接下来说Bitmap和BitmapData。

    Bitmap类
    Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下:
    1. GetPixel方法和SetPixel方法:获取和设置一个图像的指定像素的颜色.
    2. PixelFormat属性:返回图像的像素格式.
    3. Palette属性:获取和设置图像所使用的颜色调色板.
    4. Height Width属性:返回图像的高度和宽度.
    5. LockBits方法和UnlockBits方法:分别锁定和解锁系统内存中的位图像素.在基于像素点的图像处理方法中使用LockBits和UnlockBits是一个很好的方式,这两种方法可以使我们指定像素的范围来控制位图的任意一部分,从而消除了通过循环对位图的像素逐个进行处理,每调用LockBits之后都应该调用一次UnlockBits.
    BitmapData类
    BitmapData对象指定了位图的属性
    1. Height属性:被锁定位图的高度.
    2. Width属性:被锁定位图的高度.
    3. PixelFormat属性:数据的实际像素格式.
    4. Scan0属性:被锁定数组的首字节地址,如果整个图像被锁定,则是图像的第一个字节地址.
    5. Stride属性:步幅,也称为扫描宽度.

    这里要重点说说Stride属性,这个和Width有什么区别呢,可以这么说,如果你的图片大小也就是图片字节是4的整数倍,那么Stride与Width是相等的,否则Stride就是大于Width的最小4的整数倍。在处理过程中,Stride肯定是4的整数倍,这里是个坑啊。。。

                                                           

                              盗张图,连接写在文章底部

    先看看BitmapData的应用,我的场景是,我有一个一维像素点阵数组,里面放的是每个像素点的灰度值,知道宽和高,要转换成bitmap

    复制代码
     1 /// <summary>
     2 /// 像素点阵转换为bitmap
     3 /// </summary>
     4 /// <param name="rawValues">byte[]数组</param>
     5 /// <param name="width">图片的宽度</param>
     6 /// <param name="height">图片的高度</param>
     7 /// <returns>bitmap图片</returns>
     8 public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height)
     9 {
    10     Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    11     BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    12     //// 获取图像参数  
    13     //bmpData.Stride = width;
    14     int stride = bmpData.Stride;  // 扫描线的宽度  
    15     int offset = stride - width;  // 显示宽度与扫描线宽度的间隙  
    16     IntPtr iptr = bmpData.Scan0;  // 获取bmpData的内存起始位置  
    17     int scanBytes = stride * height;// 用stride宽度,表示这是内存区域的大小  
    18     //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组  
    19     int posScan = 0, posReal = 0;// 分别设置两个位置指针,指向源数组和目标数组  
    20     byte[] pixelValues = new byte[scanBytes];  //为目标数组分配内存  
    21     for (int x = 0; x < height; x++)
    22     {
    23         //// 下面的循环节是模拟行扫描  
    24         for (int y = 0; y < width; y++)
    25         {
    26             pixelValues[posScan++] = rawValues[posReal++];
    27         }
    28         posScan += offset;  //行扫描结束,要将目标位置指针移过那段“间隙”  
    29     }
    30     //// 用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中  
    31     System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes);
    32     bmp.UnlockBits(bmpData);  // 解锁内存区域  
    33     //// 下面的代码是为了修改生成位图的索引表,从伪彩修改为灰度  
    34     ColorPalette tempPalette;
    35     using (Bitmap tempBmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed))
    36     {
    37         tempPalette = tempBmp.Palette;
    38     }
    39     for (int i = 0; i < 256; i++)
    40     {
    41         tempPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
    42     }
    43 
    44     bmp.Palette = tempPalette;
    45 
    46     //// 算法到此结束,返回结果  
    47     return bmp;
    48 }
    复制代码

    这代码也是网上找的,具体哪里已经忘记了。至于24位位图数据其实就是 一个像素点有rgb三个值而已,道理一样。

    同样,我们也可以根据图片得到他的灰度数组

    复制代码
     1 //8位位图得到除去文件头信息的一位灰度数组
     2 
     3 
     4 BitmapData bmpData = map.LockBits(new System.Drawing.Rectangle(0, 0, map.Width, map.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
     5 
     6 //// 获取图像参数  
     7 
     8 int stride = bmpData.Stride;  // 扫描线的宽度  
     9 
    10 int offset = stride - map.Width;  // 显示宽度与扫描线宽度的间隙  
    11 
    12 IntPtr iptr = bmpData.Scan0;  // 获取bmpData的内存起始位置  
    13 
    14 int scanBytes = stride * map.Height;// 用stride宽度,表示这是内存区域的大小  
    15 
    16 //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组  
    17 
    18 mapdata = new byte[scanBytes];  //为目标数组分配内存
    19 
    20 System.Runtime.InteropServices.Marshal.Copy(iptr, mapdata, 0, scanBytes); //copy内存中数据到数组中
    复制代码

    这里对与bitmapdata的操作方式是ReadOnly

    为什么说stride是坑呢,因为在工作中,我有一个大小不为4的整数倍的文件,通过上面方法将他们转为图片,然后操作之后我需要存回去,继续存成文件的形式,如果你直接存回去你会发现你的文件变大了。这时候就需要避开stride。其实stride占据的空间什么都没有做,我们如何遍历构建图片,就如何反遍历回数组就可以了

    复制代码
    public static byte[] GetMapData(byte[] MapData,int width,int height)
    {
        var length = MapData.Length;
        if(width==length/height)
        {
            return MapData;
        }
        int offset=length/height-width;
        var scanBytes = width * height;
        byte[] RawMapData = new byte[scanBytes];
        int posScan = 0, posReal = 0;
        for(int x=0;x<height;x++)
        {
            for (int y=0;y<width;y++)
            {
                RawMapData[posScan++] = MapData[posReal++];
            }
            posReal += offset;
        }
        return RawMapData;
    }
    复制代码

    至于24位位图转8位位图,还是看这位博主的博客,他总结了很多,我还是觉得opencv比较快捷方便。

    http://blog.csdn.net/jiangxinyu/article/details/6222302

    另外还看到了一下c#处理图片的方法,比如光照,雾化,浮雕等,请移步下面链接

    http://www.pin5i.com/showtopic-20228.html

    种一棵树最好的时间是十年前,其次是现在。

  • 相关阅读:
    hive与hbase整合
    待重写
    hive DML
    【知识强化】第六章 总线 6.1 总线概述
    【知识强化】第五章 中央处理器 5.1 CPU的功能和基本结构
    【知识强化】第四章 指令系统 4.3 CISC和RISC的基本概念
    【知识强化】第四章 指令系统 4.2 指令寻址方式
    【知识强化】第四章 指令系统 4.1 指令格式
    【知识强化】第三章 存储系统 3.6 高速缓冲存储器
    【知识强化】第三章 存储系统 3.5 双口RAM和多模块存储器
  • 原文地址:https://www.cnblogs.com/wwwbdabc/p/10558242.html
Copyright © 2011-2022 走看看