Plaidctf2024-ICMP | 只完成了1/15的复现
ヽ( ^ω^ ゞ )
ICMP
Reporter. bluepichu
Preliminary Investigator. iamcorwin
Type. Unexplained Event
Description. (Inter-Corporeality Messaging Protocol) We left an ouija board out as a joke, but then it started moving and it stopped being a joke.
Hypotheses. …ghosts?
Attachments.
The Happening
Reward. 250 points
write up
先看爆出来的结果(视频前1/15):
(存在后期添加空格)
好的,现在我们已经知道这个闹鬼小视频要说啥了:
它会给我们一个Base64编码。开始的字母为大写,选中YES
代表按下Caps Lock
键,选中NO
代表/
(slash),good
的第一个o
代表+
,bye
的y
代替的是=
。
然后他就开始在这个取字板上漂移了两个小时了。
我们的目标是把它取到的字用脚本爆出来,正确率如上图,除了后期加了空格没有别的处理了。
虽然后期编码的部分很难去校对,但是前面语句传达信息的部分可以看到100%正确,每个单词都没有错字,漏字。
思路大致是先对原视频做一点预处理,然后追踪中间的取字板,同时记录下追踪框的中心点坐标(也可以是中心偏下的点),一连串的中心点坐标完全可以表达取字板的运动信息,和一张固定的坐标表比对就可以知道现在是运动还是静止,静止的话选中了什么字。
Why not Deep Learning?
因为我犟。
其实真没啥别的原因,只是直觉上感觉深度学习为这个炼一个丹比较耗费人力
首先数据准备就要标注很多,目标也不明确。是要直接目标检测到每一个具体的字母还是要做单纯的取字板追踪。
前者太多数据了,而且必须要把取字板也截到图像里,复杂的光线+不太优质的像素注定了这是一个要炼相对久的大丹;后者则太亏了,仅用深度学习做到这一步后续还是有很多的处理,大材小用。
总之,我觉得作为一个限时赛题不太想用这样的方式解决,我也不太乐意炼一颗不太能迁移使用的丹,所以完全都是依托opencv做的。
当然,也可能是我对这些任务不够熟悉,没有更好的解决思路。(☍﹏⁰)
或许真有符合要求够用的某个预训练模板可以简单快速的梭了。
在此博客之后的讨论中都不包含任何与深度学习有关的内容。
我把这次的脚本整理成了几个并不实用的小工具:
Preprocessing
先看一下这个原图
- 视频里面灯光是闪动的,显然对画面干扰太大了
- 两个小时的视频对于追踪仍然有挑战,依旧需要切片
- 视频里面的信息过暗了,人眼都看不清机器怎么识别(机器确实不能用人眼的要求去看,不过处理过后的数据会有显著提升)
ROI
这个处理在最后的解题版本里有可能是没有用的,不过我没有做对比实验,这里仅介绍一下做了这个处理以及为什么
ROI(region of interest),就是从原始图像中选择一个区域作为感兴趣区域,目的就是排除不感兴趣区域的干扰,同时仅对感兴趣的部分进行运算。既可以提高准确率,只对部分区域高精度运算也可以节省算力加快速度。
ROI的选取当然可以是不规则的,除了矩形也可以是一个圆形、一个多边形,或者是按照像素颜色选取,比如所有的黄色部分…
不过这道题当时的处理只是很简单的裁切掉四周的灯光,因为在一开始的算法逻辑是运动检测以及静止帧判断而不是追踪和记录坐标,闪动的灯光非常干扰运动的判断,而且存在也不提供什么价值就直接裁掉了。
有关运动
与追踪
的讨论在后文还会有几次提及。
Split
把视频切分成200份人也可以做这个题了,但是给机器只需要5份
总之我的技术还没办法做到稳稳的追踪这个视频里的取字板两个小时的,时间越长,准确度越低。所以需要把每个视频切分的小一点,这样压力就小一点。
虽然最后因为各种原因还是切成了等分的15份,不过其实个人觉得10份以内应当是可以完成任务的,5份的话有点挑战(。
当然,切分之后的衔接也需要人眼稍微检查一下,这也是同样是需要切分,切给机器更有优势的原因。
Feature extraction
仅以保证追踪效果对图像进行处理
大致对图像做了这些操作,和不做处理的原图的对比的确效果有显著提升
1 | def preProccessing(image): |
预处理前后对比
这样预处理的思路是观察转化为灰度之后的视频发现取字板中间有了一个圆形亮环,在取字板移动大部分像素都模糊失去特征的时候这个白色圆环变化较小,所以就尽可能使这个白环更加明显。
开运算与膨胀使用了不同大小的卷积核,首先卷积核开的很小是为了精准的把白环放大,而不被四周较暗的颜色影响(尤其在一开始对于没有处理过的灰度图来说),然后在完成所有图像处理后在不向上膨胀运算使提取出的白色更加明显。
Trace & Record
Trace
从代码来看就是按照模板调用了一个openCV的函数,不过我们也可以来稍微简单了解一下这个函数的背后实现。
openCV目前提供八种不同的目标追踪工具,以及一个多目标追踪。表面上各有优劣,实际上体验下来我觉得有一些已经快要被时代淘汰了(
在这个题目的案例中,我们使用了CSRT
追踪器,在openCV里实际上是用C++实现的这篇文章——CSR-DCF
因为本人目前在计算机视觉还是马喽水平,所以只能根据自己理解简单讲讲,或许之后会好好精读一下这篇。简单来说,CSRT
是在DCF
框架的基础上同时考虑空间可靠性
与通道可靠性
。加上空间可靠性主要可以解决DCF
的循环样本训练的滤波器在边缘可信度不高的问题,也能够更好的跟踪到非矩形的目标。通道可靠性则主要是更加灵活的分配特征通道的权重,让表现更好的特征通道在运算时占更多比重。
然而比较可惜的是,由于形态学上的膨胀腐蚀操作对于彩色图像表现效果不突出,以及这次我更希望强调白色圆环的突出,CSR-DCF
在空间可靠度带来的增强可能并不显著,因为这项改进是依靠颜色直方图来实现的,然而就以原图单调的色彩或许彩色图片也不会有更好的效果。 尽管openCV是开源的,截至写博客的时,我还没有查看openCV的库CSRT
相关源码对于特征提取一共使用了几种,这与加入通道可靠性带来的效果提升息息相关。
或许研究的再深入一些在连续追踪的结果上可以做到更久的时长。
Record
就是把追踪框的中心坐标点记录下来输出到txt中,没有什么别的需要注意的。
Search & Output
Search
首先是寻找静止帧,思路是根据抓取到的坐标来判断,从当前帧开始数的第三帧,第五帧与第一帧的距离小于某个范围即认为是静止,然后跳过一定的帧数。在写博客的过程中,我发现其实这个思路也是一种目标追踪的思路,详见后文更多追踪
。
再是寻找对应的字母,通过一个小工具把字母表的坐标记录下来,然后再算静止帧与表中字母位置的距离。为了提高一点容错,在遍历坐标的时候不是选择符合阈值的就停下(此时的准确性已经很高了),而是计算所有的距离选择最近的同时符合阈值的。
Output
其实这里应该多做一个工作就是比如在接收到类似‘YES’之类的结果之后,把之后的输出切换大小写这样的,但是如你所见我并没有作这一步还(((,而是直接输出了。
然后我还把符合静止帧但是找不到坐标表中对应的情况做了一个输出,一方面是视频开始时取字板有一段时间相对静止或者移动缓慢的情况需要区分,另一方面这也方便了调试。
All DOWN?
从上面的结果来看,在它开始选取BASE64编码之前,语句能够正常无误的被选中,所以我们就假设这样的流程下来的结果在准确度上不会有问题,那么是否就能完成左右的工作吗?
显然我只完成了1/15的原因是因为后面没爆出来。
问题出在在第2/15的时候,取字板多次的选中了字母A
,而字母A
又恰好在边上,通过预处理的图像在这里会因为左侧太亮了而使追踪框里的内容与我们希望的圆环有较大改变
目标追踪算法是包含一个有关update的内容使其有更好的学习和泛化能力,他总是以最近的追踪框里的内容来认为我们追踪的东西,所以之后就会出现一个很尴尬的问题那就是当取字板划过月亮的时候,机器很自然的认为月亮就是我们要追的东西,然后就一直stuck在这里。
我们的追踪失败了。
出现这样的问题不得不说的就是PlaidCTF的主办方真的很有意思能想出这样一个点子,并且使用实拍来完成它,使得这个任务变得富有挑战性和趣味性。
最简单的解决方案就是直接以此为分界重新切片,在技术上只需要找到对应的帧数就好,也不难实现。
不过或许还有一个可以尝试的思路就是不要使用裁切过的视频,因为这能够为边缘在形态学处理的时候提供更多的可能的暗部信息。
追踪与运动的区别还在于追踪的概念是对一个已经确定的目标,而运动则是在全局画面中发现移动的目标,而最后使用的追踪的流程并不与闪动的灯光相关,所以也不用担心算法反复选中运动的灯光
。
后记
这个题过了这么久还在研究完全是以熟悉opencv库与计算机视觉技术的角度出发,在没有引入简单的预训练模型时,就从人工智能图像处理的角度看能够做到什么程度。效果我觉得还行,差强人意吧。
இдஇ
看上去是那么的流畅,但是实际上踩了超级多坑
一开始的时候第一个思路是运动检测获取到取字板的bounding box,然后以此为ROI,作文字识别。
这样做的问题有以下几点:
- 灯光闪动影响运动检测(裁切解决)
- 文字识别的准确度不够高,同时无法区分
GOOD BYE
中的O
与Y
与字母表中的O
和Y
的区别 - 运动检测对于这个清晰度不是很高,加上环境灯光变化带来的明暗变化,即使追上取字板,内部的文字有可能不够清晰,或者追不上
- 首先要把所有静止选中的帧提取出来,但是依靠比对前后帧来做的静止帧提取,会有一个字选中多次或者漏字的情况,准确率不够高的情况更难判断什么时候是连续选中同一个字母两次。
下面是尝试的解决方法(与失败原因):
- 放弃文字识别,模板匹配的效果也不好,最后还是考虑建一个坐标表,拿来区分
GOOD BYE
中的O
与Y
与字母表中的O
和Y
- 更换运动检测的算法,从一开始的前后帧比较变为背景差值(可以缓解这个框四处乱跳不能跟上的问题,但是长宽比变动很大,但是仅靠中心点也得不到准确的坐标)
- 调整静止帧提取的参数(然而准确度做不到百分百对于后续的编码带来的效果就是毁灭的)
在不断的调试下,感觉以运动检测为基础的方案实在是不足以完成这个任务,不过追踪的潜力开发一下还是可以完成的。
其余技术介绍
就像过去一样,不让自己的时间白花,记录,同时分享。
神奇的调参
和神奇的调参一样神奇的是图片预处理的操作究竟是如何选定的。
其实这些东西的确定是可以逻辑推理出来的,但是推的多了或者说接收到的反馈多了,自然而然就会变成一件直觉
的事。
我在这里想要提及的原因是因为对这样的工作有一种感悟:有时候直觉
其实是做多了的推理
,而所谓推理
也可能是由一个个直觉
构建起来的。
两种减运算
在实现背景差值的时候,研究了一下几种图像的减法运算 的区别,稍微有点意思。
相应的,opencv对于图像的加法运算 也有不同的支持。
静止帧
一开始的静止帧检测是协会里的师傅给出的一个脚本,大概的逻辑是对比前后帧(就像没有目标检测的运动检测那样),如果连续几帧认为相似度很高的话就判断为静止,然后跳过几帧。
不过这里比对前后帧用的是SSIM(结构相似性算法)
,在结果上会更加符合人眼看到的结果而不单纯的RGB数据。
可能是由于调参的原因会有重复输出,可能通过一些参数调整可以优化到100%正确率,但没有选择这个方案还有一个很重要的原因:
坐标距离判断静止的逻辑和上面这个十分相似,但多了最关键的信息就是坐标本身。如果是上面的方案的话,我们只能找到取字板选中了哪些字,以图片或者知道这是视频中的第几帧的形式,无法把这个字母输出出来,仅靠人眼的话不仅会面临繁重的工作,更有可能在类似频繁切换大小写的地方出错。
更多追踪
在编写博客时,发现了有关追踪的更多可能性 (手搓方案):
质心跟踪器:在每一帧上作目标检测,计算前后两帧目标质心的距离,来标定相同的ID。
所谓目标检测的工作可以有多种方式来完成,可以是使用深度学习的模型,也有看到使用边缘检测的,或者SSIM然后diff也可以是一种选择,总之还是主要在关注前后两帧的差异,并且要有较好的目标检测能力(把物体从背景中分离出来)
但质心跟踪器是对于全图的运算,十分依赖准确的目标检测,对于这道题的效果,未必比得上封装好的cv给的追踪函数。
(´A`。)累趴
- Title: Plaidctf2024-ICMP | 只完成了1/15的复现
- Author: M1aoo0bin
- Created at : 2024-08-20 14:06:58
- Updated at : 2024-09-09 03:46:45
- Link: https://redefine.ohevan.com/2024/08/20/Plaidctf2024-复现/
- License: This work is licensed under CC BY-NC-SA 4.0.