一次月食后期折腾:RAW、计算机视觉和图形学
月食拍完以后,我本来以为后期就是“把视频拖进软件里调一下”。结果打开原始素材一看:画面灰白、月亮乱飘、亮度一跳一跳,和想象中的成片完全不是一回事。
最后为了把它做成一段能看的延时,我搭了一条小流水线:RAW 拆帧、Debayer、Lightroom 拉可见性、OpenCV 稳定月球、人工确认问题帧,再只对月面做光度平滑。这篇就记录一下这段素材是怎么被救回来的。
先看看素材有多麻烦
素材来自 ZWO Seestar S50 拍的一段月食序列,原始文件名是 2025-09-08-001651-Lunar-timelapse-RAW.avi。文件名里的时间是北京时间 2025-09-08 00:16:51,对应参数里的 DATE-OBS = 2025-09-07T16:16:51.933371 UTC。
这段素材的几个关键信息是:画幅 1080x1920,格式 RAW8,Bayer 标记为 GR,白平衡参数是 R = 110、B = 187,总共 1390 帧。听起来还挺规整,但实际处理起来一点都不省心。
拍摄时也埋了不少坑。月食过程中亮度跨度太大,不能用一组曝光参数撑完全程;自动跟踪会慢慢漂,实际还要手动修构图;到 1004-1025 这段,月亮已经接近新月形态,还带着很强的光晕,画面里最亮的地方和月球真正的几何圆心根本不是一回事。
所以这个任务不是简单的“防抖”。真正要做的是先把 RAW 变成能解释的图像,再在亮度、形态都剧烈变化的情况下,尽量稳定同一个月球。
大致流程最后长这样:
1 | RAW AVI |
本地脚本 raw_avi_to_dng.py 先把 AVI 里的 RAW 帧拆出来,写成 FITS,并把观测时间、目标、经纬度、温度、白平衡和 Bayer 信息塞进 header。之后 Siril 把 fits_frames 合成 mao.fit / mao.seq 序列,再导出 tiff/moon_00001.tif 这种 16-bit TIFF。到这里,素材才算真正进入“可以认真处理”的阶段。
这条链路里,大部分 Python / OpenCV 脚本、诊断图、统计 CSV、曲线图和后续报告整理,都是这次让 Codex 边看结果边改出来的。我主要做两件事:检查生成的视频到底稳不稳,以及在异常帧上判断哪个候选圆心更可信。换句话说,人负责验收和拍板,Codex 负责把那些又长又碎的工程步骤跑起来。
RAW AVI 为什么是灰白的
如果直接播放这段 RAW.avi,画面会灰、会淡,有些帧看起来甚至像没有颜色。不是月食没有颜色,而是播放器看到的只是单通道传感器读数。
RAW8 Bayer 帧里,每个像素只记录一个颜色滤镜位置下的亮度。完整 RGB 颜色要靠 Debayer 从周围像素插值得到。再加上传感器读数接近线性数据,没有经过黑场、白平衡、伽马、曲线、局部对比度和饱和度处理,直接看当然很惨。
下面这张图比较直观。左边是 RAW AVI 直读灰度效果,中间是简单 Debayer 预览,右边是 Lightroom 导出后的结果。

Debayer 之后颜色是出来了,但这还不是最终观感。中间列仍然有色偏、背景偏色和动态范围问题。真正让画面变得可看的是后面的白平衡、黑场、曲线、局部对比度、饱和度,以及对不同月食阶段的人工判断。
这也是我后面一直想保留诊断图、CSV 和中间结果的原因。只要每一步都有输入、输出和限制条件,结果就不只是“修得好看”,而是可以回头检查、复现和继续改的东西。
下面这张 Lightroom 输出关键帧可以看到整段序列的麻烦:亮月面、强亮边、红月、暗月面和出食月牙全都混在同一个视频里。

