「全部致我於死地的,也激發我膽魄」,姚貝娜的《心火》,是我近年來聽過最好的歌,特此推薦一下。編程
圖像處理,大概分三步:1.LockBits();2.進行處理;3.UnlockBits();這比起 C++ 來,不知清爽幾許?ide
編程,是爲了知足人的需求,因此進行灰度處理時,不是簡單的 (r + g + b) / 3,而是分別乘以合適的比例值,r * 0.30 + g * 0.59 + b * 0.11。這是由於人眼對 green 最敏感,red 次之,blue 最低。spa
只實現了灰度處理,邊緣提取,二值化,縮小,Rotate 等有限功能,代碼不言自明,無需多說。code
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace x01.Utilities { public static class BitmapHelper { /// <summary> /// 對 bitmap 進行灰度處理。r,g,b 權重相加爲 1。 /// </summary> /// <param name="bmp">所要處理的 bitmap 對象。</param> /// <param name="rWeight">red 權重。</param> /// <param name="gWeight">green 權重。</param> /// <param name="bWeight">blue 權重。</param> public static void Gray(Bitmap bmp, float rWeight = 0.30f, float gWeight = 0.59f, float bWeight = 0.11f) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); for (int y = 0; y < bmp.Height * data.Stride; y += data.Stride) { for (int x = 0; x < bmp.Width * 3; x += 3) { int i = y + x; byte b = buf[i]; byte g = buf[i + 1]; byte r = buf[i + 2]; buf[i] = buf[i + 1] = buf[i + 2] = (byte)(b * bWeight + g * gWeight + r * rWeight); } } Marshal.Copy(buf, 0, data.Scan0, buf.Length); bmp.UnlockBits(data); } /// <summary> /// 對 bitmap 進行中值濾波處理。 /// </summary> /// <param name="bmp">所要處理的 bitmap 對象。</param> public static void MedianFilter(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); unsafe { byte* pBuf = (byte*)data.Scan0.ToPointer(); for (int i = 1; i < bmp.Height - 1; i++) { for (int j = 1; j < bmp.Width - 1; j++) { List<byte>[] list = new List<byte>[3]; for (int k = 0; k < 3; k++) { list[k] = new List<byte>(); } for (int y = -1; y < 2; y++) { for (int x = -1; x < 2; x++) { int index = (i + y) * data.Stride + (j + x) * 3; for (int k = 0; k < 3; k++) { list[k].Add(pBuf[index + k]); } } } for (int k = 0; k < 3; k++) { list[k].Sort(); } int indexMedian = i * data.Stride + j * 3; for (int k = 0; k < 3; k++) { pBuf[indexMedian + k] = list[k][4]; // 4: median value after sort. list[k].Clear(); } list = null; } } } bmp.UnlockBits(data); } /// <summary> /// 獲取 bitmap 所選的顏色份量直方圖。 /// </summary> /// <param name="bmp">所要處理的 bitmap 對象</param> /// <param name="bgrOffset">所選的顏色: blue=0, green=1, red=2</param> /// <returns>返回 256 * 256 大小的 Bitmap 直方圖。</returns> public static Bitmap Histogram(Bitmap bmp, int bgrOffset = 0) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); int[] countColors = new int[256]; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; countColors[buf[index + bgrOffset]]++; } } bmp.UnlockBits(data); int maxIndex = 0; for (int i = 1; i < 256; i++) { if (countColors[maxIndex] < countColors[i]) { maxIndex = i; } } Bitmap hist = new Bitmap(256, 256); Graphics g = Graphics.FromImage(hist); g.Clear(Color.Wheat); for (int i = 0; i < 256; i++) { int h = 256 * countColors[i] / countColors[maxIndex]; g.DrawLine(new Pen(Color.FromArgb(i, i, i), 1f), i, 256, i, 256 - h); // top bottom inverse } return hist; } public static void ExtractEdge(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; byte[] edge = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); for (int y = 1; y < bmp.Height - 1; y++) { for (int x = 1; x < bmp.Width - 1; x++) { int index = y * data.Stride + x * 3; byte gray = (byte)((buf[index] + buf[index + 1] + buf[index + 2]) / 3); int value = 0; for (int i = -1; i < 2; i++) // neareat eight point { for (int j = -1; j < 2; j++) { if (i == 0 && j == 0) { continue; } int index2 = (y + i) * data.Stride + (x + i) * 3; byte gray2 = (byte)((buf[index2] + buf[index2 + 1] + buf[index2 + 2]) / 3); value += Math.Abs(gray - gray2); } } edge[index] = edge[index + 1] = edge[index + 2] = (byte)(value >> 3); } } Marshal.Copy(edge, 0, data.Scan0, edge.Length); bmp.UnlockBits(data); } /// <summary> /// 對圖像進行二值化處理。 /// </summary> /// <param name="bmp">處理的圖像。</param> /// <param name="minValue">最小閥值。</param> /// <param name="maxValue">最大閥值。</param> public static void Binary(Bitmap bmp, int minValue, int maxValue) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; int gray = (buf[index] + buf[index+1] +buf[index+2])/3; if (gray >= minValue && gray <= maxValue) { buf[index] = buf[index + 1] = buf[index + 2] = 0; } else { buf[index] = buf[index + 1] = buf[index + 2] = 255; } } } Marshal.Copy(buf, 0, data.Scan0, buf.Length); bmp.UnlockBits(data); } /// <summary> /// 對灰度圖像進行對比度加強。 /// </summary> /// <param name="bmp">灰度圖像</param> /// <param name="srcMin">原灰度下界</param> /// <param name="srcMax">原灰度上界</param> /// <param name="destMin">目標灰度下界</param> /// <param name="destMax">目標灰度上界</param> public static void Enhance(Bitmap bmp, int srcMin, int srcMax, int destMin, int destMax) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; int gray = (buf[index] + buf[index + 1] + buf[index + 2]) / 3; float value = (float)(destMax - destMin) / (srcMax - srcMin) * (gray - srcMin) + destMin; buf[index] = buf[index + 1] = buf[index + 2] = value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value); } } Marshal.Copy(buf, 0, data.Scan0, buf.Length); bmp.UnlockBits(data); } public static void Enhance(Bitmap bmp, float n) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; int gray = (buf[index] + buf[index + 1] + buf[index + 2]) / 3; float value = gray * n; buf[index] = buf[index + 1] = buf[index + 2] = value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value); } } Marshal.Copy(buf, 0, data.Scan0, buf.Length); bmp.UnlockBits(data); } public static void ConnectRegion(Bitmap bmp) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); int sign = 40; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; if (buf[index] == 0) { SignRegion(buf, x * 3, y * data.Stride, sign, data.Stride, bmp.Width, bmp.Height); sign += 40; } } } Marshal.Copy(buf, 0, data.Scan0, buf.Length); bmp.UnlockBits(data); } public static void SignRegion(byte[] buf, int x, int y, int sign, int stride, int width, int height) { int index = x + y; buf[index] = buf[index + 1] = buf[index + 2] = (byte)sign; if (x > 0 && buf[index -3] == 0) // left { SignRegion(buf, x - 3, y, sign, stride, width, height); } if (x < width * 3 - 3 && buf[index + 3] == 0) // right { SignRegion(buf, x + 3, y, sign, stride, width, height); } if (y > 0 && buf[index - stride] == 0) // top { SignRegion(buf, x, y - stride, sign, stride, width, height); } if (y < height * stride && buf[index + stride] == 0) // bottom { SignRegion(buf, x, y + stride, sign, stride, width, height); } } /// <summary> /// 縮小圖像。 /// </summary> /// <param name="bmp">圖像</param> /// <param name="widthFactor">寬度縮小倍數</param> /// <param name="heightFactor">高度縮小倍數</param> public static void Dilation(Bitmap bmp, float widthFactor, float heightFactor) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); byte[] result = new byte[data.Stride * bmp.Height]; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; int rx = (int)(x * widthFactor); int ry = (int)(y * heightFactor); if (rx < 0 || rx >= bmp.Width || ry < 0 || ry >= bmp.Height) { continue; } int rindex = ry * data.Stride + rx * 3; result[index] = buf[rindex]; result[index + 1] = buf[rindex + 1]; result[index + 2] = buf[rindex + 2]; } } Marshal.Copy(result, 0, data.Scan0, result.Length); bmp.UnlockBits(data); } public static void Translate(Bitmap bmp, int xOffset, int yOffset) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); byte[] result = new byte[data.Stride * bmp.Height]; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; int rx = x - xOffset; int ry = y - yOffset; if (rx < 0 || rx >= bmp.Width || ry < 0 || ry >= bmp.Height) { continue; } int rindex = ry * data.Stride + rx * 3; result[index] = buf[rindex]; result[index + 1] = buf[rindex + 1]; result[index + 2] = buf[rindex + 2]; } } Marshal.Copy(result, 0, data.Scan0, result.Length); bmp.UnlockBits(data); } public static void Rotate(Bitmap bmp, float angle, Point center) { BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); byte[] buf = new byte[data.Stride * bmp.Height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); byte[] result = new byte[data.Stride * bmp.Height]; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * data.Stride + x * 3; int rx = (int)( (x - center.X) * Math.Cos(angle * Math.PI / 180) - (y - center.Y) * Math.Sin(angle * Math.PI / 180) + center.X ); int ry = (int)( (x - center.X) * Math.Sin(angle * Math.PI / 180) + (y - center.Y) * Math.Cos(angle * Math.PI / 180) + center.Y ); if (rx < 0 || rx >= bmp.Width || ry < 0 || ry >= bmp.Height) { continue; } int rindex = ry * data.Stride + rx * 3; result[index] = buf[rindex]; result[index + 1] = buf[rindex + 1]; result[index + 2] = buf[rindex + 2]; } } Marshal.Copy(result, 0, data.Scan0, result.Length); bmp.UnlockBits(data); } } }
若是要處理圖像,Paint.Net 是款不錯的軟件。orm