开源选帧工具claude-real-video:三层去重秒懂视频


给AI喂视频,你以为它真在看?真相是,你选对了150帧它就看懂了,选错了它只看了一套PPT。

视频理解这个活儿,视觉大模型一次只能吞下大概150张图。同一段十分钟的视频,你喂哪150帧,直接决定了AI是在“看视频”还是在“看图说话”。

一个叫claude-real-video的开源工具折腾了大半年,踩坑无数,最后发现核心就俩字:选帧。

本文把这套选帧逻辑扒干净,包括场景检测怎么避开动画片的坑、去重算法为什么从一层变成了三层、以及字幕和画面怎么硬焊在一起才不会错位。全程零代码基础也能听懂,纯讲思路和翻车经验。

喂视频还是喂文章,这是两种完全不同的姿势

先问一个特别基础的问题:同一件事,有一篇现成的文章,也有一段原始视频,给AI喂哪个更划算?文章省钱啊,几百个token就搞定了,视频光图片就得塞进去一百多张,烧钱速度快得飞起。那为什么还有人非要喂视频?

答案特别简单。文章是别人嚼过一遍吐出来的东西。写文章那个人看完了视频,自己判断哪些重要、哪些可以扔、哪些得重点说,然后按他的想法重新组织了一遍。AI读了这篇文章,学到的全是那个人的判断标准。视频里被剪掉的那部分内容,AI永远不知道发生过什么。

举个例子你就懂了。一个教学视频,老师演示怎么装一个软件。文章只会写“点击下一步,完成安装”。但视频里实际上弹出了个报错窗口,老师捣鼓了三十秒才过去。文章作者觉得这个报错不重要,直接删了。可真正上手的人八成会遇到一模一样的报错。AI读文章的话根本不知道有这个坑,喂视频的话它亲眼看到了那个报错窗口长什么样。

这俩的差距就像读目击者证词和亲自当目击证人。前者是二手信息,已经被人加工过了。后者是一手信息,虽然更贵,但模型能自己判断什么重要。这就是为什么哪怕视频更烧token,还是有一群人死磕这个方向。剩下的所有问题,都变成同一个问题:预算这么紧,怎么把这150张图花在刀刃上。

一百到一百五十张图,选哪帧直接决定命运

整个事情里最要命的约束就是预算。图片是上下文窗口里最贵的单位,没有之一。一张图抵得上几千个文字token。所以一旦接受“只能塞一百来张图”这个现实,问题就从“怎么多提取一些帧”变成了“怎么淘汰掉大多数帧”。

市面上大多数所谓的视频理解方案,实际干的事是每隔一秒或每十秒抓一张图,然后一股脑塞给模型。这种定时采样的毛病特别明显:主持人唠嗑十分钟,全是差不多的表情和手势,模型被重复信息淹没了。但就在某一秒里,主持人手里的道具突然掉了,这个关键瞬间刚好落在采样间隔之外,完美错过。

同一个毛病两种表现:要么重复信息爆满,要么关键信息漏光。根源都一样,采样器不知道画面里发生了什么变化,它只是按闹钟干活。那怎么判断哪一帧该留哪一帧该扔?思路得换一下,不能问“过了多久”,得问“变了多少”。

动画片和慢镜头,固定阈值在这俩面前就是摆设

第一步其实挺常规的,用ffmpeg自带的scene分数来检测场景切换。每次画面出现明显变化的时候就抓一帧,同时再加一条保底规则:如果某个镜头特别长一直没变化,也得隔一段时间抓一张,免得模型以为视频中间黑屏了。

但固定阈值这套打法在两类内容上直接崩掉。第一类是动画片。卡通角色拉伸、变形、做夸张表情,每一帧都在变,但变化是流畅的连续的,从来不会出现一个“咔嚓”一下的突变。scene分数永远达不到阈值,整个视频采样器就像睡着了一样,啥也没抓到。第二类是慢速摇镜头。摄像机缓缓扫过一片风景,画面一直在变,但变的速度特别慢,分数同样够不着线。

修这个bug的办法一点不酷,但确实管用。先跑一遍全视频,算出每一帧的scene分数,但不存图只存分。然后拿每一帧的分数去跟前面一段时间的滚动平均值做比较。如果这一帧的分数明显高过这段时间的平均水平,就说明这里“相对”发生了大变化。换句话说,动作片全程都炸裂,那它的门槛就自动抬高。风景片全程都温柔,门槛就自动降低。完全不需要人手工去调什么阈值,视频自己定自己的标准。经过这轮筛选,留下来的候选帧少了一大半,但还得再补一刀去重,因为连续几帧之间可能长得几乎一样。

一个去重不够用,我做了三个因为现实太狡猾

去重这事儿一开始想得特别简单:比较两张图长得像不像,像就扔掉后一张。结果被真实视频反复打脸,去重器一路从一层升级到了三层。每一层都对应一种“肉眼一眼看得出来但代码死活看不出来”的情况。

第一层叫全局通道。把图片缩小到16乘16像素的彩色小方块,然后数一数有多少个小方块的颜色发生了明显变化。变化比例低于百分之八的帧就直接丢掉。这里有个关键细节:必须用彩色信息,不能用黑白。因为有些场景切换是从纯红画面直接切到纯绿画面,亮度几乎一模一样。如果用黑白图去比,电脑会觉得“没变化”,但肉眼一看完全是两码事。另外比较对象不是紧挨着的前一帧,而是最近被保留下来的那几帧里挑一个窗口来比。否则采访镜头里那种“主持人脸——嘉宾脸——主持人脸”的来回切,每切回主持人的时候电脑会当成新内容又收一遍,但实际上同一个画面模型已经见过了。

