如何在 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 c++ 中从图像中裁剪特定的矩形部分(ROI)
openCV - 如何在 Windows 8.1 中从为 github 下载的用于 python 的 .zip 文件重建?