关于利用人类的视觉缺陷进行人机识别理论设想
/ 12 min read
这个设想来自于一篇2025.5.30的论文—— Time Blindness: Why Video-Language Models Can’t See What Humans Can?
原PO出处:https://arxiv.org/abs/2505.24867
文中提到的time blindness,即“时间盲视”现象,引起了我的兴趣
为什么视觉语言模型看不到人类能看到的东西?
原文中为研究设置了一个基准,
叫做SpookyBench,合成了一堆由噪点组成的视频,是黑白的。
随便暂停一下,这个视频的每一帧,看起来都像是随机的雪花点或者电视噪音。但是播放的时候,我们可以非常明确的看到一只鹿。这个鹿我甚至都没法截图,因为只要截图出来就必是噪点图。
这篇论文就拿451个这样的视频,组成了一个基准,去视觉大模型进行测试。
人类可以毫不费力地识别出这些视频中的形状、文本和图案,准确率超过98%。
而大模型的准确率,为0%。
听起来令人匪夷所思,怎么天上地下无所不能的AI连最简单的三角形或是圆形都分辨不出来了?
原因其实特别简单:
AI是空间维度上的王者,但却是时间维度上的瞎子
当人们接收到信息的传递的时候,不管是出于什么形式,本质上都是在运动的,当大模型面对一个视频的时候,想要获取视频中讲了些什么,他们所做的是从视频中抽帧,识别每个帧的信息,将这些信息汇总,总结出这段视频的信息。
但这样做,无论抽帧的间隔多小,永远都是离散的散点,无法形成帧与帧之间的“流”,而人却恰好能够识别“流信息”\
这其实,就是,时间维度
在心理学中有一门学科叫做格式塔心理学,其中有一个非常重要的原则叫做 “共同命运法则”(Law of Common Fate) 这个法则是说我们的大脑会自动的把朝着同一个方向运动的物体识别为一个整体
所以当看到那个“噪点鹿”的视频时,作为人类的我们根本不需要努力,我们大脑里的共同命运法则就自动启动了。它帮你把所有一起往上移动的噪点归为一类,识别为“鹿”,把所有一起往下移动的噪点归为另一类,识别为“背景”。
我们之所以能看到鹿,不是因为我们看见了鹿,而是因为我们看见了运动本身
但AI不行。它没有我们这套“共同命运法则”的视觉系统。
它的架构,论文里叫 “Spatial Bias”空间偏见,决定了它只能先去识别空间上的特征。
它看每一帧,都是一堆杂乱无章的噪点。
但它无法从时间的维度上,去发现这些噪点之间“共同的命运”,所以,它看不到那只鹿。
这个问题,在论文中,被称为。
时间盲视,Time Blindness。
我们活在流中,而AI活在帧中。
这个世界对我们来说,首先是连续的、流动的、充满过程的。
而对AI来说,这个世界首先是离散的、静态的、充满物体的。
那么我们完全可以通过算法生成这样的视频进行人机识别,或者是动态图像,通过人类大脑的缺陷进行人机识别
除此之外,人类的视觉也有缺陷
在20世纪50年代,眼动领域有一个实验证明了一个事情,就是,人眼在注视时并非完全静止,而是不断进行微小的运动。
正是这些不自主的眼球运动,保证了我们对静止图像的持续感知。
这样的视错觉图,基本上都是利用了我们这个会自己运动的特征,来做出动态效果的。
为了使人类能够看见,视网膜上的图像必须持续发生一定程度的运动。
反过来讲,如果某个视野(无论其大小、颜色或亮度)保持严格的静止,那么在1~3秒内,该区域就会在视野中逐渐消失**。**
视觉科学里有个差不多的理论是特克斯勒消逝效应,说的是当人们长时间注视一个固定点时,周边视野中不变的刺激会逐渐淡化甚至消失。
听起来挺绕的,但如果你想试一下,刻意控制眼球静止不动的话,你可以放大这张图,然后刻意的牢牢盯住中间的十字。
应该可以感觉到十字周围的颜色在慢慢消失,然后变成一片灰白色
著名的特克斯勒消逝效应告诉我们:没有变化,则等于没有信息
所以我们不光可以利用人类大脑的缺陷,也可以利用图像生成
特克斯勒褪色效应
让人在盯住中间的十字的时候,旁边的颜色不是消失而是变成指定的颜色
然后让用户在无极调色盘上选取最符合他所看到的颜色
就可以进行人机识别
每次出现的题目可以是完全随机,完全不同的视觉图片
实现理论如下:\
Troxler效应依赖的是视觉适应 + 静止刺激。
我们可以通过算法人为地制造渐变,引导人眼在适应过程中“看到目标色”。
方法一:物理渐变模拟法
使用算法控制每个像素颜色随时间缓慢变化: 原色 → 混合背景色 → 目标色
例如:
color(t) = mix(mix(original_color, background_color, fade1(t)), target_color, fade2(t))
其中 fade1(t) 和 fade2(t) 是两个平滑的缓变函数
这样,在人眼适应的同时,图像也在缓慢、几乎察觉不到地向目标色转变。
最终,人就会主观感知到颜色从原色 → 目标色的变化,而非消失。
方法二:视觉对比操控法 利用互补色或对比色干扰来“欺骗”人眼:
背景色与目标色设计成视觉对立关系。
当原色被视觉系统“抑制”后,残留的对比效应让人“看到”目标色。
例如:
原色是蓝色,目标色是黄色。
让背景逐渐变为浅蓝,原蓝点褪去时,视神经残像会呈黄调。
从视觉上就达到了“褪色变黄”的效果。
这种方法在实验心理学中叫做afterimage color control。
方法三:算法生成思路\
伪代码结构如下
import numpy as npfrom PIL import Image, ImageDraw
def generate_troxler_custom(img_size=(800,800), dot_positions=[...], original_colors=[...], target_color=(R,G,B), background=(128,128,128)): img = Image.new("RGB", img_size, background) draw = ImageDraw.Draw(img)
for pos, color in zip(dot_positions, original_colors): draw.ellipse((pos[0]-30, pos[1]-30, pos[0]+30, pos[1]+30), fill=color)
# 用时间控制颜色变化 # fade progression t ∈ [0,1] frames = [] for t in np.linspace(0, 1, 60): # 60帧动画 frame = Image.new("RGB", img_size, background) d = ImageDraw.Draw(frame) for pos, color in zip(dot_positions, original_colors): # 模拟褪色 blend1 = tuple(np.array(color)*(1-t) + np.array(background)*t) blend2 = tuple(np.array(blend1)*(1-t/2) + np.array(target_color)*(t/2)) d.ellipse((pos[0]-30, pos[1]-30, pos[0]+30, pos[1]+30), fill=tuple(map(int, blend2))) frames.append(frame)
# 输出为GIF或逐帧视频 frames[0].save("troxler_custom.gif", save_all=True, append_images=frames[1:], duration=100, loop=0)或者还可以利用低频闪烁以增强适应效果
背景轻微噪点或随机抖动能延缓视觉适应,使目标色更清晰。
若用 WebGL 或 Canvas 实现,还可以实时调节目标色。
最终成果:
from PIL import Image, ImageDraw, ImageFontimport numpy as np
def generate_troxler_custom( img_size=(800, 800), dot_positions=None, original_colors=None, target_color=(180, 100, 255), background=(180, 180, 180), duration=100, steps=60): if dot_positions is None: w, h = img_size r = 200 # 圆环半径 cx, cy = w // 2, h // 2 # 四个点位置(上下左右) dot_positions = [ (cx - r, cy), (cx + r, cy), (cx, cy - r), (cx, cy + r) ]
if original_colors is None: original_colors = [ (255, 80, 80), # 红 (80, 255, 80), # 绿 (80, 80, 255), # 蓝 (255, 255, 80) # 黄 ]
frames = [] dot_radius = 40
for t in np.linspace(0, 1, steps): frame = Image.new("RGB", img_size, background) d = ImageDraw.Draw(frame)
cross_len = 20 cross_width = 4 cx, cy = img_size[0] // 2, img_size[1] // 2 d.rectangle([cx - cross_width // 2, cy - cross_len, cx + cross_width // 2, cy + cross_len], fill=(0, 0, 0)) d.rectangle([cx - cross_len, cy - cross_width // 2, cx + cross_len, cy + cross_width // 2], fill=(0, 0, 0))
for pos, color in zip(dot_positions, original_colors): blend1 = tuple(np.array(color) * (1 - t) + np.array(background) * t) blend2 = tuple(np.array(blend1) * (1 - t / 2) + np.array(target_color) * (t / 2)) d.ellipse( (pos[0] - dot_radius, pos[1] - dot_radius, pos[0] + dot_radius, pos[1] + dot_radius), fill=tuple(map(int, blend2)) )
frames.append(frame)
frames[0].save( "troxler_custom.gif", save_all=True, append_images=frames[1:], duration=duration, loop=0 )
print("✅ 已生成 troxler_custom.gif")
# 运行生成generate_troxler_custom()使用方法
确保已安装 Pillow:
pip install pillow numpy
将以上代码保存为 troxler_custom.py
运行:
python troxler_custom.py
会在当前目录生成 troxler_custom.gif,双击打开即可。
注视中间的“+”,几秒后四个彩点会渐变成紫色。
\
在 generate_troxler_custom() 调用里可以传参数:
generate_troxler_custom(
\ target_color=(0, 255, 255), # 目标变青色
\ background=(220, 220, 220), # 更浅的背景
\ steps=80, # 变色更慢
)