简介:本文围绕“如何让图片中的文字不被OCR识别”这一实际问题,系统讲解一种基于彩色对接光栅与对抗错觉的防护思路。读者将理解虚幻轮廓如何利用人机视觉差异隐藏字符信息,并掌握从灰度化、Otsu掩码提取、正弦光栅生成、相位反转、多通道合成到局部扰动叠加的完整实现流程,获得可落地的工程方案与参数调优建议。
在内容安全、验证码设计与敏感信息保护等场景中,一个反复出现的需求是:如何让图片对人眼依然可读,却让OCR(光学字符识别)或视觉语言模型难以稳定提取其中的文字。传统做法如加噪、模糊、旋转、字体扭曲,往往在“人眼可读性”和“机器不可读性”之间难以兼顾——噪声太弱对现代OCR无效,噪声太强人眼也无法辨认。近年来的研究提出了一条更有意思的路径:利用人类视觉系统的轮廓补全能力与神经网络特征空间的脆弱性,构造一种“人眼能看出来、模型看不出来”的图像表示。本文将从原理到实现,完整拆解这套思路,并给出可落地的工程方案。
要设计有效的防护方案,先要理解OCR与视觉语言模型的处理链路。典型流程包括:图像预处理(缩放、灰度化、二值化)、文本检测(定位文字区域)、文本识别(逐字符解码),以及在多模态模型中进一步的视觉编码器特征提取与跨模态对齐。
这条链路上有几个关键特点:
第三点正是防护方案的理论支点:如果我们把字符信息从“亮度对比”转移到“条纹相位关系”上,人眼仍能借助格式塔式的轮廓补全读出文字,而模型在特征提取后可能丢失这些线索。
人类视觉系统具有从局部不连续信息中组织出完整形状的能力,这属于知觉组织与轮廓补全的范畴。经典的“卡尼莎图形”表明,当若干图形的边缘在空间上对齐、但中间存在间隙时,人眼会“看到”一个并不存在的轮廓。利用这一机制,可以把字符的笔画边缘替换为两组条纹之间的相位错位:字符内部与背景使用空间频率、方向相同但相位相差半个周期的光栅,两者颜色分布相近,亮度对比被削弱,但相位在字符边界处发生突变。人眼将这些错位组织成字符轮廓,而机器看到的只是一片近似均匀的条纹纹理。
设光栅强度为 $I(x) = A \cdot \cos(2\pi f x + \phi)$。当字符区域与背景区域的相位差为 $\pi$(半个周期)时,两区域的条纹在边界处正好“反相”,形成明暗错位。这种错位在视觉上提供强烈的边界线索,但在全局统计上,两区域的平均亮度、颜色分布几乎一致,从而绕过了依赖亮度对比的检测器。若相位差过小,边界不明显,人眼难以补全;若过大,则接近普通条纹填充,反而容易被频域分析捕获。
单一方向的光栅在某个方向上可能被滤波器响应捕获。将不同方向、不同频率的光栅分别编码到不同颜色通道(如R、G、B),再合成彩色图像,可以进一步提升鲁棒性:任一通道单独看都只是普通条纹,只有人眼的多通道融合与轮廓补全机制才能还原字符。这本质上是把字符信息分散到多个子带中,提高了机器恢复的难度。
下面给出一条可复现的实现路径,核心参考彩色对接光栅部分,并加入局部形变与通道编码以增强效果。
首先将原图转为灰度图,使用Otsu阈值分割得到文字的二值掩码。Otsu方法基于类间方差最大化自动选取阈值,对背景较均匀的文字图效果稳定。
import cv2import numpy as npimg = cv2.imread("input.png")gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)_, mask = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)mask = mask.astype(np.float32) / 255.0 # 归一化到[0,1]
若原图为彩色文字或背景复杂,可先做轻度高斯模糊再阈值化,或改用自适应阈值。掩码质量直接决定后续相位反转的边界精度,建议对掩码做一次形态学闭运算以填补笔画内部小孔。
对掩码施加轻微的低频随机位移场,使笔画边缘产生非刚性抖动。这一步有两个目的:一是破坏OCR依赖的规则边缘先验,二是让相位错位边界更自然,避免被简单的边缘检测规则命中。
def smooth_random_field(h, w, scale=8):low = np.random.rand(max(h//scale, 2), max(w//scale, 2)).astype(np.float32)field = cv2.resize(low, (w, h), interpolation=cv2.INTER_CUBIC)return (field - 0.5) * 2.0 # 归一化到[-1,1]h, w = mask.shapedx = smooth_random_field(h, w) * 3.0dy = smooth_random_field(h, w) * 3.0grid_x, grid_y = np.meshgrid(np.arange(w), np.arange(h))map_x = (grid_x + dx).astype(np.float32)map_y = (grid_y + dy).astype(np.float32)mask_warped = cv2.remap(mask, map_x, map_y,interpolation=cv2.INTER_LINEAR,borderMode=cv2.BORDER_REFLECT)
位移幅度建议控制在2~5像素,过大将破坏字符可读性。
按通道生成不同方向与频率的正弦光栅。例如R通道用水平低频、G通道用垂直中频、B通道用对角高频。频率选择需兼顾人眼可辨与机器难还原:频率过高在缩放后易混叠为均匀灰,频率过低则条纹过粗、轮廓线索不足。
def grating(h, w, freq, theta, phase):y, x = np.mgrid[0:h, 0:w].astype(np.float32)proj = x * np.cos(theta) + y * np.sin(theta)return 0.5 + 0.5 * np.cos(2 * np.pi * freq * proj + phase)freqs = [(1/12, 0.0), (1/9, np.pi/2), (1/7, np.pi/4)]channels = []for f, th in freqs:base = grating(h, w, f, th, 0.0)# 字符区域相位反转半个周期shifted = grating(h, w, f, th, np.pi)ch = base * (1 - mask_warped) + shifted * mask_warpedchannels.append(ch)color_img = np.stack(channels, axis=-1)
关键点在于:字符内外使用同频同方向、仅相位差 $\pi$ 的两组光栅,通过掩码加权融合。融合处应做1~2像素的羽化,避免硬边产生额外的高频伪影,反而给检测器提供线索。
在合成前,对每个通道叠加小幅度的局部相位扰动,进一步削弱通道间的规律性。扰动应保持低频、小幅,避免破坏人眼可读性。
for i in range(3):noise = smooth_random_field(h, w, scale=16) * 0.15channels[i] = np.clip(channels[i] + noise, 0, 1)color_img = (np.stack(channels, axis=-1) * 255).astype(np.uint8)cv2.imwrite("protected.png", color_img)
最终图像在人眼看来是由彩色条纹构成的字符,笔画边界体现为条纹错位;而在灰度化与缩放后,字符的亮度对比被显著削弱,条纹相位信息也在特征提取中大量丢失。
上述方案属于“感知层”防护。若面向具备视觉编码器的多模态模型,还可叠加“特征层”的对抗扰动:在白盒场景下,利用目标模型梯度优化图像扰动,提高指定文本的生成概率偏移;在黑盒场景下,使用多个通用视觉编码模型作为代理,优化图像特征与目标语义特征之间的距离,从而提升扰动向其他模型迁移的可能性。工程上建议将对抗扰动幅度控制在人眼不可察觉范围内,并与光栅方案解耦调试,先保证感知层的人眼可读性,再逐步加入特征层扰动。
本文拆解了一条“以视觉感知差异对抗机器识别”的技术路径:通过Otsu掩码提取字符区域,用同频同方向、相位差半周期的彩色光栅分别填充字符与背景,把字符信息从亮度对比转移到条纹相位关系中,再辅以局部形变、多通道编码与局部扰动增强鲁棒性。其价值不在于“永久防住OCR”,而在于提供了一种兼顾人眼可读性与机器不可读性的工程思路。开发者可在此基础上,根据自身场景的识别模型类型与预处理链路,灵活调整频率、相位差与扰动强度,形成适配业务的安全防护方案。