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类似


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM