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:\test.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类似

猜你喜欢

转载自www.cnblogs.com/ybqjymy/p/12897892.html