C# 彩色圖片/照片 轉灰階&二值化(單色BMP)
C# 彩色圖片/照片 轉灰階&二值化(單色BMP)
資料來源:https://blog.holey.cc/2018/04/18/csharp-three-way-covert-bmp-rgb-to-gray/
http://hk.uwenku.com/question/p-qnyytjbn-bco.html
GITHUB: https://github.com/jash-git/CS_RGBtoGray_1Bit
CODE:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace CS_RGBtoGray { //https://blog.holey.cc/2018/04/18/csharp-three-way-covert-bmp-rgb-to-gray/ //http://hk.uwenku.com/question/p-qnyytjbn-bco.html public partial class Form1 : Form { public Form1() { InitializeComponent(); } public Bitmap RGBtoGray01(Bitmap bmpSrc) { 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; } public Bitmap RGBtoGray02(Bitmap bmpSrc) { 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; } public Bitmap RGBtoGray03(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; } public Bitmap ConvertTo1Bit(Bitmap input) { var masks = new byte[] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; var output = new Bitmap(input.Width, input.Height, PixelFormat.Format1bppIndexed); var data = new sbyte[input.Width, input.Height]; var inputData = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); try { var scanLine = inputData.Scan0; var line = new byte[inputData.Stride]; for (var y = 0; y < inputData.Height; y++, scanLine += inputData.Stride) { Marshal.Copy(scanLine, line, 0, line.Length); for (var x = 0; x < input.Width; x++) { data[x, y] = (sbyte)(64 * (GetGreyLevel(line[x * 3 + 2], line[x * 3 + 1], line[x * 3 + 0]) - 0.5)); } } } finally { input.UnlockBits(inputData); } var outputData = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); try { var scanLine = outputData.Scan0; for (var y = 0; y < outputData.Height; y++, scanLine += outputData.Stride) { var line = new byte[outputData.Stride]; for (var x = 0; x < input.Width; x++) { var j = data[x, y] > 0; if (j) line[x / 8] |= masks[x % 8]; var error = (sbyte)(data[x, y] - (j ? 32 : -32)); if (x < input.Width - 1) data[x + 1, y] += (sbyte)(7 * error / 16); if (y < input.Height - 1) { if (x > 0) data[x - 1, y + 1] += (sbyte)(3 * error / 16); data[x, y + 1] += (sbyte)(5 * error / 16); if (x < input.Width - 1) data[x + 1, y + 1] += (sbyte)(1 * error / 16); } } Marshal.Copy(line, 0, scanLine, outputData.Stride); } } finally { output.UnlockBits(outputData); } return output; } public double GetGreyLevel(byte r, byte g, byte b) { return (r * 0.299 + g * 0.587 + b * 0.114) / 255; } public Bitmap BitmapTo1Bpp(Bitmap img) { int w = img.Width; int h = img.Height; Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed); BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed); byte[] scan = new byte[(w + 7) / 8]; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { if (x % 8 == 0) scan[x / 8] = 0; Color c = img.GetPixel(x, y); if (c.GetBrightness() >= 0.7) scan[x / 8] |= (byte)(0x80 >> (x % 8)); } Marshal.Copy(scan, 0, (IntPtr)((long)data.Scan0 + data.Stride * y), scan.Length); } bmp.UnlockBits(data); return bmp; } private void Form1_Load(object sender, EventArgs e) { Bitmap RGBtoGray = RGBtoGray03(new Bitmap("20210610094646.jpg")); pictureBox1.Image = RGBtoGray; pictureBox2.Image = BitmapTo1Bpp(new Bitmap("20210610094646.jpg")); } } }