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