我需要将Drawing.Bitmap转换为4位灰度。有没有办法实现这个目标?我尝试过使用Bitmap.Clone,但我只得到通常臭名昭着的“Out of memory”异常。即使它设法转换为4位,这会是灰度吗?
任何提示都将不胜感激。
谢谢,
Nelson H
答案 0 :(得分:2)
没有4bpp灰度图像格式。接下来最好的是4bppIndexed,其中包含16种颜色的灰色调色板。 GDI +对这种格式的支持非常差,设置像素的唯一方法是使用Bitmap.LockBits()直接编写它们。这在VB.NET中很难做到,C#更倾向于用指针操作位图数据。像这样:
public unsafe static void Save4bppGrayscale(Bitmap src, string path) {
var bmp = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format4bppIndexed);
// Create gray-scale palette
var pal = bmp.Palette;
for (int ix = 0; ix < 16; ++ix) {
var c = 255 * ix / 15;
pal.Entries[ix] = Color.FromArgb(c, c, c);
}
bmp.Palette = pal;
// Map pixels
var data = bmp.LockBits(new Rectangle(0, 0, src.Width, src.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format4bppIndexed);
for (int y = 0; y < src.Height; ++y) {
byte* line = (byte*)(IntPtr)((long)data.Scan0 + y * data.Stride);
for (int x = 0; x < src.Width; ++x) {
var pix = src.GetPixel(x, y);
var c = (int)(15 * pix.GetBrightness());
if (x % 2 == 1) c <<= 4;
*(line + x / 2) |= (byte)c;
}
}
bmp.UnlockBits(data);
bmp.Save(path, System.Drawing.Imaging.ImageFormat.Bmp);
}
使用此代码转换的示例图像:
它不是特别快,调色板可以使用一些伽玛校正来避免生成太暗的图像。
答案 1 :(得分:0)
如果您尝试在ASP.NET网站上完成图像处理,则会发生内存不足异常,因为IIS应用程序池会限制分配的内存量。因此,我们创建了一个独立于IIS的独立Windows服务,并进行转换。在IIS网站中,我们只是以WCF或命名管道的形式触发服务。
答案 2 :(得分:0)
假设Imports System.Runtime.InteropServices, System.Drawing.Imaging
位于代码文件的顶部。 (LockBits并不难,我用它做了很多图像处理,而且更喜欢VB.NET而不是C#。)
Private Sub To4BitGrayScale(ByVal b As Bitmap)
Dim bd As BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, ImageFormat.Format24BppRgb)
Dim arr(bd.Width * bd.Height * 3 - 1) As Byte
Marshal.Copy(bd.Scan0, arr, 0, arr.Length)
For i As Integer = 0 To arr.Length - 1 Step 3
Dim c As Color = Color.FromArgb(255, arr(i), arr(i + 1), arr(i + 2))
' Convert c to grayscale however you want; weighted, average, whatever.
arr(i) = c.R
arr(i + 1) = c.G
arr(i + 2) = c.B
Next
Marshal.Copy(arr, 0, bd.Scan0, arr.Length)
b.UnlockBits(bd)
End Sub
这种方法当然不是很快(对我而言,800万像素的图像大约需要1-2秒),但这并不错。