修复文字淡:gamma加到2.5+范围150,白底清理改用LUT分段映射

之前Trunc+拉伸会把文字也放大变淡。改用LUT分段映射:
- <60:保持原值(文字深黑不变)
- 60-150:平滑过渡到255(灰色渐变区域推白)
- >150:纯白(背景)
文字不被拉伸,背景变纯白。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 08:41:26 +08:00
parent 0ddef2fc7c
commit b150536858

View File

@@ -367,18 +367,14 @@ public static class DocumentScanner
Marshal.Copy(resultData, 0, normU8.Data, resultData.Length);
// --- d: 非线性对比度增强 ---
// gamma 曲线压暗 + 线性拉伸加深,两步结合:
// gamma 保留笔画间灰度层次
// 线性拉伸让文字整体更黑
// gamma 曲线压暗,保留笔画间灰度层次
// 输出范围压到 0-150给白底清理留空间
byte[] lut = new byte[256];
for (int i = 0; i < 256; i++)
{
double x = i / 255.0;
// gamma=2.2 压暗
double y = Math.Pow(x, 2.2);
// 再做线性拉伸:输出范围压缩到 0-200之后白底清理会把200+推白
// 这样文字更黑但笔画间差异按比例保留
int val = (int)(y * 200.0);
double y = Math.Pow(x, 2.5);
int val = (int)(y * 150.0);
if (val > 255) val = 255;
lut[i] = (byte)val;
}
@@ -397,17 +393,37 @@ public static class DocumentScanner
contrasted.Dispose();
// --- f: 白底清理 ---
// gamma后文字大约在 0-80背景大约在 150-200
// 阈值 160>160 的推白(背景),<160 的保留(文字)
Cv2.Threshold(sharpened, sharpened, 160, 255, ThresholdTypes.Trunc);
Cv2.ConvertScaleAbs(sharpened, sharpened, 255.0 / 160.0, 0);
// 用 LUT<60 保持原值文字60-150 快速过渡到白色,>150 纯白
byte[] whiteLut = new byte[256];
for (int i = 0; i < 256; i++)
{
if (i <= 60)
{
whiteLut[i] = (byte)i; // 文字保持不变
}
else if (i <= 150)
{
// 平滑过渡到白色
double t = (double)(i - 60) / 90.0;
whiteLut[i] = (byte)(60 + (int)(t * t * 195)); // 60→255
}
else
{
whiteLut[i] = 255; // 纯白
}
}
Mat whiteLutMat = new Mat(1, 256, MatType.CV_8U, whiteLut);
Mat cleaned = new Mat();
Cv2.LUT(sharpened, whiteLutMat, cleaned);
whiteLutMat.Dispose();
sharpened.Dispose();
// 转回3通道
Mat output = new Mat();
Cv2.CvtColor(sharpened, output, ColorConversionCodes.GRAY2BGR);
Cv2.CvtColor(cleaned, output, ColorConversionCodes.GRAY2BGR);
gray.Dispose();
sharpened.Dispose();
cleaned.Dispose();
src.Dispose();
return output;