第四章 星点提取算法:从图像到质心的完整链路
星敏感器这东西,说白了就是卫星的「眼睛」。它拍到的星空图像,我们得从中找到星星的位置。这个过程的专业叫法,就是星点提取。
我个人习惯把星点提取拆成三步走:图像预处理 → 连通域分析 → 质心定位。每一步都有坑,我踩过不少,今天一并讲清楚。
4.1 图像预处理:去噪与背景抑制
星敏感器拍到的原始图像,噪声其实挺多的。CMOS传感器的暗电流噪声、读出噪声,还有空间高能粒子带来的椒盐噪声……嗯,这些都会干扰星点提取。
4.1.1 去噪滤波
我常用的去噪方法有两种:
- 中值滤波:对椒盐噪声特别有效。窗口大小我一般选3×3或5×5,太大容易把星点抹平。
- 高斯滤波:适合处理高斯噪声。但要注意,高斯滤波会模糊星点边缘,影响后续质心精度。
这里有个经验:先中值滤波,再高斯滤波。我在项目中试过很多组合,这个顺序效果最稳。
核心原则:去噪不能过度。星点本身可能只有几个像素大小,滤波窗口太大,星点就没了。
4.1.2 背景抑制
星空背景不是均匀的。地气光、杂散光、甚至卫星本体反射的光,都会让背景有起伏。背景抑制的目的,就是把这种起伏去掉,只留下星点信号。
我常用的方法是背景估计与减除:
- 将图像分成若干小块(比如32×32像素)
- 统计每个块的灰度均值或中值
- 用双线性插值得到全图背景估计
- 原图减去背景估计
为什么用中值而不是均值?因为星点本身是亮斑,如果块内有星点,均值会被拉高,导致背景估计偏大。中值更鲁棒。
避坑指南:我曾经在强杂散光环境下,背景估计出现「块效应」——块与块之间有明显边界。后来改用重叠分块+加权插值,问题就解决了。
4.2 连通域分析:找到星点候选区域
预处理之后,图像里亮的地方就是星点候选。但怎么把每个星点单独拎出来?这就需要连通域分析。
4.2.1 二值化
先要把灰度图变成二值图。阈值怎么选?
- 固定阈值:简单,但适应性差。不同星等、不同曝光时间,阈值都得调。
- 自适应阈值:根据局部灰度统计动态计算。我常用的是「全局均值 + 3倍标准差」作为阈值。
说实话,阈值选择是星点提取里最玄学的部分。我一般会预留一个可调参数,在轨测试时根据实际图像微调。
4.2.2 连通域标记
二值图里,相邻的亮像素组成一个连通域。常用的算法有:
- 两遍扫描法:第一遍给每个像素临时标号,记录等价关系;第二遍合并等价标号。效率高,适合嵌入式实现。
- 种子填充法:递归或栈实现,简单但容易栈溢出。我一般不推荐在星上使用。
连通域分析后,我们会得到每个星点的像素集合。接下来就可以算质心了。
注意:连通域面积太小的(比如小于3像素)可能是噪声,直接丢弃。面积太大的(比如超过100像素)可能是热像素或卫星本体反射,也要排除。
4.3 质心定位:从像素到亚像素精度
星敏感器的精度要求通常是角秒级。如果只取像素中心,精度最多到像素级(比如1/2像素)。所以我们需要亚像素定位。
我常用的方法有两种:灰度重心法和高斯曲面拟合法。
4.3.1 灰度重心法
这个方法简单粗暴:把星点区域的灰度值当作「质量」,求加权平均位置。
// 灰度重心法计算质心
// (x0, y0) 为星点区域左上角坐标
// w, h 为区域宽高
// img 为灰度图像数据
float sum_x = 0.0f, sum_y = 0.0f, sum_g = 0.0f;
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
float g = (float)img[(y0 + j) * width + (x0 + i)];
sum_x += (x0 + i) * g;
sum_y += (y0 + j) * g;
sum_g += g;
}
}
float cx = sum_x / sum_g;
float cy = sum_y / sum_g;
优点:计算快,适合嵌入式实时处理。
缺点:对噪声敏感,星点不对称时精度下降。
4.3.2 高斯曲面拟合法
星点的能量分布理论上符合高斯函数。我们可以用二维高斯模型去拟合星点区域,得到更精确的中心位置。
二维高斯模型:
G(x, y) = A * exp(-((x - x0)^2 / (2 * σx^2) + (y - y0)^2 / (2 * σy^2))) + B
其中:
- A:星点峰值强度
- (x0, y0):质心位置(我们要的就是这个)
- σx, σy:高斯宽度参数
- B:背景偏移
拟合方法我常用最小二乘法。具体实现时,可以先取对数,把非线性问题转化为线性问题,再用最小二乘求解。
精度对比:灰度重心法一般能达到0.1~0.2像素精度,高斯拟合法可以到0.01~0.05像素。但高斯拟合法计算量大约是重心法的10倍。
我在项目中遇到过这样的情况:星点太暗(信噪比低),高斯拟合会发散。这时候我会退回到灰度重心法,或者先做一次重心法得到初值,再用高斯拟合做一次精化。
4.4 本章知识体系
下面这张图,是我自己总结的星点提取完整流程。你可以把它当作一个检查清单:
4.5 工程实现要点
最后,我总结几个工程实现时的关键点:
| 环节 | 常见问题 | 我的建议 |
|---|---|---|
| 去噪 | 滤波过度导致星点丢失 | 先做星点检测,再局部滤波 |
| 背景抑制 | 块效应、背景估计不准 | 用重叠分块+中值统计 |
| 连通域 | 星点粘连、噪声误检 | 加形态学开运算分离粘连 |
| 质心定位 | 信噪比低时精度下降 | 重心法粗定位+高斯拟合精化 |
个人经验:星点提取的精度,70%取决于预处理,30%取决于质心算法。把预处理做好了,后面就轻松了。我曾经在一个项目里花了两周调质心算法,精度死活上不去。后来发现是背景抑制没做好,改完之后精度直接翻倍。
嗯,星点提取这部分就讲到这里。下一章我们会聊星图识别——怎么从一堆星点坐标里认出这是哪片星空。
公众号:蓝海资料掘金营,微信deep3321