C# 快速 彩色(RGB) 轉灰階
C# 快速 彩色(RGB) 轉灰階
資料來源: https://blog.holey.cc/2018/04/18/csharp-three-way-covert-bmp-rgb-to-gray/
1. GetPixel/SetPixel
static Bitmap RGBtoGray(Bitmap srcbmp)
{
Bitmap bitmap = new Bitmap(bmpSrc);
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
int gray = (
bitmap.GetPixel(x, y).R +
bitmap.GetPixel(x, y).G +
bitmap.GetPixel(x, y).B) / 3;
Color color = Color.FromArgb(gray, gray, gray);
bitmap.SetPixel(x, y, color);
}
}
return bitmap;
}
2. unsafe 指標法
static Bitmap RGBtoGray(Bitmap srcbmp)
{
Bitmap bitmap = new Bitmap(bmpSrc);
BitmapData bmpData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite,
bitmap.PixelFormat);
unsafe
{
int stride = bmpData.Stride;
int offset = stride - bitmap.Width * 3;
IntPtr intPtr = bmpData.Scan0;
byte* p = (byte*)(void*)intPtr;
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
byte gray = (byte)((
p[y * (bitmap.Width * 3 + offset) + (x * 3) + 0] +
p[y * (bitmap.Width * 3 + offset) + (x * 3) + 1] +
p[y * (bitmap.Width * 3 + offset) + (x * 3) + 2]) / 3);
for (int i = 0; i < 3; i++)
{
p[y * (bitmap.Width * 3 + offset) + (x * 3) + i] = gray;
}
}
}
}
bitmap.UnlockBits(bmpData);
return bitmap;
}
3. Graphics 重繪法
static Bitmap RGBtoGray(Bitmap bmpSrc)
{
ColorMatrix cm = new ColorMatrix(new float[][]
{
new float[] { 0.30f, 0.30f, 0.30f, 0.00f, 0.00f } ,
new float[] { 0.59f, 0.59f, 0.59f, 0.00f, 0.00f } ,
new float[] { 0.11f, 0.11f, 0.11f, 0.00f, 0.00f } ,
new float[] { 0.00f, 0.00f, 0.00f, 1.00f, 0.00f } ,
new float[] { 0.00f, 0.00f, 0.00f, 0.00f, 1.00f }
});
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
Bitmap bitmap = new Bitmap(bmpSrc.Width, bmpSrc.Height, bmpSrc.PixelFormat);
Graphics g = Graphics.FromImage(bitmap);
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
g.DrawImage(bmpSrc, rect, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, ia);
return bitmap;
}
測試:
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
List<long> records = new List<long>() { 0, 0, 0 };
Bitmap bitmap = new Bitmap("input.bmp");
Console.WriteLine("========== Bitmap Info ==========");
Console.WriteLine(
$"Filename\t{ "input.bmp"} " + Environment.NewLine +
$"Palette \t{ Image.GetPixelFormatSize(bitmap.PixelFormat) }" + Environment.NewLine +
$"Width \t{ bitmap.Height }" + Environment.NewLine +
$"Height \t{ bitmap.Width }" + Environment.NewLine);
for (int i = 0; i < 10; i++)
{
Console.WriteLine($"========== Count { i } ==========");
sw = Stopwatch.StartNew();
RGBtoGray1(new Bitmap("input.bmp"));
sw.Stop();
records[0] += sw.ElapsedMilliseconds;
Console.WriteLine(string.Format("Method 1 cost {0,5} milliseconds", sw.ElapsedMilliseconds));
sw.Reset();
sw = Stopwatch.StartNew();
RGBtoGray2(new Bitmap("input.bmp"));
sw.Stop();
records[1] += sw.ElapsedMilliseconds;
Console.WriteLine(string.Format("Method 2 cost {0,5} milliseconds", sw.ElapsedMilliseconds));
sw = Stopwatch.StartNew();
RGBtoGray3(new Bitmap("input.bmp"));
sw.Stop();
records[2] += sw.ElapsedMilliseconds;
Console.WriteLine(string.Format("Method 3 cost {0,5} milliseconds", sw.ElapsedMilliseconds));
Console.WriteLine();
}
Console.WriteLine("========== Average ==========");
Console.WriteLine(string.Format("Method 1: {0, 7} milliseconds", (float)records[0] / 10));
Console.WriteLine(string.Format("Method 2: {0, 7} milliseconds", (float)records[1] / 10));
Console.WriteLine(string.Format("Method 3: {0, 7} milliseconds", (float)records[2] / 10));
Console.ReadKey();
}