简介:本文从攻防视角拆解“让OCR识别失败”的通用技术思路:利用字号悬殊的“大字藏小字/小字藏大字”隐写布局,诱导检测模型把区域误判为已识别,从而放弃二次检测,同时保持人眼可读。文章给出参数化实现方案、调参方法论、适用边界与安全合规提醒,帮助开发者在文档防爬、截图水印、内容保护等场景中做出理性取舍。
在文档防爬、截图溯源、内容版权保护等场景中,一个常见的诉求是:图片对人眼清晰可读,但对自动化OCR流水线不可读或误读。这并非“加密”,而是一种针对识别流程的误导性对抗。
需要先厘清一个前提:OCR不是单一模型,而是一条流水线——图像预处理、文本检测(定位文字区域)、文本识别(把区域转成字符)、后处理(语言模型纠错、版面还原)。攻击面存在于每一环,但性价比最高的攻击点,是文本检测环节。因为检测一旦漏检或误检,后续识别再强也无从发挥。
本文讨论的方法,核心不是“把文字藏得看不见”,而是让检测模型“以为这里已经处理过了”,从而主动放弃二次检测。这与传统隐写术(把信息藏进像素低位、频域)思路不同:它利用的是检测算法的区域合并与去重逻辑,属于“语义层”的对抗。
主流文本检测器(无论是基于分割的还是基于回归的)在输出阶段通常要做两件事:
隐写布局正是攻击第2点:在同一空间区域内叠放两种字号悬殊的文本,让检测器先检测到大字文本并生成一个覆盖整个区域的框;当它继续扫描该区域时,小字产生的候选框与大字框高度重叠,在去重阶段被抑制掉。结果是:检测器“认为”这块区域已经识别完毕,输出的是大字内容,小字内容被静默丢弃。
对人眼而言,两种字号差异足够大时,视觉系统可以分别解析——大字提供主干语义,小字作为独立文本被阅读。人眼的多尺度并行解析能力,远强于当前检测器的单尺度主导逻辑,这是该方法成立的根本不对称性。
据此衍生出两种布局策略:
两种策略并非互斥,实践中往往需要试错选型:不同OCR流水线的预处理尺度、最小检测尺寸、合并阈值都不同,没有万能参数。“见招拆招”本身就是方法的一部分。
关键可控变量有四个:大字字号、小字字号、行间距、字间距。原始实践给出的参考组合包括:
规律很明显:字号差异越大、间距越紧凑,掩护层越容易“吃掉”被掩护层。但间距过小会导致人眼阅读困难,因此需要在“机器误判率”和“人类可读性”之间取平衡点。
早期实现采用“全局从上到下、从左到右”的顺序逐字填充,导致小字在大字笔画间隙中的分布不均,人眼识别难度高。改进方案是按大字逐字填充:先确定每个大字字符的包围盒,再在其内部及周边区域按序排布小字。这样小字的分布与大字结构对齐,视觉上更规整,人眼阅读负担显著下降。
伪代码示意:
def layout_cover_text(big_glyphs, small_text, big_size, small_size):canvas = create_canvas(big_glyphs, big_size)idx = 0for glyph_box in big_glyphs.boxes: # 逐个大字包围盒for slot in grid_slots(glyph_box, small_size): # 盒内网格槽位if idx >= len(small_text):breakdraw_char(canvas, small_text[idx], slot, small_size)idx += 1return canvas
注意:以上为示意逻辑,实际需处理字形轮廓避让、抗锯齿、以及导出时的压缩损失。
调参不能靠猜,要建立可复现的验证闭环:
这里有个容易被忽略的坑:图片上传链路常带压缩。移动端往往有二次编码,导致小字笔画糊掉、检测框漂移。因此验证应尽量使用无损原图,并在移动端与桌面端分别测试;如果只能拿到压缩图,参数应留出更大字号余量。
一个常见反驳是:给图片加高斯模糊,OCR不就识别不了了吗?这个思路的问题在于决策主体错位。
模糊确实能破坏识别,但前提是有人判断“这里有文字需要模糊”。自动化流水线不会无缘无故对整图加模糊——如果它真的不分青红皂白全局模糊,那么一张正常文档截图也会被一并毁掉,OCR系统等于自废武功。反过来,一旦需要人类介入判断“哪里该模糊”,人类已经直接读懂了内容,OCR就失去了意义。
而本文方法的巧妙之处在于:它不破坏图像质量,只破坏检测决策。图片对人眼完全正常,对机器则产生“已处理”的错觉。防的是自动化,不防人——这正是其设计初衷,也是其边界。
必须诚实地指出该方法的局限:
给准备落地这类方案的开发者:
“让OCR识别不到”的本质,不是与识别模型正面对抗,而是利用检测流水线的决策惯性制造信息盲区。字号悬殊的叠层布局,以极低的实现成本换取了可观的自动化对抗效果,同时完整保留了人类可读性。理解它的原理,既能帮助内容保护方合理使用,也能帮助OCR系统设计方识别此类对抗样本、改进多尺度检测与分层识别能力——攻防两端,认知对称才是真正的安全边界。