C#图像处理中使用Marshal.Copy与LockBits实现灰度滤镜的问题求助
现有代码核心错误点
- 双重循环逻辑完全错误:外层
GetPixel的像素遍历逻辑和内层LockBits逻辑完全脱节,你在循环里每处理1个像素就对整张图执行一次锁、读、改红色通道、写回操作,不仅效率比原来的GetPixel还低,也根本没有执行灰度赋值的逻辑,反而把所有像素的红色通道强制设为255,自然不会出现灰度效果 - 锁模式错误:
LockBits传入的是ImageLockMode.ReadOnly,该模式下修改后的像素数据无法写回位图 - 像素字节顺序处理错误:GDI+中位图的字节存储顺序是*BGR(蓝、绿、红)*而非RGB,24位位图每3个字节为一组,顺序是索引0=B,1=G,2=R
- 没有处理步长(Stride)的对齐偏移:位图每行的实际字节数是4的整数倍,存在填充字节,不能直接按
宽度*3遍历所有像素,需要按行计算偏移
修正后的实现代码
using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; namespace dnm2709normalimg { class GrayFilter { public static Bitmap DoGray(Bitmap bmp) { // 锁定位图全部区域,使用读写模式 BitmapData bmpData = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); // 获取像素数据的起始地址 IntPtr ptr = bmpData.Scan0; // 计算全部像素的字节数 int byteCount = Math.Abs(bmpData.Stride) * bmp.Height; byte[] pixelBytes = new byte[byteCount]; // 把像素数据复制到字节数组 Marshal.Copy(ptr, pixelBytes, 0, byteCount); // 计算单像素的字节数(兼容24位RGB、32位ARGB格式) int pixelSize = Image.GetPixelFormatSize(bmp.PixelFormat) / 8; // 逐行遍历像素 for (int y = 0; y < bmp.Height; y++) { // 计算当前行的起始偏移(解决Stride对齐填充问题) int rowOffset = y * bmpData.Stride; for (int x = 0; x < bmp.Width; x++) { // 计算当前像素的起始索引 int pixelOffset = rowOffset + x * pixelSize; // 按BGR顺序取色 byte b = pixelBytes[pixelOffset]; byte g = pixelBytes[pixelOffset + 1]; byte r = pixelBytes[pixelOffset + 2]; // 灰度计算:采用人眼感知权重公式,比平均法效果更自然 byte gray = (byte)(r * 0.299 + g * 0.587 + b * 0.114); // 把三个通道都赋值为灰度值 pixelBytes[pixelOffset] = gray; // B通道 pixelBytes[pixelOffset + 1] = gray; // G通道 pixelBytes[pixelOffset + 2] = gray; // R通道 // 32位带Alpha通道的格式保留原Alpha值 if (pixelSize >=4) { pixelBytes[pixelOffset + 3] = pixelBytes[pixelOffset + 3]; } } } // 把修改后的字节数组写回位图 Marshal.Copy(pixelBytes, 0, ptr, byteCount); // 解锁位图 bmp.UnlockBits(bmpData); return bmp; } } }
注意事项
- 不要在像素遍历循环内部执行
LockBits/UnlockBits操作,只需锁一次整张图,处理完全部像素后再解锁,才能获得比GetPixel高百倍的性能提升 - 如果仅需处理24位RGB格式,可以固定
pixelSize=3,省略格式判断逻辑进一步提升性能 - 灰度计算如果需要保持和你原来的平均值逻辑一致,可以把灰度计算代码替换为
byte gray = (byte)((r + g + b) / 3);
内容的提问来源于stack exchange,提问作者user16815856
相关产品推荐
相关产品推荐

