using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using Tesseract; public static class OcrFinalHelper { private static readonly string _tessDataPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tessdata"); /// /// 针对白底黑字/截图优化的中文识别(强化浅灰色文字处理) /// public static string RecognizeScreenshot(string imagePath) { if (!File.Exists(imagePath)) return "文件不存在"; try { using var original = new Bitmap(imagePath); using var scaled = ScaleImage(original, original.Width * 2, original.Height * 2); // 预处理:灰度 → 对比度拉伸 → OTSU 二值化 using var gray = ToGrayscale(scaled); using var stretched = AutoContrast(gray); using var binary = BinarizeOtsu(stretched); using var engine = new TesseractEngine( _tessDataPath, "chi_sim+eng", EngineMode.LstmOnly); engine.SetVariable("preserve_interword_spaces", "1"); engine.SetVariable("tessedit_pageseg_mode", "6"); engine.SetVariable("textord_min_linesize", "2.5"); using var pix = BitmapToPix(binary); using var result = engine.Process(pix); return result.GetText()?.Trim() ?? ""; } catch (Exception ex) { return $"识别失败:{ex.Message}"; } } #region 预处理 private static Bitmap ScaleImage(Bitmap original, int newWidth, int newHeight) { var scaled = new Bitmap(newWidth, newHeight); using (var g = Graphics.FromImage(scaled)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawImage(original, 0, 0, newWidth, newHeight); } return scaled; } private static Bitmap ToGrayscale(Bitmap bmp) { var gray = new Bitmap(bmp.Width, bmp.Height); using (var g = Graphics.FromImage(gray)) { var cm = new ColorMatrix(new float[][] { new float[]{0.299f,0.299f,0.299f,0,0}, new float[]{0.587f,0.587f,0.587f,0,0}, new float[]{0.114f,0.114f,0.114f,0,0}, new float[]{0,0,0,1,0}, new float[]{0,0,0,0,1} }); using (var ia = new ImageAttributes()) { ia.SetColorMatrix(cm); g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, ia); } } return gray; } /// /// 强化版对比度拉伸(专门优化:浅灰文字 + 低对比度文字) /// 不破坏图像、不炸图、Tesseract 可正常识别 /// private static Bitmap AutoContrast(Bitmap gray) { int min = 255, max = 0; int width = gray.Width; int height = gray.Height; // 第一步:统计灰度(忽略纯白 255,避免背景干扰文字) for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int val = gray.GetPixel(x, y).R; if (val == 255) continue; // 跳过纯白背景 if (val < min) min = val; if (val > max) max = val; } } // 如果无有效内容,返回原图 if (min >= max || max - min < 10) return (Bitmap)gray.Clone(); // 第二步:强化拉伸(专门强化 180~240 浅灰色文字) Bitmap result = new Bitmap(width, height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int val = gray.GetPixel(x, y).R; // 核心:浅灰色文字强制增强 if (val >= 180 && val <= 245) { val = val - 30; // 把浅灰 → 变深灰 } // 标准对比度拉伸(强化文字边缘) int newVal = (int)(((val - min) / (double)(max - min)) * 220 + 20); newVal = Math.Clamp(newVal, 0, 255); result.SetPixel(x, y, Color.FromArgb(newVal, newVal, newVal)); } } return result; } /// /// OTSU 大津法二值化,自动寻找最佳阈值,适应各种灰度文字 /// private static Bitmap BinarizeOtsu(Bitmap gray) { int[] histogram = new int[256]; int totalPixels = gray.Width * gray.Height; // 统计直方图 for (int y = 0; y < gray.Height; y++) { for (int x = 0; x < gray.Width; x++) { int val = gray.GetPixel(x, y).R; histogram[val]++; } } // 计算 OTSU 阈值 double sum = 0; for (int i = 0; i < 256; i++) sum += i * histogram[i]; double sumB = 0; int wB = 0, wF = 0; double maxVariance = 0; int threshold = 128; // 默认 for (int t = 0; t < 256; t++) { wB += histogram[t]; // 背景像素数 if (wB == 0) continue; wF = totalPixels - wB; // 前景像素数 if (wF == 0) break; sumB += t * histogram[t]; double mB = sumB / wB; // 背景平均灰度 double mF = (sum - sumB) / wF; // 前景平均灰度 double variance = wB * (double)wF * (mB - mF) * (mB - mF); if (variance > maxVariance) { maxVariance = variance; threshold = t; } } // 白底黑字:大于阈值 -> 白,否则 -> 黑 var bin = new Bitmap(gray.Width, gray.Height); for (int y = 0; y < gray.Height; y++) { for (int x = 0; x < gray.Width; x++) { int val = gray.GetPixel(x, y).R; bin.SetPixel(x, y, val > threshold ? Color.White : Color.Black); } } return bin; } private static Pix BitmapToPix(Bitmap bmp) { using var ms = new MemoryStream(); bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png); ms.Position = 0; return Pix.LoadFromMemory(ms.ToArray()); } #endregion }