Temp/OcrFinalHelper.cs
2026-05-15 11:34:44 +08:00

206 lines
6.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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");
/// <summary>
/// 针对白底黑字/截图优化的中文识别(强化浅灰色文字处理)
/// </summary>
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;
}
/// <summary>
/// 强化版对比度拉伸(专门优化:浅灰文字 + 低对比度文字)
/// 不破坏图像、不炸图、Tesseract 可正常识别
/// </summary>
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;
}
/// <summary>
/// OTSU 大津法二值化,自动寻找最佳阈值,适应各种灰度文字
/// </summary>
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
}