让月球站稳
几何稳定最自然的想法是用 OpenCV 找圆。月球在一小段延时里视直径变化很小,可以近似看成固定半径圆。只要每帧找到圆心,再把圆心平移到统一位置,视频就应该稳了。
这个想法在边界清楚的帧上很好用,但月食非常不讲武德。
明亮阶段,光晕和亮边会把算法吸过去;全食阶段,月面太暗,圆弧证据又不够;有些片段不是每帧都乱跳,而是先跳到一个偏移位置,然后在那个错误位置附近继续“稳定”。这种情况只靠相邻帧平滑救不回来,必须回到绝对的月球几何圆心。
为了不把原有脚本搅乱,我单独建了一个 stabilization_lab,直接以 Lightroom 导出的 lr_out 为输入:
1 | lr_out |
这里最后做了两个取舍。
第一个是固定半径。估计出的半径大约是 412.84 px。后面每帧只估圆心,不让算法把亮边、暗边或光晕误解释成“月球忽大忽小”。
第二个是把相邻帧修正降级成诊断量。相位相关一开始看起来能减少局部抖动,但它也可能把“跳一下然后稳定”的问题传播下去。最终合成时还是以几何圆心为主,不让相邻帧对齐变成新的真值。
这是早期稳定关键帧预览,用来检查不同亮度阶段下月球有没有居中。

算法翻车的地方
人工 review 后,问题主要集中在 385、459-470、541、661-667、675-680、799、838、875-900、1011、1068 这些帧或区间。它们都处在偏暗、亮度突变、光晕、亮边或新月形态附近,但翻车原因不完全一样。
我没有只看最终视频猜哪里错,而是生成了 review windows,把问题帧放回局部时间窗口里看。这样能分清楚两种情况:有的是单帧检测突然跑偏,有的是某一帧跳了以后,后续帧在偏移位置附近继续稳定。

进一步的诊断图会把多种候选圆心画在同一张图上。黄色是 Hough,红色是当前流程结果,绿色是 radial,紫色是 local。它们一分歧,问题就很明显了:不是完全没有正确答案,而是自动流程不知道该信谁。

1068 这种帧尤其典型。画面里可见部分像新月,亮区中心和整个月球的几何圆心差得很远。如果算法追着最亮区域跑,稳定出来的视频就会稳定在错误对象上。

人工介入,但别手填坐标
最后我没有逐帧手动输入圆心坐标,那样太痛苦,也不好复现。更稳的办法是:程序先给出几个候选,人只选“这一帧该相信哪种方法”。
每个问题帧都会被整理成一行,列出 hough、ring、current、radial、local 等候选,并把固定半径圆弧画出来。人工只需要在表格里填一个方法名。

这次检查下来,所有问题帧里 hough 都能给出最贴合真实圆弧的候选,而 current 往往已经发生偏移。所以 problem_method_choices.csv 全部填成 hough,再由脚本转换成显式坐标覆盖文件 center_xy_overrides.csv。
最后的覆盖文件大概是这样:
1 | enabled,mode,start_frame,end_frame,x,y,method,reason |
全量合成时把它喂进去:
1 | python stabilize_from_lr_out.py --all --video --phase-mode none --overrides center_xy_overrides.csv |
最终输出 1390 帧,其中 57 帧用了 manual_xy 覆盖,其余帧仍然走自动流程。也就是说,人只在最难判断的地方插了一脚,没有把整条流水线变成手工活。
下面这张图来自最终视频抽帧。这里要看的是几何圆盘是否稳定,不是可见亮区中心是否一致。像 1011、1068 这种帧,亮区本来就不是整个月球。

