Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect the Sun from the space sky in OpenCv?

I need to detect the Sun from the space sky.

These are examples of the input images:

I've got such results after Morphologic filtering ( open operation for twice )

Here's the algorithm code of this processing:

// 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);

Isn't it too heavy processing for such a simple task? And how to find the center of the Sun? If I find white points, than I'll find white points of big Earth ( left top corner on first example image )

Please advise me please my further action to detect the Sun.

UPDATE 1:

Trying algorithm of getting centroid by formula : {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);

And where Earth is in the photo, I got such a result:

So, centroid is on the Earth. :(

UPDATE 2:

Trying 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 ); 
}

First example: bingo, but the second - no ;(

I've tried different configuration of cvHoughCircles() - couldn't find configuration to fit every my example photo.

UPDATE3:

matchTemplate approach worked for me ( response of mevatron ). It worked with big number of tests.

like image 694
Larry Cinnabar Avatar asked Nov 21 '11 21:11

Larry Cinnabar


3 Answers

How about trying a simple matchTemplate approach. I used this template image:
enter image description here

And, it detected the 3 out of 3 of the sun images I tried: enter image description hereenter image description hereenter image description here

This should work due to the fact that circles (in your case the sun) are rotationally invariant, and since you are so far away from the sun it should be roughly scale invariant as well. So, template matching will work quite nicely here.

Finally, here is the code that I used to do this:

#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;
}

Hope you find that helpful!

like image 129
mevatron Avatar answered Nov 12 '22 22:11

mevatron


Color Segmentation Approach

Do a color segmentation on the images to identify objects on the black background. You may identify the sun according to its area (given this uniquely identifies it, resp. don't varies largely accross images). A more sophisticated approach could compute image moments, e.g. hu moments of the objects. See this page for these features.

Use a classification algorithm of your choice to do the actual classification of the objects found. The most simple approach is to manually specify thresholds, resp. value ranges that turn out to work for all(most) of your object/image combinations.

You may compute the actual position from the raw moments, as for the circular sun the position is equal to the center of mass

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

Edge Map Approach

Another option would be a circle hough transformation of the edge map, this will hopefully return some candidate circles (by position and radius). You may select the sun-circle according to the radius you expect (if you are lucky there is at most one).

like image 2
moooeeeep Avatar answered Nov 12 '22 22:11

moooeeeep


A simple addition to your code is to filter out objects based on their size. If you always expect the earth to be much bigger than the sun, or the sun to have almost the same area in each picture, you can filter it by area.

Try Blob detector for this task.

And note that it may be good to apply a morphological opening/closing instead of simple erode or dilate, so your sun will have almost the same area before and after processing.

like image 2
Sam Avatar answered Nov 12 '22 23:11

Sam