Как обнаружить Солнце из космического неба в OpenCv?

Мне нужно обнаружить Солнце от космического неба.

Это примеры входных изображений:

b2gUH.pngA6Mvf.png

У меня есть такие результаты после морфологической фильтрации (open операция в два раза)

Nquaz.png35cFH.png

Здесь код алгоритма этой обработки:

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

И где Земля находится на фотографии, я получил такой результат: c2Soq.png

Итак, центроид находится на Земле.: (

ОБНОВЛЕНИЕ 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 ); 
}

cd68M.pngY5zUJ.png

Первый пример: bingo, а второй - no; (

Я пробовал различную конфигурацию cvHoughCircles() - не смог найти конфигурацию, соответствующую каждой моей примерной фотографии.

Update3:

Подход

matchTemplate работал у меня (ответ mevatron). Он работал с большим количеством тестов.

Ответ 1

Как пробовать простой подход matchTemplate. Я использовал этот шаблон изображения:
enter image description here

И он обнаружил 3 из 3 солнечных изображений, которые я пробовал: enter image description hereenter image description hereenter image description here

Это должно работать из-за того, что круги (в вашем случае Солнце) являются вращательно-инвариантными, и поскольку вы так далеко от солнца, это должно быть также масштабно-инвариантным. Таким образом, сопоставление шаблонов будет работать здесь довольно хорошо.

Наконец, вот код, который я использовал для этого:

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

Надеюсь, вы сочтете это полезным!

Ответ 2

Сегментация цвета

Сделайте сегментирование цвета на изображениях, чтобы идентифицировать объекты на черном фоне. Вы можете идентифицировать солнце в соответствии с его областью (при условии, что это однозначно идентифицирует его, соответственно, не изменяется в значительной степени по сравнению с изображениями). Более сложный подход может вычислять моменты изображения, например. hu моменты объектов. Для этих функций см. эту страницу.

Используйте алгоритм классификации по вашему выбору для фактической классификации найденных объектов. Самый простой подход - указать вручную пороговые значения, соответственно. диапазоны значений, которые работают для всех (большинства) ваших комбинаций объектов и изображений.

Вы можете вычислить фактическое положение из необработанных моментов, так как для кругового солнца позиция равна центру масс

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

Подход к граничной карте

Другим вариантом будет преобразование окружности каркаса, это, мы надеемся, вернет некоторые круги кандидатов (по положению и радиусу). Вы можете выбрать круг солнца в соответствии с радиусом, который вы ожидаете (если вам повезет, что не более одного).

Ответ 3

Простое дополнение к вашему коду - отфильтровывать объекты на основе их размера. Если вы всегда ожидаете, что земля будет намного больше, чем солнце, или солнце будет иметь почти одну и ту же площадь на каждом снимке, вы можете отфильтровать его по области.

Попробуйте детектор Blob для этой задачи.

И обратите внимание, что может быть полезно применять морфологическое открытие/закрытие вместо простого эрозии или расширения, поэтому ваше солнце будет иметь почти ту же площадь до и после обработки.