使用 Bitmap.LockBits 直接操作像素資料進行灰度化與閾值二值化,但結果保留大量彩色雜點。問題在於灰度計算與閾值邏輯。
var grays = Convert.ToInt16(srcRGBValues[i * scanWidth + k + 2]) + // R
Convert.ToInt16(srcRGBValues[i * scanWidth + k + 1]) + // G
Convert.ToInt16(srcRGBValues[i * scanWidth + k + 0]); // B
if (grays >= 382) { /* 設為白 */ } else { /* 設為黑 */ }
三大缺陷:
// 標準灰度公式:Y = 0.299R + 0.587G + 0.114B int gray = (int)(0.299 * R + 0.587 * G + 0.114 * B); // 自適應閾值 (Otsu 演算法) 或固定閾值 (如 128) byte binary = (gray > 128) ? (byte)255 : (byte)0; srcRGBValues[idx + 0] = srcRGBValues[idx + 1] = srcRGBValues[idx + 2] = binary;
PixelFormat.Format32bppArgb 統一 4 bytes/pixel,避免行跨越計算錯誤scanWidth = bmpData.Stride 而非 Width * 3,Stride 含記憶體對齊填充idx = y * stride + x * 4UnlockBits 釋放鎖定生產環境建議使用 OpenCvSharp 或 Emgu CV (OpenCV .NET 封裝),提供工業級影像處理管線:
using (var mat = BitmapConverter.ToMat(bitmap))
using (var gray = new Mat())
using (var binary = new Mat()) {
Cv2.CvtColor(mat, gray, ColorConversionCodes.BGR2GRAY);
Cv2.Threshold(gray, binary, 0, 255, ThresholdTypes.Otsu);
// 形態學去噪
Cv2.MorphologyEx(binary, binary, MorphTypes.Open, Cv2.GetStructuringElement(MorphShapes.Rect, new Size(2,2)));
return BitmapConverter.ToBitmap(binary);
}
自行實作易遺漏邊界條件、效能優化,引用成熟庫更可靠。