简介:本文从人机视觉感知差异出发,详解一种让图中文字“人眼可读、机器难识”的图像处理思路:用二值掩码提取字符轮廓,以彩色光栅相位错位重构笔画边界,再叠加轻微形变与通道编码扰动,削弱视觉编码器的特征提取。读者可掌握可落地的实现步骤、参数取舍与效果评估方法。
在验证码、内容防爬、敏感信息脱敏等场景中,一个常见诉求是:让图片里的文字对人眼依然清晰可读,却给自动化文本识别流程制造足够大的障碍。传统的做法是加噪、扭曲、干扰线,但这些手段往往同时降低了人类识别的体验,且面对基于深度学习的识别模型时防护效果有限。近年来,多模态大模型在视觉理解上的能力快速提升,使得“只加噪声”的思路愈发吃力。
本文围绕一个更精细的方向展开:利用人类视觉系统的轮廓补全能力与神经网络特征空间的脆弱性之间的差异,构造一种“人机感知不一致”的图像。核心手段有两个——彩色对接光栅(Colored Abutting Grating)与对抗错觉(Adversarial Illusion)。前者负责在感知层制造相位错位,后者负责在特征层施加定向扰动。下面从原理到实现逐步拆解。
要理解方案的合理性,先要明确对手是谁。当前的文字识别与多模态理解模型,通常经历如下流程:图像缩放与归一化 → 视觉编码器提取特征图 → 序列解码或跨模态对齐 → 输出文本。这个链条上有两个关键特性:
因此,有效的策略不是“把图弄脏”,而是“改变模型所依赖的线索形态”。彩色对接光栅正是做了这件事:它并不破坏字符的整体形状,而是把连续的笔画边缘替换成两组光栅之间的相位错位。人眼依靠格式塔心理学中的知觉组织与轮廓补全,能把局部不连续的条纹“脑补”成完整字符;而模型在缩放与特征提取过程中,细密的相位关系容易被稀释,字符形状判断随之失准。
整体流程可概括为:灰度化 → 掩码提取 → 轮廓微形变 → 光栅生成与相位反转 → 多通道编码合成。下面给出关键步骤与示意代码。
先对原图做灰度化,再用 Otsu 阈值分割得到字符的二值掩码。Otsu 的优点在于自适应选择阈值,对光照不均的图片比固定阈值更稳健。
import cv2import numpy as npgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)_, mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 视需要做形态学闭运算,填补笔画内部小孔洞kernel = np.ones((3, 3), np.uint8)mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
直接用原始掩码生成的边界过于规整,容易被模型稳定捕捉。可借助正弦函数叠加低频随机位移场,对字符轮廓做轻微局部形变。位移幅度要克制——过大则人眼也难辨认,过小则起不到干扰作用,实践中建议控制在几个像素量级。
h, w = mask.shapeyy, xx = np.mgrid[0:h, 0:w]# 低频随机位移场:可用低分辨率随机场插值放大得到dx = amp * np.sin(2 * np.pi * xx / period + phase_x) + low_freq_noise_xdy = amp * np.sin(2 * np.pi * yy / period + phase_y) + low_freq_noise_ymap_x = (xx + dx).astype(np.float32)map_y = (yy + dy).astype(np.float32)mask_warped = cv2.remap(mask, map_x, map_y, cv2.INTER_LINEAR)
这是方案的核心。生成两组空间频率、方向相同但相位相差半个周期的彩色光栅,分别填充字符区域与背景区域。结果是字符内外颜色分布接近,而字符边界处出现条纹错位。
def grating(h, w, freq, theta, phase, color):yy, xx = np.mgrid[0:h, 0:w]proj = xx * np.cos(theta) + yy * np.sin(theta)wave = 0.5 + 0.5 * np.sin(2 * np.pi * freq * proj + phase)return wave[..., None] * np.array(color)[None, None, :]phase_shift = np.pi # 半个周期g_char = grating(h, w, freq=0.08, theta=np.pi/4, phase=0.0, color=(255, 120, 60))g_bg = grating(h, w, freq=0.08, theta=np.pi/4, phase=phase_shift, color=(255, 120, 60))m = (mask_warped > 127)[..., None].astype(np.float32)out = g_char * m + g_bg * (1 - m)
注意频率与方向的选择:频率过高会在缩放阶段被抹平,频率过低则相位错位不够细密,人眼补全效果差。方向建议与笔画主方向保持一定夹角,使边界错位更明显。
进一步把不同方向、不同频率的光栅编码到不同颜色通道,并在局部叠加轻微条纹扰动,再合成为彩色图像。这样做既丰富了颜色分布,也让不同通道承载不同的相位线索,增加模型统一建模的难度。
ch_r = grating(h, w, 0.06, np.pi/6, 0.0, (255, 0, 0))[..., 0]ch_g = grating(h, w, 0.09, np.pi/3, np.pi, (0, 255, 0))[..., 1]ch_b = grating(h, w, 0.07, np.pi/2, np.pi/2, (0, 0, 255))[..., 2]color_img = np.stack([ch_r, ch_g, ch_b], axis=-1)color_img = np.clip(color_img * m + color_img * (1 - m) * 0.9, 0, 255).astype(np.uint8)
至此,感知层的构造完成:人眼看到的仍是可辨识的字符轮廓,而像素层面已不存在连续、稳定的笔画边缘。
仅有感知层构造,对部分鲁棒性较强的模型仍可能不够。对抗错觉的思路是:通过优化图像扰动,让视觉编码器提取的特征偏向攻击者指定的语义目标,从而进一步降低正确文本的生成概率。按攻击者掌握的信息量,可分两种情形:
需要强调的是,对抗错觉属于增强手段,工程落地时应优先保证感知层构造的正确性——光栅的频率、方向、相位差与掩码质量,才是决定“人眼可读、机器难识”这一基本效果的主导因素。对抗扰动更适合在受控评估环境中作为附加项验证。
评估应分两条线进行:
调参经验上,可遵循以下优先级:
该方案适合用于自有内容的防自动化抓取、验证码增强、演示性脱敏等正当场景。需要明确的是,任何以规避他人系统安全机制、绕过访问控制为目的的使用都不应被鼓励。此外,随着识别模型持续演进,单一静态方案的防护效果会衰减,实际系统中建议结合动态参数、随机化光栅方向与频率、定期更新策略等方式维持有效性。
总结来看,这一思路的价值不在于某个具体参数,而在于提供了一个可复用的设计视角:从人类感知的组织规律出发构造线索,同时针对神经网络的特征提取弱点施加扰动,在“可读”与“难识”之间寻找平衡点。掌握掩码提取、相位对接与通道编码这三个基本环节后,开发者可以按自身场景灵活组合,形成适配的图像处理管线。