如何在 OpenCv 中从太空中探测太阳?

Posted

技术标签:

【中文标题】如何在 OpenCv 中从太空中探测太阳?【英文标题】:How to detect the Sun from the space sky in OpenCv? 【发布时间】:2011-11-21 21:49:44 【问题描述】:

我需要从太空中探测太阳。

这些是输入图像的示例:

我在形态学过滤后得到了这样的结果(open 操作两次)

这是这个处理的算法代码:

// Color to Gray
cvCvtColor(image, gray, CV_RGB2GRAY);

// color threshold
cvThreshold(gray,gray,150,255,CV_THRESH_BINARY);

// Morphologic open for 2 times
cvMorphologyEx( gray, dst, NULL, CV_SHAPE_RECT, CV_MOP_OPEN, 2);

对于这样一个简单的任务来说是不是太繁重了?以及如何找到太阳的中心?如果我找到白点,我会找到大地球的白点(第一个示例图像的左上角)

请告知我检测太阳的进一步行动。

更新 1:

尝试通过公式获取centroid的算法:x,y = M10/M00, M01/M00

CvMoments moments;
cvMoments(dst, &moments, 1);
double m00, m10, m01;

m00 = cvGetSpatialMoment(&moments, 0,0);
m10 = cvGetSpatialMoment(&moments, 1,0);
m01 = cvGetSpatialMoment(&moments, 0,1);

// calculating centroid
float centroid_x = m10/m00;
float centroid_y = m01/m00;

    cvCircle( image, 
              cvPoint(cvRound(centroid_x), cvRound(centroid_y)), 
              50, CV_RGB(125,125,0), 4, 8,0);

而地球在照片中的位置,我得到了这样的结果:

所以,质心在地球上。 :(

更新 2:

尝试cvHoughCircles:

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* circles = cvHoughCircles(dst, storage, CV_HOUGH_GRADIENT, 12, 
                                dst->width/2, 255, 100, 0, 35);

if ( circles->total > 0 ) 
    // getting first found circle
    float* circle = (float*)cvGetSeqElem( circles, 0 ); 

    // Drawing:
    // green center dot
    cvCircle( image, cvPoint(cvRound(circle[0]),cvRound(circle[1])), 
          3, CV_RGB(0,255,0), -1, 8, 0 ); 
    // wrapping red circle
    cvCircle( image, cvPoint(cvRound(circle[0]),cvRound(circle[1])), 
        cvRound(circle[2]), CV_RGB(255,0,0), 3, 8, 0 ); 

第一个例子:宾果游戏,但第二个 - 没有;(

我尝试了 cvHoughCircles() 的不同配置 - 找不到适合我的每张示例照片的配置。

更新3:

matchTemplate 方法对我有用(mevatron 的响应)。它适用于大量测试。

【问题讨论】:

【参考方案1】:

试试简单的matchTemplate 方法怎么样。我使用了这个模板图片:

而且,它检测到了我尝试的 3 个太阳图像中的 3 个:

这应该有效,因为圆(在你的情况下是太阳)是旋转不变的,并且由于你离太阳很远,它也应该大致是尺度不变的。所以,模板匹配在这里会很好地工作。

最后,这是我用来执行此操作的代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])

    /// Load image and template
    string inputName = "sun2.png";
    string outputName = "sun2_detect.png";
    Mat img   = imread( inputName, 1 );
    Mat templ = imread( "sun_templ.png", 1 );

    /// Create the result matrix
    int result_cols =  img.cols - templ.cols + 1;
    int result_rows = img.rows - templ.rows + 1;

    Mat result( result_cols, result_rows, CV_32FC1 );

    /// Do the Matching and Normalize
    matchTemplate(img, templ, result, CV_TM_CCOEFF);
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

    Point maxLoc;
    minMaxLoc(result, NULL, NULL, NULL, &maxLoc);

    rectangle(img, maxLoc, Point( maxLoc.x + templ.cols , maxLoc.y + templ.rows ), Scalar(0, 255, 0), 2);
    rectangle(result, maxLoc, Point( maxLoc.x + templ.cols , maxLoc.y + templ.rows ), Scalar(0, 255, 0), 2);

    imshow("img", img);
    imshow("result", result);

    imwrite(outputName, img);

    waitKey(0);

    return 0;

希望对您有所帮助!

【讨论】:

实际上,它起作用的原因与提到的不同。首先,在这些图像中的其他任何地方都没有类似使用的模板。此外,这更有可能比最初的形态学方法慢几倍。 确实不错 :) 但是,由于我假设宇宙飞船在我们的太阳系中,我相信可以肯定地说只有一个太阳会出现 :D 我猜如果 HUD(试点用户界面)的任何部分位于太阳之上,这将失败。除非模板匹配对匹配的好坏给出分数,否则您可以对最佳结果进行阈值处理,并且可能会遇到一些障碍。【参考方案2】:

颜色分割方法

对图像进行颜色分割以识别黑色背景上的对象。您可以根据太阳的面积来识别太阳(鉴于这可以唯一地识别它,因此图像之间的差异不会很大)。 更复杂的方法可以计算图像时刻,例如胡瞬间的对象。有关这些功能,请参阅 this page。

使用您选择的分类算法对找到的对象进行实际分类。最简单的方法是手动指定阈值,resp。最终适用于所有(大多数)对象/图像组合的值范围。

您可以根据原始时刻计算实际位置,如for the circular sun the position is equal to the center of mass

Centroid: x, y  =  M10/M00, M01/M00 

边缘地图法

另一个选项是边缘图的圆形霍夫变换,这将有望返回一些候选圆(按位置和半径)。您可以根据您期望的半径选择太阳圆(如果幸运的话,最多有一个)。

【讨论】:

我认为图像时刻是行不通的。如果屏幕上只有太阳,那么太阳的中心是Centroid 点。但是,如果地球占据了屏幕的某个部分(如左上图 #1 所示),则该部分比太阳“重”,并且质心将被移动。我已经尝试过使用 CircleHough,但它不适用于我的所有示例照片......【参考方案3】:

对代码的一个简单补充是根据对象的大小过滤掉对象。如果您总是期望地球比太阳大得多,或者太阳在每张图片中的面积几乎相同,您可以按面积过滤。

试试Blob detector 来完成这个任务。

请注意,应用形态开/关而不是简单的侵蚀或扩张可能会更好,因此您的太阳在处理前后将具有几乎相同的面积。

【讨论】:

thanx,我认为这对我有用,但我的 openCv 版本没有 blob 检测器,而且我是 C++ 新手(我无法编译最新版本) 从 sourceforge sourceforge.net/projects/opencvlibrary 获取最新的 OpenCV 并且使用它就像增量运算符一样简单 :) 它已经编译好了。而且..您是否添加了使用命名空间简历?你怎么没有斑点检测器?

以上是关于如何在 OpenCv 中从太空中探测太阳?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 OpenCV 2 中从图像中获取通道数?

如何在 OpenCV c++ 中从图像中裁剪特定的矩形部分(ROI)

openCV - 如何在 Windows 8.1 中从为 github 下载的用于 python 的 .zip 文件重建?

在 OpenCV、Java 中从 Mat 中减去 double

天源财富:“星际访客”和太阳系彗星中探测到镍

因一个计算机故障而“停工”!观测宇宙 30 多年的哈勃太空望远镜还能坚持多久?...