新增条带状折痕检测:按列/行投影识别窄条暗带
深色窄折痕的边缘方差高(亮暗跳变),双级方差检测不到。 新增条带检测:按列/行统计暗像素比例,超过40%的列/行 标记为折痕条带,条带内低方差像素推白,高方差像素(文字)保留。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -461,13 +461,81 @@ public static class DocumentScanner
|
|||||||
{
|
{
|
||||||
if (inkData[i] > 10 && varDataS[i] < 5 && varDataL[i] < 12)
|
if (inkData[i] > 10 && varDataS[i] < 5 && varDataL[i] < 12)
|
||||||
{
|
{
|
||||||
// 两级方差都低 → 折痕/阴影
|
|
||||||
double suppressRatio = (double)varDataS[i] / 5.0;
|
double suppressRatio = (double)varDataS[i] / 5.0;
|
||||||
int origVal = resultData[i];
|
int origVal = resultData[i];
|
||||||
resultData[i] = (byte)(origVal + (int)((255 - origVal) * (1.0 - suppressRatio)));
|
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];
|
byte[] shadowFlag = new byte[w * h];
|
||||||
int darkThresh = (int)(paperBright * 0.55);
|
int darkThresh = (int)(paperBright * 0.55);
|
||||||
|
|||||||
Reference in New Issue
Block a user