简介:本文面向需要保护图片中文字信息的开发者,系统讲解如何利用人眼轮廓补全机制与对抗扰动,让OCR与多模态模型难以稳定提取图中文字。读者将掌握二值掩码提取、彩色光栅相位错位、多通道编码与局部形变等可落地方法,并理解白盒与黑盒场景下的扰动优化思路与工程权衡。
在内容审核、隐私保护、票据脱敏、验证码设计等场景中,一个常见的需求是:图片对人来说仍然可读,但机器视觉系统(OCR、多模态大模型)难以稳定识别其中的文字。这本质上是一个“人机感知差异”问题——人类视觉依赖轮廓补全与格式塔组织,而神经网络依赖像素统计与特征空间中的连续线索。本文从这一差异出发,给出一套可落地的技术方案,并讨论其边界与工程注意事项。
很多人第一反应是对图片做高斯模糊、加噪点或降低分辨率。这类方法的问题在于:
更合理的思路是:不破坏文字的整体语义结构,而是把文字信息“编码”到人眼擅长、机器不擅长的表征中。具体可以从两个层面入手——视觉感知层与特征表示层。
人类视觉系统具有轮廓补全能力:当一组局部不连续的条纹在空间频率、方向上一致,仅相位存在错位时,大脑会将其组织成完整的边界,这属于格式塔心理学中的知觉组织现象。利用这一点,可以把字符的笔画边缘替换为“光栅相位跳变”,人眼仍能读出字符,而机器提取到的边缘线索被显著削弱。
第一步:提取文字二值掩码。 将原图灰度化,使用Otsu自适应阈值分割得到字符掩码。Otsu在光照较均匀的文档图上表现稳定,若背景复杂可先用局部自适应阈值做粗分割,再做形态学开闭运算去除噪点。
import cv2import numpy as npgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)_, mask = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)kernel = np.ones((2, 2), np.uint8)mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
第二步:对字符轮廓做轻微局部形变。 用低频随机位移场对掩码进行重映射,让笔画边界产生不规则的微抖动。这一步的作用是打断机器视觉中过于“整齐”的笔画先验,同时人眼几乎无感。位移场应保持低频、小幅度(例如几个像素量级),否则会破坏可读性。
h, w = mask.shapelow_freq = cv2.resize(np.random.randn(h // 32, w // 32).astype(np.float32),(w, h), interpolation=cv2.INTER_CUBIC)dx = cv2.GaussianBlur(low_freq, (0, 0), 3) * ampdy = cv2.GaussianBlur(np.roll(low_freq, 7, axis=1), (0, 0), 3) * ampxx, yy = np.meshgrid(np.arange(w), np.arange(h))map_x = (xx + dx).astype(np.float32)map_y = (yy + dy).astype(np.float32)warped_mask = cv2.remap(mask, map_x, map_y, cv2.INTER_LINEAR)
第三步:生成周期性彩色光栅并做相位反转。 用正弦函数生成两组空间频率、方向相同但相位相差半个周期的光栅,分别填充字符内部与背景。这样字符内外具有相近的颜色分布(整体色调统计接近),但边界处出现条纹错位。对OCR而言,颜色统计不再提供“前景/背景”的强区分信号;对人眼而言,相位错位恰好构成可感知的轮廓。
freq, theta = 0.08, np.pi / 4x = np.arange(w)[None, :]y = np.arange(h)[:, None]phase = 2 * np.pi * freq * (x * np.cos(theta) + y * np.sin(theta))grating = 0.5 + 0.5 * np.sin(phase)grating_shift = 0.5 + 0.5 * np.sin(phase + np.pi) # 相位差半周期m = (warped_mask > 127).astype(np.float32)field = m * grating + (1 - m) * grating_shift
第四步:多通道编码与合成。 将不同方向、频率的光栅分别编码到R/G/B通道,并叠加少量局部条纹扰动,最后合成彩色图像。多通道编码进一步分散了单通道中的文字结构信息,使基于灰度或单通道边缘检测的识别路径更难奏效。
channels = []for i, th in enumerate([0, np.pi / 3, 2 * np.pi / 3]):ph = 2 * np.pi * freq * (x * np.cos(th) + y * np.sin(th))g = 0.5 + 0.5 * np.sin(ph + np.pi * m)channels.append(g)out = (np.stack(channels, axis=-1) * 255).astype(np.uint8)
需要客观说明:这类方法属于提高识别成本,而非绝对不可识别。面对专门针对光栅伪影做增强的模型,或在极高分辨率下保留完整相位信息的输入,仍存在被恢复的可能。因此实际部署中应结合业务风险等级,配合尺寸约束、动态随机化(每次生成不同频率/方向/形变种子)等手段提升攻击面。
仅靠视觉混淆还不够,因为多模态模型的视觉编码器可能仍从残余纹理中提取出与字符相关的特征。第二层思路是引入对抗扰动,让编码器输出的特征偏向攻击者指定的语义目标,从而降低目标文本的生成概率。
工程上要注意三点:其一,扰动幅度需与人眼可读性做联合评估,建议用结构相似性指标与人工抽检双重把关;其二,扰动应做随机化(随机步长、随机代理子集),避免固定模式被防御方学习;其三,整条管线应纳入版本管理与回归测试,因为模型迭代会改变迁移效果。
总结而言,图片防OCR的核心不是“把字弄糊”,而是重构文字信息的表征方式:用相位错位承载轮廓、用多通道分散结构、用对抗扰动干扰特征空间。理解人机感知差异,才能 design 出兼顾可用性与安全性的方案。