再处理亮度闪烁
位置稳定之后,另一个问题就更明显了:相邻帧之间还是会忽明忽暗。这不是圆心问题,而是拍摄时手动调整曝光、Lightroom 批量参数、以及月食本身亮度变化叠在一起造成的。视频播放时,它就表现成闪烁。
这里不能对整张画面做自动曝光。月食视频大部分区域都是黑色天空,如果把全图拿来算亮度,算法很容易把背景噪声也拉起来,结果月亮没稳多少,天空先开始闪。
所以我又单独建了 photometry_lab,只处理稳定后视频里的月面光度:
1 | stabilization_lab/out/stabilized_from_lr_out.mp4 |
做法是两遍。第一遍读稳定视频,用固定圆心和固定半径生成月面统计区域,只在月面内部统计中位亮度、对比度和饱和度。第二遍把这些曲线做滑动窗口平滑,再通过羽化圆形 mask 写回画面。
这个 mask 很重要。月面内部完整调整,靠近边缘逐渐衰减,圆盘外不调整;同时对近黑像素加保护,避免把天空背景抬亮。

第一版参数比较保守:亮度增益限制在 0.88-1.14,对比度缩放限制在 0.88-1.12,饱和度缩放限制在 0.92-1.10。目标不是重新调色,而是压住相邻帧之间不自然的尖峰,同时保留月食整体变暗、变红、再出食变亮的趋势。
曲线图里,灰色是原始测量值,蓝色是平滑并经过幅度限制后的目标值。大趋势还在,局部尖峰被压下去了。

修正最明显的片段集中在亮边和曝光变化剧烈的阶段,比如 315-409 附近。下面是自动挑出来的强修正帧,左侧是平滑前,右侧是平滑后。

从网页对话到 Codex
其实这段素材是 2025 年 9 月拍的。当时我也试过用 ChatGPT 网页对话生成 Python 脚本来处理,确实能写出能跑的代码,也能做一些基础拆帧、检测和合成。但体验很拧巴:我需要自己运行脚本、截图、描述哪里不对、再把报错或结果贴回去。中间反馈链路很长,而且网页对话本身看不到当前目录、看不到生成的视频,也不知道哪张诊断图已经不对劲。
这就导致一个问题:模型在“写代码”这一步还可以,但它没有实际感知处理结果的能力。它不知道视频稳没稳,不知道某一批问题帧是不是更糟了,也不会主动发现输出目录里多了一堆没用的中间文件。最后脚本虽然能跑,结果却很容易停在“看起来像是做了处理,但成片还是不太对”的状态。
这次换成 Codex 之后舒服很多。它可以直接读项目、改脚本、跑命令、看生成的诊断图和统计结果,再根据当前实际情况继续调整方案。比如它会发现相邻帧相位相关可能把偏移传播下去,于是建议把它降级成诊断量;也会看到困难帧里 Hough 候选反而更可靠,于是把人工确认流程改成“选择候选方法”,而不是让我手填坐标。
最后
这次最大的感受是,月食后期不能只靠一个“智能稳定”或“一键增强”。RAW 先要被正确解码,颜色和亮度要被合理映射;几何稳定不能追着最亮区域跑,而要尽量回到月球这个圆盘本身;光度平滑也不能对整张图乱做自动曝光,而要限制在月面区域内。
计算机视觉在这里不是魔法,它只是帮我把“月球在哪里”“哪几帧不可信”“哪个候选更像真实圆弧”这些问题画出来。图形学和图像处理也不是最后导出 MP4 才出现,它们从 Debayer、白平衡、曲线、mask、羽化到视频编码,一直贯穿整条链路。Codex 的价值也不只是帮我写几段 OpenCV,而是能把这些步骤连起来,一边看实际输出,一边把流程修到能用。
最后得到的不是一张“修出来”的月亮,而是一条能解释的流程:原始 RAW 怎么变成可看的图,算法哪里能自动处理,哪里需要人确认,亮度闪烁又是怎么被限制在月面内部修掉的。对于月食这种亮度和形态都在剧烈变化的素材,这种笨一点、但有记录的流程,比盲目追求全自动更让我放心。
一次月食后期折腾:RAW、计算机视觉和图形学
