You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在星轨图像中检测北天极(NCP)的像素坐标

基于OpenCV的星轨图像北天极(NCP)检测解决方案

核心思路

星轨是恒星绕NCP旋转形成的圆弧,cv::HoughCircles更适合完整圆形检测,对圆弧拟合效果较差。改用提取星轨边缘点→对每组弧点拟合圆→计算所有拟合圆的圆心均值的方案定位NCP,具体步骤如下:

具体实现步骤

1. 图像预处理

  • 将彩色图像转为灰度图:cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
  • 高斯模糊降噪,避免干扰边缘检测:cv::GaussianBlur(gray, blurred, cv::Size(5,5), 0);
  • Canny边缘检测提取星轨轮廓,可根据图像亮度调整阈值(示例:低阈值50,高阈值150):cv::Canny(blurred, edges, 50, 150);

2. 提取星轨边缘点并分组

  • 用cv::findContours提取边缘轮廓,过滤过短轮廓(星轨弧长通常较长,示例最小长度设为50像素):
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(edges.clone(), contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    std::vector<std::vector<cv::Point>> validContours;
    for (auto& cnt : contours) {
        if (cv::arcLength(cnt, false) > 50) {
            validContours.push_back(cnt);
        }
    }
    

3. 对每组轮廓拟合圆

  • 采用最小二乘法对每个有效轮廓拟合圆(适配星轨圆弧特性):
    struct Circle {
        cv::Point2f center;
        float radius;
    };
    
    std::vector<Circle> fittedCircles;
    for (auto& cnt : validContours) {
        int n = cnt.size();
        if (n < 5) continue; // 至少需要5个点拟合圆
        double sumX = 0, sumY = 0, sumX2 = 0, sumY2 = 0, sumX3 = 0, sumY3 = 0, sumXY = 0, sumX2Y = 0, sumXY2 = 0;
        for (auto& p : cnt) {
            double x = p.x, y = p.y;
            sumX += x; sumY += y;
            sumX2 += x*x; sumY2 += y*y;
            sumX3 += x*x*x; sumY3 += y*y*y;
            sumXY += x*y;
            sumX2Y += x*x*y;
            sumXY2 += x*y*y;
        }
        double C = n * sumX2 - sumX * sumX;
        double D = n * sumXY - sumX * sumY;
        double E = n * sumX3 + n * sumXY2 - sumX * (sumX2 + sumY2);
        double G = n * sumY2 - sumY * sumY;
        double H = n * sumX2Y + n * sumY3 - sumY * (sumX2 + sumY2);
        double denominator = C*G - D*D;
        if (fabs(denominator) < 1e-6) continue;
        double cx = (G*E - D*H) / denominator;
        double cy = (C*H - D*E) / denominator;
        float radius = 0;
        for (auto& p : cnt) {
            radius += sqrt(pow(p.x - cx, 2) + pow(p.y - cy, 2));
        }
        radius /= n;
        fittedCircles.push_back({cv::Point2f(cx, cy), radius});
    }
    

4. 计算NCP坐标(拟合圆圆心的均值)

  • 过滤半径异常的拟合圆,再计算剩余圆心的平均坐标:
    // 计算半径均值与标准差,过滤异常值
    std::vector<float> radii;
    for (auto& c : fittedCircles) radii.push_back(c.radius);
    float meanRadius = std::accumulate(radii.begin(), radii.end(), 0.0f) / radii.size();
    float stdDev = 0;
    for (float r : radii) stdDev += pow(r - meanRadius, 2);
    stdDev = sqrt(stdDev / radii.size());
    
    std::vector<cv::Point2f> validCenters;
    for (auto& c : fittedCircles) {
        if (fabs(c.radius - meanRadius) < 2*stdDev) { // 保留2倍标准差内的圆
            validCenters.push_back(c.center);
        }
    }
    
    // 计算平均圆心即NCP坐标
    cv::Point2f ncp(0,0);
    for (auto& p : validCenters) {
        ncp.x += p.x;
        ncp.y += p.y;
    }
    ncp.x /= validCenters.size();
    ncp.y /= validCenters.size();
    

5. 在原图标记NCP

  • 用红色圆圈标记NCP并添加文字标注:
    cv::circle(src, ncp, 10, cv::Scalar(0,0,255), 2);
    cv::putText(src, "NCP", cv::Point(ncp.x+15, ncp.y), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0,0,255), 2);
    cv::imshow("NCP Detection", src);
    cv::waitKey(0);
    

关键注意事项

  • Canny阈值需根据图像实际亮度调整,过强会丢失星轨边缘,过弱会引入噪声。
  • 轮廓过滤的长度阈值要适配星轨实际长度,避免误将噪声轮廓当成星轨。
  • 拟合圆时的异常值过滤能排除非星轨拟合结果,提升NCP定位精度。

内容的提问来源于stack exchange,提问作者Ladislav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 03:05:53