第二层叫动作通道。百分比阈值有个结构性的盲区:画面里有个小人只占了百分之零点五的面积,就算他原地翻跟头,像素变化总量也到不了百分之八。这一帧明明是整个视频里最关键的动作瞬间,但去重器会毫不犹豫地扔掉。这个问题不是在实验室里发现的,是有用户跑了2181个真实视频之后跑来报的bug。修法是在32乘32的网格上再加一条硬规则:只要有一小块区域发生了剧烈变化——颜色变化超过45/255——这一帧就强制保留,不看百分比。小主体但动作猛,照收不误。

第三层叫稳定通道。全局通道还有个看不见的东西:画面大部分没动,但角落里有一行字幕变了,或者白板上多写了一行字,或者界面上某个按钮从灰色变成亮色。在16乘16的缩略图里这些变化只有零点几个像素,根本测不出来。这一层换了个更精细的192乘192签名,专门去搜那些跟窗口里所有已保留帧都不一样的小区域。匹配的时候允许正负一个像素的偏移,因为摄像机本身有轻微抖动和噪点,否则整个画面都会被判定为“全变了”。

这层的保护机制比检测本身还关键。它只在画面整体静止的时候才启动,动来动去的画面让前两层去管。候选像素得经过两轮筛选,第二轮的容忍度更严,能把烟雾消散那种软绵绵的变化滤掉,墨水出现和文字更新这种硬边界就能留下来。而且每次触发保留都会把门槛抬高然后慢慢降回去。如果有一面旗子一直在飘,它不会每秒钟都抢到一帧。但如果有一行新文字出现,第一次出现的时候门槛最低,直接放行。没有这个冷却机制,单靠这一层就能把全部帧预算烧光在一面破旗子上。

字幕和画面要是对不齐,模型就精神分裂了

画面选完了,还得把声音和字幕接上。文字来源分两种情况:视频自带内嵌字幕的直接提取,没有的就用本地Whisper跑一遍语音识别。这两个方向各有一个坑,各自花了老半天才查出来。

Whisper有个诡异的毛病:音乐纯享类的视频,它会在视频结束之后凭空再幻觉出一段台词,时间戳远远超出视频长度。做时间轴的时候如果不做保护,这条幽灵字幕就会混进去。解决方案是把所有字幕段落的结束时间强行卡死在视频总时长上,再加一秒钟容错,因为有些上游工具会把时长截断成整数。

第二个坑更隐蔽。把字幕和画面一起扔给模型,让模型自己按时间戳去配对,短视频完全没问题。但视频一长就开始阴悄悄地错位。某一个画面被模型引用的时候,对应的是前一句完全不相干的话。因为长视频里时间戳稍微偏一点,偏移就会累积。解决办法是不让模型自己动手。提前算好每一段字幕对应哪些帧,把时间轴焊死。每个字幕段前面挂一个列表,里面是落在它时间范围内的所有帧。超过一点五秒的纯静音段落单独作为一个纯画面区间,没有字幕只有图。一个时钟,全算好了,模型只管读包就行。

所有东西最后落盘成最朴素的格式:JPEG图片集、纯文本字幕文件、外加一个说明文档告诉模型这个包里每个文件是干嘛的。输出设计得越无聊越好,越通用,越能在不同的模型上跑通。这玩意儿不是为了炫技,是为了能插进任何支持图片输入的模型里直接干活。

代码全给你了,但有些事儿它真看不见

上面说的整套流程,现在已经打包成一个叫claude-real-video的开源工具,MIT协议随便用。最新的接口做成了MCP服务器模式,装完就能让各种客户端直接调。视频输入可以是本地文件也可以是网址,输出就是上面说的那三样东西。

再补两个预算层面的决策。所有帧在返回之前会被统一缩放到长边768像素。原图一张几兆,缩完之后信息几乎不损失,但上下文窗口能省出大量空间给更多帧。另外每个视频分析完会缓存结果,同一个视频追问第二个问题的时候不会重新下载也不会重新解帧。

关键帧加上对齐好的字幕,能告诉模型画面上有什么、说了什么。但镜头运动、剪辑节奏、说话人的语气这些信息,目前的方案一概抓不到。那是另一个层面的感知问题,不在本文讨论范围里。不过对于绝大多数日常场景——让模型看完东西再回答问题——这套选帧加融合的方案,在自己的电脑上就能跑,覆盖的范围已经挺吓人了。

代码地址放最后,有兴趣的自己拿去玩。

# needs Python 3.10+ and ffmpeg
pip install "claude-real-video[whisper]"

crv "https://youtube.com/watch?v=..."   # or a local file
→ frames/*.jpg      # the selected keyframes
→ transcript.txt    # timestamped, fused with the frames
→ MANIFEST.txt      # tells any LLM how to read the package


回头看整件事,核心就一个动作:选帧。承认预算有限,承认固定规则会失效,承认现实视频比想象中狡猾,然后一层一层补丁打上去。承认问题是解决问题的起点,发现问题藏在实际用户手里而不是论文里,行动上把去重从一层做到三层,最后对每一个被保留的帧负责。帧选对了,AI就在看视频。帧选错了,AI只是在翻一本缺了页的连环画。你猜用户更想要哪种?