zoukankan      html  css  js  c++  java
  • C# Bitmap图片GetPixel 和 SetPixel 效率问题

    在对Bitmap图片操作的时候,有时需要用到获取或设置像素颜色方法:GetPixel 和 SetPixel,

    如果直接对这两个方法进行操作的话速度很慢,这里我们可以通过把数据提取出来操作,然后操作完在复制回去可以加快访问速度

    其实对Bitmap的访问还有两种方式,一种是内存法,一种是指针法

    1、内存法

      这里定义一个类LockBitmap,通过把Bitmap数据拷贝出来,在内存上直接操作,操作完成后在拷贝到Bitmap中

      1      public class LockBitmap
      2         {
      3             Bitmap source = null;
      4             IntPtr Iptr = IntPtr.Zero;
      5             BitmapData bitmapData = null;
      6 
      7             public byte[] Pixels { get; set; }
      8             public int Depth { get; private set; }
      9             public int Width { get; private set; }
     10             public int Height { get; private set; }
     11 
     12             public LockBitmap(Bitmap source)
     13             {
     14                 this.source = source;
     15             }
     16 
     17             /// <summary>
     18             /// Lock bitmap data
     19             /// </summary>
     20             public void LockBits()
     21             {
     22                 try
     23                 {
     24                     // Get width and height of bitmap
     25                     Width = source.Width;
     26                     Height = source.Height;
     27 
     28                     // get total locked pixels count
     29                     int PixelCount = Width * Height;
     30 
     31                     // Create rectangle to lock
     32                     Rectangle rect = new Rectangle(0, 0, Width, Height);
     33 
     34                     // get source bitmap pixel format size
     35                     Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
     36 
     37                     // Check if bpp (Bits Per Pixel) is 8, 24, or 32
     38                     if (Depth != 8 && Depth != 24 && Depth != 32)
     39                     {
     40                         throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
     41                     }
     42 
     43                     // Lock bitmap and return bitmap data
     44                     bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
     45                                                  source.PixelFormat);
     46 
     47                     // create byte array to copy pixel values
     48                     int step = Depth / 8;
     49                     Pixels = new byte[PixelCount * step];
     50                     Iptr = bitmapData.Scan0;
     51 
     52                     // Copy data from pointer to array
     53                     Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
     54                 }
     55                 catch (Exception ex)
     56                 {
     57                     throw ex;
     58                 }
     59             }
     60 
     61             /// <summary>
     62             /// Unlock bitmap data
     63             /// </summary>
     64             public void UnlockBits()
     65             {
     66                 try
     67                 {
     68                     // Copy data from byte array to pointer
     69                     Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
     70 
     71                     // Unlock bitmap data
     72                     source.UnlockBits(bitmapData);
     73                 }
     74                 catch (Exception ex)
     75                 {
     76                     throw ex;
     77                 }
     78             }
     79 
     80             /// <summary>
     81             /// Get the color of the specified pixel
     82             /// </summary>
     83             /// <param name="x"></param>
     84             /// <param name="y"></param>
     85             /// <returns></returns>
     86             public Color GetPixel(int x, int y)
     87             {
     88                 Color clr = Color.Empty;
     89 
     90                 // Get color components count
     91                 int cCount = Depth / 8;
     92 
     93                 // Get start index of the specified pixel
     94                 int i = ((y * Width) + x) * cCount;
     95 
     96                 if (i > Pixels.Length - cCount)
     97                     throw new IndexOutOfRangeException();
     98 
     99                 if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
    100                 {
    101                     byte b = Pixels[i];
    102                     byte g = Pixels[i + 1];
    103                     byte r = Pixels[i + 2];
    104                     byte a = Pixels[i + 3]; // a
    105                     clr = Color.FromArgb(a, r, g, b);
    106                 }
    107                 if (Depth == 24) // For 24 bpp get Red, Green and Blue
    108                 {
    109                     byte b = Pixels[i];
    110                     byte g = Pixels[i + 1];
    111                     byte r = Pixels[i + 2];
    112                     clr = Color.FromArgb(r, g, b);
    113                 }
    114                 if (Depth == 8)
    115                 // For 8 bpp get color value (Red, Green and Blue values are the same)
    116                 {
    117                     byte c = Pixels[i];
    118                     clr = Color.FromArgb(c, c, c);
    119                 }
    120                 return clr;
    121             }
    122 
    123             /// <summary>
    124             /// Set the color of the specified pixel
    125             /// </summary>
    126             /// <param name="x"></param>
    127             /// <param name="y"></param>
    128             /// <param name="color"></param>
    129             public void SetPixel(int x, int y, Color color)
    130             {
    131                 // Get color components count
    132                 int cCount = Depth / 8;
    133 
    134                 // Get start index of the specified pixel
    135                 int i = ((y * Width) + x) * cCount;
    136 
    137                 if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
    138                 {
    139                     Pixels[i] = color.B;
    140                     Pixels[i + 1] = color.G;
    141                     Pixels[i + 2] = color.R;
    142                     Pixels[i + 3] = color.A;
    143                 }
    144                 if (Depth == 24) // For 24 bpp set Red, Green and Blue
    145                 {
    146                     Pixels[i] = color.B;
    147                     Pixels[i + 1] = color.G;
    148                     Pixels[i + 2] = color.R;
    149                 }
    150                 if (Depth == 8)
    151                 // For 8 bpp set color value (Red, Green and Blue values are the same)
    152                 {
    153                     Pixels[i] = color.B;
    154                 }
    155             }
    156         }
     使用:先锁定Bitmap,然后通过Pixels操作颜色对象,最后释放锁,把数据更新到Bitmap中
     1         string file = @"C:	est.jpg";
     2             Bitmap bmp = new Bitmap(Image.FromFile(file));
     3             
     4             LockBitmap lockbmp = new LockBitmap(bmp);
     5             //锁定Bitmap,通过Pixel访问颜色
     6             lockbmp.LockBits();
     7 
     8             //获取颜色
     9             Color color = lockbmp.GetPixel(10, 10);
    10 
    11             //从内存解锁Bitmap
    12             lockbmp.UnlockBits();

    2、指针法
    
      这种方法访问速度比内存法更快,直接通过指针对内存进行操作,不需要进行拷贝,但是在C#中直接通过指针操作内存是不安全的,所以需要在代码中加入unsafe关键字,在生成选项中把允许不安全代码勾上,才能编译通过
    
      这里定义成PointerBitmap类
      1          public class PointBitmap
      2             {
      3                 Bitmap source = null;
      4                 IntPtr Iptr = IntPtr.Zero;
      5                 BitmapData bitmapData = null;
      6 
      7                 public int Depth { get; private set; }
      8                 public int Width { get; private set; }
      9                 public int Height { get; private set; }
     10 
     11                 public PointBitmap(Bitmap source)
     12                 {
     13                     this.source = source;
     14                 }
     15 
     16                 public void LockBits()
     17                 {
     18                     try
     19                     {
     20                         // Get width and height of bitmap
     21                         Width = source.Width;
     22                         Height = source.Height;
     23 
     24                         // get total locked pixels count
     25                         int PixelCount = Width * Height;
     26 
     27                         // Create rectangle to lock
     28                         Rectangle rect = new Rectangle(0, 0, Width, Height);
     29 
     30                         // get source bitmap pixel format size
     31                         Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
     32 
     33                         // Check if bpp (Bits Per Pixel) is 8, 24, or 32
     34                         if (Depth != 8 && Depth != 24 && Depth != 32)
     35                         {
     36                             throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
     37                         }
     38 
     39                         // Lock bitmap and return bitmap data
     40                         bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
     41                                                      source.PixelFormat);
     42 
     43                         //得到首地址
     44                         unsafe
     45                         {
     46                             Iptr = bitmapData.Scan0;
     47                             //二维图像循环
     48                             
     49                         }
     50                     }
     51                     catch (Exception ex)
     52                     {
     53                         throw ex;
     54                     }
     55                 }
     56 
     57                 public void UnlockBits()
     58                 {
     59                     try
     60                     {
     61                         source.UnlockBits(bitmapData);
     62                     }
     63                     catch (Exception ex)
     64                     {
     65                         throw ex;
     66                     }
     67                 }
     68 
     69                 public Color GetPixel(int x, int y)
     70                 {
     71                     unsafe
     72                     {
     73                         byte* ptr = (byte*)Iptr;
     74                         ptr = ptr + bitmapData.Stride * y;
     75                         ptr += Depth * x / 8;
     76                         Color c = Color.Empty;
     77                         if (Depth == 32)
     78                         {
     79                             int a = ptr[3];
     80                             int r = ptr[2];
     81                             int g = ptr[1];
     82                             int b = ptr[0];
     83                             c = Color.FromArgb(a, r, g, b);
     84                         }
     85                         else if (Depth == 24)
     86                         {
     87                             int r = ptr[2];
     88                             int g = ptr[1];
     89                             int b = ptr[0];
     90                             c = Color.FromArgb(r, g, b);
     91                         }
     92                         else if (Depth == 8)
     93                         {
     94                             int r = ptr[0];
     95                             c = Color.FromArgb(r, r, r);
     96                         }
     97                         return c;
     98                     }
     99                 }
    100 
    101                 public void SetPixel(int x, int y, Color c)
    102                 {
    103                     unsafe
    104                     {
    105                         byte* ptr = (byte*)Iptr;
    106                         ptr = ptr + bitmapData.Stride * y;
    107                         ptr += Depth * x / 8;
    108                         if (Depth == 32)
    109                         {
    110                             ptr[3] = c.A;
    111                             ptr[2] = c.R;
    112                             ptr[1] = c.G;
    113                             ptr[0] = c.B;
    114                         }
    115                         else if (Depth == 24)
    116                         {
    117                             ptr[2] = c.R;
    118                             ptr[1] = c.G;
    119                             ptr[0] = c.B;
    120                         }
    121                         else if (Depth == 8)
    122                         {
    123                             ptr[2] = c.R;
    124                             ptr[1] = c.G;
    125                             ptr[0] = c.B;
    126                         }
    127                     }
    128                 }
    129             }

    使用方法这里就不列出来了,跟上面的LockBitmap类似

  • 相关阅读:
    [页面布局方式]
    padding and margin
    【浏览器中的页面】
    【浏览器的页面循环系统】
    Activity启动模式详解(二)--->singleTask
    finish、onDestory、System.exit的区别
    Androidndk开发打包时我们应该如何注意平台的兼容(x86,arm,arm-v7a)
    关于WifiManager的一些看法
    高效的找出两个List中的不同元素
    关于Activity的生命周期
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/12897892.html
Copyright © 2011-2022 走看看