diff --git a/CamScanner.cs b/CamScanner.cs index 447d216..cb038aa 100644 --- a/CamScanner.cs +++ b/CamScanner.cs @@ -461,13 +461,81 @@ public static class DocumentScanner { if (inkData[i] > 10 && varDataS[i] < 5 && varDataL[i] < 12) { - // 两级方差都低 → 折痕/阴影 double suppressRatio = (double)varDataS[i] / 5.0; int origVal = resultData[i]; resultData[i] = (byte)(origVal + (int)((255 - origVal) * (1.0 - suppressRatio))); } } + // --- 条带状折痕检测 --- + // 折痕特征:垂直或水平方向上,某列/行有大量连续暗像素 + // 文字不会形成这种长条状连续暗区域 + // + // 对每列统计暗像素比例,高比例的列标记为折痕条带 + int inkThreshForStripe = 30; // 墨迹强度>30才算暗像素 + double stripeRatioThresh = 0.4; // 一列中40%以上是暗像素就是条带 + int stripeHalfWidth = 3; // 条带半宽(左右各扩展3像素) + + // 垂直条带检测(按列扫描) + bool[] vStripe = new bool[w]; + for (int x = 0; x < w; x++) + { + int darkCount = 0; + for (int y = 0; y < h; y++) + { + if (inkData[y * w + x] > inkThreshForStripe) darkCount++; + } + vStripe[x] = ((double)darkCount / h) > stripeRatioThresh; + } + + // 水平条带检测(按行扫描) + bool[] hStripe = new bool[h]; + for (int y = 0; y < h; y++) + { + int darkCount = 0; + for (int x = 0; x < w; x++) + { + if (inkData[y * w + x] > inkThreshForStripe) darkCount++; + } + hStripe[y] = ((double)darkCount / w) > stripeRatioThresh; + } + + // 扩展条带宽度并抑制 + for (int i = 0; i < resultData.Length; i++) + { + int x = i % w; + int y = i / w; + + bool inStripe = false; + // 检查是否在垂直条带范围内 + for (int dx = -stripeHalfWidth; dx <= stripeHalfWidth; dx++) + { + int nx = x + dx; + if (nx >= 0 && nx < w && vStripe[nx]) { inStripe = true; break; } + } + // 检查是否在水平条带范围内 + if (!inStripe) + { + for (int dy = -stripeHalfWidth; dy <= stripeHalfWidth; dy++) + { + int ny = y + dy; + if (ny >= 0 && ny < h && hStripe[ny]) { inStripe = true; break; } + } + } + + if (inStripe && inkData[i] > 5) + { + // 在条带内:检查这个像素是否真的是文字 + // 文字在条带内的特征:小核方差高(笔画边缘锐利) + if (varDataS[i] < 10) + { + // 方差不高 → 不是文字,是折痕本身 → 推白 + resultData[i] = 255; + } + // 方差高 → 是文字,保留不动 + } + } + // --- 边缘阴影修复:从边缘向内扫描连续暗像素 --- byte[] shadowFlag = new byte[w * h]; int darkThresh = (int)(paperBright * 0.55);