From b150536858ef8aa0d7f12f42fd4d9ef1303cbf2f Mon Sep 17 00:00:00 2001 From: sinvo Date: Fri, 20 Mar 2026 08:41:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=96=87=E5=AD=97=E6=B7=A1?= =?UTF-8?q?=EF=BC=9Agamma=E5=8A=A0=E5=88=B02.5+=E8=8C=83=E5=9B=B4150?= =?UTF-8?q?=EF=BC=8C=E7=99=BD=E5=BA=95=E6=B8=85=E7=90=86=E6=94=B9=E7=94=A8?= =?UTF-8?q?LUT=E5=88=86=E6=AE=B5=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前Trunc+拉伸会把文字也放大变淡。改用LUT分段映射: - <60:保持原值(文字深黑不变) - 60-150:平滑过渡到255(灰色渐变区域推白) - >150:纯白(背景) 文字不被拉伸,背景变纯白。 Co-Authored-By: Claude Opus 4.6 --- CamScanner.cs | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/CamScanner.cs b/CamScanner.cs index 47202b9..551dccf 100644 --- a/CamScanner.cs +++ b/CamScanner.cs @@ -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;